Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow tracking empty directories #157

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion gitless/cli/commit_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import shlex


from . import pprint
from . import pprint, helpers


IS_PY2 = sys.version_info[0] == 2
Expand Down Expand Up @@ -56,6 +56,7 @@ def show(files, repo):
pprint.msg(
'These are the files whose changes will be committed:', stream=cf.write)
for f in files:
f = helpers.remove_keep_file_name(f)
pprint.item(f, stream=cf.write)
pprint.sep(stream=cf.write)
cf.close()
Expand Down
10 changes: 8 additions & 2 deletions gitless/cli/file_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

from __future__ import unicode_literals

from gitless import core

from . import helpers, pprint


Expand Down Expand Up @@ -35,11 +37,15 @@ def f(args, repo):

for fp in args.files:
try:
empty_dir = fp.endswith(core.GL_KEEP_FILENAME)
getattr(curr_b, subcmd + '_file')(fp)
fp = helpers.remove_keep_file_name(fp)
pprint.ok(
'File {0} is now a{1} {2}{3}d file'.format(
'{0} {1} is now a{2} {3}{4}d {5}'.format(
'Empty directory' if empty_dir else 'File',
fp, 'n' if subcmd.startswith(VOWELS) else '', subcmd,
'' if subcmd.endswith('e') else 'e'))
'' if subcmd.endswith('e') else 'e',
'directory' if empty_dir else 'file'))
except KeyError:
pprint.err('Can\'t {0} non-existent file {1}'.format(subcmd, fp))
success = False
Expand Down
6 changes: 5 additions & 1 deletion gitless/cli/gl_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,10 @@ def _print_tracked_mod_files(tracked_mod_list, relative_paths, repo):
for f in tracked_mod_list:
exp = ''
color = colored.yellow
is_keep_file = f.fp.endswith(core.GL_KEEP_FILENAME)
if not f.exists_at_head:
exp = ' (new file)'
kind = 'directory' if is_keep_file else 'file'
exp = ' (new {0})'.format(kind)
color = colored.green
elif not f.exists_in_wd:
exp = ' (deleted)'
Expand All @@ -97,6 +99,7 @@ def _print_tracked_mod_files(tracked_mod_list, relative_paths, repo):
fp = os.path.relpath(os.path.join(root, f.fp)) if relative_paths else f.fp
if fp == '.':
continue
fp = helpers.remove_keep_file_name(fp)

pprint.item(color(fp), opt_text=exp)

Expand Down Expand Up @@ -128,6 +131,7 @@ def _print_untracked_files(untracked_list, relative_paths, repo):
fp = os.path.relpath(os.path.join(root, f.fp)) if relative_paths else f.fp
if fp == '.':
continue
fp = helpers.remove_keep_file_name(fp)

pprint.item(color(fp), opt_text=exp)

Expand Down
10 changes: 10 additions & 0 deletions gitless/cli/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ def process_paths():
self.skip_dir_cb(curr_dir_rel)
dirs[:] = []
continue
if not fps:
open(os.path.join(curr_dir, core.GL_KEEP_FILENAME), 'a').close()
fps.append(core.GL_KEEP_FILENAME)
dirs[:] = []
for fp in fps:
yield os.path.join(curr_dir_rel, fp)
else:
Expand Down Expand Up @@ -247,3 +251,9 @@ def validate(fps, check_fn, msg):
for e in err:
pprint.err(e)
return False


def remove_keep_file_name(fp):
if(fp.endswith(core.GL_KEEP_FILENAME)):
return fp.replace(core.GL_KEEP_FILENAME, '')
return fp
10 changes: 10 additions & 0 deletions gitless/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ class ApplyFailedError(GlError): pass
GL_STATUS_TRACKED = 2
GL_STATUS_IGNORED = 3

GL_KEEP_FILENAME = '.glkeep'


