#!/usr/bin/env python
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-
#
# This file is part of Déjà Dup.
# For copyright information, see AUTHORS.
#
# Déjà Dup is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Déjà Dup is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Déjà Dup.  If not, see <http://www.gnu.org/licenses/>.

# Test whether we correctly handle symlinks

import sys
import os
sys.path.insert(0, sys.path[0]+'/..')
import base

# symlinks are expanded at build time from a tarball, so look for them in
# the builddir, not the default of srcdir
if 'builddir' in os.environ:
  builddir = os.environ['builddir']
else:
  builddir = '.'
datadir = os.path.join(builddir, 'data', 'symlink')

def direct():
  restoredir = base.get_temp_name('restore')
  base.setup()
  base.backup_simple(backend='file', includes=['%s/one' % datadir], add_srcdir=False)
  base.restore_simple(restoredir)
  root = os.path.join(restoredir, os.path.abspath('%s/one' % datadir)[1:])
  assert os.path.islink(root), root
  assert os.path.exists(root), root

def subdir():
  restoredir = base.get_temp_name('restore')
  base.setup()
  base.backup_simple(backend='file', includes=['%s/one/two/fourreal' % datadir], add_srcdir=False)
  base.restore_simple(restoredir)
  root = os.path.join(restoredir, os.path.abspath(datadir)[1:])
  assert os.path.islink(root+'/one')
  assert os.path.exists(root+'/one')
  assert os.path.islink(root+'/one/two')
  assert os.path.exists(root+'/one/two')
  assert not os.path.exists(root+'/one/two/three')
  assert not os.path.exists(root+'/onereal/tworeal/threereal')
  assert base.file_equals(root+'/onereal/tworeal/fourreal/four.txt', 'four\n')
  assert base.file_equals(root+'/one/two/fourreal/four.txt', 'four\n')

def exclude():
  restoredir = base.get_temp_name('restore')
  base.setup()
  base.backup_simple(backend='file',
                     includes=[datadir],
                     excludes=['%s/one/two/fourreal' % datadir], add_srcdir=False)
  base.restore_simple(restoredir)
  root = os.path.join(restoredir, os.path.abspath(datadir)[1:])
  assert os.path.islink(root+'/one')
  assert os.path.exists(root+'/one')
  assert os.path.islink(root+'/one/two')
  assert os.path.exists(root+'/one/two')
  assert os.path.islink(root+'/one/two/three')
  assert os.path.exists(root+'/one/two/three')
  assert base.file_equals(root+'/onereal/tworeal/threereal', 'three\n')
  assert not os.path.exists(root+'/onereal/tworeal/fourreal')

def exclude2():
  # non-matching prefixes but they still point to same data
  restoredir = base.get_temp_name('restore')
  base.setup()
  base.backup_simple(backend='file',
                     includes=['%s/one/tworeal' % datadir],
                     excludes=['%s/onereal/tworeal/fourreal' % datadir], add_srcdir=False)
  base.restore_simple(restoredir)
  root = os.path.join(restoredir, os.path.abspath(datadir)[1:])
  assert os.path.islink(root+'/one')
  assert os.path.exists(root+'/one')
  assert not os.path.islink(root+'/one/two')
  assert not os.path.exists(root+'/one/two')
  assert not os.path.islink(root+'/onereal/tworeal')
  assert os.path.exists(root+'/onereal/tworeal')
  assert os.path.islink(root+'/onereal/tworeal/three')
  assert os.path.exists(root+'/onereal/tworeal/three')
  assert base.file_equals(root+'/onereal/tworeal/threereal', 'three\n')
  assert not os.path.islink(root+'/onereal/tworeal/fourreal')
  assert not os.path.exists(root+'/onereal/tworeal/fourreal')

def recursive():
  restoredir = base.get_temp_name('restore')
  base.setup()
  base.backup_simple(backend='file',
                     includes=['%s/tree' % datadir],
                     excludes=['%s/tree/sub/symtotree' % datadir], add_srcdir=False)
  base.restore_simple(restoredir)
  root = os.path.join(restoredir, os.path.abspath(datadir)[1:])
  assert not os.path.islink(root+'/tree')
  assert os.path.exists(root+'/tree')
  assert not os.path.islink(root+'/tree/sub')
  assert os.path.exists(root+'/tree/sub')
  assert not os.path.islink(root+'/tree/sub/symtotree')
  assert not os.path.exists(root+'/tree/sub/symtotree')

