def test_cant_overwrite_file_with_symlink(): if ub.WIN32: # Can't distinguish this case on windows pytest.skip() dpath = ub.ensure_app_cache_dir('ubelt', 'test_cant_overwrite_file_with_symlink') ub.delete(dpath, verbose=2) ub.ensuredir(dpath, verbose=2) happy_fpath = join(dpath, 'happy_fpath.txt') happy_flink = join(dpath, 'happy_flink.txt') for verbose in [2, 1, 0]: print('=======') print('verbose = {!r}'.format(verbose)) ub.delete(dpath, verbose=verbose) ub.ensuredir(dpath, verbose=verbose) ub.touch(happy_fpath, verbose=verbose) ub.touch(happy_flink) # create a file where a link should be util_links._dirstats(dpath) with pytest.raises(FileExistsError): # file exists error ub.symlink(happy_fpath, happy_flink, overwrite=False, verbose=verbose) with pytest.raises(FileExistsError): # file exists error ub.symlink(happy_fpath, happy_flink, overwrite=True, verbose=verbose)
def test_broken_link(): """ CommandLine: python -m ubelt.tests.test_links test_broken_link """ dpath = ub.ensure_app_cache_dir('ubelt', 'test_broken_link') ub.delete(dpath, verbose=2) ub.ensuredir(dpath, verbose=2) util_links._dirstats(dpath) broken_fpath = join(dpath, 'broken_fpath.txt') broken_flink = join(dpath, 'broken_flink.txt') ub.touch(broken_fpath, verbose=2) util_links._dirstats(dpath) ub.symlink(broken_fpath, broken_flink, verbose=2) util_links._dirstats(dpath) ub.delete(broken_fpath, verbose=2) util_links._dirstats(dpath) # make sure I am sane that this is the correct check. can_symlink = util_links._can_symlink() print('can_symlink = {!r}'.format(can_symlink)) if can_symlink: # normal behavior assert islink(broken_flink) assert not exists(broken_flink) else: # on windows hard links are essentially the same file. # there is no trace that it was actually a link. assert exists(broken_flink)
def check_path_condition(path, positive, want, msg): if not want: positive = not positive msg = 'not ' + msg if not positive: util_links._dirstats(dpath) print('About to raise error: {}'.format(msg)) print('path = {!r}'.format(path)) print('exists(path) = {!r}'.format(exists(path))) print('islink(path) = {!r}'.format(islink(path))) print('isdir(path) = {!r}'.format(isdir(path))) print('isfile(path) = {!r}'.format(isfile(path))) raise AssertionError('path={} {}'.format(path, msg))
def test_overwrite_symlink(): """ CommandLine: python ~/code/ubelt/tests/test_links.py test_overwrite_symlink """ # TODO: test that we handle broken links dpath = ub.ensure_app_cache_dir('ubelt', 'test_overwrite_symlink') ub.delete(dpath, verbose=2) ub.ensuredir(dpath, verbose=2) happy_fpath = join(dpath, 'happy_fpath.txt') other_fpath = join(dpath, 'other_fpath.txt') happy_flink = join(dpath, 'happy_flink.txt') for verbose in [2, 1, 0]: print('@==========@') print('verbose = {!r}'.format(verbose)) print('[test] Setup') ub.delete(dpath, verbose=verbose) ub.ensuredir(dpath, verbose=verbose) ub.touch(happy_fpath, verbose=verbose) ub.touch(other_fpath, verbose=verbose) print('[test] Dirstats dpath') util_links._dirstats(dpath) print('[test] Create initial link (to happy)') ub.symlink(happy_fpath, happy_flink, verbose=verbose) print('[test] Dirstats dpath') util_links._dirstats(dpath) # Creating a duplicate link print('[test] Create a duplicate link (to happy)') ub.symlink(happy_fpath, happy_flink, verbose=verbose) print('[test] Dirstats dpath') util_links._dirstats(dpath) print('[test] Create an unauthorized overwrite link (to other)') with pytest.raises(Exception) as exc_info: # file exists error ub.symlink(other_fpath, happy_flink, verbose=verbose) print(' * exc_info = {!r}'.format(exc_info)) print('[test] Create an authorized overwrite link (to other)') ub.symlink(other_fpath, happy_flink, verbose=verbose, overwrite=True) print('[test] Dirstats dpath') ub.delete(other_fpath, verbose=verbose) print('[test] Create an unauthorized overwrite link (back to happy)') with pytest.raises(Exception) as exc_info: # file exists error ub.symlink(happy_fpath, happy_flink, verbose=verbose) print(' * exc_info = {!r}'.format(exc_info)) print('[test] Create an authorized overwrite link (back to happy)') ub.symlink(happy_fpath, happy_flink, verbose=verbose, overwrite=True)
def test_overwrite_symlink(): """ CommandLine: python -m ubelt.tests.test_links test_overwrite_symlink """ # TODO: test that we handle broken links dpath = ub.ensure_app_cache_dir('ubelt', 'test_overwrite_symlink') ub.delete(dpath, verbose=2) ub.ensuredir(dpath, verbose=2) happy_fpath = join(dpath, 'happy_fpath.txt') other_fpath = join(dpath, 'other_fpath.txt') happy_flink = join(dpath, 'happy_flink.txt') for verbose in [2, 1, 0]: print('=======') print('verbose = {!r}'.format(verbose)) ub.delete(dpath, verbose=verbose) ub.ensuredir(dpath, verbose=verbose) ub.touch(happy_fpath, verbose=verbose) ub.touch(other_fpath, verbose=verbose) util_links._dirstats(dpath) ub.symlink(happy_fpath, happy_flink, verbose=verbose) # Creating a duplicate link # import six # import sys # if not six.PY2 and sys.platform.startswith('win32'): util_links._dirstats(dpath) ub.symlink(happy_fpath, happy_flink, verbose=verbose) util_links._dirstats(dpath) with pytest.raises(Exception): # file exists error ub.symlink(other_fpath, happy_flink, verbose=verbose) ub.symlink(other_fpath, happy_flink, verbose=verbose, overwrite=True) ub.delete(other_fpath, verbose=verbose) with pytest.raises(Exception): # file exists error ub.symlink(happy_fpath, happy_flink, verbose=verbose) ub.symlink(happy_fpath, happy_flink, verbose=verbose, overwrite=True)
def _win32_can_symlink(verbose=0, force=0, testing=0): """ Args: verbose (int, default=0): flag force (int, default=0): flag testing (int, default=0): flag Example: >>> # xdoctest: +REQUIRES(WIN32) >>> import ubelt as ub >>> _win32_can_symlink(verbose=1, force=1, testing=1) """ global __win32_can_symlink__ if verbose: print('__win32_can_symlink__ = {!r}'.format(__win32_can_symlink__)) if __win32_can_symlink__ is not None and not force: return __win32_can_symlink__ from ubelt import util_platform tempdir = util_platform.ensure_app_cache_dir('ubelt', '_win32_can_symlink') util_io.delete(tempdir) util_path.ensuredir(tempdir) dpath = join(tempdir, 'dpath') fpath = join(tempdir, 'fpath.txt') dlink = join(tempdir, 'dlink') flink = join(tempdir, 'flink.txt') util_path.ensuredir(dpath) util_io.touch(fpath) # Add broken variants of the links for testing purposes # Its ugly, but so is all this windows code. if testing: broken_dpath = join(tempdir, 'broken_dpath') broken_fpath = join(tempdir, 'broken_fpath.txt') # Create files that we will delete after we link to them util_path.ensuredir(broken_dpath) util_io.touch(broken_fpath) try: _win32_symlink(dpath, dlink) if testing: _win32_symlink(broken_dpath, join(tempdir, 'broken_dlink')) can_symlink_directories = os.path.islink(dlink) except OSError: can_symlink_directories = False if verbose: print('can_symlink_directories = {!r}'.format(can_symlink_directories)) try: _win32_symlink(fpath, flink) if testing: _win32_symlink(broken_fpath, join(tempdir, 'broken_flink')) can_symlink_files = os.path.islink(flink) # os.path.islink(flink) except OSError: can_symlink_files = False if verbose: print('can_symlink_files = {!r}'.format(can_symlink_files)) if int(can_symlink_directories) + int(can_symlink_files) == 1: raise AssertionError( 'can do one but not both. Unexpected {} {}'.format( can_symlink_directories, can_symlink_files)) try: # test that we can create junctions, even if symlinks are disabled djunc = _win32_junction(dpath, join(tempdir, 'djunc')) fjunc = _win32_junction(fpath, join(tempdir, 'fjunc.txt')) if testing: _win32_junction(broken_dpath, join(tempdir, 'broken_djunc')) _win32_junction(broken_fpath, join(tempdir, 'broken_fjunc.txt')) if not _win32_is_junction(djunc): raise AssertionError('expected junction') if not _win32_is_hardlinked(fpath, fjunc): raise AssertionError('expected hardlink') except Exception: warnings.warn('We cannot create junctions either!') raise if testing: # break the links util_io.delete(broken_dpath) util_io.delete(broken_fpath) if verbose: from ubelt import util_links util_links._dirstats(tempdir) try: # Cleanup the test directory util_io.delete(tempdir) except Exception: print('ERROR IN DELETE') from ubelt import util_links util_links._dirstats(tempdir) raise can_symlink = can_symlink_directories and can_symlink_files __win32_can_symlink__ = can_symlink if not can_symlink: warnings.warn('Cannot make real symlink. Falling back to junction') if verbose: print('can_symlink = {!r}'.format(can_symlink)) print('__win32_can_symlink__ = {!r}'.format(__win32_can_symlink__)) return can_symlink
def test_rel_file_link(): dpath = ub.ensure_app_cache_dir('ubelt', 'test_rel_file_link') ub.delete(dpath, verbose=2) ub.ensuredir(dpath, verbose=2) real_fpath = join(ub.ensuredir((dpath, 'dir1')), 'real') link_fpath = join(ub.ensuredir((dpath, 'dir2')), 'link') ub.touch(real_fpath) orig = os.getcwd() try: os.chdir(dpath) real_path = relpath(real_fpath, dpath) link_path = relpath(link_fpath, dpath) link = ub.symlink(real_path, link_path) import sys if sys.platform.startswith('win32') and isfile(link): # Note: if windows hard links the file there is no way we can # tell that it was a symlink. Just verify it exists. from ubelt import _win32_links assert _win32_links._win32_is_hardlinked(real_fpath, link_fpath) else: pointed = ub.util_links._readlink(link) resolved = ub.truepath(join(dirname(link), pointed), real=True) assert ub.truepath(real_fpath, real=True) == resolved except Exception: util_links._dirstats(dpath) util_links._dirstats(join(dpath, 'dir1')) util_links._dirstats(join(dpath, 'dir2')) print('TEST FAILED: test_rel_link') print('real_fpath = {!r}'.format(real_fpath)) print('link_fpath = {!r}'.format(link_fpath)) print('real_path = {!r}'.format(real_path)) print('link_path = {!r}'.format(link_path)) try: if 'link' in vars(): print('link = {!r}'.format(link)) if 'pointed' in vars(): print('pointed = {!r}'.format(pointed)) if 'resolved' in vars(): print('resolved = {!r}'.format(resolved)) except Exception: print('...rest of the names are not available') raise finally: util_links._dirstats(dpath) util_links._dirstats(join(dpath, 'dir1')) util_links._dirstats(join(dpath, 'dir2')) os.chdir(orig)
def test_rel_dir_link(): dpath = ub.ensure_app_cache_dir('ubelt', 'test_rel_dir_link') ub.delete(dpath, verbose=2) ub.ensuredir(dpath, verbose=2) real_dpath = join(ub.ensuredir((dpath, 'dir1')), 'real') link_dpath = join(ub.ensuredir((dpath, 'dir2')), 'link') ub.ensuredir(real_dpath) orig = os.getcwd() try: os.chdir(dpath) real_path = relpath(real_dpath, dpath) link_path = relpath(link_dpath, dpath) link = ub.symlink(real_path, link_path) # Note: on windows this is hacked. pointed = ub.util_links._readlink(link) resolved = ub.truepath(join(dirname(link), pointed), real=True) assert ub.truepath(real_dpath, real=True) == resolved except Exception: util_links._dirstats(dpath) util_links._dirstats(join(dpath, 'dir1')) util_links._dirstats(join(dpath, 'dir2')) print('TEST FAILED: test_rel_link') print('real_dpath = {!r}'.format(real_dpath)) print('link_dpath = {!r}'.format(link_dpath)) print('real_path = {!r}'.format(real_path)) print('link_path = {!r}'.format(link_path)) try: if 'link' in vars(): print('link = {!r}'.format(link)) if 'pointed' in vars(): print('pointed = {!r}'.format(pointed)) if 'resolved' in vars(): print('resolved = {!r}'.format(resolved)) except Exception: print('...rest of the names are not available') raise finally: util_links._dirstats(dpath) util_links._dirstats(join(dpath, 'dir1')) util_links._dirstats(join(dpath, 'dir2')) os.chdir(orig)
def test_delete_symlinks(): """ CommandLine: python -m ubelt.tests.test_links test_delete_symlinks """ # TODO: test that we handle broken links dpath = ub.ensure_app_cache_dir('ubelt', 'test_delete_links') happy_dpath = join(dpath, 'happy_dpath') happy_dlink = join(dpath, 'happy_dlink') happy_fpath = join(dpath, 'happy_fpath.txt') happy_flink = join(dpath, 'happy_flink.txt') broken_dpath = join(dpath, 'broken_dpath') broken_dlink = join(dpath, 'broken_dlink') broken_fpath = join(dpath, 'broken_fpath.txt') broken_flink = join(dpath, 'broken_flink.txt') def check_path_condition(path, positive, want, msg): if not want: positive = not positive msg = 'not ' + msg if not positive: util_links._dirstats(dpath) print('About to raise error: {}'.format(msg)) print('path = {!r}'.format(path)) print('exists(path) = {!r}'.format(exists(path))) print('islink(path) = {!r}'.format(islink(path))) print('isdir(path) = {!r}'.format(isdir(path))) print('isfile(path) = {!r}'.format(isfile(path))) raise AssertionError('path={} {}'.format(path, msg)) def assert_sometrace(path, want=True): # Either exists or is a broken link positive = exists(path) or islink(path) check_path_condition(path, positive, want, 'has trace') def assert_broken_link(path, want=True): if util_links._can_symlink(): print('path={} should{} be a broken link'.format( path, ' ' if want else ' not')) positive = not exists(path) and islink(path) check_path_condition(path, positive, want, 'broken link') else: # TODO: we can test this # positive = util_links._win32_is_junction(path) print('path={} should{} be a broken link (junction)'.format( path, ' ' if want else ' not')) print('cannot check this yet') # We wont be able to differentiate links and nonlinks for junctions # positive = exists(path) # check_path_condition(path, positive, want, 'broken link') util_links._dirstats(dpath) ub.delete(dpath, verbose=2) ub.ensuredir(dpath, verbose=2) util_links._dirstats(dpath) ub.ensuredir(happy_dpath, verbose=2) ub.ensuredir(broken_dpath, verbose=2) ub.touch(happy_fpath, verbose=2) ub.touch(broken_fpath, verbose=2) util_links._dirstats(dpath) ub.symlink(broken_fpath, broken_flink, verbose=2) ub.symlink(broken_dpath, broken_dlink, verbose=2) ub.symlink(happy_fpath, happy_flink, verbose=2) ub.symlink(happy_dpath, happy_dlink, verbose=2) util_links._dirstats(dpath) # Deleting the files should not delete the symlinks (windows) ub.delete(broken_fpath, verbose=2) util_links._dirstats(dpath) ub.delete(broken_dpath, verbose=2) util_links._dirstats(dpath) assert_broken_link(broken_flink, 1) assert_broken_link(broken_dlink, 1) assert_sometrace(broken_fpath, 0) assert_sometrace(broken_dpath, 0) assert_broken_link(happy_flink, 0) assert_broken_link(happy_dlink, 0) assert_sometrace(happy_fpath, 1) assert_sometrace(happy_dpath, 1) # broken symlinks no longer exist after they are deleted ub.delete(broken_dlink, verbose=2) util_links._dirstats(dpath) assert_sometrace(broken_dlink, 0) ub.delete(broken_flink, verbose=2) util_links._dirstats(dpath) assert_sometrace(broken_flink, 0) # real symlinks no longer exist after they are deleted # but the original data is fine ub.delete(happy_dlink, verbose=2) util_links._dirstats(dpath) assert_sometrace(happy_dlink, 0) assert_sometrace(happy_dpath, 1) ub.delete(happy_flink, verbose=2) util_links._dirstats(dpath) assert_sometrace(happy_flink, 0) assert_sometrace(happy_fpath, 1)