def init_repository(url=None):
"""Creates a new Gitless's repository in the cwd.
Expand Down Expand Up @@ -769,6 +771,14 @@ def status(self):
yield self.FileStatus(
fp, GL_STATUS_UNTRACKED, True, exists_in_wd, True, False)

# find untracked empty dirs
for dirpath, dirs, files in os.walk('.', topdown=True):
dirs[:] = [d for d in dirs if d not in ['.git'] and not
self.path_is_ignored(d)]
if not dirs and not files:
yield self.FileStatus(dirpath, GL_STATUS_UNTRACKED, False, True, False,
False)

def status_file(self, path):
"""Return the status (see FileStatus) of the given path."""
return self._status_file(path)[0]
Expand Down
87 changes: 87 additions & 0 deletions gitless/tests/test_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
gl = Command('gl')
git = Command('git')

from gitless import core

from gitless.tests import utils

Expand Down Expand Up @@ -683,6 +684,92 @@ def test_uncommitted_tracked_changes_that_conflict_append(self):
self.assertTrue('contents 2' in contents)


class TestEmptyDir(TestEndToEnd):

def test_empty_dir_status(self):
untracked_empty_dir = self._mk_empty_dir('untracked_empty_dir')

out = utils.stdout(gl.status())

self.assertIn(untracked_empty_dir, out, 'Empty dir didn\'t appear in status')

def test_ignored_empty_dir_status(self):
ignored_empty_dir = self._mk_empty_dir('ignored_empty_dir')
utils.write_file(os.path.join(self.path, '.gitignore'), ignored_empty_dir)

out = utils.stdout(gl.status())

self.assertFalse(ignored_empty_dir in out,
'Ignored empty dir was listed in status')

def test_track_empty_dir(self):
dir_to_track = self._mk_empty_dir('wanted_empty_dir')
expected_out = 'Empty directory {0} is now a tracked directory'.format(
self._dir_path(dir_to_track))

out = utils.stdout(gl.track(dir_to_track))

self.assertIn(expected_out, out, 'Empty dir wasn\'t tracked')

def test_track_parent_empty_dir(self):
parent_empty_dir = self._mk_empty_dir('parent_empty_dir')
child_dir = self._mk_empty_dir(os.path.join(parent_empty_dir, 'child_dir'))
unexpected_out = 'Empty directory {0} is now a tracked directory'.format(
os.path.join(child_dir, ''))

out = utils.stdout(gl.track(parent_empty_dir))

self.assertFalse(unexpected_out in out, 'Tracked empty dir child')

def test_tracked_empty_dir_status(self):
tracked_empty_dir = self._mk_empty_dir('tracked_empty_dir')
gl.track(tracked_empty_dir)
expected_out = '{0} (new directory)'.format(
self._dir_path(tracked_empty_dir))

out = utils.stdout(gl.status())

self.assertIn(expected_out, out, 'Didn\'t report newly tracked dir')

def test_commit_empty_dir(self):
empty_dir = self._mk_empty_dir('wanted_empty_dir')
gl.track(empty_dir)
pipe = 'std.out'
gl.commit(_out = pipe, _bg = True)

f = open(pipe)
out = previous_out = ''
while(os.path.getsize(pipe) == 0 or out != previous_out):
time.sleep(0.1)
previous_out = out
f.seek(0)
out = f.read()
f.close()

self.assertIn(self._dir_path(empty_dir), out)
self.assertFalse(core.GL_KEEP_FILENAME in out,
'Output included gitless keep file name')

def test_untracked_empty_dir_status(self):
untracked_empty_dir = self._mk_empty_dir('untracked_empty_dir')
gl.track(untracked_empty_dir)
gl.commit(m = 'Add empty dir')
gl.untrack(untracked_empty_dir)
expected_out = '{0} (exists at head)'.format(
self._dir_path(untracked_empty_dir))

out = utils.stdout(gl.status())

self.assertIn(expected_out, out, 'Didn\'t report untracked dir')

def _mk_empty_dir(self, name):
os.mkdir(os.path.join(self.path, name))
return name

def _dir_path(self, path):
return os.path.join(path, '')


class TestPerformance(TestEndToEnd):

FPS_QTY = 10000
Expand Down