#!/usr/bin/env python3
# Python rewrite of testsuite/alt-dest.test.
#
# Exercise rsync's --compare-dest, --copy-dest and --link-dest
# alternative-destination options, both locally and across the lsh.sh
# remote-shell stand-in. Also covers the tmpfile path in copy_file() by
# pointing --copy-dest at a directory holding a same-name candidate.

import os
import shutil
import time

from rsyncfns import (
    CHKDIR, FROMDIR, RSYNC, RSYNC_PEER, SCRATCHDIR, SRCDIR, TMPDIR, TODIR,
    checkit, hands_setup, rmtree, run_rsync, test_fail, rsync_path_arg, rsh_cmd,
)


alt1dir = TMPDIR / 'alt1'
alt2dir = TMPDIR / 'alt2'
alt3dir = TMPDIR / 'alt3'

SSH = rsh_cmd()

hands_setup()

# Seed alt1 and alt2 with disjoint single-file subtrees of fromdir.
run_rsync('-av', '--include=text', '--include=*/', '--exclude=*',
          f'{FROMDIR}/', f'{alt1dir}/')
run_rsync('-av', '--include=etc-ltr-list', '--include=*/', '--exclude=*',
          f'{FROMDIR}/', f'{alt2dir}/')

# Create a side dir with one identically-named candidate so copy_file()'s
# tmpfile path gets exercised.
(FROMDIR / 'likely').write_text("This is a test file\n")
alt3dir.mkdir()
(alt3dir / 'likely').write_text("This is a test file\n")

time.sleep(1)
os.utime(FROMDIR / 'dir' / 'text')
os.utime(FROMDIR / 'likely')

# chkdir: what a vanilla copy would produce, minus /text and etc-ltr-list.
run_rsync('-av', '--exclude=/text', '--exclude=etc-ltr-list',
          f'{FROMDIR}/', f'{CHKDIR}/')

# Stacked --compare-dest: dest grows just the deltas alt1+alt2 don't have.
checkit(['-avv', '--no-whole-file',
         f'--compare-dest={alt1dir}', f'--compare-dest={alt2dir}',
         f'{FROMDIR}/', f'{TODIR}/'], CHKDIR, TODIR)

rmtree(TODIR)
# Stacked --copy-dest: dest gets full copy because content can be hardlinked
# from the alt dirs where available.
checkit(['-avv', '--no-whole-file',
         f'--copy-dest={alt1dir}', f'--copy-dest={alt2dir}',
         f'{FROMDIR}/', f'{TODIR}/'], FROMDIR, TODIR)

# Test that copy_file() works correctly with tmpfiles. Combine each of
# {direct, --inplace} with each of {local, remote-source, remote-dest}.
for maybe_inplace in ([], ['--inplace']):
    rmtree(TODIR)
    checkit(['-av', *maybe_inplace, f'--copy-dest={alt3dir}',
             f'{FROMDIR}/', f'{TODIR}/'], FROMDIR, TODIR)
    # --copy-dest must COPY the unchanged candidate, not hard-link it: the
    # result is a distinct inode from the alt-dir source (this is the property
    # that distinguishes --copy-dest from --link-dest, which checkit's tree
    # comparison alone does not capture).
    if os.stat(TODIR / 'likely').st_ino == os.stat(alt3dir / 'likely').st_ino:
        test_fail(f"--copy-dest{' --inplace' if maybe_inplace else ''} "
                  "hard-linked 'likely' instead of copying it")

    for srchost in ('', 'localhost:'):
        desthost = 'localhost:' if not srchost else ''
        rmtree(TODIR)
        checkit(['-ave', SSH, f'--rsync-path={rsync_path_arg()}', *maybe_inplace,
                 f'--copy-dest={alt3dir}',
                 f'{srchost}{FROMDIR}/', f'{desthost}{TODIR}/'],
                FROMDIR, TODIR)