def trickshot():
  # Normally, DD will sort includes and excludes from most to least specific
  # to satisfy duplicity.  But these symlinks make that hard.
  restoredir = base.get_temp_name('restore')
  base.setup()
  base.backup_simple(backend='file',
                     includes=['%s/x' % datadir, '%s/x/y' % datadir],
                     excludes=['%s/a/b/c' % datadir], add_srcdir=False)
  base.restore_simple(restoredir)
  root = os.path.join(restoredir, os.path.abspath(datadir)[1:])
  assert os.path.islink(root+'/x')
  assert os.path.exists(root+'/x')
  assert os.path.islink(root+'/x/y')
  assert os.path.exists(root+'/x/y')
  assert not os.path.islink(root+'/a')
  assert os.path.exists(root+'/a')
  assert not os.path.islink(root+'/a/b')
  assert os.path.exists(root+'/a/b')
  assert not os.path.islink(root+'/a/b/c')
  assert os.path.exists(root+'/a/b/c')
  assert not os.path.islink(root+'/a/b/c/c.txt')
  assert not os.path.exists(root+'/a/b/c/c.txt')
  assert not os.path.islink(root+'/a/b/c/d')
  assert os.path.exists(root+'/a/b/c/d')
  assert os.path.islink(root+'/a/b/c/d/y')
  assert os.path.exists(root+'/a/b/c/d/y')

def loop():
  # Just make sure DD doesn't go off the rails
  restoredir = base.get_temp_name('restore')
  base.setup()
  base.backup_simple(backend='file', includes=['%s/loop' % datadir], add_srcdir=False)
  base.restore_simple(restoredir)
  root = os.path.join(restoredir, os.path.abspath(datadir)[1:])
  assert os.path.islink(root+'/loop')
  assert not os.path.exists(root+'/loop')

def follow():
  restoredir = base.get_temp_name('restore')
  base.setup()
  base.backup_simple(backend='file', includes=['%s/follow/follow' % datadir], add_srcdir=False)
  base.restore_simple(restoredir)
  root = os.path.join(restoredir, os.path.abspath(datadir)[1:])
  assert not os.path.islink(root+'/follow')
  assert os.path.exists(root+'/follow')
  assert os.path.islink(root+'/follow/follow')
  assert os.path.exists(root+'/follow/follow')
  assert os.path.islink(root+'/follow/me')
  assert os.path.exists(root+'/follow/me')
  assert not os.path.islink(root+'/follow/here')
  assert os.path.exists(root+'/follow/here')
  assert not os.path.islink(root+'/follow/here/extra')
  assert os.path.exists(root+'/follow/here/extra')
  assert base.file_equals(root+'/follow/here/extra', 'extra\n')
  assert not os.path.islink(root+'/follow/here/sub')
  assert os.path.exists(root+'/follow/here/sub')
  assert not os.path.islink(root+'/follow/here/sub/pot.of')
  assert os.path.exists(root+'/follow/here/sub/pot.of')
  assert base.file_equals(root+'/follow/here/sub/pot.of', 'gold\n')

def follow_dir():
  restoredir = base.get_temp_name('restore')
  base.setup()
  base.backup_simple(backend='file', includes=['%s/follow/follow/sub' % datadir], add_srcdir=False)
  base.restore_simple(restoredir)
  root = os.path.join(restoredir, os.path.abspath(datadir)[1:])
  assert not os.path.islink(root+'/follow')
  assert os.path.exists(root+'/follow')
  assert os.path.islink(root+'/follow/follow')
  assert os.path.exists(root+'/follow/follow')
  assert os.path.islink(root+'/follow/me')
  assert os.path.exists(root+'/follow/me')
  assert not os.path.islink(root+'/follow/here')
  assert os.path.exists(root+'/follow/here')
  assert not os.path.islink(root+'/follow/here/extra')
  assert not os.path.exists(root+'/follow/here/extra')
  assert not os.path.islink(root+'/follow/here/sub')
  assert os.path.exists(root+'/follow/here/sub')
  assert not os.path.islink(root+'/follow/here/sub/pot.of')
  assert os.path.exists(root+'/follow/here/sub/pot.of')
  assert base.file_equals(root+'/follow/here/sub/pot.of', 'gold\n')

base.run(direct)
base.run(subdir)
base.run(exclude)
base.run(exclude2)
base.run(recursive)
base.run(trickshot)
base.run(loop)
base.run(follow)
base.run(follow_dir)
