Skip to content

Commit

Permalink
Merge pull request #224 from docoleman/stop_following_symlinks_216
Browse files Browse the repository at this point in the history
Stop following symlinks 216
  • Loading branch information
spderosso committed Feb 13, 2020
2 parents ce7f069 + 98f14e1 commit eccad4a
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 3 deletions.
5 changes: 4 additions & 1 deletion gitless/cli/helpers.py
Expand Up @@ -121,7 +121,10 @@ def __call__(self, parser, namespace, paths, option_string=None):
def process_paths():
for path in paths:
path = os.path.abspath(path)
if self.recursive and os.path.isdir(path):
# Treat symlinks as normal files, even if the link points to a
# directory. The directory could be outside of the repo, then things
# get weird... This is standard git behavior.
if self.recursive and os.path.isdir(path) and not os.path.islink(path):
for curr_dir, dirs, fps in os.walk(path, topdown=True):
if curr_dir.startswith(normalized_repo_path):
dirs[:] = []
Expand Down
51 changes: 49 additions & 2 deletions gitless/tests/test_core.py
Expand Up @@ -43,6 +43,12 @@
REPO_FP = os.path.join(REPO_DIR, 'HEAD')
GITTEST_DIR = '.gittest'
GITTEST_FP = os.path.join(GITTEST_DIR, 'fp')
SYMLINK_TARGET = 'symtarget'
SYMLINK_TARGET_FP_CONTENTS = 'symf1\n'
SYMLINK_TARGET_FP = os.path.join(SYMLINK_TARGET, 'symf1')
SYMLINK_DIR = 'symdir'
SYMLINK_FP = os.path.join(SYMLINK_DIR, 'sym')
SYMLINK_GIT = 'gitsym'
UNTRACKED_DIR_FP = os.path.join(DIR, 'f1')
UNTRACKED_DIR_FP_WITH_SPACE = os.path.join(DIR, 'f1 space')
TRACKED_DIR_FP = os.path.join(DIR, 'f2')
Expand All @@ -57,12 +63,16 @@
IGNORED_FP, IGNORED_FP_WITH_SPACE, UNTRACKED_DIR_FP,
UNTRACKED_DIR_FP_WITH_SPACE, TRACKED_DIR_FP, TRACKED_DIR_FP_WITH_SPACE,
UNTRACKED_DIR_DIR_FP, UNTRACKED_DIR_DIR_FP_WITH_SPACE, TRACKED_DIR_DIR_FP,
TRACKED_DIR_DIR_FP_WITH_SPACE, GITIGNORE_FP, GITTEST_FP]
TRACKED_DIR_DIR_FP_WITH_SPACE, GITIGNORE_FP, GITTEST_FP, SYMLINK_TARGET_FP,
SYMLINK_FP, SYMLINK_GIT]
# the symbolic link is both a file and directory. The OS typically treats it
# like a directory but we want to treat it as a file for tracking purposes.
ALL_DIR_FPS_IN_WD = [
TRACKED_DIR_FP, TRACKED_DIR_FP_WITH_SPACE, UNTRACKED_DIR_FP,
UNTRACKED_DIR_FP_WITH_SPACE, TRACKED_DIR_DIR_FP,
TRACKED_DIR_DIR_FP_WITH_SPACE, UNTRACKED_DIR_DIR_FP,
UNTRACKED_DIR_DIR_FP_WITH_SPACE, GITTEST_DIR]
UNTRACKED_DIR_DIR_FP_WITH_SPACE, GITTEST_DIR, SYMLINK_TARGET, SYMLINK_DIR,
SYMLINK_FP, SYMLINK_GIT]
BRANCH = 'b1'
REMOTE_BRANCH = 'rb'
FP_IN_CONFLICT = 'f_conflict'
Expand Down Expand Up @@ -178,6 +188,12 @@ def setUp(self):
utils_lib.write_file(IGNORED_FP_WITH_SPACE)
utils_lib.write_file(GITTEST_FP)

# Testing with symlinks! The symlink calls will be no ops on Windows
utils_lib.write_file(SYMLINK_TARGET_FP, contents=SYMLINK_TARGET_FP_CONTENTS)
utils_lib.symlink(REPO_DIR, SYMLINK_GIT)
os.mkdir(SYMLINK_DIR)
utils_lib.symlink(SYMLINK_TARGET, SYMLINK_FP)

self.curr_b = self.repo.current_branch


Expand Down Expand Up @@ -796,6 +812,37 @@ def test_path_processor_track_gittest_dir(self):
self.assertEqual(len(files), 1)
self.assertTrue(GITTEST_FP in files)

@assert_no_side_effects(GITTEST_FP)
def test_path_processor_track_gittest_fp(self):
argv = ['track', GITTEST_FP]
args = self.parser.parse_args(argv)
files = [fp for fp in args.files]

self.assertEqual(len(files), 1)
self.assertTrue(GITTEST_FP in files)

@assert_no_side_effects(SYMLINK_TARGET_FP)
def test_path_processor_track_symlink(self):
argv = ['track', SYMLINK_FP]
args = self.parser.parse_args(argv)
files = [fp for fp in args.files]

if os.path.exists(SYMLINK_FP):
self.assertEqual(len(files), 1)
self.assertTrue(SYMLINK_FP in files)
self.assertFalse(SYMLINK_TARGET_FP in files)

@assert_no_side_effects(SYMLINK_TARGET_FP)
def test_path_processor_track_symlink_dir(self):
argv = ['track', SYMLINK_DIR]
args = self.parser.parse_args(argv)
files = [fp for fp in args.files]

if os.path.exists(SYMLINK_FP):
self.assertEqual(len(files), 1)
self.assertTrue(SYMLINK_FP in files)
self.assertFalse(SYMLINK_TARGET_FP in files)


# Unit tests for branch related operations

Expand Down
16 changes: 16 additions & 0 deletions gitless/tests/utils.py
Expand Up @@ -82,6 +82,22 @@ def onerror(func, path, unused_exc_info): # error handler for rmtree
logging.debug('Removed dir {0}'.format(path))


def symlink(src, dst):
try:
os.symlink(src, dst)
except (AttributeError, NotImplementedError, OSError):
# Swallow the exceptions, because Windows is very weird about creating
# symlinks. Python 2 does not have a symlink method on in the os module,
# AttributeError will handle that. Python 3 does have a symlink method in
# the os module, however, it has some quirks. NotImplementedError handles
# the case where the Windows version is prior to Vista. OSError handles the
# case where python doesn't have permissions to create a symlink on
# windows. In all cases, it's not necessary to test this, so skip it.
# See: https://docs.python.org/3.5/library/os.html#os.symlink and
# https://docs.python.org/2.7/library/os.html#os.symlink for full details.
pass


def write_file(fp, contents=''):
_x_file('w', fp, contents=contents)

Expand Down

0 comments on commit eccad4a

Please sign in to comment.