From 6098acbde2f942aa6d915b44070219a70086091c Mon Sep 17 00:00:00 2001 From: Stephan Fitzpatrick Date: Mon, 3 Oct 2016 12:12:50 -0700 Subject: [PATCH 001/196] fixed potential unicode encoding error --- gitless/cli/pprint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/cli/pprint.py b/gitless/cli/pprint.py index d0ff6d2..0df0d70 100644 --- a/gitless/cli/pprint.py +++ b/gitless/cli/pprint.py @@ -37,7 +37,7 @@ def puts(s='', newline=True, stream=sys.stdout.write): isinstance(s, unicode) or isinstance(s, colored.ColoredString)) if IS_PY2: - s = s.encode(ENCODING) + s = s.encode(ENCODING, errors='ignore') clint_puts(s, newline=newline, stream=stream) From 24a9c7d2c3d09968962a8e29255f4cd75d39cea7 Mon Sep 17 00:00:00 2001 From: Volker Mische Date: Wed, 5 Oct 2016 10:02:07 +0200 Subject: [PATCH 002/196] The `color.ui` setting isn't a boolean The `color.ui` setting can not only have boolean values, but also values like `never`, `always` or `auto`. Hence the check for color needs to be expanded, else if it is set to `auto` it would lead to an error like: $ python gl.py -h Traceback (most recent call last): File "gl.py", line 10, in from gitless.cli import gl File "/home/vmx/src/python/gitless/gitless/gitless/cli/gl.py", line 39, in colored.DISABLE_COLOR = not repo.config.get_bool('color.ui') File "/usr/lib/python2.7/dist-packages/pygit2/config.py", line 199, in get_bool check_error(err) File "/usr/lib/python2.7/dist-packages/pygit2/errors.py", line 64, in check_error raise GitError(message) _pygit2.GitError: Failed to parse 'auto' as a boolean value This fixes #42. --- gitless/cli/gl.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index b11b7f8..5b2a00e 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -36,7 +36,8 @@ repo = None try: repo = core.Repository() - colored.DISABLE_COLOR = not repo.config.get_bool('color.ui') + colored.DISABLE_COLOR = (repo.config['color.ui'] in + ['false', '0', 'off', 'no', 'never']) except (core.NotInRepoError, KeyError): pass From db21d6b60a8338b31982899711b66fb6edd2ea25 Mon Sep 17 00:00:00 2001 From: Roger Pate Date: Fri, 7 Oct 2016 10:07:35 -0400 Subject: [PATCH 003/196] update link for Google Python Style Guide --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 77452e4..0d03137 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ merge the changes onto `master` when the changes are stable and we're ready to cut a new release. So you'll find on `develop` the latest changes - We follow (to some extent) the [Google Python Style Guide]( - http://google-styleguide.googlecode.com/svn/trunk/pyguide.html + https://google.github.io/styleguide/pyguide.html "Google Python Style Guide"). Before submitting code, take a few seconds to look at the style guide and the Gitless's code so that your edits are consistent with the codebase From 821a8455716c999df358781dee8a5e589d6c283c Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 7 Oct 2016 21:42:47 -0400 Subject: [PATCH 004/196] bump libgit2 version in travis --- .travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.sh b/.travis.sh index f7c041d..8fa184c 100755 --- a/.travis.sh +++ b/.travis.sh @@ -2,7 +2,7 @@ cd ~ -git clone --depth=1 -b maint/v0.23 https://github.com/libgit2/libgit2.git +git clone --depth=1 -b maint/v0.24 https://github.com/libgit2/libgit2.git cd libgit2/ mkdir build && cd build From 681ecf161c53687da80826060b22fb080e150869 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 7 Oct 2016 22:31:01 -0400 Subject: [PATCH 005/196] cover more values for color.ui --- gitless/cli/gl.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 5b2a00e..ee21db6 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -36,8 +36,11 @@ repo = None try: repo = core.Repository() - colored.DISABLE_COLOR = (repo.config['color.ui'] in - ['false', '0', 'off', 'no', 'never']) + try: + colored.DISABLE_COLOR = not repo.config.get_bool('color.ui') + except pygit2.GitError: + colored.DISABLE_COLOR = ( + repo.config['color.ui'] in ['no', 'never']) except (core.NotInRepoError, KeyError): pass From 2736b9e0f4c66c51416eac6ce1187d411514cbac Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 7 Oct 2016 22:56:09 -0400 Subject: [PATCH 006/196] drop 2.6 add 3.5 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1a024be..faa6d47 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,11 @@ language: python python: - - "2.6" - "2.7" - "3.2" - "3.3" - "3.4" + - "3.5" - "pypy" env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib From 6bc86d698c20b0b3fcd2ef1be1ff4e632c167be6 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sat, 8 Oct 2016 17:01:06 -0400 Subject: [PATCH 007/196] err if we can't launch the editor --- gitless/cli/commit_dialog.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gitless/cli/commit_dialog.py b/gitless/cli/commit_dialog.py index 51af52d..ca8baa5 100644 --- a/gitless/cli/commit_dialog.py +++ b/gitless/cli/commit_dialog.py @@ -68,8 +68,13 @@ def _launch_editor(fp, repo): except KeyError: editor = os.environ['EDITOR'] if 'EDITOR' in os.environ else 'vim' - if subprocess.call([editor, fp]) != 0: - raise Exception('Call to editor {0} failed'.format(editor)) + try: + ret = subprocess.call([editor, fp]) + if ret != 0: + pprint.err('Call to editor {0} failed'.format(editor)) + except OSError: + pprint.err('Couldn\'t launch editor {0}'.format(editor)) + pprint.err_exp('change the value of git\'s core.editor setting') def _extract_msg(repo): From 2f3e67dc8b52cd8798c6a83613123cce1009de55 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sat, 8 Oct 2016 17:48:43 -0400 Subject: [PATCH 008/196] err if there's no commit author info set --- gitless/cli/gl_commit.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gitless/cli/gl_commit.py b/gitless/cli/gl_commit.py index 8769d66..96a0eb3 100644 --- a/gitless/cli/gl_commit.py +++ b/gitless/cli/gl_commit.py @@ -48,6 +48,15 @@ def main(args, repo): if args.p: partials = _do_partial_selection(commit_files, curr_b) + if not repo.config['user.name']: + pprint.err('Missing name for commit author') + pprint.err_exp('change the value of git\'s user.name setting') + return False + if not repo.config['user.email']: + pprint.err('Missing email for commit author') + pprint.err_exp('change the value of git\'s user.email setting') + return False + msg = args.m if args.m else commit_dialog.show(commit_files, repo) if not msg.strip(): if partials: From c125eec3d7fb99c603ef8e8deb5597164ddd51a6 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sun, 9 Oct 2016 11:16:23 -0400 Subject: [PATCH 009/196] prep for 0.8.4 --- README.md | 10 +++++----- gitless/cli/gl.py | 2 +- setup.py | 5 +---- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 77452e4..93b4b78 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,10 @@ the Python Package Index). ### Installing from source -To install from source you need to have Python (2.6, 2.7, 3.2+ or pypy) +To install from source you need to have Python (2.7, 3.2+ or pypy) installed. -Additionaly, you need to [install pygit2 (v0.23.0)]( +Additionaly, you need to [install pygit2]( http://www.pygit2.org/install.html "pygit2 install"). Then, [download the source code tarball](http://gitless.com "Gitless's website") @@ -69,9 +69,9 @@ and do: If you are a Python fan you might find it easier to install Gitless via the Python Package Index. To do this, you need to have -Python (2.6, 2.7, 3.2+ or pypy) installed. +Python (2.7, 3.2+ or pypy) installed. -Additionaly, you need to [install pygit2 (v0.23.0)]( +Additionaly, you need to [install pygit2]( http://www.pygit2.org/install.html "pygit2 install"). Then, just do: @@ -114,4 +114,4 @@ Gitless's code so that your edits are consistent with the codebase - Finally, if you don't want [Travis]( https://travis-ci.org/sdg-mit/gitless "Travis") to -be mad at you, check that tests pass in python 2.6, 2.7 and 3.2+ +be mad at you, check that tests pass in Python 2.7 and 3.2+ diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index ee21db6..39c872e 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -29,7 +29,7 @@ INTERNAL_ERROR = 3 NOT_IN_GL_REPO = 4 -VERSION = '0.8.3' +VERSION = '0.8.4' URL = 'http://gitless.com' diff --git a/setup.py b/setup.py index c68fd3d..278520e 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ from setuptools import setup -VERSION = '0.8.3' +VERSION = '0.8.4' # Build helper @@ -54,9 +54,6 @@ More info, downloads and documentation @ `Gitless's website `__. - -Questions or comments about Gitless can be sent to the `Gitless users -mailing list `__. """ setup( From aba7c5c3df58c59176aa2a9311ec5e7626f1f0c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rainer=20M=C3=BCller?= Date: Fri, 14 Oct 2016 02:24:58 +0200 Subject: [PATCH 010/196] Treat core.pager as a command with arguments This is required to support commands such as 'less -S'. --- gitless/cli/helpers.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 5cfb480..cd3d625 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -11,6 +11,7 @@ import os import subprocess import sys +import shlex from gitless import core @@ -72,7 +73,11 @@ def page(fp, repo): pager = repo.config['core.pager'] except KeyError: pass - cmd = [pager, fp] if pager else ['less', '-r', '-f', fp] + if pager: + cmd = shlex.split(pager) + cmd.append(fp) + else: + cmd = ['less', '-r', '-f', fp] subprocess.call(cmd, stdin=sys.stdin, stdout=sys.stdout) From f3da4093c31ea49d83d0f890df106f89bc0dd4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rainer=20M=C3=BCller?= Date: Fri, 14 Oct 2016 02:25:00 +0200 Subject: [PATCH 011/196] Treat EDITOR as a command with arguments Closes #64 --- gitless/cli/commit_dialog.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gitless/cli/commit_dialog.py b/gitless/cli/commit_dialog.py index ca8baa5..8bde875 100644 --- a/gitless/cli/commit_dialog.py +++ b/gitless/cli/commit_dialog.py @@ -12,6 +12,7 @@ import os import subprocess import sys +import shlex from . import pprint @@ -68,8 +69,11 @@ def _launch_editor(fp, repo): except KeyError: editor = os.environ['EDITOR'] if 'EDITOR' in os.environ else 'vim' + cmd = shlex.split(editor) + cmd.append(fp) + try: - ret = subprocess.call([editor, fp]) + ret = subprocess.call(cmd) if ret != 0: pprint.err('Call to editor {0} failed'.format(editor)) except OSError: From 5bf3e5628552655a3c805689453d961a47627c99 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Fri, 28 Oct 2016 02:54:21 +0300 Subject: [PATCH 012/196] Link pygit2 for Windows users --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f720962..af4aeef 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,8 @@ going to disappear soon once we finish with our migration to pygit2). Note to Windows users: we currently have no binary release for Windows. If you are having trouble getting the latest version to work (we now depend -on pygit2 in addition to `git`), you can try v0.6.2 instead (which depends only +on [pygit2](https://github.com/libgit2/pygit2) in addition to `git`), you can +try v0.6.2 instead (which depends only on `git`) and people have managed to get it working. From 811e2fae4c5bc7a3eed2b9da8fbe76ac7222d471 Mon Sep 17 00:00:00 2001 From: Sobolev Nikita Date: Sat, 29 Oct 2016 15:13:38 +0300 Subject: [PATCH 013/196] Updated readme.md with svg badges --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index af4aeef..b7ae0f5 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ Gitless ======= -[![PyPI version](https://badge.fury.io/py/gitless.png)]( +[![PyPI version](https://badge.fury.io/py/gitless.svg)]( http://badge.fury.io/py/gitless) -[![Build Status](https://travis-ci.org/sdg-mit/gitless.png?branch=develop)]( +[![Build Status](https://travis-ci.org/sdg-mit/gitless.svg?branch=develop)]( https://travis-ci.org/sdg-mit/gitless) [Gitless](http://gitless.com "Gitless's website") is an experimental version From cc23db03c66059a281aeda60d70484a241c8fc5f Mon Sep 17 00:00:00 2001 From: Eugen Martynov Date: Wed, 2 Nov 2016 06:07:31 +0100 Subject: [PATCH 014/196] Added brew installation --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index b7ae0f5..56c5111 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,13 @@ Then, just do: $ pip install gitless +### Installing via Homebrew +If you are using [Homebrew](http://brew.sh/ "Homebrew homepage") as missing Mac OS packet manager then you can simply install Gitless with: +``` +brew update +brew install gitless +``` Documentation ------------- From ba2bfc9da4f65c04349c1125e9eada2a505f1d7c Mon Sep 17 00:00:00 2001 From: Eugen Martynov Date: Wed, 2 Nov 2016 09:02:41 +0100 Subject: [PATCH 015/196] Added homebrew badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 56c5111..921267f 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Gitless http://badge.fury.io/py/gitless) [![Build Status](https://travis-ci.org/sdg-mit/gitless.svg?branch=develop)]( https://travis-ci.org/sdg-mit/gitless) +[![homebrew](https://img.shields.io/homebrew/v/cake.svg)](http://braumeister.org/formula/gitless) [Gitless](http://gitless.com "Gitless's website") is an experimental version control system built on top of Git. Many From e79023f9f125bbf0d4cb0c2b2ce29e3a4fd319a0 Mon Sep 17 00:00:00 2001 From: Eugen Martynov Date: Wed, 2 Nov 2016 17:14:27 +0100 Subject: [PATCH 016/196] Corrected package for badge and put up for consistency --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 921267f..653a2e1 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ Gitless [![PyPI version](https://badge.fury.io/py/gitless.svg)]( http://badge.fury.io/py/gitless) +[![homebrew](https://img.shields.io/homebrew/v/gitless.svg)](http://braumeister.org/formula/gitless) [![Build Status](https://travis-ci.org/sdg-mit/gitless.svg?branch=develop)]( https://travis-ci.org/sdg-mit/gitless) -[![homebrew](https://img.shields.io/homebrew/v/cake.svg)](http://braumeister.org/formula/gitless) [Gitless](http://gitless.com "Gitless's website") is an experimental version control system built on top of Git. Many From 5fe511aec821e9e4e271456b1e84080eb0e731ed Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Thu, 3 Nov 2016 05:17:35 -0400 Subject: [PATCH 017/196] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 653a2e1..b77a883 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ Then, just do: ### Installing via Homebrew -If you are using [Homebrew](http://brew.sh/ "Homebrew homepage") as missing Mac OS packet manager then you can simply install Gitless with: +If you are using [Homebrew](http://brew.sh/ "Homebrew homepage"), a package manager for Mac OS, then you can simply install Gitless with: ``` brew update brew install gitless From fed5751ae7d981049e8cefbe6dcb2efdce8495f7 Mon Sep 17 00:00:00 2001 From: Arne Bachmann Date: Sun, 13 Nov 2016 09:03:11 +0100 Subject: [PATCH 018/196] Small code cleanups; dedented one 'return' statement to provide more exhaustive error messages. --- gitless/cli/helpers.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index cd3d625..4845bea 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -143,12 +143,11 @@ def oei_fs(args, repo): # Tracked modified files ret = frozenset( f.fp for f in curr_b.status() - if f.type == core.GL_STATUS_TRACKED and f.modified) - ret = ret.difference(exclude) - ret = ret.union(include) + if f.type == core.GL_STATUS_TRACKED and f.modified) # using generator expression + ret -= exclude + ret &= include - ret = list(ret) - ret.sort() + ret = sorted(list(ret)) return ret @@ -163,13 +162,17 @@ def _oei_validate(only, exclude, include, curr_b): """ if only and (exclude or include): pprint.err( - 'You provided a list of filenames to be committed only but also ' - 'provided a list of files to be excluded or included') + 'You provided a list of filenames to be committed only (-o) but also ' + 'provided a list of files to be excluded (-e) or included (-i)') return False err = [] def validate(fps, check_fn, msg): + ''' fps: files + check_fn: lambda(file) -> boolean + msg: string-format of pre-defined constant string. + ''' ret = True if not fps: return ret @@ -178,12 +181,12 @@ def validate(fps, check_fn, msg): f = curr_b.status_file(fp) except KeyError: err.append('File {0} doesn\'t exist'.format(fp)) - ret = False - else: + ret = False # set error flag, but keep assessing other files + else: # executed after "try", exeption will be ignored here if not check_fn(f): - err.append(msg(fp)) + err.append(msg(fp)) # dynamic string formatting ret = False - return ret + return ret only_valid = validate( only, lambda f: f.type == core.GL_STATUS_UNTRACKED or ( From 787da2f34a9aea6699531353be053bda41f8e224 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sun, 13 Nov 2016 21:10:24 -0500 Subject: [PATCH 019/196] typo fix --- gitless/cli/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 4845bea..86b32c3 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -182,7 +182,7 @@ def validate(fps, check_fn, msg): except KeyError: err.append('File {0} doesn\'t exist'.format(fp)) ret = False # set error flag, but keep assessing other files - else: # executed after "try", exeption will be ignored here + else: # executed after "try", exception will be ignored here if not check_fn(f): err.append(msg(fp)) # dynamic string formatting ret = False From b70bb46d592fb925d7cae0e6ae2ec87ae9fe1025 Mon Sep 17 00:00:00 2001 From: Peter Pentchev Date: Thu, 17 Nov 2016 13:12:36 +0200 Subject: [PATCH 020/196] Improve the invocation of the pager. Also check for the PAGER environment variable. Add the -f and -r arguments if the user-specified pager is "less", too. --- gitless/cli/helpers.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 86b32c3..a8a11ab 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -73,11 +73,11 @@ def page(fp, repo): pager = repo.config['core.pager'] except KeyError: pass - if pager: - cmd = shlex.split(pager) - cmd.append(fp) - else: - cmd = ['less', '-r', '-f', fp] + pager = pager or os.environ.get('PAGER', None) or 'less' + cmd = shlex.split(pager) + if os.path.basename(cmd[0]) == 'less': + cmd.extend(['-r', '-f']) + cmd.append(fp) subprocess.call(cmd, stdin=sys.stdin, stdout=sys.stdout) From d01e8ea6ce6e2fe9cbbd9932bb1c23f269ff3dd3 Mon Sep 17 00:00:00 2001 From: Peter Pentchev Date: Thu, 17 Nov 2016 13:15:22 +0200 Subject: [PATCH 021/196] Fix an infinite readline() loop. At least I am in the habit of removing the boilerplate text, just so that I'm absolutely sure that the commit message won't contain anything other than what I've written (e.g. if I accidentally deleted a character or two from the boilerplate text). Thus, the end of the commit message may be reached before the separator is found. --- gitless/cli/commit_dialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/cli/commit_dialog.py b/gitless/cli/commit_dialog.py index 8bde875..f28dad5 100644 --- a/gitless/cli/commit_dialog.py +++ b/gitless/cli/commit_dialog.py @@ -86,7 +86,7 @@ def _extract_msg(repo): sep = pprint.SEP + '\n' msg = '' l = cf.readline() - while l != sep: + while l != sep and len(l) > 0: msg += l l = cf.readline() # We reached the separator, this marks the end of the commit msg From 036298343924870dca289067a0b2409f581f7b46 Mon Sep 17 00:00:00 2001 From: Peter Pentchev Date: Thu, 17 Nov 2016 13:17:02 +0200 Subject: [PATCH 022/196] Correct some typographical errors. --- README.md | 4 ++-- gitless/cli/commit_dialog.py | 2 +- gitless/core.py | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b77a883..a759006 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ the Python Package Index). To install from source you need to have Python (2.7, 3.2+ or pypy) installed. -Additionaly, you need to [install pygit2]( +Additionally, you need to [install pygit2]( http://www.pygit2.org/install.html "pygit2 install"). Then, [download the source code tarball](http://gitless.com "Gitless's website") @@ -73,7 +73,7 @@ If you are a Python fan you might find it easier to install Gitless via the Python Package Index. To do this, you need to have Python (2.7, 3.2+ or pypy) installed. -Additionaly, you need to [install pygit2]( +Additionally, you need to [install pygit2]( http://www.pygit2.org/install.html "pygit2 install"). Then, just do: diff --git a/gitless/cli/commit_dialog.py b/gitless/cli/commit_dialog.py index 8bde875..4efb61b 100644 --- a/gitless/cli/commit_dialog.py +++ b/gitless/cli/commit_dialog.py @@ -54,7 +54,7 @@ def show(files, repo): pprint.msg('the commit.', stream=cf.write) pprint.blank(stream=cf.write) pprint.msg( - 'These are the files whose changes will be commited:', stream=cf.write) + 'These are the files whose changes will be committed:', stream=cf.write) for f in files: pprint.item(f, stream=cf.write) pprint.sep(stream=cf.write) diff --git a/gitless/core.py b/gitless/core.py index 6ecc4eb..2060e0d 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -231,7 +231,7 @@ def switch_current_branch(self, dst_b, move_over=False): Args: dst_b: the destination branch. - move_over: if True, then uncommited changes made in the current branch are + move_over: if True, then uncommitted changes made in the current branch are moved to the destination branch (defaults to False). """ if dst_b.is_current: @@ -807,7 +807,7 @@ def track_file(self, path): git('update-index', '--no-assume-unchanged', path, _cwd=self.gl_repo.root) else: - raise GlError('File {0} in unkown status {1}'.format(path, git_st)) + raise GlError('File {0} in unknown status {1}'.format(path, git_st)) def untrack_file(self, path): """Stop tracking changes to path.""" @@ -837,7 +837,7 @@ def untrack_file(self, path): git('update-index', '--assume-unchanged', path, _cwd=self.gl_repo.root) else: - raise GlError('File {0} in unkown status {1}'.format(path, git_st)) + raise GlError('File {0} in unknown status {1}'.format(path, git_st)) def resolve_file(self, path): """Mark the given path as resolved.""" From 5d070f5b437fb52009814431eac13be9f0bd1545 Mon Sep 17 00:00:00 2001 From: Arne Bachmann Date: Mon, 21 Nov 2016 20:46:17 +0100 Subject: [PATCH 023/196] Added Windows pager command to page() --- gitless/cli/helpers.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index a8a11ab..0de390f 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -68,16 +68,18 @@ def get_branch_or_use_upstream(branch_name, arg, repo): def page(fp, repo): - pager = '' - try: - pager = repo.config['core.pager'] - except KeyError: - pass - pager = pager or os.environ.get('PAGER', None) or 'less' - cmd = shlex.split(pager) - if os.path.basename(cmd[0]) == 'less': - cmd.extend(['-r', '-f']) - cmd.append(fp) + if sys.platform != 'win32': # e.g. Linux, BSD, Cygwin, Darwin + try: + pager = repo.config['core.pager'] + except KeyError: + pager = '' # empty string will evaluate to False below + pager = pager or os.environ.get('PAGER', None) or 'less' + cmd = shlex.split(pager) # split into constituents + if os.path.basename(cmd[0]) == 'less': + cmd.extend(['-r', '-f']) # append arguments + else: # running on native Windows + cmd = ['more', '/C'] + cmd.append(fp) # add file name to page command subprocess.call(cmd, stdin=sys.stdin, stdout=sys.stdout) From e011750bd2d80f5b982d90d7c6a31747978b84c8 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Tue, 22 Nov 2016 13:34:24 -0500 Subject: [PATCH 024/196] fix --- gitless/cli/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 0de390f..4478371 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -147,7 +147,7 @@ def oei_fs(args, repo): f.fp for f in curr_b.status() if f.type == core.GL_STATUS_TRACKED and f.modified) # using generator expression ret -= exclude - ret &= include + ret |= include ret = sorted(list(ret)) return ret From 0d898fe5d1698f67903b7d41bf7c19f6541a32a8 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Tue, 22 Nov 2016 13:38:30 -0500 Subject: [PATCH 025/196] make travis run tests on the master branch too --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index faa6d47..91fa0c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,7 @@ script: branches: only: + - master - develop sudo: false From e04f22f00905d838d4f670267fffcb691b462e50 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Tue, 22 Nov 2016 17:04:37 -0500 Subject: [PATCH 026/196] sort the list of tags and branches when listed --- gitless/cli/gl_branch.py | 6 +++--- gitless/cli/gl_tag.py | 6 +++--- gitless/tests/test_e2e.py | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index a484032..f6034fc 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -81,7 +81,7 @@ def _do_list(repo, list_remote, v=False): pprint.blank() - for b in (repo.lookup_branch(n) for n in repo.listall_branches()): + for b in (repo.lookup_branch(n) for n in sorted(repo.listall_branches())): current_str = '*' if b.is_current else ' ' upstream_str = '(upstream is {0})'.format(b.upstream) if b.upstream else '' color = colored.green if b.is_current else colored.yellow @@ -91,8 +91,8 @@ def _do_list(repo, list_remote, v=False): pprint.item(' ➜ head is {0}'.format(pprint.commit_str(b.head))) if list_remote: - for r in repo.remotes: - for b in (r.lookup_branch(n) for n in r.listall_branches()): + for r in sorted(repo.remotes, key=lambda r: r.name): + for b in (r.lookup_branch(n) for n in sorted(r.listall_branches())): pprint.item(' {0}'.format(colored.yellow(str(b)))) if v: pprint.item(' ➜ head is {0}'.format(pprint.commit_str(b.head))) diff --git a/gitless/cli/gl_tag.py b/gitless/cli/gl_tag.py index c7a92fa..10df37b 100644 --- a/gitless/cli/gl_tag.py +++ b/gitless/cli/gl_tag.py @@ -56,13 +56,13 @@ def _do_list(repo, list_remote): pprint.blank() no_tags = True - for t in (repo.lookup_tag(n) for n in repo.listall_tags()): + for t in (repo.lookup_tag(n) for n in sorted(repo.listall_tags())): pprint.item('{0} ➜ tags {1}'.format(t, pprint.commit_str(t.commit))) no_tags = False if list_remote: - for r in repo.remotes: - for t in (r.lookup_tag(n) for n in r.listall_tags()): + for r in sorted(repo.remotes, key=lambda r: r.name): + for t in (r.lookup_tag(n) for n in sorted(r.listall_tags())): pprint.item('{0} ➜ tags {1}'.format(t, pprint.commit_str(t.commit))) no_tags = False diff --git a/gitless/tests/test_e2e.py b/gitless/tests/test_e2e.py index 13ca5a4..39ff290 100755 --- a/gitless/tests/test_e2e.py +++ b/gitless/tests/test_e2e.py @@ -286,10 +286,18 @@ def test_upstream(self): self.assertRaises( ErrorReturnCode, gl.branch, '-su', 'non-existent/non-existent') + def test_list(self): + gl.branch(c=self.BRANCH_1) + gl.branch(c=self.BRANCH_2) + branch_out = utils.stdout(gl.branch(_tty_out=False)) + self.assertTrue( + branch_out.find(self.BRANCH_1) < branch_out.find(self.BRANCH_2)) + class TestTag(TestEndToEnd): TAG_1 = 'tag1' + TAG_2 = 'tag2' def setUp(self): super(TestTag, self).setUp() @@ -310,6 +318,13 @@ def test_remove(self): if self.TAG_1 in utils.stdout(gl.tag(_tty_out=False)): self.fail() + def test_list(self): + gl.tag(c=self.TAG_1) + gl.tag(c=self.TAG_2) + tag_out = utils.stdout(gl.tag(_tty_out=False)) + self.assertTrue( + tag_out.find(self.TAG_1) < tag_out.find(self.TAG_2)) + class TestDiffFile(TestEndToEnd): From 255b6d4fd2270429c666bc15598134f106e8f4d7 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Wed, 23 Nov 2016 11:07:15 -0500 Subject: [PATCH 027/196] group flags of 'gl branch' and 'gl tag' and throw error on invalid combinations --- gitless/cli/gl_branch.py | 44 +++++++++++++++++++++++++++------------- gitless/cli/gl_tag.py | 27 +++++++++++++++++------- 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index f6034fc..e03fb10 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -16,48 +16,64 @@ def parser(subparsers, _): """Adds the branch parser to the given subparsers object.""" - desc = 'list, create, edit or delete branches' + desc = 'list, create, delete, or edit branches' branch_parser = subparsers.add_parser( 'branch', help=desc, description=desc.capitalize()) - branch_parser.add_argument( + + list_group = branch_parser.add_argument_group('list branches') + list_group.add_argument( '-r', '--remote', help='list remote branches in addition to local branches', action='store_true') + list_group.add_argument( + '-v', '--verbose', help='be verbose, will output the head of each branch', + action='store_true') - branch_parser.add_argument( + create_group = branch_parser.add_argument_group('create branches') + create_group.add_argument( '-c', '--create', nargs='+', help='create branch(es)', dest='create_b', metavar='branch') - branch_parser.add_argument( + create_group.add_argument( '-dp', '--divergent-point', help='the commit from where to \'branch out\' (only relevant if a new ' - 'branch is created; defaults to HEAD)', default='HEAD', - dest='dp') - branch_parser.add_argument( + 'branch is created; defaults to HEAD)', dest='dp') + + delete_group = branch_parser.add_argument_group('delete branches') + delete_group.add_argument( '-d', '--delete', nargs='+', help='delete branch(es)', dest='delete_b', metavar='branch') - branch_parser.add_argument( + edit_group = branch_parser.add_argument_group('edit the current branch') + edit_group.add_argument( '-sh', '--set-head', help='set the head of the current branch', dest='new_head', metavar='commit_id') - branch_parser.add_argument( + edit_group.add_argument( '-su', '--set-upstream', help='set the upstream branch of the current branch', dest='upstream_b', metavar='branch') - branch_parser.add_argument( + edit_group.add_argument( '-uu', '--unset-upstream', help='unset the upstream branch of the current branch', action='store_true') - branch_parser.add_argument( - '-v', '--verbose', help='be verbose, will output the head of each branch', - action='store_true') branch_parser.set_defaults(func=main) def main(args, repo): + is_list = bool(args.verbose or args.remote) + is_create = bool(args.create_b or args.dp) + is_delete = bool(args.delete_b) + is_edit = bool(args.new_head or args.upstream_b or args.unset_upstream) + + if is_list + is_create + is_delete + is_edit > 1: + pprint.err('Invalid flag combination') + pprint.err_exp( + 'Can only do one of list, create, delete, or edit branches at a time') + return False + ret = True if args.create_b: - ret = _do_create(args.create_b, args.dp, repo) + ret = _do_create(args.create_b, args.dp or 'HEAD', repo) elif args.delete_b: ret = _do_delete(args.delete_b, repo) elif args.upstream_b: diff --git a/gitless/cli/gl_tag.py b/gitless/cli/gl_tag.py index 10df37b..a3d3dd3 100644 --- a/gitless/cli/gl_tag.py +++ b/gitless/cli/gl_tag.py @@ -17,20 +17,24 @@ def parser(subparsers, _): desc = 'list, create, or delete tags' tag_parser = subparsers.add_parser( 'tag', help=desc, description=desc.capitalize()) - tag_parser.add_argument( + + list_group = tag_parser.add_argument_group('list tags') + list_group.add_argument( '-r', '--remote', help='list remote tags in addition to local tags', action='store_true') - tag_parser.add_argument( + create_group = tag_parser.add_argument_group('create tags') + create_group.add_argument( '-c', '--create', nargs='+', help='create tag(s)', dest='create_t', metavar='tag') - tag_parser.add_argument( + create_group.add_argument( '-ci', '--commit', help='the commit to tag (only relevant if a new ' - 'tag is created; defaults to the HEAD commit)', default='HEAD', - dest='ci') - tag_parser.add_argument( + 'tag is created; defaults to the HEAD commit)', dest='ci') + + delete_group = tag_parser.add_argument_group('delete tags') + delete_group.add_argument( '-d', '--delete', nargs='+', help='delete tag(s)', dest='delete_t', metavar='tag') @@ -38,9 +42,18 @@ def parser(subparsers, _): def main(args, repo): + is_list = bool(args.remote) + is_create = bool(args.create_t or args.ci) + is_delete = bool(args.delete_t) + + if is_list + is_create + is_delete > 1: + pprint.err('Invalid flag combination') + pprint.err_exp('Can only do one of list, create, or delete tags at a time') + return False + ret = True if args.create_t: - ret = _do_create(args.create_t, args.ci, repo) + ret = _do_create(args.create_t, args.ci or 'HEAD', repo) elif args.delete_t: ret = _do_delete(args.delete_t, repo) else: From db23034a15d34edac1813f51ee211f3fd902b363 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Wed, 23 Nov 2016 11:16:59 -0500 Subject: [PATCH 028/196] 'gl' without any argument now displays the help message --- gitless/cli/gl.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 39c872e..041e2b0 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -7,6 +7,7 @@ from __future__ import unicode_literals +import sys import argparse import traceback import pygit2 @@ -65,6 +66,10 @@ def main(): for sub_cmd in sub_cmds: sub_cmd.parser(subparsers, repo) + if len(sys.argv) == 1: + parser.print_help() + return SUCCESS + args = parser.parse_args() try: if args.subcmd_name != 'init' and not repo: From 549ea16ce38cff917018dbe341d24d295bf1e4dc Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Wed, 23 Nov 2016 15:32:21 -0500 Subject: [PATCH 029/196] ignore .git dir when processing paths --- gitless/cli/helpers.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 4478371..b9466b5 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -86,19 +86,23 @@ def page(fp, repo): class PathProcessor(argparse.Action): def __init__(self, option_strings, dest, repo=None, **kwargs): - self.root = repo.root if repo else '' + self.repo = repo super(PathProcessor, self).__init__(option_strings, dest, **kwargs) def __call__(self, parser, namespace, paths, option_string=None): + root = self.repo.root if self.repo else '' + repo_dir = self.repo.path[:-1] if self.repo else '' # strip trailing / def process_paths(): for path in paths: path = os.path.normpath(path) if os.path.isdir(path): for curr_dir, _, fps in os.walk(path): - for fp in fps: - yield os.path.relpath(os.path.join(curr_dir, fp), self.root) + if not os.path.abspath(curr_dir).startswith(repo_dir): + for fp in fps: + yield os.path.relpath(os.path.join(curr_dir, fp), root) else: - yield os.path.relpath(path, self.root) + if not os.path.abspath(path).startswith(repo_dir): + yield os.path.relpath(path, root) setattr(namespace, self.dest, process_paths()) From 561ff8fe5dc47ab02db581dcfcb3f7b2d17984a9 Mon Sep 17 00:00:00 2001 From: breisfeld Date: Mon, 28 Nov 2016 09:14:22 -0700 Subject: [PATCH 030/196] Add try/except clauses to catch potential decode errors on stdout and stderr --- gitless/core.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gitless/core.py b/gitless/core.py index 2060e0d..0532fb8 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -1270,10 +1270,18 @@ def _stash_msg_merge(name): 'OpCb', ['apply_ok', 'apply_err', 'save', 'restore_ok']) def stdout(p): - return p.stdout.decode(ENCODING) + try: + pstdout = p.stdout.decode(ENCODING) + except AttributeError: + pstdout = p.stdout + return pstdout def stderr(p): - return p.stderr.decode(ENCODING) + try: + pstderr = p.stderr.decode(ENCODING) + except AttributeError: + pstderr = p.stderr + return pstderr def walker(git_repo, target, reverse): flags = pygit2.GIT_SORT_TOPOLOGICAL | pygit2.GIT_SORT_TIME From 5a9e73c62eee740151cfa7ef0e64a1e1768a5763 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Wed, 30 Nov 2016 15:32:03 -0500 Subject: [PATCH 031/196] skip ignored dirs when tracking, untracking, or doing a checkout of files --- gitless/cli/file_cmd.py | 6 +++++- gitless/cli/helpers.py | 22 +++++++++++++++++----- gitless/core.py | 5 +++++ setup.py | 2 +- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/gitless/cli/file_cmd.py b/gitless/cli/file_cmd.py index 8d56741..e1ea45a 100644 --- a/gitless/cli/file_cmd.py +++ b/gitless/cli/file_cmd.py @@ -19,7 +19,11 @@ def f(subparsers, repo): subcmd, help=help_msg, description=help_msg.capitalize()) p.add_argument( 'files', nargs='+', help='the file(s) to {0}'.format(subcmd), - action=helpers.PathProcessor, repo=repo) + action=helpers.PathProcessor, repo=repo, + skip_dir_test=repo and repo.current_branch.path_is_ignored, + skip_dir_cb=lambda path: pprint.warn( + 'Skipped files under directory {0} since they are all ' + 'ignored'.format(path))) p.set_defaults(func=main(subcmd)) return f diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index b9466b5..a80ac3d 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -85,8 +85,12 @@ def page(fp, repo): class PathProcessor(argparse.Action): - def __init__(self, option_strings, dest, repo=None, **kwargs): + def __init__( + self, option_strings, dest, repo=None, skip_dir_test=None, + skip_dir_cb=None, **kwargs): self.repo = repo + self.skip_dir_test = skip_dir_test + self.skip_dir_cb = skip_dir_cb super(PathProcessor, self).__init__(option_strings, dest, **kwargs) def __call__(self, parser, namespace, paths, option_string=None): @@ -96,10 +100,18 @@ def process_paths(): for path in paths: path = os.path.normpath(path) if os.path.isdir(path): - for curr_dir, _, fps in os.walk(path): - if not os.path.abspath(curr_dir).startswith(repo_dir): - for fp in fps: - yield os.path.relpath(os.path.join(curr_dir, fp), root) + for curr_dir, dirs, fps in os.walk(path, topdown=True): + if os.path.abspath(curr_dir).startswith(repo_dir): + dirs[:] = [] + continue + curr_dir_rel = os.path.relpath(curr_dir, root) + if self.skip_dir_test and self.skip_dir_test(curr_dir_rel): + if self.skip_dir_cb: + self.skip_dir_cb(curr_dir_rel) + dirs[:] = [] + continue + for fp in fps: + yield os.path.join(curr_dir_rel, fp) else: if not os.path.abspath(path).startswith(repo_dir): yield os.path.relpath(path, root) diff --git a/gitless/core.py b/gitless/core.py index 2060e0d..3c5b43a 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -780,6 +780,11 @@ def _status_file(self, path): f_st = self.FileStatus(path, *self._st_map[git_st]) return f_st, git_st, is_au + def path_is_ignored(self, path): + assert not os.path.isabs(path) + + return self.gl_repo.git_repo.path_is_ignored(path) + # File related methods diff --git a/setup.py b/setup.py index 278520e..e7568e7 100755 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ sys.exit() -reqs = ['pygit2>=0.23.0', 'sh>=1.11', 'clint>=0.3.6'] +reqs = ['pygit2>=0.24.0', 'sh>=1.11', 'clint>=0.3.6'] if sys.version_info < (2, 7) or ( sys.version_info < (3, 3) and sys.version_info > (3, 0)): reqs.append('argparse') From 18328a55ddf6e46e0a88049fe3af1c0753cae0ac Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Wed, 30 Nov 2016 17:56:17 -0500 Subject: [PATCH 032/196] fix in PathProcessor ('.' is considered an ignored path by libgit2) --- gitless/cli/helpers.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index a80ac3d..17c3ab4 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -98,14 +98,15 @@ def __call__(self, parser, namespace, paths, option_string=None): repo_dir = self.repo.path[:-1] if self.repo else '' # strip trailing / def process_paths(): for path in paths: - path = os.path.normpath(path) + path = os.path.abspath(path) if os.path.isdir(path): for curr_dir, dirs, fps in os.walk(path, topdown=True): - if os.path.abspath(curr_dir).startswith(repo_dir): + if curr_dir.startswith(repo_dir): dirs[:] = [] continue curr_dir_rel = os.path.relpath(curr_dir, root) - if self.skip_dir_test and self.skip_dir_test(curr_dir_rel): + if (curr_dir_rel != "." and self.skip_dir_test and + self.skip_dir_test(curr_dir_rel)): if self.skip_dir_cb: self.skip_dir_cb(curr_dir_rel) dirs[:] = [] @@ -113,7 +114,7 @@ def process_paths(): for fp in fps: yield os.path.join(curr_dir_rel, fp) else: - if not os.path.abspath(path).startswith(repo_dir): + if not path.startswith(repo_dir): yield os.path.relpath(path, root) setattr(namespace, self.dest, process_paths()) From c0ee851912d96ce9958cbb383a80bf4d52dbd88c Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sat, 3 Dec 2016 17:37:39 -0500 Subject: [PATCH 033/196] stop using sh's tty_out option in tests (it's not present in pbs) --- gitless/tests/test_e2e.py | 61 +++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/gitless/tests/test_e2e.py b/gitless/tests/test_e2e.py index 39ff290..bd416a9 100755 --- a/gitless/tests/test_e2e.py +++ b/gitless/tests/test_e2e.py @@ -27,7 +27,12 @@ class TestEndToEnd(utils.TestBase): def setUp(self): super(TestEndToEnd, self).setUp('gl-e2e-test') gl.init() + # Disable colored output so that we don't need to worry about ANSI escape + # codes git.config('color.ui', False) + # Disable paging so that we don't have to use sh's _tty_out option, which is + # not available on pbs + git.config('core.pager', 'cat') utils.set_test_config() @@ -64,7 +69,7 @@ def test_basic_functionality(self): gl.commit(m='file1 commit') self.assertRaises(ErrorReturnCode, gl.commit, m='nothing to commit') # History - if 'file1 commit' not in utils.stdout(gl.history(_tty_out=False)): + if 'file1 commit' not in utils.stdout(gl.history()): self.fail('Commit didn\'t appear in history') # Branch # Make some changes to file1 and branch out @@ -77,7 +82,7 @@ def test_basic_functionality(self): gl.switch('master') if 'New' not in utils.read_file('file1'): self.fail('Branch not independent!') - out = utils.stdout(gl.branch(_tty_out=False)) + out = utils.stdout(gl.branch()) if '* master' not in out: self.fail('Branch status output wrong: {0}'.format(out)) if 'branch1' not in out: @@ -95,7 +100,7 @@ def test_basic_functionality(self): gl.fuse('master') except ErrorReturnCode as e: self.fail(utils.stderr(e)) - out = utils.stdout(gl.history(_tty_out=False)) + out = utils.stdout(gl.history()) if 'file1 commit' not in out: self.fail(out) @@ -103,7 +108,7 @@ def test_basic_functionality(self): gl.switch('branch2') self.assertRaises(ErrorReturnCode, gl.merge) # no upstream set gl.merge('master') - out = utils.stdout(gl.history(_tty_out=False)) + out = utils.stdout(gl.history()) if 'file1 commit' not in out: self.fail(out) @@ -111,24 +116,24 @@ def test_basic_functionality(self): gl.switch('branch-conflict1') utils.write_file('file1', 'Conflicting changes to file1') gl.commit(m='changes in branch-conflict1') - err = utils.stderr(gl.fuse('master', _tty_out=False, _ok_code=[1])) + err = utils.stderr(gl.fuse('master', _ok_code=[1])) if 'conflict' not in err: self.fail(err) - out = utils.stdout(gl.status(_tty_out=False)) + out = utils.stdout(gl.status()) if 'file1 (with conflicts)' not in out: self.fail(out) # Try aborting gl.fuse('--abort') - out = utils.stdout(gl.status(_tty_out=False)) + out = utils.stdout(gl.status()) if 'file1' in out: self.fail(out) # Ok, now let's fix the conflicts - err = utils.stderr(gl.fuse('master', _tty_out=False, _ok_code=[1])) + err = utils.stderr(gl.fuse('master', _ok_code=[1])) if 'conflict' not in err: self.fail(err) - out = utils.stdout(gl.status(_tty_out=False)) + out = utils.stdout(gl.status()) if 'file1 (with conflicts)' not in out: self.fail(out) @@ -209,7 +214,7 @@ def test_commit_dir(self): self.__assert_commit('dir/f') def __assert_commit(self, *expected_committed): - h = utils.stdout(gl.history(v=True, _tty_out=False)) + h = utils.stdout(gl.history(v=True)) for fp in expected_committed: if fp not in h: self.fail('{0} was apparently not committed!'.format(fp)) @@ -235,7 +240,7 @@ def setUp(self): def test_status_relative(self): utils.write_file(self.TRACKED_DIR_FP, contents='some modifications') - st = utils.stdout(gl.status(_tty_out=False)) + st = utils.stdout(gl.status()) if self.TRACKED_DIR_FP not in st: self.fail() if self.UNTRACKED_DIR_FP not in st: @@ -243,7 +248,7 @@ def test_status_relative(self): os.chdir(self.DIR) - st = utils.stdout(gl.status(_tty_out=False)) + st = utils.stdout(gl.status()) rel_tracked = os.path.relpath(self.TRACKED_DIR_FP, self.DIR) rel_untracked = os.path.relpath(self.UNTRACKED_DIR_FP, self.DIR) if (self.TRACKED_DIR_FP in st) or (rel_tracked not in st): @@ -266,7 +271,7 @@ def test_create(self): gl.branch(c=self.BRANCH_1) self.assertRaises(ErrorReturnCode, gl.branch, c=self.BRANCH_1) self.assertRaises(ErrorReturnCode, gl.branch, c='evil*named*branch') - if self.BRANCH_1 not in utils.stdout(gl.branch(_tty_out=False)): + if self.BRANCH_1 not in utils.stdout(gl.branch()): self.fail() def test_remove(self): @@ -277,7 +282,7 @@ def test_remove(self): gl.switch(self.BRANCH_2) gl.branch(d=self.BRANCH_1, _in='n') gl.branch(d=self.BRANCH_1, _in='y') - if self.BRANCH_1 in utils.stdout(gl.branch(_tty_out=False)): + if self.BRANCH_1 in utils.stdout(gl.branch()): self.fail() def test_upstream(self): @@ -289,7 +294,7 @@ def test_upstream(self): def test_list(self): gl.branch(c=self.BRANCH_1) gl.branch(c=self.BRANCH_2) - branch_out = utils.stdout(gl.branch(_tty_out=False)) + branch_out = utils.stdout(gl.branch()) self.assertTrue( branch_out.find(self.BRANCH_1) < branch_out.find(self.BRANCH_2)) @@ -308,20 +313,20 @@ def test_create(self): gl.tag(c=self.TAG_1) self.assertRaises(ErrorReturnCode, gl.tag, c=self.TAG_1) self.assertRaises(ErrorReturnCode, gl.tag, c='evil*named*tag') - if self.TAG_1 not in utils.stdout(gl.tag(_tty_out=False)): + if self.TAG_1 not in utils.stdout(gl.tag()): self.fail() def test_remove(self): gl.tag(c=self.TAG_1) gl.tag(d=self.TAG_1, _in='n') gl.tag(d=self.TAG_1, _in='y') - if self.TAG_1 in utils.stdout(gl.tag(_tty_out=False)): + if self.TAG_1 in utils.stdout(gl.tag()): self.fail() def test_list(self): gl.tag(c=self.TAG_1) gl.tag(c=self.TAG_2) - tag_out = utils.stdout(gl.tag(_tty_out=False)) + tag_out = utils.stdout(gl.tag()) self.assertTrue( tag_out.find(self.TAG_1) < tag_out.find(self.TAG_2)) @@ -341,20 +346,20 @@ def setUp(self): utils.write_file(self.UNTRACKED_FP) def test_empty_diff(self): - if 'No files to diff' not in utils.stdout(gl.diff(_tty_out=False)): + if 'No files to diff' not in utils.stdout(gl.diff()): self.fail() def test_diff_nonexistent_fp(self): - err = utils.stderr(gl.diff(o='file', _ok_code=[1], _tty_out=False)) + err = utils.stderr(gl.diff(o='file', _ok_code=[1])) if 'doesn\'t exist' not in err: self.fail() def test_basic_diff(self): utils.write_file(self.TRACKED_FP, contents='contents') - out1 = utils.stdout(gl.diff(_tty_out=False)) + out1 = utils.stdout(gl.diff()) if '+contents' not in out1: self.fail() - out2 = utils.stdout(gl.diff(o=self.TRACKED_FP, _tty_out=False)) + out2 = utils.stdout(gl.diff(o=self.TRACKED_FP)) if '+contents' not in out2: self.fail() self.assertEqual(out1, out2) @@ -363,30 +368,30 @@ def test_basic_diff_relative(self): utils.write_file(self.TRACKED_FP, contents='contents_tracked') utils.write_file(self.DIR_TRACKED_FP, contents='contents_dir_tracked') os.chdir(self.DIR) - out1 = utils.stdout(gl.diff(_tty_out=False)) + out1 = utils.stdout(gl.diff()) if '+contents_tracked' not in out1: self.fail() if '+contents_dir_tracked' not in out1: self.fail() rel_dir_tracked_fp = os.path.relpath(self.DIR_TRACKED_FP, self.DIR) - out2 = utils.stdout(gl.diff(o=rel_dir_tracked_fp, _tty_out=False)) + out2 = utils.stdout(gl.diff(o=rel_dir_tracked_fp)) if '+contents_dir_tracked' not in out2: self.fail() def test_diff_dir(self): fp = 'dir/dir/f' utils.write_file(fp, contents='contents') - out = utils.stdout(gl.diff(o=fp, _tty_out=False)) + out = utils.stdout(gl.diff(o=fp)) if '+contents' not in out: self.fail() def test_diff_non_ascii(self): contents = '’◕‿◕’©Ä☺’ಠ_ಠ’' utils.write_file(self.TRACKED_FP, contents=contents) - out1 = utils.stdout(gl.diff(_tty_out=False)) + out1 = utils.stdout(gl.diff()) if '+' + contents not in out1: self.fail('out is ' + out1) - out2 = utils.stdout(gl.diff(o=self.TRACKED_FP, _tty_out=False)) + out2 = utils.stdout(gl.diff(o=self.TRACKED_FP)) if '+' + contents not in out2: self.fail('out is ' + out2) self.assertEqual(out1, out2) @@ -425,7 +430,7 @@ def create_commits(branch_name, fp): class TestFuse(TestOp): def __assert_history(self, expected): - out = utils.stdout(gl.history(_tty_out=False)) + out = utils.stdout(gl.history()) cids = list(reversed(re.findall(r'ci (.*) in (.*)', out, re.UNICODE))) self.assertEqual( cids, expected, 'cids is ' + text(cids) + ' exp ' + text(expected)) From 2765cac41bafa93cf345c98ac2bfcc5ef4314bbd Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sat, 3 Dec 2016 18:32:18 -0500 Subject: [PATCH 034/196] prevent git from paging output when running commands in core --- gitless/core.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gitless/core.py b/gitless/core.py index 3c5b43a..8011cd2 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -24,6 +24,8 @@ import pygit2 from sh import git, ErrorReturnCode +git = git.bake('--no-pager') + ENCODING = getpreferredencoding() or 'utf-8' @@ -1248,8 +1250,7 @@ def __str__(self): def _stash(pattern): """Returns the id and msg of the stash that matches the given pattern.""" - out = stdout( - git.stash.list(grep=pattern, format='|*|%gd|*|%B|*|', _tty_out=False)) + out = stdout(git.stash.list(grep=pattern, format='|*|%gd|*|%B|*|')) if not out: return None, None From d0aabff3cd0c7cf466d4fe67d11c3a1a156d57a9 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sun, 4 Dec 2016 19:49:22 -0500 Subject: [PATCH 035/196] windows support --- gitless/cli/gl.py | 6 ++++- gitless/cli/gl_commit.py | 8 +++++- gitless/cli/helpers.py | 28 ++++++++++++-------- gitless/core.py | 52 +++++++++++++++++++++++++------------- gitless/tests/test_core.py | 12 +++++++-- gitless/tests/test_e2e.py | 34 +++++++++++++++++-------- gitless/tests/utils.py | 30 +++++++++++++++++++--- setup.py | 8 +++++- 8 files changed, 131 insertions(+), 47 deletions(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 041e2b0..16a768f 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -11,7 +11,11 @@ import argparse import traceback import pygit2 -from sh import ErrorReturnCode + +if sys.platform != 'win32': + from sh import ErrorReturnCode +else: + from pbs import ErrorReturnCode from clint.textui import colored diff --git a/gitless/cli/gl_commit.py b/gitless/cli/gl_commit.py index 96a0eb3..dedc1f4 100644 --- a/gitless/cli/gl_commit.py +++ b/gitless/cli/gl_commit.py @@ -8,7 +8,13 @@ from __future__ import unicode_literals import subprocess -from sh import git + +import sys +if sys.platform != 'win32': + from sh import git +else: + from pbs import Command + git = Command('git') from gitless import core diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 17c3ab4..5ceba33 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -68,17 +68,18 @@ def get_branch_or_use_upstream(branch_name, arg, repo): def page(fp, repo): - if sys.platform != 'win32': # e.g. Linux, BSD, Cygwin, Darwin - try: - pager = repo.config['core.pager'] - except KeyError: - pager = '' # empty string will evaluate to False below - pager = pager or os.environ.get('PAGER', None) or 'less' - cmd = shlex.split(pager) # split into constituents - if os.path.basename(cmd[0]) == 'less': - cmd.extend(['-r', '-f']) # append arguments - else: # running on native Windows - cmd = ['more', '/C'] + # On Windows, we need to call 'more' through cmd.exe (with 'cmd'). The /C is + # so that the command window gets closed after 'more' finishes + default_pager = 'less' if sys.platform != 'win32' else 'cmd /C more' + try: + pager = repo.config['core.pager'] + except KeyError: + pager = '' # empty string will evaluate to False below + pager = pager or os.environ.get('PAGER', None) or default_pager + cmd = shlex.split(pager) # split into constituents + if os.path.basename(cmd[0]) == 'less': + cmd.extend(['-r', '-f']) # append arguments + cmd.append(fp) # add file name to page command subprocess.call(cmd, stdin=sys.stdin, stdout=sys.stdout) @@ -163,6 +164,11 @@ def oei_fs(args, repo): ret = frozenset( f.fp for f in curr_b.status() if f.type == core.GL_STATUS_TRACKED and f.modified) # using generator expression + # We get the files from status with forward slashes. On Windows, these + # won't match the paths provided by the user, which are normalized by + # PathProcessor + if sys.platform == 'win32': + ret = frozenset(p.replace('/', '\\') for p in ret) ret -= exclude ret |= include diff --git a/gitless/core.py b/gitless/core.py index 8011cd2..793bec1 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -22,7 +22,14 @@ import shutil import pygit2 -from sh import git, ErrorReturnCode + + +import sys +if sys.platform != 'win32': + from sh import git, ErrorReturnCode +else: + from pbs import Command, ErrorReturnCode + git = Command('git') git = git.bake('--no-pager') @@ -769,8 +776,9 @@ def status_file(self, path): def _status_file(self, path): assert not os.path.isabs(path) - git_st = self.gl_repo.git_repo.status_file(path) + git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + git_st = self.gl_repo.git_repo.status_file(git_path) root = self.gl_repo.root cmd_out = stdout(git('ls-files', '-v', '--full-name', path, _cwd=root)) is_au = cmd_out and cmd_out[0] == 'h' @@ -785,7 +793,8 @@ def _status_file(self, path): def path_is_ignored(self, path): assert not os.path.isabs(path) - return self.gl_repo.git_repo.path_is_ignored(path) + git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + return self.gl_repo.git_repo.path_is_ignored(git_path) # File related methods @@ -809,7 +818,8 @@ def track_file(self, path): # (ii) an assumed unchanged file => unmark it. if git_st == pygit2.GIT_STATUS_WT_NEW: # Case (i) with self._index as index: - index.add(path) + git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + index.add(git_path) elif is_au: # Case (ii) git('update-index', '--no-assume-unchanged', path, _cwd=self.gl_repo.root) @@ -834,12 +844,13 @@ def untrack_file(self, path): # If we reached this point we know that the file to untrack is a tracked # file. This means that in the Git world, the file could be either: # (i) a new file for Git that is staged (the user executed `gl track` on - # an uncomitted file) => reset changes; + # an uncommitted file) => reset changes; # (ii) the file is a previously committed file => mark it as assumed # unchanged. if git_st == pygit2.GIT_STATUS_INDEX_NEW: # Case (i) with self._index as index: - index.remove(path) + git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + index.remove(git_path) elif not is_au: # Case (ii) git('update-index', '--assume-unchanged', path, _cwd=self.gl_repo.root) @@ -855,39 +866,42 @@ def resolve_file(self, path): raise ValueError('File {0} has no conflicts'.format(path)) with self._index as index: - index.add(path) + git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + index.add(git_path) def checkout_file(self, path, commit): """Checkouts the given path at the given commit.""" assert not os.path.isabs(path) - data = self.gl_repo.git_repo[commit.tree[path].id].data + git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + data = self.gl_repo.git_repo[commit.tree[git_path].id].data with io.open(os.path.join(self.gl_repo.root, path), mode='wb') as dst: dst.write(data) # So as to not get confused with the status of the file we also add it with self._index as index: - index.add(path) + index.add(git_path) def diff_file(self, path): """Diff the working version of path with its committed version.""" assert not os.path.isabs(path) git_repo = self.gl_repo.git_repo + git_path = path if sys.platform != 'win32' else path.replace('\\', '/') try: - blob_at_head = git_repo[git_repo.head.peel().tree[path].id] + blob_at_head = git_repo[git_repo.head.peel().tree[git_path].id] except KeyError: # no blob at head - wt_blob = git_repo[git_repo.create_blob_fromworkdir(path)] + wt_blob = git_repo[git_repo.create_blob_fromworkdir(git_path)] nil_blob = git_repo[git_repo.create_blob('')] - return nil_blob.diff(wt_blob, 0, path, path) + return nil_blob.diff(wt_blob, 0, git_path, git_path) try: - wt_blob = git_repo[git_repo.create_blob_fromworkdir(path)] + wt_blob = git_repo[git_repo.create_blob_fromworkdir(git_path)] except KeyError: # no blob at wd (the file was deleted) nil_blob = git_repo[git_repo.create_blob('')] - return blob_at_head.diff(nil_blob, 0, path, path) + return blob_at_head.diff(nil_blob, 0, git_path, git_path) - return blob_at_head.diff(wt_blob, 0, path, path) + return blob_at_head.diff(wt_blob, 0, git_path, git_path) # Merge related methods @@ -1148,17 +1162,19 @@ def update(): """Add/remove files to the index.""" for f in files: assert not os.path.isabs(f) + git_f = f if sys.platform != 'win32' else f.replace('\\', '/') if not os.path.exists(os.path.join(self.gl_repo.root, f)): - index.remove(f) + index.remove(git_f) elif f not in partials: - index.add(f) + index.add(git_f) # Update index to how it should look like after the commit partial_entries = {} with index: update() for f in partials: - partial_entries[f] = index._git_index[f] + git_f = f if sys.platform != 'win32' else f.replace('\\', '/') + partial_entries[f] = index._git_index[git_f] # To create the commit tree with only the changes to the given files we: # (i) reset the index to HEAD, diff --git a/gitless/tests/test_core.py b/gitless/tests/test_core.py index 366bd29..1ccda5a 100644 --- a/gitless/tests/test_core.py +++ b/gitless/tests/test_core.py @@ -12,7 +12,12 @@ import shutil import tempfile -from sh import git +import sys +if sys.platform != 'win32': + from sh import git +else: + from pbs import Command + git = Command('git') from gitless import core import gitless.tests.utils as utils_lib @@ -662,6 +667,9 @@ def test_diff_new_fp(self): self.assertEqual('new line', hunk.lines[1].content) def test_diff_non_ascii(self): + if sys.platform == 'win32': + # Skip this test on Windows until we fix Unicode support + return fp = 'new' new_fp_contents = '’◕‿◕’©Ä☺’ಠ_ಠ’\n' utils_lib.write_file(fp, contents=new_fp_contents) @@ -884,7 +892,7 @@ def setUp(self): def tearDown(self): """Removes the temporary dir.""" super(TestRemote, self).tearDown() - shutil.rmtree(self.remote_path) + utils_lib.rmtree(self.remote_path) class TestRemoteCreate(TestRemote): diff --git a/gitless/tests/test_e2e.py b/gitless/tests/test_e2e.py index bd416a9..d24d794 100755 --- a/gitless/tests/test_e2e.py +++ b/gitless/tests/test_e2e.py @@ -12,7 +12,14 @@ import re import time -from sh import ErrorReturnCode, gl, git +import sys +if sys.platform != 'win32': + from sh import ErrorReturnCode, gl, git +else: + from pbs import ErrorReturnCode, Command + gl = Command('gl') + git = Command('git') + from gitless.tests import utils @@ -32,7 +39,12 @@ def setUp(self): git.config('color.ui', False) # Disable paging so that we don't have to use sh's _tty_out option, which is # not available on pbs - git.config('core.pager', 'cat') + if sys.platform != 'win32': + git.config('core.pager', 'cat') + else: + # On Windows, we need to call 'type' through cmd.exe (with 'cmd'). The /C + # is so that the command window gets closed after 'type' finishes + git.config('core.pager', 'cmd /C type') utils.set_test_config() @@ -228,9 +240,8 @@ def __assert_commit(self, *expected_committed): class TestStatus(TestEndToEnd): DIR = 'dir' - TRACKED_DIR_FP = 'dir/file1' - TRACKED_DIR_FP = 'dir/file1' - UNTRACKED_DIR_FP = 'dir/file2' + TRACKED_DIR_FP = os.path.join('dir', 'file1') + UNTRACKED_DIR_FP = os.path.join('dir', 'file2') def setUp(self): super(TestStatus, self).setUp() @@ -334,7 +345,7 @@ def test_list(self): class TestDiffFile(TestEndToEnd): TRACKED_FP = 't_fp' - DIR_TRACKED_FP = 'dir/t_fp' + DIR_TRACKED_FP = os.path.join('dir', 't_fp') UNTRACKED_FP = 'u_fp' DIR = 'dir' @@ -386,6 +397,9 @@ def test_diff_dir(self): self.fail() def test_diff_non_ascii(self): + if sys.platform == 'win32': + # Skip this test on Windows until we fix Unicode support + return contents = '’◕‿◕’©Ä☺’ಠ_ಠ’' utils.write_file(self.TRACKED_FP, contents=contents) out1 = utils.stdout(gl.diff()) @@ -413,12 +427,12 @@ def create_commits(branch_name, fp): utils.append_to_file(fp, contents='contents {0}\n'.format(0)) out = utils.stdout(gl.commit(m='ci 0 in {0}'.format(branch_name), inc=fp)) self.commits[branch_name].append( - re.search(r'Commit Id: (.*)', out, re.UNICODE).group(1)) + re.search(r'Commit Id: (\S*)', out, re.UNICODE).group(1)) for i in range(1, self.COMMITS_NUMBER): utils.append_to_file(fp, contents='contents {0}\n'.format(i)) out = utils.stdout(gl.commit(m='ci {0} in {1}'.format(i, branch_name))) self.commits[branch_name].append( - re.search(r'Commit Id: (.*)', out, re.UNICODE).group(1)) + re.search(r'Commit Id: (\S*)', out, re.UNICODE).group(1)) gl.branch(c=self.OTHER) create_commits('master', self.MASTER_FILE) @@ -431,8 +445,8 @@ class TestFuse(TestOp): def __assert_history(self, expected): out = utils.stdout(gl.history()) - cids = list(reversed(re.findall(r'ci (.*) in (.*)', out, re.UNICODE))) - self.assertEqual( + cids = list(reversed(re.findall(r'ci (.*) in (\S*)', out, re.UNICODE))) + self.assertItemsEqual( cids, expected, 'cids is ' + text(cids) + ' exp ' + text(expected)) st_out = utils.stdout(gl.status()) diff --git a/gitless/tests/utils.py b/gitless/tests/utils.py index 13fa378..c0159a0 100644 --- a/gitless/tests/utils.py +++ b/gitless/tests/utils.py @@ -13,11 +13,16 @@ import os import re import shutil +import stat import sys import tempfile import unittest -from sh import git, ErrorReturnCode +if sys.platform != 'win32': + from sh import git, ErrorReturnCode +else: + from pbs import ErrorReturnCode, Command + git = Command('git') IS_PY2 = sys.version_info[0] == 2 @@ -35,8 +40,7 @@ def setUp(self, prefix_for_tmp_repo): def tearDown(self): """Removes the temporary dir.""" - shutil.rmtree(self.path) - logging.debug('Removed dir {0}'.format(self.path)) + rmtree(self.path) # Python 2/3 compatibility def assertItemsEqual(self, actual, expected, msg=None): @@ -44,6 +48,8 @@ def assertItemsEqual(self, actual, expected, msg=None): return super(TestBase, self).assertItemsEqual(actual, expected, msg=msg) except AttributeError: try: + # Checks that actual and expected have the same elements in the same + # number, regardless of their order return super(TestBase, self).assertCountEqual(actual, expected, msg=msg) except AttributeError: return self.assertEqual(sorted(actual), sorted(expected), msg=msg) @@ -58,6 +64,24 @@ def assertRaisesRegexp(self, exc, r, fun, *args, **kwargs): self.fail('No "{0}" found in "{1}"'.format(r, msg)) +def rmtree(path): + # On Windows, running shutil.rmtree on a folder that contains read-only + # files throws errors. To workaround this, if removing a path fails, we make + # the path writable and then try again + def onerror(func, path, unused_exc_info): # error handler for rmtree + if not os.access(path, os.W_OK): + os.chmod(path, stat.S_IWUSR) + func(path) + else: + # Swallow errors for now (on Windows there seems to be something weird + # going on and we can't remove the temp directory even after all files + # in it have been successfully removed) + pass + + shutil.rmtree(path, onerror=onerror) + logging.debug('Removed dir {0}'.format(path)) + + def write_file(fp, contents=''): _x_file('w', fp, contents=contents) diff --git a/setup.py b/setup.py index e7568e7..f3d21e2 100755 --- a/setup.py +++ b/setup.py @@ -36,7 +36,13 @@ sys.exit() -reqs = ['pygit2>=0.24.0', 'sh>=1.11', 'clint>=0.3.6'] +reqs = ['pygit2>=0.24.0', 'clint>=0.3.6'] + +if sys.platform != 'win32': + reqs.append('sh>=1.11') +else: + reqs.append('pbs>=0.11') + if sys.version_info < (2, 7) or ( sys.version_info < (3, 3) and sys.version_info > (3, 0)): reqs.append('argparse') From fda224b7eae598fa32ac1ad26e80c619cb9b7b0c Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sun, 4 Dec 2016 21:48:09 -0500 Subject: [PATCH 036/196] only page output if we are running in a tty --- gitless/cli/helpers.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 5ceba33..25b1e8c 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -12,6 +12,7 @@ import subprocess import sys import shlex +import shutil from gitless import core @@ -68,6 +69,12 @@ def get_branch_or_use_upstream(branch_name, arg, repo): def page(fp, repo): + if not sys.stdout.isatty(): # we are being piped or redirected + # memory-friendly way to output contents of file to stdout + with open(fp, 'r') as f: + shutil.copyfileobj(f, sys.stdout) + return + # On Windows, we need to call 'more' through cmd.exe (with 'cmd'). The /C is # so that the command window gets closed after 'more' finishes default_pager = 'less' if sys.platform != 'win32' else 'cmd /C more' From ffec1936a7fabf62bd1da44d6b23508856473cd5 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sun, 4 Dec 2016 21:48:32 -0500 Subject: [PATCH 037/196] err if we can't launch the pager --- gitless/cli/helpers.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 25b1e8c..ba2444d 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -88,7 +88,13 @@ def page(fp, repo): cmd.extend(['-r', '-f']) # append arguments cmd.append(fp) # add file name to page command - subprocess.call(cmd, stdin=sys.stdin, stdout=sys.stdout) + try: + ret = subprocess.call(cmd, stdin=sys.stdin, stdout=sys.stdout) + if ret != 0: + pprint.err('Call to pager {0} failed'.format(pager)) + except OSError: + pprint.err('Couldn\'t launch pager {0}'.format(pager)) + pprint.err_exp('change the value of git\'s core.pager setting') class PathProcessor(argparse.Action): From 38457cc357e5d86f4232b12230fe5228cfd7cd35 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sun, 4 Dec 2016 22:46:31 -0500 Subject: [PATCH 038/196] prevent broken pipe error if the user pipes output to a process --- gitless/cli/helpers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index ba2444d..593f5b5 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -70,6 +70,9 @@ def get_branch_or_use_upstream(branch_name, arg, repo): def page(fp, repo): if not sys.stdout.isatty(): # we are being piped or redirected + # Prevent Python from throwing exceptions on SIGPIPE + from signal import signal, SIGPIPE, SIG_DFL + signal(SIGPIPE, SIG_DFL) # memory-friendly way to output contents of file to stdout with open(fp, 'r') as f: shutil.copyfileobj(f, sys.stdout) From 9e31a4624c0884c7169733adafa22aca87ffc6af Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sun, 4 Dec 2016 22:51:58 -0500 Subject: [PATCH 039/196] only output colors in diff if coloring is enabled and we are not being piped or redirected --- gitless/cli/pprint.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/gitless/cli/pprint.py b/gitless/cli/pprint.py index 0df0d70..82633e3 100644 --- a/gitless/cli/pprint.py +++ b/gitless/cli/pprint.py @@ -289,14 +289,23 @@ def _format_line(diff_line, padding, bold_delim=None): """Format a standard diff line. Returns: - a colored version of the diff line using ANSI control characters. + a padded and colored version of the diff line with line numbers """ # Color constants - GREEN = '\033[32m' - GREEN_BOLD = '\033[1;32m' - RED = '\033[31m' - RED_BOLD = '\033[1;31m' - CLEAR = '\033[0m' + # We only output colored lines if the coloring is enabled and we are not being + # piped or redirected + if colored.DISABLE_COLOR or not sys.stdout.isatty(): + GREEN = '' + GREEN_BOLD = '' + RED = '' + RED_BOLD = '' + CLEAR = '' + else: + GREEN = '\033[32m' + GREEN_BOLD = '\033[1;32m' + RED = '\033[31m' + RED_BOLD = '\033[1;31m' + CLEAR = '\033[0m' formatted = '' st = diff_line.origin From d948e16a97a1aff2efdd09a92bb998e4e1041079 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 9 Dec 2016 21:05:34 -0500 Subject: [PATCH 040/196] windows-related fix --- gitless/cli/helpers.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 593f5b5..7fedfc2 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -70,9 +70,10 @@ def get_branch_or_use_upstream(branch_name, arg, repo): def page(fp, repo): if not sys.stdout.isatty(): # we are being piped or redirected - # Prevent Python from throwing exceptions on SIGPIPE - from signal import signal, SIGPIPE, SIG_DFL - signal(SIGPIPE, SIG_DFL) + if sys.platform != 'win32': + # Prevent Python from throwing exceptions on SIGPIPE + from signal import signal, SIGPIPE, SIG_DFL + signal(SIGPIPE, SIG_DFL) # memory-friendly way to output contents of file to stdout with open(fp, 'r') as f: shutil.copyfileobj(f, sys.stdout) From 164734f944c7d8a540ce3f97be54fdde47321b73 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Wed, 21 Dec 2016 13:06:48 -0500 Subject: [PATCH 041/196] prep for v0.8.5 --- README.md | 18 +++++------------- gitless/cli/gl.py | 2 +- setup.py | 2 +- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index a759006..9c5a277 100644 --- a/README.md +++ b/README.md @@ -27,18 +27,11 @@ way, you can keep using Git, and switch between Git and Gitless seamlessly. We currently require Git (1.7.12+) to be installed (but this requirement is going to disappear soon once we finish with our migration to pygit2). -Note to Windows users: we currently have no binary release for Windows. If you -are having trouble getting the latest version to work (we now depend -on [pygit2](https://github.com/libgit2/pygit2) in addition to `git`), you can -try v0.6.2 instead (which depends only -on `git`) and people have managed to get it working. - ### Binary releases Binary releases for Mac OS and Linux are available from the -[Gitless's website](http://gitless.com "Gitless's website"). This is the easiest -way to get Gitless. +[Gitless's website](http://gitless.com "Gitless's website"). If you've downloaded a binary release of Gitless everything is contained in the gl binary, so to install simply do: @@ -82,11 +75,14 @@ Then, just do: ### Installing via Homebrew -If you are using [Homebrew](http://brew.sh/ "Homebrew homepage"), a package manager for Mac OS, then you can simply install Gitless with: +If you are using [Homebrew](http://brew.sh/ "Homebrew homepage"), a package +manager for Mac OS, then you can simply install Gitless with: + ``` brew update brew install gitless ``` + Documentation ------------- @@ -110,10 +106,6 @@ feedback/questions/suggestions or shoot us an email If you're planning on submitting code here are some useful things to know: -- We only have two branches, `master` and `develop`. We code in `develop` and -merge the changes onto `master` when the changes are stable and we're ready to -cut a new release. So you'll find on `develop` the latest changes - - We follow (to some extent) the [Google Python Style Guide]( https://google.github.io/styleguide/pyguide.html "Google Python Style Guide"). diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 16a768f..73386b0 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -34,7 +34,7 @@ INTERNAL_ERROR = 3 NOT_IN_GL_REPO = 4 -VERSION = '0.8.4' +VERSION = '0.8.5' URL = 'http://gitless.com' diff --git a/setup.py b/setup.py index f3d21e2..3526736 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ from setuptools import setup -VERSION = '0.8.4' +VERSION = '0.8.5' # Build helper From f09afe9afaa6b2f8d6d884be50b9afb1e8900340 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 20 Jan 2017 01:56:08 -0500 Subject: [PATCH 042/196] more info on commit and publish output --- gitless/cli/gl_commit.py | 2 +- gitless/cli/gl_publish.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/gitless/cli/gl_commit.py b/gitless/cli/gl_commit.py index dedc1f4..487b331 100644 --- a/gitless/cli/gl_commit.py +++ b/gitless/cli/gl_commit.py @@ -71,7 +71,7 @@ def main(args, repo): _auto_track(commit_files, curr_b) ci = curr_b.create_commit(commit_files, msg, partials=partials) - pprint.ok('Commit succeeded') + pprint.ok('Commit on branch {0} succeeded'.format(repo.current_branch)) pprint.blank() pprint.commit(ci) diff --git a/gitless/cli/gl_publish.py b/gitless/cli/gl_publish.py index b9bb6cc..c932861 100644 --- a/gitless/cli/gl_publish.py +++ b/gitless/cli/gl_publish.py @@ -22,6 +22,9 @@ def parser(subparsers, _): def main(args, repo): current_b = repo.current_branch - current_b.publish(helpers.get_branch_or_use_upstream(args.dst, 'dst', repo)) - pprint.ok('Publish succeeded') + dst_b = helpers.get_branch_or_use_upstream(args.dst, 'dst', repo) + current_b.publish(dst_b) + pprint.ok( + 'Publish of commits from branch {0} to branch {1} succeeded'.format( + current_b, dst_b)) return True From 76997d43b8902073307d44448d1ad634473b4775 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 20 Jan 2017 02:01:44 -0500 Subject: [PATCH 043/196] use libgit2 2.5 on travis --- .travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.sh b/.travis.sh index 8fa184c..b628059 100755 --- a/.travis.sh +++ b/.travis.sh @@ -2,7 +2,7 @@ cd ~ -git clone --depth=1 -b maint/v0.24 https://github.com/libgit2/libgit2.git +git clone --depth=1 -b maint/v0.25 https://github.com/libgit2/libgit2.git cd libgit2/ mkdir build && cd build From 5bc6bf6717bc731988d01fbd47bb4d8699fc5089 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 20 Jan 2017 14:25:48 -0500 Subject: [PATCH 044/196] show an error message if user.name or user.email is unset --- gitless/cli/gl_commit.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/gitless/cli/gl_commit.py b/gitless/cli/gl_commit.py index 487b331..0fcdc34 100644 --- a/gitless/cli/gl_commit.py +++ b/gitless/cli/gl_commit.py @@ -54,13 +54,7 @@ def main(args, repo): if args.p: partials = _do_partial_selection(commit_files, curr_b) - if not repo.config['user.name']: - pprint.err('Missing name for commit author') - pprint.err_exp('change the value of git\'s user.name setting') - return False - if not repo.config['user.email']: - pprint.err('Missing email for commit author') - pprint.err_exp('change the value of git\'s user.email setting') + if not _author_info_is_ok(repo): return False msg = args.m if args.m else commit_dialog.show(commit_files, repo) @@ -84,6 +78,24 @@ def main(args, repo): return True +def _author_info_is_ok(repo): + def show_config_error(key): + pprint.err('Missing {0} for commit author'.format(key)) + pprint.err_exp('change the value of git\'s user.{0} setting'.format(key)) + + def config_is_ok(key): + try: + if not repo.config['user.{0}'.format(key)]: + show_config_error(key) + return False + except KeyError: + show_config_error(key) + return False + return True + + return config_is_ok('name') and config_is_ok('email') + + def _do_partial_selection(files, curr_b): partials = [] for fp in files: From 298a90c942bd44f920e1b12ea0af384b7f06c6f1 Mon Sep 17 00:00:00 2001 From: Katrin Leinweber Date: Thu, 23 Feb 2017 20:09:05 +0100 Subject: [PATCH 045/196] Make `switch` command a bit more helpful --- gitless/cli/gl_switch.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gitless/cli/gl_switch.py b/gitless/cli/gl_switch.py index d61a9f5..703fa72 100644 --- a/gitless/cli/gl_switch.py +++ b/gitless/cli/gl_switch.py @@ -30,6 +30,7 @@ def main(args, repo): if not b: pprint.err('Branch {0} doesn\'t exist'.format(args.branch)) pprint.err_exp('to list existing branches do gl branch') + pprint.err_exp('to create a new branch do gl branch -c feature/foo') return False repo.switch_current_branch(b, move_over=args.move_over) From 7830d1675dc4b623498737e8a43a2a271733761e Mon Sep 17 00:00:00 2001 From: Katrin Leinweber Date: Mon, 27 Feb 2017 17:26:28 +0100 Subject: [PATCH 046/196] Make `switch` command even more helpful with branch name --- gitless/cli/gl_switch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/cli/gl_switch.py b/gitless/cli/gl_switch.py index 703fa72..c543dc9 100644 --- a/gitless/cli/gl_switch.py +++ b/gitless/cli/gl_switch.py @@ -30,7 +30,7 @@ def main(args, repo): if not b: pprint.err('Branch {0} doesn\'t exist'.format(args.branch)) pprint.err_exp('to list existing branches do gl branch') - pprint.err_exp('to create a new branch do gl branch -c feature/foo') + pprint.err_exp('to create a new branch do gl branch -c {0}'.format(args.branch)) return False repo.switch_current_branch(b, move_over=args.move_over) From 7121af116b4908959c69aaaf79212ce8af12bb55 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Wed, 22 Mar 2017 02:47:47 +0300 Subject: [PATCH 047/196] Print help for humans, fixes #124 --- gitless/cli/gl.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 73386b0..e71d986 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -50,11 +50,28 @@ pass +def print_help(parser): + """print help for humans""" + print(parser.description) + print('\ncommands:\n') + + # https://stackoverflow.com/questions/20094215/argparse-subparser-monolithic-help-output + # retrieve subparsers from parser + subparsers_actions = [ + action for action in parser._actions + if isinstance(action, argparse._SubParsersAction)] + # there will probably only be one subparser_action, + # but better save than sorry + for subparsers_action in subparsers_actions: + # get all subparsers and print help + for choice in subparsers_action._choices_actions: + print(' {:<19} {}'.format(choice.dest, choice.help)) + def main(): parser = argparse.ArgumentParser( description=( - 'Gitless: a version control system built on top of Git. More info, ' - 'downloads and documentation available at {0}'.format(URL)), + 'Gitless: a version control system built on top of Git.\nMore info, ' + 'downloads and documentation at {0}'.format(URL)), formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument( '--version', action='version', version=( @@ -71,7 +88,7 @@ def main(): sub_cmd.parser(subparsers, repo) if len(sys.argv) == 1: - parser.print_help() + print_help(parser) return SUCCESS args = parser.parse_args() From b67a73d8f5289502251ae7b37696babb39d6eeb5 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Wed, 22 Mar 2017 00:46:39 -0400 Subject: [PATCH 048/196] fix typo --- gitless/cli/gl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index e71d986..2ad55e5 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -61,7 +61,7 @@ def print_help(parser): action for action in parser._actions if isinstance(action, argparse._SubParsersAction)] # there will probably only be one subparser_action, - # but better save than sorry + # but better safe than sorry for subparsers_action in subparsers_actions: # get all subparsers and print help for choice in subparsers_action._choices_actions: From af92a041519457527fa9a63055d09451c1caf51d Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Mon, 2 Jan 2017 13:24:27 +0300 Subject: [PATCH 049/196] Remove -o option from diff and commit (fixes #54) --- gitless/cli/helpers.py | 6 +++--- gitless/tests/test_e2e.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 7fedfc2..61fc134 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -151,8 +151,8 @@ def __call__(self, parser, namespace, revs, option_string=None): def oei_flags(subparsers, repo): subparsers.add_argument( - '-o', '--only', nargs='+', - help='use only files given (files must be tracked modified or untracked)', + 'only', nargs='*', + help='use only files given (tracked modified or untracked)', action=PathProcessor, repo=repo, metavar='file') subparsers.add_argument( '-e', '--exclude', nargs='+', @@ -204,7 +204,7 @@ def _oei_validate(only, exclude, include, curr_b): """ if only and (exclude or include): pprint.err( - 'You provided a list of filenames to be committed only (-o) but also ' + 'You provided a list of filenames to be committed but also ' 'provided a list of files to be excluded (-e) or included (-i)') return False diff --git a/gitless/tests/test_e2e.py b/gitless/tests/test_e2e.py index d24d794..2eeeec8 100755 --- a/gitless/tests/test_e2e.py +++ b/gitless/tests/test_e2e.py @@ -353,7 +353,7 @@ def setUp(self): super(TestDiffFile, self).setUp() utils.write_file(self.TRACKED_FP) utils.write_file(self.DIR_TRACKED_FP) - gl.commit('-o', self.TRACKED_FP, self.DIR_TRACKED_FP, m='commit') + gl.commit(self.TRACKED_FP, self.DIR_TRACKED_FP, m='commit') utils.write_file(self.UNTRACKED_FP) def test_empty_diff(self): @@ -472,7 +472,7 @@ def test_only_one(self): self.__build(self.OTHER, cids=[0]) + self.__build('master')) def test_only_some(self): - gl.fuse(self.OTHER, '-o', self.commits[self.OTHER][:2]) + gl.fuse(self.OTHER, self.commits[self.OTHER][:2]) self.__assert_history( self.__build(self.OTHER, [0, 1]) + self.__build('master')) From 1cf8a4a69f9822bd3c4689f31e91d108be6cb0b9 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 19 May 2017 17:09:43 +0300 Subject: [PATCH 050/196] Attempt to fix test_commit_only and pass file before option https://travis-ci.org/sdg-mit/gitless/jobs/213617137#L723 --- gitless/tests/test_e2e.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/tests/test_e2e.py b/gitless/tests/test_e2e.py index 2eeeec8..935e60a 100755 --- a/gitless/tests/test_e2e.py +++ b/gitless/tests/test_e2e.py @@ -181,7 +181,7 @@ def test_commit_relative(self): self.__assert_commit(self.TRACKED_FP, self.DIR_TRACKED_FP) def test_commit_only(self): - gl.commit(o=self.TRACKED_FP, m='msg') + gl.commit(self.TRACKED_FP, '-m="msg"') self.__assert_commit(self.TRACKED_FP) def test_commit_only_relative(self): From 7226f2798f0bdb83de927381e2367244775bfd0e Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 19 May 2017 17:28:46 +0300 Subject: [PATCH 051/196] Fix rest of tests broken by removal of -o --- gitless/tests/test_e2e.py | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/gitless/tests/test_e2e.py b/gitless/tests/test_e2e.py index 935e60a..5ea3309 100755 --- a/gitless/tests/test_e2e.py +++ b/gitless/tests/test_e2e.py @@ -181,39 +181,39 @@ def test_commit_relative(self): self.__assert_commit(self.TRACKED_FP, self.DIR_TRACKED_FP) def test_commit_only(self): - gl.commit(self.TRACKED_FP, '-m="msg"') + gl.commit(self.TRACKED_FP, m="msg") self.__assert_commit(self.TRACKED_FP) def test_commit_only_relative(self): os.chdir(self.DIR) - self.assertRaises(ErrorReturnCode, gl.commit, o=self.TRACKED_FP, m='msg') - gl.commit(o='../' + self.TRACKED_FP, m='msg') + self.assertRaises(ErrorReturnCode, gl.commit, self.TRACKED_FP, "-m='msg'") + gl.commit('../' + self.TRACKED_FP, m='msg') self.__assert_commit(self.TRACKED_FP) def test_commit_only_untrack(self): - gl.commit(o=self.UNTRACKED_FP, m='msg') + gl.commit("-m='msg'", self.UNTRACKED_FP) self.__assert_commit(self.UNTRACKED_FP) def test_commit_only_untrack_relative(self): os.chdir(self.DIR) - self.assertRaises(ErrorReturnCode, gl.commit, o=self.UNTRACKED_FP, m='msg') - gl.commit(o='../' + self.UNTRACKED_FP, m='msg') + self.assertRaises(ErrorReturnCode, gl.commit, self.UNTRACKED_FP, m='msg') + gl.commit('../' + self.UNTRACKED_FP, m='msg') self.__assert_commit(self.UNTRACKED_FP) def test_commit_include(self): - gl.commit(m='msg', include=self.UNTRACKED_FP) + gl.commit("-m='msg'", include=self.UNTRACKED_FP) self.__assert_commit( self.TRACKED_FP, self.DIR_TRACKED_FP, self.UNTRACKED_FP) def test_commit_exclude_include(self): - gl.commit(m='msg', include=self.UNTRACKED_FP, exclude=self.TRACKED_FP) + gl.commit("-m='msg'", include=self.UNTRACKED_FP, exclude=self.TRACKED_FP) self.__assert_commit(self.UNTRACKED_FP, self.DIR_TRACKED_FP) def test_commit_no_files(self): self.assertRaises( ErrorReturnCode, gl.commit, '--exclude', self.TRACKED_FP, self.DIR_TRACKED_FP, m='msg') - self.assertRaises(ErrorReturnCode, gl.commit, o='non-existent', m='msg') + self.assertRaises(ErrorReturnCode, gl.commit, 'non-existent', m='msg') self.assertRaises( ErrorReturnCode, gl.commit, m='msg', exclude='non-existent') self.assertRaises( @@ -222,7 +222,7 @@ def test_commit_no_files(self): def test_commit_dir(self): fp = 'dir/f' utils.write_file(fp) - gl.commit(o=fp, m='msg') + gl.commit(fp, m='msg') self.__assert_commit('dir/f') def __assert_commit(self, *expected_committed): @@ -247,7 +247,7 @@ def setUp(self): super(TestStatus, self).setUp() utils.write_file(self.TRACKED_DIR_FP) utils.write_file(self.UNTRACKED_DIR_FP) - gl.commit(o=self.TRACKED_DIR_FP, m='commit') + gl.commit(self.TRACKED_DIR_FP, m='commit') def test_status_relative(self): utils.write_file(self.TRACKED_DIR_FP, contents='some modifications') @@ -276,7 +276,7 @@ class TestBranch(TestEndToEnd): def setUp(self): super(TestBranch, self).setUp() utils.write_file('f') - gl.commit(o='f', m='commit') + gl.commit('f', m='commit') def test_create(self): gl.branch(c=self.BRANCH_1) @@ -318,7 +318,7 @@ class TestTag(TestEndToEnd): def setUp(self): super(TestTag, self).setUp() utils.write_file('f') - gl.commit(o='f', m='commit') + gl.commit('f', m='commit') def test_create(self): gl.tag(c=self.TAG_1) @@ -361,7 +361,7 @@ def test_empty_diff(self): self.fail() def test_diff_nonexistent_fp(self): - err = utils.stderr(gl.diff(o='file', _ok_code=[1])) + err = utils.stderr(gl.diff('file', _ok_code=[1])) if 'doesn\'t exist' not in err: self.fail() @@ -370,7 +370,7 @@ def test_basic_diff(self): out1 = utils.stdout(gl.diff()) if '+contents' not in out1: self.fail() - out2 = utils.stdout(gl.diff(o=self.TRACKED_FP)) + out2 = utils.stdout(gl.diff(self.TRACKED_FP)) if '+contents' not in out2: self.fail() self.assertEqual(out1, out2) @@ -385,14 +385,14 @@ def test_basic_diff_relative(self): if '+contents_dir_tracked' not in out1: self.fail() rel_dir_tracked_fp = os.path.relpath(self.DIR_TRACKED_FP, self.DIR) - out2 = utils.stdout(gl.diff(o=rel_dir_tracked_fp)) + out2 = utils.stdout(gl.diff(rel_dir_tracked_fp)) if '+contents_dir_tracked' not in out2: self.fail() def test_diff_dir(self): fp = 'dir/dir/f' utils.write_file(fp, contents='contents') - out = utils.stdout(gl.diff(o=fp)) + out = utils.stdout(gl.diff(fp)) if '+contents' not in out: self.fail() @@ -405,7 +405,7 @@ def test_diff_non_ascii(self): out1 = utils.stdout(gl.diff()) if '+' + contents not in out1: self.fail('out is ' + out1) - out2 = utils.stdout(gl.diff(o=self.TRACKED_FP)) + out2 = utils.stdout(gl.diff(self.TRACKED_FP)) if '+' + contents not in out2: self.fail('out is ' + out2) self.assertEqual(out1, out2) @@ -472,7 +472,7 @@ def test_only_one(self): self.__build(self.OTHER, cids=[0]) + self.__build('master')) def test_only_some(self): - gl.fuse(self.OTHER, self.commits[self.OTHER][:2]) + gl.fuse(self.OTHER, '-o', self.commits[self.OTHER][:2]) self.__assert_history( self.__build(self.OTHER, [0, 1]) + self.__build('master')) @@ -722,7 +722,7 @@ def assert_status_performance(): def test_branch_switch_performance(self): MAX_TOLERANCE = 100 - gl.commit(o='f1', m='commit') + gl.commit('f1', m='commit') t = time.time() gl.branch(c='develop') From 573de0b2bf0c965b58fd475fb4a3bb889c8e41f1 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 19 May 2017 19:08:25 +0300 Subject: [PATCH 052/196] Use newer PyPy https://docs.travis-ci.com/user/languages/python/#PyPy-Support Because current pypy 2.5.0 builds are too slow https://travis-ci.org/sdg-mit/gitless/builds/213701497 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 91fa0c6..14a6510 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ python: - "3.3" - "3.4" - "3.5" - - "pypy" + - "pypy-5.3.1" env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib From b6a2e457b794531f68928f6b5349c3a9be705511 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sat, 20 May 2017 12:42:25 +0300 Subject: [PATCH 053/196] Add Python 3.6 and remove 3.2 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 14a6510..9d47838 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,10 @@ language: python python: - "2.7" - - "3.2" - "3.3" - "3.4" - "3.5" + - "3.6" - "pypy-5.3.1" env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib From 2a0b6a6fc54f0836c79751cdedede6c890704382 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sat, 20 May 2017 18:12:52 -0400 Subject: [PATCH 054/196] first attempt to get appveyor working --- .appveyor.yml | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .appveyor.yml diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..4ce9836 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,59 @@ +# Based on pygit2's appveyor config +environment: + matrix: + - GENERATOR: 'Visual Studio 10' + PYTHON: 'C:\Python27\python.exe' + - GENERATOR: 'Visual Studio 10 Win64' + PYTHON: 'C:\Python27-x64\python.exe' + - GENERATOR: 'Visual Studio 10' + PYTHON: 'C:\Python33\python.exe' + - GENERATOR: 'Visual Studio 10 Win64' + PYTHON: 'C:\Python33-x64\python.exe' + - GENERATOR: 'Visual Studio 10' + PYTHON: 'C:\Python34\python.exe' + - GENERATOR: 'Visual Studio 10 Win64' + PYTHON: 'C:\Python34-x64\python.exe' + - GENERATOR: 'Visual Studio 14' + PYTHON: 'C:\Python35\python.exe' + - GENERATOR: 'Visual Studio 14 Win64' + PYTHON: 'C:\Python35-x64\python.exe' + - GENERATOR: 'Visual Studio 14' + PYTHON: 'C:\Python36\python.exe' + - GENERATOR: 'Visual Studio 14 Win64' + PYTHON: 'C:\Python36-x64\python.exe' + +init: + - cmd: '%PYTHON% -m pip install -U nose wheel' + +build_script: + - cmd: | + set LIBGIT2=%APPVEYOR_BUILD_FOLDER%\build\libgit2 + git clone --depth=1 -b maint/v0.25 https://github.com/libgit2/libgit2.git libgit2 + mkdir build + + cd build + cmake -DSTDCALL=OFF -DBUILD_CLAR=OFF -DCMAKE_INSTALL_PREFIX="%LIBGIT2%" ../libgit2 -G "%GENERATOR%" + cmake --build . --config Release --target install + cd .. + + IF "%GENERATOR%"=="Visual Studio 10 Win64" ( call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" ) + + "%PYTHON%" setup.py bdist_wheel + +before_test: + - cmd: git config --global user.name "appveyor-test" + - cmd: git config --global user.email "appveyor@test.com" + +test_script: + - ps: | + cp build\Release\git2.dll . + &$env:PYTHON setup.py nosetests --logging-level=WARN --with-xunit + if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) } + # upload results to AppVeyor + $wc = New-Object 'System.Net.WebClient' + $wc.UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\nosetests.xml)) + +branches: + only: + - master + - develop From 2b7e711658966710c4663f97a21fc5750a268920 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Tue, 23 May 2017 12:03:34 -0400 Subject: [PATCH 055/196] fix in branch confirmation message --- gitless/cli/gl_branch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index e03fb10..5d91381 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -158,8 +158,8 @@ def _do_delete(delete_b, repo): branch_str = 'Branch {0} will be removed'.format(b.branch_name) remote_str = '' if isinstance(b, core.RemoteBranch): - remote_str = 'from remote repository {0}'.format(b.remote_name) - if not pprint.conf_dialog('{0} {1}'.format(branch_str, remote_str)): + remote_str = ' from remote repository {0}'.format(b.remote_name) + if not pprint.conf_dialog('{0}{1}'.format(branch_str, remote_str)): pprint.msg('Aborted: removal of branch {0}'.format(b)) continue From b0883d9b8ff2b0b2d633badc72940479a537f9ee Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 7 Jul 2017 21:28:41 +0300 Subject: [PATCH 056/196] .appveyor.yml: Install pygit2 from compiled wheels (#146) --- .appveyor.yml | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4ce9836..f456c9d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -23,22 +23,7 @@ environment: PYTHON: 'C:\Python36-x64\python.exe' init: - - cmd: '%PYTHON% -m pip install -U nose wheel' - -build_script: - - cmd: | - set LIBGIT2=%APPVEYOR_BUILD_FOLDER%\build\libgit2 - git clone --depth=1 -b maint/v0.25 https://github.com/libgit2/libgit2.git libgit2 - mkdir build - - cd build - cmake -DSTDCALL=OFF -DBUILD_CLAR=OFF -DCMAKE_INSTALL_PREFIX="%LIBGIT2%" ../libgit2 -G "%GENERATOR%" - cmake --build . --config Release --target install - cd .. - - IF "%GENERATOR%"=="Visual Studio 10 Win64" ( call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" ) - - "%PYTHON%" setup.py bdist_wheel + - cmd: '%PYTHON% -m pip install -U nose wheel pygit2' before_test: - cmd: git config --global user.name "appveyor-test" @@ -46,7 +31,6 @@ before_test: test_script: - ps: | - cp build\Release\git2.dll . &$env:PYTHON setup.py nosetests --logging-level=WARN --with-xunit if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) } # upload results to AppVeyor From 1a6f24d02d74c49e4d2dbe5ffb83f8694fe0804c Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 7 Jul 2017 21:32:53 +0300 Subject: [PATCH 057/196] .appveyor.yml: Disable build step Otherwise AppVeyor fails with `Specify a project or solution file. The directory does not contain a project or solution file.` https://ci.appveyor.com/project/spderosso/gitless/build/1.0.3/job/e54caey8a0b8knx3 --- .appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index f456c9d..c01c09f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -25,6 +25,8 @@ environment: init: - cmd: '%PYTHON% -m pip install -U nose wheel pygit2' +build: off + before_test: - cmd: git config --global user.name "appveyor-test" - cmd: git config --global user.email "appveyor@test.com" From ffc53003abb068eaca0c4c77251b824e1e36c9d0 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Tue, 11 Jul 2017 01:51:00 +0300 Subject: [PATCH 058/196] Fix Travis - bump libgit2 to 0.26 --- .travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.sh b/.travis.sh index b628059..185b179 100755 --- a/.travis.sh +++ b/.travis.sh @@ -2,7 +2,7 @@ cd ~ -git clone --depth=1 -b maint/v0.25 https://github.com/libgit2/libgit2.git +git clone --depth=1 -b maint/v0.26 https://github.com/libgit2/libgit2.git cd libgit2/ mkdir build && cd build From fa8c44263515c7d69c8e4aa646145f0b84390198 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Tue, 11 Jul 2017 01:59:45 +0300 Subject: [PATCH 059/196] README.md Show build status for master Because it is default branch where all PRs are merged [skip ci] --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 9c5a277..f55dc1a 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,7 @@ Gitless [![PyPI version](https://badge.fury.io/py/gitless.svg)]( http://badge.fury.io/py/gitless) [![homebrew](https://img.shields.io/homebrew/v/gitless.svg)](http://braumeister.org/formula/gitless) -[![Build Status](https://travis-ci.org/sdg-mit/gitless.svg?branch=develop)]( - https://travis-ci.org/sdg-mit/gitless) +[![Build Status](https://travis-ci.org/sdg-mit/gitless.svg?branch=master)](https://travis-ci.org/sdg-mit/gitless) [Gitless](http://gitless.com "Gitless's website") is an experimental version control system built on top of Git. Many From e71af312da7669f60a40fb6a9b30856cbe9f9be1 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Tue, 11 Jul 2017 02:15:13 +0300 Subject: [PATCH 060/196] Fix AppVeyor - end2end tests need installed gl binary --- .appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.appveyor.yml b/.appveyor.yml index c01c09f..27f2ef3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -33,6 +33,7 @@ before_test: test_script: - ps: | + &$env:PYTHON -m pip install . &$env:PYTHON setup.py nosetests --logging-level=WARN --with-xunit if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) } # upload results to AppVeyor From 85b3e0c050540f2d676cbe38e4e99e46ece7c9c7 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Tue, 11 Jul 2017 10:33:30 +0300 Subject: [PATCH 061/196] Fix AppVeyor - add Scripts to path for current Python Tests are failing, because only Python 2.7 is present in PATH --- .appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index 27f2ef3..fe14345 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -33,7 +33,10 @@ before_test: test_script: - ps: | + # e2e tests require `gl` binary &$env:PYTHON -m pip install . + # 'gl' is installed in Python Scripts directory + $env:PATH += ";$(Split-Path $env:PYTHON)\Scripts" &$env:PYTHON setup.py nosetests --logging-level=WARN --with-xunit if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) } # upload results to AppVeyor From 6b3dab59c34b5eff545eff61f86d8e8aaf925ad5 Mon Sep 17 00:00:00 2001 From: embs Date: Sat, 21 Oct 2017 11:58:16 -0300 Subject: [PATCH 062/196] Add testing instructions to the README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index f55dc1a..f84af49 100644 --- a/README.md +++ b/README.md @@ -114,3 +114,11 @@ Gitless's code so that your edits are consistent with the codebase - Finally, if you don't want [Travis]( https://travis-ci.org/sdg-mit/gitless "Travis") to be mad at you, check that tests pass in Python 2.7 and 3.2+ + +Tests can be run with + +``` +pip install nose +nosetests # run tests other than end-to-end tests +nosetests ./gitless/tests/test_e2e.py # run end-to-end tests +``` From f1d46cb61b2d5bbca9bbb6ed05a7a7fa6c56bbeb Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sat, 21 Oct 2017 13:25:39 -0400 Subject: [PATCH 063/196] moved test instructions inside bullet --- README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f84af49..8eeb2e8 100644 --- a/README.md +++ b/README.md @@ -113,12 +113,9 @@ Gitless's code so that your edits are consistent with the codebase - Finally, if you don't want [Travis]( https://travis-ci.org/sdg-mit/gitless "Travis") to -be mad at you, check that tests pass in Python 2.7 and 3.2+ - -Tests can be run with - -``` -pip install nose -nosetests # run tests other than end-to-end tests -nosetests ./gitless/tests/test_e2e.py # run end-to-end tests -``` +be mad at you, check that tests pass in Python 2.7 and 3.2+. Tests can be run with + ``` + pip install nose + nosetests # run tests other than end-to-end tests + nosetests ./gitless/tests/test_e2e.py # run end-to-end tests + ``` From a9e3aea653575add7c645e95a15ce210f7e94e89 Mon Sep 17 00:00:00 2001 From: embs Date: Fri, 1 Dec 2017 14:42:49 -0300 Subject: [PATCH 064/196] Use fixed version of pygit2 on appveyor config Newer versions don't have wheels due to pygit2 appveyor's build breakage. --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index fe14345..1a24708 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -23,7 +23,7 @@ environment: PYTHON: 'C:\Python36-x64\python.exe' init: - - cmd: '%PYTHON% -m pip install -U nose wheel pygit2' + - cmd: '%PYTHON% -m pip install -U nose wheel pygit2==0.26.1' build: off From 81e098fc61d34515570a0c60de27396b84cdceb5 Mon Sep 17 00:00:00 2001 From: embs Date: Fri, 1 Dec 2017 16:29:11 -0300 Subject: [PATCH 065/196] Drop support for Windows + Python3 This fixes appveyor build. --- .appveyor.yml | 16 ---------------- README.md | 6 ++++++ 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 1a24708..a6c50f8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -5,22 +5,6 @@ environment: PYTHON: 'C:\Python27\python.exe' - GENERATOR: 'Visual Studio 10 Win64' PYTHON: 'C:\Python27-x64\python.exe' - - GENERATOR: 'Visual Studio 10' - PYTHON: 'C:\Python33\python.exe' - - GENERATOR: 'Visual Studio 10 Win64' - PYTHON: 'C:\Python33-x64\python.exe' - - GENERATOR: 'Visual Studio 10' - PYTHON: 'C:\Python34\python.exe' - - GENERATOR: 'Visual Studio 10 Win64' - PYTHON: 'C:\Python34-x64\python.exe' - - GENERATOR: 'Visual Studio 14' - PYTHON: 'C:\Python35\python.exe' - - GENERATOR: 'Visual Studio 14 Win64' - PYTHON: 'C:\Python35-x64\python.exe' - - GENERATOR: 'Visual Studio 14' - PYTHON: 'C:\Python36\python.exe' - - GENERATOR: 'Visual Studio 14 Win64' - PYTHON: 'C:\Python36-x64\python.exe' init: - cmd: '%PYTHON% -m pip install -U nose wheel pygit2==0.26.1' diff --git a/README.md b/README.md index 8eeb2e8..0fde515 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,12 @@ brew update brew install gitless ``` +### Windows Compatibility + +For now, Windows support is unavailable for Python3+ due to pbs dependency +(which is not Python3 compatible). Checkout +[#146](https://github.com/sdg-mit/gitless/issues/146) for more info. + Documentation ------------- From 017e974279c5a514be6220d947dd1fc1df8c560b Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sat, 2 Dec 2017 13:18:17 -0500 Subject: [PATCH 066/196] minor change --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0fde515..1ddf72c 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ brew install gitless ### Windows Compatibility For now, Windows support is unavailable for Python3+ due to pbs dependency -(which is not Python3 compatible). Checkout +(which is not Python3 compatible). See [#146](https://github.com/sdg-mit/gitless/issues/146) for more info. Documentation From bd6761c8c7af85237e2c00f9a3ceda8b373744ec Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sat, 2 Dec 2017 14:09:40 -0500 Subject: [PATCH 067/196] refactor readme --- README.md | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 1ddf72c..3eb8a57 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,10 @@ Gitless ======= [![PyPI version](https://badge.fury.io/py/gitless.svg)]( - http://badge.fury.io/py/gitless) -[![homebrew](https://img.shields.io/homebrew/v/gitless.svg)](http://braumeister.org/formula/gitless) -[![Build Status](https://travis-ci.org/sdg-mit/gitless.svg?branch=master)](https://travis-ci.org/sdg-mit/gitless) + http://badge.fury.io/py/gitless "PyPI version") +[![Homebrew Formula](https://img.shields.io/homebrew/v/gitless.svg)](http://braumeister.org/formula/gitless "Homebrew Formula") +[![Travis Build Status](https://travis-ci.org/sdg-mit/gitless.svg?branch=master)](https://travis-ci.org/sdg-mit/gitless "Travis Build Status") +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/sdg-mit/gitless?svg=true)](https://ci.appveyor.com/project/spderosso/gitless "AppVeyor Build Status") [Gitless](http://gitless.com "Gitless's website") is an experimental version control system built on top of Git. Many @@ -27,10 +28,10 @@ We currently require Git (1.7.12+) to be installed (but this requirement is going to disappear soon once we finish with our migration to pygit2). -### Binary releases +### Binary releases (macOS and Linux only) -Binary releases for Mac OS and Linux are available from the -[Gitless's website](http://gitless.com "Gitless's website"). +Binary releases for macOS and Linux are available from the +[Gitless website](http://gitless.com "Gitless's website"). If you've downloaded a binary release of Gitless everything is contained in the gl binary, so to install simply do: @@ -41,15 +42,18 @@ You can put the binary in other locations as well, just be sure to update your `PATH`. If for some reason this doesn't work (maybe you are running an old version of -your OS?), try one of the other options (installing from source code or via +your OS?), try one of the other options (installing from source or via the Python Package Index). ### Installing from source -To install from source you need to have Python (2.7, 3.2+ or pypy) +To install from source you need to have Python (2.7, 3.2+ or PyPy) installed. +Note to Windows users: Python 3 is not supported yet, +see [#146](https://github.com/sdg-mit/gitless/issues/146) for more info. + Additionally, you need to [install pygit2]( http://www.pygit2.org/install.html "pygit2 install"). @@ -63,7 +67,10 @@ and do: If you are a Python fan you might find it easier to install Gitless via the Python Package Index. To do this, you need to have -Python (2.7, 3.2+ or pypy) installed. +Python (2.7, 3.2+ or PyPy) installed. + +Note to Windows users: Python 3 is not supported yet, +see [#146](https://github.com/sdg-mit/gitless/issues/146) for more info. Additionally, you need to [install pygit2]( http://www.pygit2.org/install.html "pygit2 install"). @@ -72,22 +79,16 @@ Then, just do: $ pip install gitless -### Installing via Homebrew +### Installing via Homebrew (macOS only) If you are using [Homebrew](http://brew.sh/ "Homebrew homepage"), a package -manager for Mac OS, then you can simply install Gitless with: +manager for macOS, you can install Gitless with: ``` brew update brew install gitless ``` -### Windows Compatibility - -For now, Windows support is unavailable for Python3+ due to pbs dependency -(which is not Python3 compatible). See -[#146](https://github.com/sdg-mit/gitless/issues/146) for more info. - Documentation ------------- From ad906aebeef3f0d4906d84981288c665b75195c0 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 5 Jan 2018 19:06:59 -0500 Subject: [PATCH 068/196] checkout dirs + misc cleanups --- gitless/cli/gl.py | 2 +- gitless/cli/gl_checkout.py | 9 +++- gitless/cli/helpers.py | 7 ++- gitless/core.py | 102 ++++++++++++++++++++++++++----------- 4 files changed, 85 insertions(+), 35 deletions(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 2ad55e5..ff8a98e 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -58,7 +58,7 @@ def print_help(parser): # https://stackoverflow.com/questions/20094215/argparse-subparser-monolithic-help-output # retrieve subparsers from parser subparsers_actions = [ - action for action in parser._actions + action for action in parser._actions if isinstance(action, argparse._SubParsersAction)] # there will probably only be one subparser_action, # but better safe than sorry diff --git a/gitless/cli/gl_checkout.py b/gitless/cli/gl_checkout.py index c4b6d5d..df3e75e 100644 --- a/gitless/cli/gl_checkout.py +++ b/gitless/cli/gl_checkout.py @@ -23,7 +23,7 @@ def parser(subparsers, repo): dest='cp', default='HEAD') checkout_parser.add_argument( 'files', nargs='+', help='the file(s) to checkout', - action=helpers.PathProcessor, repo=repo) + action=helpers.PathProcessor, repo=repo, recursive=False) checkout_parser.set_defaults(func=main) @@ -51,6 +51,13 @@ def main(args, repo): pprint.ok( 'File {0} checked out successfully to its state at {1}'.format( fp, cp)) + except core.PathIsDirectoryError: + commit = repo.revparse_single(cp) + for fp in curr_b.get_paths(fp, commit): + curr_b.checkout_file(fp, commit) + pprint.ok( + 'File {0} checked out successfully to its state at {1}'.format( + fp, cp)) except KeyError: pprint.err('Checkout aborted') pprint.err('There\'s no file {0} at {1}'.format(fp, cp)) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 61fc134..3f4faa1 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -105,10 +105,11 @@ class PathProcessor(argparse.Action): def __init__( self, option_strings, dest, repo=None, skip_dir_test=None, - skip_dir_cb=None, **kwargs): + skip_dir_cb=None, recursive=True, **kwargs): self.repo = repo self.skip_dir_test = skip_dir_test self.skip_dir_cb = skip_dir_cb + self.recursive = recursive super(PathProcessor, self).__init__(option_strings, dest, **kwargs) def __call__(self, parser, namespace, paths, option_string=None): @@ -117,7 +118,7 @@ def __call__(self, parser, namespace, paths, option_string=None): def process_paths(): for path in paths: path = os.path.abspath(path) - if os.path.isdir(path): + if self.recursive and os.path.isdir(path): for curr_dir, dirs, fps in os.walk(path, topdown=True): if curr_dir.startswith(repo_dir): dirs[:] = [] @@ -134,6 +135,8 @@ def process_paths(): else: if not path.startswith(repo_dir): yield os.path.relpath(path, root) + else: + yield path setattr(namespace, self.dest, process_paths()) diff --git a/gitless/core.py b/gitless/core.py index 793bec1..7401a4d 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -8,6 +8,7 @@ from __future__ import unicode_literals import collections +import errno import io try: from itertools import izip as zip @@ -47,6 +48,8 @@ class BranchIsCurrentError(GlError): pass class ApplyFailedError(GlError): pass +class PathIsDirectoryError(ValueError): pass + # File status @@ -165,7 +168,7 @@ def _ref_target(self, ref): return self.git_repo.lookup_reference(ref).target - # Tag related methods + # Tag-related methods def create_tag(self, name, commit): tagger = self.git_repo.default_signature @@ -200,7 +203,7 @@ def listall_tags(self): yield ref[10:] - # Branch related methods + # Branch-related methods @property def current_branch(self): @@ -450,7 +453,7 @@ def __init__(self, git_remote, gl_repo): self.url = self.git_remote.url - # Branch related methods + # Branch-related methods def create_branch(self, name, head): if self.lookup_branch(name): @@ -489,7 +492,7 @@ def lookup_branch(self, branch_name): return RemoteBranch(git_branch, self.gl_repo) - # Tag related methods + # Tag-related methods def create_tag(self, name, commit): if self.lookup_tag(name): @@ -774,11 +777,9 @@ def status_file(self, path): return self._status_file(path)[0] def _status_file(self, path): - assert not os.path.isabs(path) - - git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + _check_path_is_repo_relative(path) - git_st = self.gl_repo.git_repo.status_file(git_path) + git_st = self.gl_repo.git_repo.status_file(_get_git_path(path)) root = self.gl_repo.root cmd_out = stdout(git('ls-files', '-v', '--full-name', path, _cwd=root)) is_au = cmd_out and cmd_out[0] == 'h' @@ -791,17 +792,17 @@ def _status_file(self, path): return f_st, git_st, is_au def path_is_ignored(self, path): - assert not os.path.isabs(path) + _check_path_is_repo_relative(path) - git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + git_path = _get_git_path(path) return self.gl_repo.git_repo.path_is_ignored(git_path) - # File related methods + # File-related methods def track_file(self, path): """Start tracking changes to path.""" - assert not os.path.isabs(path) + _check_path_is_repo_relative(path) gl_st, git_st, is_au = self._status_file(path) @@ -818,7 +819,7 @@ def track_file(self, path): # (ii) an assumed unchanged file => unmark it. if git_st == pygit2.GIT_STATUS_WT_NEW: # Case (i) with self._index as index: - git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + git_path = _get_git_path(path) index.add(git_path) elif is_au: # Case (ii) git('update-index', '--no-assume-unchanged', path, @@ -828,7 +829,7 @@ def track_file(self, path): def untrack_file(self, path): """Stop tracking changes to path.""" - assert not os.path.isabs(path) + _check_path_is_repo_relative(path) gl_st, git_st, is_au = self._status_file(path) @@ -849,7 +850,7 @@ def untrack_file(self, path): # unchanged. if git_st == pygit2.GIT_STATUS_INDEX_NEW: # Case (i) with self._index as index: - git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + git_path = _get_git_path(path) index.remove(git_path) elif not is_au: # Case (ii) git('update-index', '--assume-unchanged', path, @@ -859,35 +860,66 @@ def untrack_file(self, path): def resolve_file(self, path): """Mark the given path as resolved.""" - assert not os.path.isabs(path) + _check_path_is_repo_relative(path) gl_st, _, _ = self._status_file(path) if not gl_st.in_conflict: raise ValueError('File {0} has no conflicts'.format(path)) with self._index as index: - git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + git_path = _get_git_path(path) index.add(git_path) def checkout_file(self, path, commit): """Checkouts the given path at the given commit.""" - assert not os.path.isabs(path) + _check_path_is_repo_relative(path) + + git_path = _get_git_path(path) + o = self.gl_repo.git_repo[commit.tree[git_path].id] + assert o.type != pygit2.GIT_OBJ_COMMIT + assert o.type != pygit2.GIT_OBJ_TAG + + if o.type == pygit2.GIT_OBJ_BLOB: + full_path = os.path.join(self.gl_repo.root, path) + dirname = os.path.dirname(full_path) + if not os.path.exists(dirname): + try: + os.makedirs(dirname) + except OSError as exc: # guard against race condition + if exc.errno != errno.EEXIST: + raise + with io.open(full_path, mode='wb') as dst: + dst.write(o.data) + + elif o.type == pygit2.GIT_OBJ_TREE: + raise PathIsDirectoryError( + 'Path {0} at {1} is a directory and not a file'.format( + path, commit.id)) + else: + raise Exception('Unexpected object type {0}'.format(o.type)) - git_path = path if sys.platform != 'win32' else path.replace('\\', '/') - data = self.gl_repo.git_repo[commit.tree[git_path].id].data - with io.open(os.path.join(self.gl_repo.root, path), mode='wb') as dst: - dst.write(data) + def get_paths(self, path, commit): + """Return a generator of all filepaths under path at commit.""" + _check_path_is_repo_relative(path) - # So as to not get confused with the status of the file we also add it - with self._index as index: - index.add(git_path) + git_path = _get_git_path(path) + tree = self.gl_repo.git_repo[commit.tree[git_path].id] + assert tree.type == pygit2.GIT_OBJ_TREE + + for tree_entry in tree: + tree_entry_path = os.path.join(path, tree_entry.name) + if tree_entry.type == 'tree': + for fp in self.get_paths(tree_entry_path, commit): + yield fp + else: + yield tree_entry_path def diff_file(self, path): """Diff the working version of path with its committed version.""" - assert not os.path.isabs(path) + _check_path_is_repo_relative(path) git_repo = self.gl_repo.git_repo - git_path = path if sys.platform != 'win32' else path.replace('\\', '/') + git_path = _get_git_path(path) try: blob_at_head = git_repo[git_repo.head.peel().tree[git_path].id] except KeyError: # no blob at head @@ -904,7 +936,7 @@ def diff_file(self, path): return blob_at_head.diff(wt_blob, 0, git_path, git_path) - # Merge related methods + # Merge-related methods def merge(self, src, op_cb=None): """Merges the divergent changes of the src branch onto this one.""" @@ -949,7 +981,7 @@ def abort_merge(self): git.merge(abort=True) - # Fuse related methods + # Fuse-related methods @property def _fuse_commits_fp(self): @@ -1162,7 +1194,7 @@ def update(): """Add/remove files to the index.""" for f in files: assert not os.path.isabs(f) - git_f = f if sys.platform != 'win32' else f.replace('\\', '/') + git_f = _get_git_path(f) if not os.path.exists(os.path.join(self.gl_repo.root, f)): index.remove(git_f) elif f not in partials: @@ -1173,7 +1205,7 @@ def update(): with index: update() for f in partials: - git_f = f if sys.platform != 'win32' else f.replace('\\', '/') + git_f = _get_git_path(f) partial_entries[f] = index._git_index[git_f] # To create the commit tree with only the changes to the given files we: @@ -1302,3 +1334,11 @@ def walker(git_repo, target, reverse): if reverse: flags = flags | pygit2.GIT_SORT_REVERSE return git_repo.walk(target, flags) + +def _get_git_path(path): + return path if sys.platform != 'win32' else path.replace('\\', '/') + +def _check_path_is_repo_relative(path): + if os.path.isabs(path): + raise ValueError( + "path {0} is absolute but should be relative to the repo root".format(path)) From 8f64582020be4f7b3ad18734c8336ce84c25c1e8 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sun, 7 Jan 2018 16:42:41 -0500 Subject: [PATCH 069/196] stage file after checkout --- gitless/core.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gitless/core.py b/gitless/core.py index 7401a4d..a5941c2 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -891,6 +891,15 @@ def checkout_file(self, path, commit): with io.open(full_path, mode='wb') as dst: dst.write(o.data) + # So as to not get confused with the status of the file we also add it. + # This prevents getting into a situation in which the staged version is + # different from the working version. In such a case, the file would + # appear as modified to Gitless when it shouldn't. This is also consistent + # with the behavior of `git checkout ` that also adds the + # file to the staging area. + with self._index as index: + index.add(git_path) + elif o.type == pygit2.GIT_OBJ_TREE: raise PathIsDirectoryError( 'Path {0} at {1} is a directory and not a file'.format( From 75ac3fa645fd56c412cb83321988c83fa0a04fbc Mon Sep 17 00:00:00 2001 From: Robb Shecter Date: Sat, 20 Jan 2018 19:54:33 -0800 Subject: [PATCH 070/196] Removed the using-upstream-branch warning --- gitless/cli/helpers.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 3f4faa1..24c454c 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -61,8 +61,6 @@ def get_branch_or_use_upstream(branch_name, arg, repo): 'branch set'.format(arg)) ret = current_b.upstream - pprint.warn( - 'No {0} branch specified, using upstream branch {1}'.format(arg, ret)) else: ret = get_branch(branch_name, repo) return ret From 3d0ec9e50cb8315686d978c870d6f2d6a6cf8387 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Mon, 5 Feb 2018 16:40:42 -0500 Subject: [PATCH 071/196] Revert "Updated readme.md with svg badges" This reverts commit 811e2fae4c5bc7a3eed2b9da8fbe76ac7222d471. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3eb8a57..0a82051 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ Gitless ======= -[![PyPI version](https://badge.fury.io/py/gitless.svg)]( +[![PyPI version](https://badge.fury.io/py/gitless.png)]( http://badge.fury.io/py/gitless "PyPI version") [![Homebrew Formula](https://img.shields.io/homebrew/v/gitless.svg)](http://braumeister.org/formula/gitless "Homebrew Formula") -[![Travis Build Status](https://travis-ci.org/sdg-mit/gitless.svg?branch=master)](https://travis-ci.org/sdg-mit/gitless "Travis Build Status") +[![Travis Build Status](https://travis-ci.org/sdg-mit/gitless.png?branch=master)](https://travis-ci.org/sdg-mit/gitless "Travis Build Status") [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/sdg-mit/gitless?svg=true)](https://ci.appveyor.com/project/spderosso/gitless "AppVeyor Build Status") [Gitless](http://gitless.com "Gitless's website") is an experimental version From c57408591e96b5fe89281472da27c37a6615600c Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Mon, 5 Feb 2018 16:48:50 -0500 Subject: [PATCH 072/196] Revert "Changed reqs declaration in setup.py to permit dependencies >= required version." This reverts commit 5446d9426d123571753f55ee09e7a957e31fbe3f. --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 3526736..815dcfa 100755 --- a/setup.py +++ b/setup.py @@ -36,10 +36,10 @@ sys.exit() -reqs = ['pygit2>=0.24.0', 'clint>=0.3.6'] +reqs = ['pygit2==0.24.0', 'clint==0.3.6'] if sys.platform != 'win32': - reqs.append('sh>=1.11') + reqs.append('sh==1.11') else: reqs.append('pbs>=0.11') From 5cf24799ac93d455dbbb93c5fe81c2417b4aac2a Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Mon, 5 Feb 2018 17:07:13 -0500 Subject: [PATCH 073/196] Change license from GPLv2 to MIT --- LICENSE.md | 394 ++--------------------------------- gitless/cli/commit_dialog.py | 4 +- gitless/cli/file_cmd.py | 4 +- gitless/cli/gl.py | 4 +- gitless/cli/gl_branch.py | 4 +- gitless/cli/gl_checkout.py | 4 +- gitless/cli/gl_commit.py | 4 +- gitless/cli/gl_diff.py | 4 +- gitless/cli/gl_fuse.py | 4 +- gitless/cli/gl_history.py | 4 +- gitless/cli/gl_init.py | 4 +- gitless/cli/gl_merge.py | 4 +- gitless/cli/gl_publish.py | 4 +- gitless/cli/gl_remote.py | 4 +- gitless/cli/gl_resolve.py | 4 +- gitless/cli/gl_status.py | 4 +- gitless/cli/gl_switch.py | 4 +- gitless/cli/gl_tag.py | 4 +- gitless/cli/gl_track.py | 4 +- gitless/cli/gl_untrack.py | 4 +- gitless/cli/helpers.py | 4 +- gitless/cli/pprint.py | 4 +- gitless/core.py | 4 +- gitless/tests/test_core.py | 2 +- gitless/tests/test_e2e.py | 4 +- gitless/tests/utils.py | 4 +- gl.py | 4 +- setup.py | 4 +- 28 files changed, 72 insertions(+), 428 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 00d12de..4298406 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,375 +1,19 @@ -Copyright (C) 2013 Santiago Perez De Rosso - -This program 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 2 -of the License, or (at your option) any later version. - -This program 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. - ---------------------------------------------------------------- - -### GNU GENERAL PUBLIC LICENSE - -Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -### Preamble - -The licenses for most software are designed to take away your freedom -to share and change it. By contrast, the GNU General Public License is -intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - -When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - -To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if -you distribute copies of the software, or if you modify it. - -For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - -We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - -Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, -we want its recipients to know that what they have is not the -original, so that any problems introduced by others will not reflect -on the original authors' reputations. - -Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at -all. - -The precise terms and conditions for copying, distribution and -modification follow. - -### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -**0.** This License applies to any program or other work which -contains a notice placed by the copyright holder saying it may be -distributed under the terms of this General Public License. The -"Program", below, refers to any such program or work, and a "work -based on the Program" means either the Program or any derivative work -under copyright law: that is to say, a work containing the Program or -a portion of it, either verbatim or with modifications and/or -translated into another language. (Hereinafter, translation is -included without limitation in the term "modification".) Each licensee -is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the Program -(independent of having been made by running the Program). Whether that -is true depends on what the Program does. - -**1.** You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a -fee. - -**2.** You may modify your copy or copies of the Program or any -portion of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - -**a)** You must cause the modified files to carry prominent notices -stating that you changed the files and the date of any change. - - -**b)** You must cause any work that you distribute or publish, that in -whole or in part contains or is derived from the Program or any part -thereof, to be licensed as a whole at no charge to all third parties -under the terms of this License. - - -**c)** If the modified program normally reads commands interactively -when run, you must cause it, when started running for such interactive -use in the most ordinary way, to print or display an announcement -including an appropriate copyright notice and a notice that there is -no warranty (or else, saying that you provide a warranty) and that -users may redistribute the program under these conditions, and telling -the user how to view a copy of this License. (Exception: if the -Program itself is interactive but does not normally print such an -announcement, your work based on the Program is not required to print -an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - -**3.** You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - -**a)** Accompany it with the complete corresponding machine-readable -source code, which must be distributed under the terms of Sections 1 -and 2 above on a medium customarily used for software interchange; or, - - -**b)** Accompany it with a written offer, valid for at least three -years, to give any third party, for a charge no more than your cost of -physically performing source distribution, a complete machine-readable -copy of the corresponding source code, to be distributed under the -terms of Sections 1 and 2 above on a medium customarily used for -software interchange; or, - - -**c)** Accompany it with the information you received as to the offer -to distribute corresponding source code. (This alternative is allowed -only for noncommercial distribution and only if you received the -program in object code or executable form with such an offer, in -accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - -**4.** You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt otherwise -to copy, modify, sublicense or distribute the Program is void, and -will automatically terminate your rights under this License. However, -parties who have received copies, or rights, from you under this -License will not have their licenses terminated so long as such -parties remain in full compliance. - -**5.** You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - -**6.** Each time you redistribute the Program (or any work based on -the Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - -**7.** If, as a consequence of a court judgment or allegation of -patent infringement or for any other reason (not limited to patent -issues), conditions are imposed on you (whether by court order, -agreement or otherwise) that contradict the conditions of this -License, they do not excuse you from the conditions of this License. -If you cannot distribute so as to satisfy simultaneously your -obligations under this License and any other pertinent obligations, -then as a consequence you may not distribute the Program at all. For -example, if a patent license would not permit royalty-free -redistribution of the Program by all those who receive copies directly -or indirectly through you, then the only way you could satisfy both it -and this License would be to refrain entirely from distribution of the -Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - -**8.** If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - -**9.** The Free Software Foundation may publish revised and/or new -versions of the General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Program does not specify a -version number of this License, you may choose any version ever -published by the Free Software Foundation. - -**10.** If you wish to incorporate parts of the Program into other -free programs whose distribution conditions are different, write to -the author to ask for permission. For software which is copyrighted by -the Free Software Foundation, write to the Free Software Foundation; -we sometimes make exceptions for this. Our decision will be guided by -the two goals of preserving the free status of all derivatives of our -free software and of promoting the sharing and reuse of software -generally. - -**NO WARRANTY** - -**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - -### END OF TERMS AND CONDITIONS - -### How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. - -To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - one line to give the program's name and an idea of what it does. - Copyright (C) yyyy name of author - - This program 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 2 - of the License, or (at your option) any later version. - - This program 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 this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -Also add information on how to contact you by electronic and paper -mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details - type `show w'. This is free software, and you are welcome - to redistribute it under certain conditions; type `show c' - for details. - -The hypothetical commands \`show w' and \`show c' should show the -appropriate parts of the General Public License. Of course, the -commands you use may be called something other than \`show w' and -\`show c'; they could even be mouse-clicks or menu items--whatever -suits your program. - -You should also get your employer (if you work as a programmer) or -your school, if any, to sign a "copyright disclaimer" for the program, -if necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright - interest in the program `Gnomovision' - (which makes passes at compilers) written - by James Hacker. - - signature of Ty Coon, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, -you may consider it more useful to permit linking proprietary -applications with the library. If this is what you want to do, use the -[GNU Lesser General Public -License](http://www.gnu.org/licenses/lgpl.html) instead of this -License. +Copyright (c) 2018 Santiago Perez De Rosso + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/gitless/cli/commit_dialog.py b/gitless/cli/commit_dialog.py index e0b570f..891fd42 100644 --- a/gitless/cli/commit_dialog.py +++ b/gitless/cli/commit_dialog.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """Gitless's commit dialog.""" diff --git a/gitless/cli/file_cmd.py b/gitless/cli/file_cmd.py index e1ea45a..f5f3120 100644 --- a/gitless/cli/file_cmd.py +++ b/gitless/cli/file_cmd.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """Helper module for gl_{track, untrack, resolve}.""" diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index ff8a98e..239071e 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl - Main Gitless's command. Dispatcher to the other cmds.""" diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index 5d91381..f5032a0 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl branch - List, create, edit or delete branches.""" diff --git a/gitless/cli/gl_checkout.py b/gitless/cli/gl_checkout.py index df3e75e..74141da 100644 --- a/gitless/cli/gl_checkout.py +++ b/gitless/cli/gl_checkout.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl checkout - Checkout committed versions of files.""" diff --git a/gitless/cli/gl_commit.py b/gitless/cli/gl_commit.py index 0fcdc34..df39901 100644 --- a/gitless/cli/gl_commit.py +++ b/gitless/cli/gl_commit.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl commit - Record changes in the local repository.""" diff --git a/gitless/cli/gl_diff.py b/gitless/cli/gl_diff.py index dee799d..169c0f0 100644 --- a/gitless/cli/gl_diff.py +++ b/gitless/cli/gl_diff.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl diff - Show changes in files.""" diff --git a/gitless/cli/gl_fuse.py b/gitless/cli/gl_fuse.py index 0039e09..9202e84 100644 --- a/gitless/cli/gl_fuse.py +++ b/gitless/cli/gl_fuse.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl fuse - Fuse the divergent changes of a branch onto the current branch.""" diff --git a/gitless/cli/gl_history.py b/gitless/cli/gl_history.py index a38d048..9c648d8 100644 --- a/gitless/cli/gl_history.py +++ b/gitless/cli/gl_history.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl history - Show commit history.""" diff --git a/gitless/cli/gl_init.py b/gitless/cli/gl_init.py index 0152007..eb6bbde 100644 --- a/gitless/cli/gl_init.py +++ b/gitless/cli/gl_init.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl init - Create an empty repo or make a clone.""" diff --git a/gitless/cli/gl_merge.py b/gitless/cli/gl_merge.py index cebcb21..a37ad49 100644 --- a/gitless/cli/gl_merge.py +++ b/gitless/cli/gl_merge.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl merge - Merge the divergent changes of one branch onto another.""" diff --git a/gitless/cli/gl_publish.py b/gitless/cli/gl_publish.py index c932861..f99bdb9 100644 --- a/gitless/cli/gl_publish.py +++ b/gitless/cli/gl_publish.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl publish - Publish commits upstream.""" diff --git a/gitless/cli/gl_remote.py b/gitless/cli/gl_remote.py index b9d7e46..4957f97 100644 --- a/gitless/cli/gl_remote.py +++ b/gitless/cli/gl_remote.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl remote - List, create, edit or delete remotes.""" diff --git a/gitless/cli/gl_resolve.py b/gitless/cli/gl_resolve.py index e5bfd00..213df43 100644 --- a/gitless/cli/gl_resolve.py +++ b/gitless/cli/gl_resolve.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl resolve - Mark a file with conflicts as resolved.""" diff --git a/gitless/cli/gl_status.py b/gitless/cli/gl_status.py index c5a6158..2524ef2 100644 --- a/gitless/cli/gl_status.py +++ b/gitless/cli/gl_status.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl status - Show the status of files in the repo.""" diff --git a/gitless/cli/gl_switch.py b/gitless/cli/gl_switch.py index c543dc9..a2ef0ce 100644 --- a/gitless/cli/gl_switch.py +++ b/gitless/cli/gl_switch.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl switch - Switch branches.""" diff --git a/gitless/cli/gl_tag.py b/gitless/cli/gl_tag.py index a3d3dd3..4035caa 100644 --- a/gitless/cli/gl_tag.py +++ b/gitless/cli/gl_tag.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl tag - List, create, edit or delete tags.""" diff --git a/gitless/cli/gl_track.py b/gitless/cli/gl_track.py index 3e636ee..afcfd0d 100644 --- a/gitless/cli/gl_track.py +++ b/gitless/cli/gl_track.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl track - Start tracking changes to files.""" diff --git a/gitless/cli/gl_untrack.py b/gitless/cli/gl_untrack.py index 0792598..2f2d2d7 100644 --- a/gitless/cli/gl_untrack.py +++ b/gitless/cli/gl_untrack.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """gl untrack - Stop tracking changes to files.""" diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 3f4faa1..86d0f54 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """Some helpers for commands.""" diff --git a/gitless/cli/pprint.py b/gitless/cli/pprint.py index 82633e3..8faa349 100644 --- a/gitless/cli/pprint.py +++ b/gitless/cli/pprint.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """Module for pretty printing Gitless output.""" diff --git a/gitless/core.py b/gitless/core.py index a5941c2..a15abf1 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """Gitless's library.""" diff --git a/gitless/tests/test_core.py b/gitless/tests/test_core.py index 1ccda5a..8037446 100644 --- a/gitless/tests/test_core.py +++ b/gitless/tests/test_core.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Gitless - a version control system built on top of Git -# Licensed under GNU GPL v2 +# Licensed under MIT """Core unit tests.""" diff --git a/gitless/tests/test_e2e.py b/gitless/tests/test_e2e.py index 5ea3309..9a9333b 100755 --- a/gitless/tests/test_e2e.py +++ b/gitless/tests/test_e2e.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """End-to-end test.""" diff --git a/gitless/tests/utils.py b/gitless/tests/utils.py index c0159a0..30602d0 100644 --- a/gitless/tests/utils.py +++ b/gitless/tests/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL, version 2. +# Gitless - a version control system built on top of Git +# Licensed under MIT """Utility library for tests.""" diff --git a/gl.py b/gl.py index df45370..d10d85f 100755 --- a/gl.py +++ b/gl.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Gitless - a version control system built on top of Git. -# Licensed under GNU GPL v2. +# Gitless - a version control system built on top of Git +# Licensed under MIT # This file is for PyInstaller diff --git a/setup.py b/setup.py index 815dcfa..4f747ba 100755 --- a/setup.py +++ b/setup.py @@ -72,11 +72,11 @@ url='http://gitless.com', packages=['gitless', 'gitless.cli'], install_requires=reqs, - license='GPLv2', + license='MIT', classifiers=( 'Development Status :: 2 - Pre-Alpha', 'Intended Audience :: Developers', - 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', + 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Programming Language :: Python', 'Programming Language :: Python :: 2', From b84a3c63ddb3a123ebd9207a5199f0132551d321 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Mon, 5 Feb 2018 17:44:13 -0500 Subject: [PATCH 074/196] drop support for very old versions of python --- setup.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/setup.py b/setup.py index 4f747ba..7c69203 100755 --- a/setup.py +++ b/setup.py @@ -43,10 +43,6 @@ else: reqs.append('pbs>=0.11') -if sys.version_info < (2, 7) or ( - sys.version_info < (3, 3) and sys.version_info > (3, 0)): - reqs.append('argparse') - ld = """ Gitless is an experimental version control system built on top of Git. @@ -80,12 +76,7 @@ 'Natural Language :: English', 'Programming Language :: Python', 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', 'Topic :: Software Development :: Version Control'), entry_points={ 'console_scripts': [ From f426f65882b6073c2083e114f747b512eae351cb Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Mon, 5 Feb 2018 19:02:32 -0500 Subject: [PATCH 075/196] create requirements.txt file --- .appveyor.yml | 2 +- .travis.yml | 2 +- requirements.txt | 4 ++++ setup.py | 14 +++++--------- 4 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 requirements.txt diff --git a/.appveyor.yml b/.appveyor.yml index a6c50f8..77cff4b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,7 +7,7 @@ environment: PYTHON: 'C:\Python27-x64\python.exe' init: - - cmd: '%PYTHON% -m pip install -U nose wheel pygit2==0.26.1' + - cmd: '%PYTHON% -m pip install -r requirements.txt -U nose wheel' build: off diff --git a/.travis.yml b/.travis.yml index 9d47838..17e18d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib before_install: "./.travis.sh" -install: pip install . +install: pip install -r requirements.txt . before_script: - git config --global user.name "travis-test" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..29b7d9e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +pygit2==0.26.3 # requires libgit2 0.26 +clint==0.5.1 +sh==1.12.14;sys_platform!='win32' +pbs==0.11;sys_platform=='win32' diff --git a/setup.py b/setup.py index 7c69203..89d749b 100755 --- a/setup.py +++ b/setup.py @@ -36,14 +36,6 @@ sys.exit() -reqs = ['pygit2==0.24.0', 'clint==0.3.6'] - -if sys.platform != 'win32': - reqs.append('sh==1.11') -else: - reqs.append('pbs>=0.11') - - ld = """ Gitless is an experimental version control system built on top of Git. Many people complain that Git is hard to use. We think the problem lies @@ -67,7 +59,11 @@ author_email='sperezde@csail.mit.edu', url='http://gitless.com', packages=['gitless', 'gitless.cli'], - install_requires=reqs, + install_requires=[ + 'pygit2>=0.24.0', + 'clint>=0.3.6', + 'sh>=1.11' if sys.platform != 'win32' else 'pbs>=0.11' + ], license='MIT', classifiers=( 'Development Status :: 2 - Pre-Alpha', From fde86e85f4833c5b0218047e5e602f515dade5b2 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Mon, 5 Feb 2018 19:13:44 -0500 Subject: [PATCH 076/196] add requirements.txt to manifest --- .appveyor.yml | 2 +- MANIFEST.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 77cff4b..26d25d1 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -18,7 +18,7 @@ before_test: test_script: - ps: | # e2e tests require `gl` binary - &$env:PYTHON -m pip install . + &$env:PYTHON -m pip install . -r requirements.txt # 'gl' is installed in Python Scripts directory $env:PATH += ";$(Split-Path $env:PYTHON)\Scripts" &$env:PYTHON setup.py nosetests --logging-level=WARN --with-xunit diff --git a/MANIFEST.in b/MANIFEST.in index 83fcc2c..10e12fa 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1 @@ -include README.md LICENSE.md +include README.md LICENSE.md requirements.txt From 275f52f689016deb0e769aee89f12726f09a1b4c Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Mon, 5 Feb 2018 19:24:42 -0500 Subject: [PATCH 077/196] fix appveyor config --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 26d25d1..6f7d40b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,7 +7,7 @@ environment: PYTHON: 'C:\Python27-x64\python.exe' init: - - cmd: '%PYTHON% -m pip install -r requirements.txt -U nose wheel' + - cmd: '%PYTHON% -m pip install -r requirements.txt . -U nose wheel' build: off @@ -18,7 +18,7 @@ before_test: test_script: - ps: | # e2e tests require `gl` binary - &$env:PYTHON -m pip install . -r requirements.txt + &$env:PYTHON -m pip install -r requirements.txt . # 'gl' is installed in Python Scripts directory $env:PATH += ";$(Split-Path $env:PYTHON)\Scripts" &$env:PYTHON setup.py nosetests --logging-level=WARN --with-xunit From b7de5ab42997907a9cf227540cdcb4df02287df8 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Mon, 5 Feb 2018 19:32:55 -0500 Subject: [PATCH 078/196] only install reqs on init (appveyor) --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 6f7d40b..77cff4b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,7 +7,7 @@ environment: PYTHON: 'C:\Python27-x64\python.exe' init: - - cmd: '%PYTHON% -m pip install -r requirements.txt . -U nose wheel' + - cmd: '%PYTHON% -m pip install -r requirements.txt -U nose wheel' build: off @@ -18,7 +18,7 @@ before_test: test_script: - ps: | # e2e tests require `gl` binary - &$env:PYTHON -m pip install -r requirements.txt . + &$env:PYTHON -m pip install . # 'gl' is installed in Python Scripts directory $env:PATH += ";$(Split-Path $env:PYTHON)\Scripts" &$env:PYTHON setup.py nosetests --logging-level=WARN --with-xunit From 282a5d413a476729cbfcb2715f8a861290b61d51 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Mon, 5 Feb 2018 19:35:22 -0500 Subject: [PATCH 079/196] appveyor fix --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 77cff4b..aa0f705 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,7 +7,7 @@ environment: PYTHON: 'C:\Python27-x64\python.exe' init: - - cmd: '%PYTHON% -m pip install -r requirements.txt -U nose wheel' + - cmd: '%PYTHON% -m pip install -U nose wheel' build: off @@ -18,7 +18,7 @@ before_test: test_script: - ps: | # e2e tests require `gl` binary - &$env:PYTHON -m pip install . + &$env:PYTHON -m pip install -r requirements.txt . # 'gl' is installed in Python Scripts directory $env:PATH += ";$(Split-Path $env:PYTHON)\Scripts" &$env:PYTHON setup.py nosetests --logging-level=WARN --with-xunit From 40b43991b6aeb8fe8345eb30c91b3a1569d8461e Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Mon, 5 Feb 2018 19:38:43 -0500 Subject: [PATCH 080/196] fix pbs version in requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 29b7d9e..8ac8ced 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ pygit2==0.26.3 # requires libgit2 0.26 clint==0.5.1 sh==1.12.14;sys_platform!='win32' -pbs==0.11;sys_platform=='win32' +pbs==0.110;sys_platform=='win32' From 8cd6ec111e58828c80c9f62820218247bb539c05 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Tue, 6 Feb 2018 13:22:49 -0500 Subject: [PATCH 081/196] 0.8.6 --- gitless/cli/gl.py | 6 +++--- gl.spec | 3 --- setup.py | 13 ++++++++++--- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 239071e..e5be6c7 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -34,7 +34,7 @@ INTERNAL_ERROR = 3 NOT_IN_GL_REPO = 4 -VERSION = '0.8.5' +__version__ = '0.8.6' URL = 'http://gitless.com' @@ -76,7 +76,7 @@ def main(): parser.add_argument( '--version', action='version', version=( 'GL Version: {0}\nYou can check if there\'s a new version of Gitless ' - 'available at {1}'.format(VERSION, URL))) + 'available at {1}'.format(__version__, URL))) subparsers = parser.add_subparsers(title='subcommands', dest='subcmd_name') subparsers.required = True @@ -117,5 +117,5 @@ def main(): pprint.err_exp( 'If you want to help, see {0} for info on how to report bugs and ' 'include the following information:\n\n{1}\n\n{2}'.format( - URL, VERSION, traceback.format_exc())) + URL, __version__, traceback.format_exc())) return INTERNAL_ERROR diff --git a/gl.spec b/gl.spec index d8f5e7f..dfdee1f 100644 --- a/gl.spec +++ b/gl.spec @@ -3,12 +3,9 @@ import os a = Analysis(['gl.py'], pathex=[os.getcwd()], - hiddenimports=['pygit2_cffi_51591433xe8494016'], hookspath=None, runtime_hooks=None) -# this is a file pygit2 requires -a.datas += [('decl.h', '../pygit2/pygit2/decl.h', 'DATA')] pyz = PYZ(a.pure) exe = EXE(pyz, diff --git a/setup.py b/setup.py index 89d749b..2a16dce 100755 --- a/setup.py +++ b/setup.py @@ -2,12 +2,19 @@ # -*- coding: utf-8 -*- +import ast +import re import sys from setuptools import setup -VERSION = '0.8.5' +_version_re = re.compile(r'__version__\s+=\s+(.*)') + + +with open('gitless/cli/gl.py', 'rb') as f: + version = str(ast.literal_eval(_version_re.search( + f.read().decode('utf-8')).group(1))) # Build helper @@ -18,7 +25,7 @@ import platform rel = 'gl-v{0}-{1}-{2}'.format( - VERSION, platform.system().lower(), platform.machine()) + version, platform.system().lower(), platform.machine()) print('running pyinstaller...') pyinstaller( @@ -52,7 +59,7 @@ setup( name='gitless', - version=VERSION, + version=version, description='A version control system built on top of Git', long_description=ld, author='Santiago Perez De Rosso', From 166b258553c4f8a7c163f607874b0ad4356e9a35 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 6 May 2018 03:16:06 +0300 Subject: [PATCH 082/196] Start packagins - build an empty snap Building on Fedora seems to work only woth Docker and :z flag for mounts: $ docker run -v /home/anatoli/p/gitless:/home/anatoli/p/gitless:z -w /home/anatoli/p/gitless snapcore/snapcraft snapcraft $ sudo snap install gitless_*_amd64.snap --devmode This snap doesn't contain anything. It is just to test that build works and `gitless` snap can be installed. https://github.com/sdg-mit/gitless/issues/174 --- snap/snapcraft.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 snap/snapcraft.yaml diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml new file mode 100644 index 0000000..58de377 --- /dev/null +++ b/snap/snapcraft.yaml @@ -0,0 +1,15 @@ +name: gitless +version: git +summary: A simple version control system built on top of Git +description: | + Version control system that is built on top of Git in + attempt to make user interface easier by playing with + underlying concepts. Gitless is fully compatible with + Git and can be used with it interchangeably. + +grade: devel +confinement: devmode + +parts: + gitless-cli: + plugin: nil From 539bd7726b7261c9a9d3dd59bea0078716490f7e Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 6 May 2018 05:19:37 +0300 Subject: [PATCH 083/196] Try to build snap on Travis --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 17e18d2..7e02664 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,3 +30,8 @@ branches: - develop sudo: false + +jobs: + include: + - stage: Pack snap + script: docker run -v $(PWD):$(PWD) -w $(PWD) snapcore/snapcraft snapcraft From af479363e011a19b02c3d177497f5f8d7932f273 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 6 May 2018 05:39:29 +0300 Subject: [PATCH 084/196] Travis skip before step, attempt to clean env --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 7e02664..882d959 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,4 +34,6 @@ sudo: false jobs: include: - stage: Pack snap + env: EMPTY + before_script: skip script: docker run -v $(PWD):$(PWD) -w $(PWD) snapcore/snapcraft snapcraft From 352a48d5628b226ea6637ce82c86e3ce792a4cc3 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 6 May 2018 05:41:35 +0300 Subject: [PATCH 085/196] Fix $(PWD) should be $(pwd) or ${PWD} --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 882d959..d9a9e04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,4 +36,4 @@ jobs: - stage: Pack snap env: EMPTY before_script: skip - script: docker run -v $(PWD):$(PWD) -w $(PWD) snapcore/snapcraft snapcraft + script: docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft snapcraft From 5ff6809de3d5fdcd1dae01605cfe9dc19cb2e335 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 6 May 2018 05:50:13 +0300 Subject: [PATCH 086/196] Skip before_install and install for snap on Travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d9a9e04..91fc19d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,5 +35,5 @@ jobs: include: - stage: Pack snap env: EMPTY - before_script: skip + install: skip script: docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft snapcraft From e3565ee79416fbe37317f17c6b0715a2b9b933d6 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 6 May 2018 06:24:24 +0300 Subject: [PATCH 087/196] Skip before_install explicitly --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 91fc19d..892701b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,5 +35,6 @@ jobs: include: - stage: Pack snap env: EMPTY + before_install: skip install: skip script: docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft snapcraft From 5443213726c58933e6a08f3cf4886b21fb85ca10 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 6 May 2018 06:53:58 +0300 Subject: [PATCH 088/196] Use Python plugin to build gitless snap --- snap/snapcraft.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 58de377..f260ad7 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -12,4 +12,5 @@ confinement: devmode parts: gitless-cli: - plugin: nil + plugin: python + source: . From 7d6d7b64926151d1f77f98be490914197ffb557a Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 6 May 2018 08:00:02 +0300 Subject: [PATCH 089/196] libgit2-dev is needed to compile pygit2 dependency fatal error: git2.h: No such file or directory compilation terminated. error: command 'x86_64-linux-gnu-gcc' failed with exit status 1 --- snap/snapcraft.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index f260ad7..bffbf41 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -10,6 +10,9 @@ description: | grade: devel confinement: devmode +build-packages: + - libgit2-dev + parts: gitless-cli: plugin: python From df93a1d58fbc3b376ffe7934d2b62e878dc50459 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 6 May 2018 08:28:50 +0300 Subject: [PATCH 090/196] Need newer version of libgit2 than in Ubuntu snap core Setting up libgit2-dev:amd64 (0.24.1-2) ... ... src/types.h:36:2: error: #error You need a compatible libgit2 version (v0.27.x) --- snap/snapcraft.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index bffbf41..05a6b92 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -10,10 +10,13 @@ description: | grade: devel confinement: devmode -build-packages: - - libgit2-dev - parts: + libgit2: + plugin: cmake + source: https://github.com/libgit2/libgit2/archive/v0.27.0.tar.gz + gitless-cli: plugin: python source: . + after: [libgit2] + From df8855f26e986e44f29bce7f8a40dc54016b203c Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 6 May 2018 08:52:42 +0300 Subject: [PATCH 091/196] Add OpenSSL lib for libgit2 -- Could NOT find OpenSSL, try to set the path to OpenSSL root CMake Error at src/CMakeLists.txt:180 (MESSAGE): Asked for OpenSSL TLS backend, but it wasn't found --- snap/snapcraft.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 05a6b92..888d816 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -14,6 +14,8 @@ parts: libgit2: plugin: cmake source: https://github.com/libgit2/libgit2/archive/v0.27.0.tar.gz + build-packages: + - libssl-dev gitless-cli: plugin: python From e426a7bace9ad55edb2cd39288e0eef41e8e4007 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sat, 12 May 2018 13:36:00 +0300 Subject: [PATCH 092/196] Add `gl` command (that doesn't work) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✗ gitless.gl Traceback (most recent call last): File "/snap/gitless/x5/bin/gl", line 11, in load_entry_point('gitless==0.8.6', 'console_scripts', 'gl')() File "/snap/gitless/x5/lib/python3.5/site-packages/pkg_resources/__init__.py", line 480, in load_entry_point return get_distribution(dist).load_entry_point(group, name) File "/snap/gitless/x5/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2691, in load_entry_point return ep.load() File "/snap/gitless/x5/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2322, in load return self.resolve() File "/snap/gitless/x5/lib/python3.5/site-packages/pkg_resources/__init__.py", line 2328, in resolve module = __import__(self.module_name, fromlist=['__name__'], level=0) File "/snap/gitless/x5/lib/python3.5/site-packages/gitless/cli/gl.py", line 22, in from gitless import core File "/snap/gitless/x5/lib/python3.5/site-packages/gitless/core.py", line 30, in from sh import git, ErrorReturnCode ImportError: cannot import name 'git' --- snap/snapcraft.yaml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 888d816..36f9ae6 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,3 +1,5 @@ +# obligatory fields + name: gitless version: git summary: A simple version control system built on top of Git @@ -7,8 +9,14 @@ description: | underlying concepts. Gitless is fully compatible with Git and can be used with it interchangeably. -grade: devel -confinement: devmode +grade: devel # 'stable' for stable/candidate upload +confinement: devmode # 'strict' after right plugs and slots + +# 'optional' fields + +apps: + gl: + command: bin/gl parts: libgit2: From f9525ea80f5e219b3feb7c8cc536d0dea67486d6 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 13 May 2018 01:38:47 +0300 Subject: [PATCH 093/196] `gitless` snap needs `git` binary to operate --- snap/snapcraft.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 36f9ae6..55afbf1 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -29,4 +29,9 @@ parts: plugin: python source: . after: [libgit2] - + # need git until https://github.com/sdg-mit/gitless/issues/176 + stage-packages: + - git + build-packages: + - git + \ No newline at end of file From 3d45996f0fbb36790f5c8dd79dbc2b471cefb120 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Sun, 13 May 2018 20:44:17 -0400 Subject: [PATCH 094/196] update description to match the one used in pypi --- snap/snapcraft.yaml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 55afbf1..a7e32e8 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -4,10 +4,14 @@ name: gitless version: git summary: A simple version control system built on top of Git description: | - Version control system that is built on top of Git in - attempt to make user interface easier by playing with - underlying concepts. Gitless is fully compatible with - Git and can be used with it interchangeably. + Gitless is an experimental version control system built on top of Git. + Many people complain that Git is hard to use. We think the problem lies + deeper than the user interface, in the concepts underlying Git. Gitless + is an experiment to see what happens if you put a simple veneer on an + app that changes the underlying concepts. Because Gitless is implemented + on top of Git (could be considered what Git pros call a "porcelain" of + Git), you can always fall back on Git. And of course your coworkers you + share a repo with need never know that you're not a Git aficionado. grade: devel # 'stable' for stable/candidate upload confinement: devmode # 'strict' after right plugs and slots @@ -34,4 +38,4 @@ parts: - git build-packages: - git - \ No newline at end of file + From 5f5ae31fc4cf794f9ee1fa5525c00f9643f6e645 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Tue, 29 May 2018 23:08:10 -0700 Subject: [PATCH 095/196] Enable continuous delivery of the snap from Travis CI --- .snapcraft/travis_snapcraft.cfg | Bin 0 -> 2432 bytes .travis.yml | 61 ++++++++++++++++---------------- 2 files changed, 31 insertions(+), 30 deletions(-) create mode 100644 .snapcraft/travis_snapcraft.cfg diff --git a/.snapcraft/travis_snapcraft.cfg b/.snapcraft/travis_snapcraft.cfg new file mode 100644 index 0000000000000000000000000000000000000000..dabd4f26f2079f3a00b132e1cdf1d5392011ae8d GIT binary patch literal 2432 zcmV-`34ivs*cc6nzotZ;mDV-oxLVfB+*Cll{&18H+wJ9C(&`|QsZ%7rIaM@c+I-Is z9naUIhFX=%J2H0?$4*{S`ksBfTZ)7!x+?yS%r)(}KL=1g*GHPt7Xx(cYux7L<3=b3 z9dWrD8OY~pYcW!}*4*%7CNAih$)sZ)eX$Y1hQs9houkU2KjPJlzr|ETrf76oo3PeX z|G#@Ppt)i-RzR+Nq8f7sEyiIy5_|$$m&iQW47A@6Lddy*@H%fU2D!&OY=W<*cP+GgX<20=G4_)Ao9ffg$z&P^U?-Bw5^GvfoPq5F%R z#E`HaEbCa-H!wY@dT}-2RLId*?miougDFzkl7w&5<-QZSrR{tzDEf_W&BqsLLc*RT zHIGltKm)=*GNmlv&=dCMF!m|(NWB{6+8XLi0L^R3W%XjNnSJR_AF!i-zo%$Ua0RrQ z#tNolW}E#BPLENgF(u_beh%hQzZ{;h0CV2r28ReGjY%f%;uW4j<);?t$wD^Jwcszy zNGN1HPNIiaD7I1p(NGsu&WYzN-4VT-3(-PZxkvZ6?F~DXe3FX$gYyETNY&;!djh2q z1z9H%q+9c$)~dRT@lUT&G^sZygrLy1onE`z+H>$W@HJR9HV*JHFcn2h52cHqI}5By zpknTFkk@N4P}M($$U-+i95%@#ti?q~io;}YRyR_x@(`nkIoV#A$PIoS3tSf<8~0f_ z92{q|Fs3RZW0ko-!z_@(5gIMm{-6Yz26>mS6;3t3qL&%37AsfrrLelIH2>`({sd`m zu(%YyV}Q9N@d`k~dzZ`j%a{*+#t+Zp3%vQkgKwW1bq{-xky! zxY83A?6QOfc5ry97fLpr!_@&N^pW%y)46V5j#rk=V7jzK>0v>Ab(|5BJKAR&rY;2W zfMVrevmYrI{Hr`JuP4g-yVN?~dZE%ui3g3hhou_r!NVThsEpg3xxVN8U%@u+xnmb9 zM1{nqy=1UZsMgi;O;cAWpYZO2%tu*ML6zTY+8<&om|J1SSeONlB1f$A%GHmc>NvWM zmj=OK`Ua}1by!mfq<_3~H1nD{=`Y_*_wz&9B?Uke$N=38e2E44Vj70H=rf!keF~WiR&O$m(~9hYdjSD_ z$o&%zsUjpl|CHw=G~D_f&HI}{-16Wj{b8l=hs0vRDOMXm_MT?j&Dx5Y%zGuDz#O5a zCVbp>!h)XdH?Kvb(~x?EoK4C~qodMJvZthcog_PcEnpJbLAYvTPZ2IxP6upL)RG{0 zG(R-+#FzpbGFn>I-WC2!V%j~ozV%e(wkXXba05B3N*0;T&XbSow{8x~IXnhi6N<^Z z{_8J;vMaMUu{qTL9inrm7Y=0b7mbRz$ya01Ln}pmBPTc9;^yS}dh}-fKOxZ49~Hj5 zaae?l0@exmgO8Mf8?Nk4;$X;w>&+lD)m81_*3%ZDqqh1Bg@uU8T04~W<`&emQa+mZ*4Mw_lwOIYB<0KU!}9gt)4;V z@Ng)SU5WGlbC_2|*MFI?(PDBiPeGfw$6kQ4QpRPhx={idN;+`{S6U&5bU{-N zOMA-$8B}XtUOU~uA8;hnR32v%nzs0%trY_+54R1hw)Hc-}is6Vi{zxWC+;Q~e9NGSrt;jP@O^Y5OgBy{vtX6@>e_sFaF8Rh0qn2YgYXc>e`Y4UpchFA)D`Lzz|#(vRsxt)n5_ z{R|)ZS8azxx$VA$(lV&sm}|1QnSZ-yi&+We+hoQASiixMdgu=LAhWeoy{=_r2R-L! zA+e=eVu6c)LmXWdm2kEtS(7zBVUvBL_p1C5rKc7jDQkR-Bcy8Xzdn%&+5&?{7e?U2 zU%^|!zLcV@$MfWxxcSX|^5=m_kt@{VGi?{S+MD0C%af&eQt4COu3!+!fe~dby+HgP zMS@SNZTN5U%f-IV1!$+pI~g18hWD+2Qkp33`8osVm#k{_FRm#Hw$IPHDAC+8*r{Pm zycPPr-25aB^5NXKj1P`6m?wf=aEnD0GTX}7Br(eES6Vm`${U>H|CV_e9~6*G|AcnE z19;;H3w3s6#|E%yO!FLC{j>vaKMt3>3$D-E60z0UNUOX68Jdy=udZ3&Qaam}8CJTM z3IPD`mM#AO1Pmu2VX5;wVWuPDG32)X18=*->TQdZa$Lau)wMUmqC*AKu%IsI@(>{) z1to~7^)ZTfHW^62=I%$N8ce3*%9gFQEYB26=<9ejcx5kUCa;Ng^DPkLK`vXdG+qMx zs{bFfAqOGU5zXR2sL`M${gGaW(m|4yl#ZRt3W<^VA@))335E4cc_}J1yz=HH6c(4k z_KT>9Z}^2Y-XZz>!s+~3 zqCY@j%U)h347*r_sq)0!iA)P9<@Xo>TCw35M=#?8QdKo7{+oGUud24NCY*alb)KET7xG5xd(M`Hi^n=qF{ yUxcJfq`OL?dv8#Z4s-g*Ft6V;g`nI4C{;}?)Ioq+m^$Dbh58il(Y7ps+KX+xXT`Yy literal 0 HcmV?d00001 diff --git a/.travis.yml b/.travis.yml index 892701b..ea2b28c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,40 +1,41 @@ language: python - python: - - "2.7" - - "3.3" - - "3.4" - - "3.5" - - "3.6" - - "pypy-5.3.1" - +- '2.7' +- '3.3' +- '3.4' +- '3.5' +- '3.6' +- pypy-5.3.1 env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib - -before_install: "./.travis.sh" - +before_install: ./.travis.sh install: pip install -r requirements.txt . - before_script: - - git config --global user.name "travis-test" - - git config --global user.email "travis@test.com" - +- git config --global user.name "travis-test" +- git config --global user.email "travis@test.com" script: - - nosetests --logging-level=WARN - # nose doesn't like the number on test_e2e so it's not detected by the - # previous command. - - nosetests gitless/tests/test_e2e.py --logging-level=WARN - +- nosetests --logging-level=WARN +- nosetests gitless/tests/test_e2e.py --logging-level=WARN branches: only: - - master - - develop - -sudo: false - + - master + - develop +sudo: required jobs: include: - - stage: Pack snap - env: EMPTY - before_install: skip - install: skip - script: docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft snapcraft + - stage: Pack snap + env: EMPTY + before_install: skip + install: skip + script: docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft snapcraft +after_success: +- openssl aes-256-cbc -K $encrypted_8b01c2e263fa_key -iv $encrypted_8b01c2e263fa_iv + -in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d +services: +- docker +deploy: + 'on': + branch: master + provider: script + script: docker run -v $(pwd):$(pwd) -t snapcore/snapcraft sh -c "apt update -qq + && cd $(pwd) && snapcraft && snapcraft push *.snap --release edge" + skip_cleanup: true From 1ab4f7772b9d397f6e09ee7f8707b2e6ee115250 Mon Sep 17 00:00:00 2001 From: Peter Pentchev Date: Sat, 25 Aug 2018 20:09:52 +0300 Subject: [PATCH 096/196] Handle pygit2.discover_repository() returning None. A breaking change was made in pygit2 0.27.1: it now returns None instead of raising a KeyError if the specified path is not in a Git repository. --- gitless/core.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gitless/core.py b/gitless/core.py index 4fd203c..66b292b 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -58,6 +58,13 @@ class PathIsDirectoryError(ValueError): pass GL_STATUS_IGNORED = 3 +def error_on_none(path): + """Raise a KeyError if the ```path``` argument is None.""" + if path is None: + raise KeyError('path') + return path + + def init_repository(url=None): """Creates a new Gitless's repository in the cwd. @@ -67,7 +74,7 @@ def init_repository(url=None): """ cwd = os.getcwd() try: - pygit2.discover_repository(cwd) + error_on_none(pygit2.discover_repository(cwd)) raise GlError('You are already in a Gitless repository') except KeyError: # Expected if not url: @@ -108,7 +115,7 @@ class Repository(object): def __init__(self): """Create a Repository out of the current working repository.""" try: - path = pygit2.discover_repository(os.getcwd()) + path = error_on_none(pygit2.discover_repository(os.getcwd())) except KeyError: raise NotInRepoError('You are not in a Gitless\'s repository') From f9fba3ebc13f8db9d50378b391e63bbdf315a496 Mon Sep 17 00:00:00 2001 From: Peter Pentchev Date: Sat, 25 Aug 2018 20:25:56 +0300 Subject: [PATCH 097/196] Correct two typographical errors. --- gitless/cli/gl_fuse.py | 2 +- gitless/core.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gitless/cli/gl_fuse.py b/gitless/cli/gl_fuse.py index 9202e84..3863320 100644 --- a/gitless/cli/gl_fuse.py +++ b/gitless/cli/gl_fuse.py @@ -18,7 +18,7 @@ def parser(subparsers, repo): 'fuse', help=desc, description=( desc.capitalize() + '. ' + 'By default all divergent changes from the given source branch are ' - 'fused. To customize the set of commmits to fuse use the only and ' + 'fused. To customize the set of commits to fuse use the only and ' 'exclude flags')) fuse_parser.add_argument( 'src', nargs='?', diff --git a/gitless/core.py b/gitless/core.py index 4fd203c..6aed1e3 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -1020,7 +1020,7 @@ def fuse(self, src, ip, only=None, exclude=None, op_cb=None): """Fuse the given commits onto this branch. Args: - src: the branch (Brach obj) to fuse commits from. + src: the branch (Branch obj) to fuse commits from. ip: id of the commit to act as the insertion point. The commits to fuse are inserted after this commit. ip has to correspond to one of the divergent commits from self or the divergent point. From 6a669c35dc501e128a5bf64538f4b41da2bb07b7 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Tue, 30 Oct 2018 19:35:04 +0300 Subject: [PATCH 098/196] requirements.txt Update pygit2 0.26.3 --> 0.26.4 Might fix #187 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8ac8ced..5de1a5a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -pygit2==0.26.3 # requires libgit2 0.26 +pygit2==0.26.4 # requires libgit2 0.26 clint==0.5.1 sh==1.12.14;sys_platform!='win32' pbs==0.110;sys_platform=='win32' From 9d000058f06fa184eff2aa12037bef0da09d75cf Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Tue, 30 Oct 2018 20:01:03 +0300 Subject: [PATCH 099/196] .travis.yml Use stable snapcraft --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ea2b28c..533324c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,6 @@ deploy: 'on': branch: master provider: script - script: docker run -v $(pwd):$(pwd) -t snapcore/snapcraft sh -c "apt update -qq + script: docker run -v $(pwd):$(pwd) -t snapcore/snapcraft:stable sh -c "apt update -qq && cd $(pwd) && snapcraft && snapcraft push *.snap --release edge" skip_cleanup: true From ce0b211e3f116228b054f09bf3c5833d1f1648e4 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Tue, 30 Oct 2018 20:53:29 +0300 Subject: [PATCH 100/196] .travis.yml Fix another missing snapcraft:stable --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 533324c..6e3fc2e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ jobs: env: EMPTY before_install: skip install: skip - script: docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft snapcraft + script: docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft:stable snapcraft after_success: - openssl aes-256-cbc -K $encrypted_8b01c2e263fa_key -iv $encrypted_8b01c2e263fa_iv -in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d From 7409816eb7110b0cca66d6ce9b7dc4584f15cb87 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Tue, 30 Oct 2018 21:44:26 +0300 Subject: [PATCH 101/196] .travis.yml Run apt update before snapcraft Also unify syntax for long command lines. This should fix build failure. See https://forum.snapcraft.io/t/ant-and-others-fails-using-docker-image/7673 --- .travis.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6e3fc2e..c6309fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,9 @@ jobs: env: EMPTY before_install: skip install: skip - script: docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft:stable snapcraft + script: > + docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft:stable sh -c "apt + update && snapcraft" after_success: - openssl aes-256-cbc -K $encrypted_8b01c2e263fa_key -iv $encrypted_8b01c2e263fa_iv -in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d @@ -36,6 +38,7 @@ deploy: 'on': branch: master provider: script - script: docker run -v $(pwd):$(pwd) -t snapcore/snapcraft:stable sh -c "apt update -qq + script: > + docker run -v $(pwd):$(pwd) -t snapcore/snapcraft:stable sh -c "apt update -qq && cd $(pwd) && snapcraft && snapcraft push *.snap --release edge" skip_cleanup: true From 21cdb9550ea8b29a41bcf54d257d8e4ce75a7c1c Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Tue, 30 Oct 2018 22:40:43 +0300 Subject: [PATCH 102/196] .travis.yml Use apt-get to avoid warnings Also unify `snapcraft` calls --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index c6309fa..d76c8d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ jobs: before_install: skip install: skip script: > - docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft:stable sh -c "apt + docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft:stable sh -c "apt-get update && snapcraft" after_success: - openssl aes-256-cbc -K $encrypted_8b01c2e263fa_key -iv $encrypted_8b01c2e263fa_iv @@ -39,6 +39,6 @@ deploy: branch: master provider: script script: > - docker run -v $(pwd):$(pwd) -t snapcore/snapcraft:stable sh -c "apt update -qq - && cd $(pwd) && snapcraft && snapcraft push *.snap --release edge" + docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft:stable sh -c "apt-get + update && snapcraft && snapcraft push *.snap --release edge" skip_cleanup: true From 87e2adbbc3945887ad868c7cd4d4774f7a8a3e9d Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Wed, 31 Oct 2018 06:06:25 +0300 Subject: [PATCH 103/196] .travis.yml Deploy only at Pack snap step --- .travis.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index d76c8d5..62ca0df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: python +services: +- docker python: - '2.7' - '3.3' @@ -29,16 +31,14 @@ jobs: script: > docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft:stable sh -c "apt-get update && snapcraft" -after_success: -- openssl aes-256-cbc -K $encrypted_8b01c2e263fa_key -iv $encrypted_8b01c2e263fa_iv - -in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d -services: -- docker -deploy: - 'on': - branch: master - provider: script - script: > - docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft:stable sh -c "apt-get - update && snapcraft && snapcraft push *.snap --release edge" - skip_cleanup: true + after_success: + - openssl aes-256-cbc -K $encrypted_8b01c2e263fa_key -iv $encrypted_8b01c2e263fa_iv + -in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d + deploy: + on: + branch: master + provider: script + script: > + docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft:stable sh -c "apt-get + update && snapcraft && snapcraft push *.snap --release edge" + skip_cleanup: true From cbc1db4a8b7d8cdf9ac46b35c0cb0196deb1974f Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Sat, 29 Dec 2018 22:41:27 +0300 Subject: [PATCH 104/196] Fix snap upload using native deploy provider This may need generating and setting SNAP_TOKEN as described in https://docs.travis-ci.com/user/deployment/snaps/ --- .travis.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 62ca0df..072c8e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,9 @@ language: python +dist: xenial +addons: + apt: + packages: + - snapcraft services: - docker python: @@ -21,24 +26,20 @@ branches: only: - master - develop -sudo: required jobs: include: - stage: Pack snap env: EMPTY before_install: skip install: skip - script: > - docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft:stable sh -c "apt-get - update && snapcraft" + script: snapcraft after_success: - openssl aes-256-cbc -K $encrypted_8b01c2e263fa_key -iv $encrypted_8b01c2e263fa_iv -in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d deploy: on: branch: master - provider: script - script: > - docker run -v $(pwd):$(pwd) -w $(pwd) snapcore/snapcraft:stable sh -c "apt-get - update && snapcraft && snapcraft push *.snap --release edge" + provider: snap + snap: *.snap + channel: edge skip_cleanup: true From ac0764ac72956ea14341002f760f5bb6a593e2a4 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Thu, 3 Jan 2019 11:33:44 +0300 Subject: [PATCH 105/196] Remove docker and fix YAML I tried to figure out why builds are not running and somebody from https://travis-ci.community/c/product hinted that invalid YAML can bring those issues. I run it through linter and found that asterisk needs to be escaped or it will be treated as an alias, invalid alias in this case. https://yaml.org/YAML_for_ruby.html#simple_alias_example Also removed docker leftover from the previous commit. --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 072c8e0..0d7d6a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,6 @@ addons: apt: packages: - snapcraft -services: -- docker python: - '2.7' - '3.3' @@ -40,6 +38,6 @@ jobs: on: branch: master provider: snap - snap: *.snap + snap: "*.snap" channel: edge skip_cleanup: true From dff5c5b3ce4a4ea07315b7beee45be460c76666a Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Thu, 3 Jan 2019 20:05:40 -0800 Subject: [PATCH 106/196] update python versions in travis.yml file --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0d7d6a9..c7ca4ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,11 +6,11 @@ addons: - snapcraft python: - '2.7' -- '3.3' - '3.4' - '3.5' - '3.6' -- pypy-5.3.1 +- '3.7' +- 'pypy3.5' env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib before_install: ./.travis.sh install: pip install -r requirements.txt . From f17ccd394185a2e1e3266445d535050f80dce693 Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Fri, 4 Jan 2019 13:52:10 +0300 Subject: [PATCH 107/196] Clean up old intregration remnants --- .snapcraft/travis_snapcraft.cfg | Bin 2432 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .snapcraft/travis_snapcraft.cfg diff --git a/.snapcraft/travis_snapcraft.cfg b/.snapcraft/travis_snapcraft.cfg deleted file mode 100644 index dabd4f26f2079f3a00b132e1cdf1d5392011ae8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2432 zcmV-`34ivs*cc6nzotZ;mDV-oxLVfB+*Cll{&18H+wJ9C(&`|QsZ%7rIaM@c+I-Is z9naUIhFX=%J2H0?$4*{S`ksBfTZ)7!x+?yS%r)(}KL=1g*GHPt7Xx(cYux7L<3=b3 z9dWrD8OY~pYcW!}*4*%7CNAih$)sZ)eX$Y1hQs9houkU2KjPJlzr|ETrf76oo3PeX z|G#@Ppt)i-RzR+Nq8f7sEyiIy5_|$$m&iQW47A@6Lddy*@H%fU2D!&OY=W<*cP+GgX<20=G4_)Ao9ffg$z&P^U?-Bw5^GvfoPq5F%R z#E`HaEbCa-H!wY@dT}-2RLId*?miougDFzkl7w&5<-QZSrR{tzDEf_W&BqsLLc*RT zHIGltKm)=*GNmlv&=dCMF!m|(NWB{6+8XLi0L^R3W%XjNnSJR_AF!i-zo%$Ua0RrQ z#tNolW}E#BPLENgF(u_beh%hQzZ{;h0CV2r28ReGjY%f%;uW4j<);?t$wD^Jwcszy zNGN1HPNIiaD7I1p(NGsu&WYzN-4VT-3(-PZxkvZ6?F~DXe3FX$gYyETNY&;!djh2q z1z9H%q+9c$)~dRT@lUT&G^sZygrLy1onE`z+H>$W@HJR9HV*JHFcn2h52cHqI}5By zpknTFkk@N4P}M($$U-+i95%@#ti?q~io;}YRyR_x@(`nkIoV#A$PIoS3tSf<8~0f_ z92{q|Fs3RZW0ko-!z_@(5gIMm{-6Yz26>mS6;3t3qL&%37AsfrrLelIH2>`({sd`m zu(%YyV}Q9N@d`k~dzZ`j%a{*+#t+Zp3%vQkgKwW1bq{-xky! zxY83A?6QOfc5ry97fLpr!_@&N^pW%y)46V5j#rk=V7jzK>0v>Ab(|5BJKAR&rY;2W zfMVrevmYrI{Hr`JuP4g-yVN?~dZE%ui3g3hhou_r!NVThsEpg3xxVN8U%@u+xnmb9 zM1{nqy=1UZsMgi;O;cAWpYZO2%tu*ML6zTY+8<&om|J1SSeONlB1f$A%GHmc>NvWM zmj=OK`Ua}1by!mfq<_3~H1nD{=`Y_*_wz&9B?Uke$N=38e2E44Vj70H=rf!keF~WiR&O$m(~9hYdjSD_ z$o&%zsUjpl|CHw=G~D_f&HI}{-16Wj{b8l=hs0vRDOMXm_MT?j&Dx5Y%zGuDz#O5a zCVbp>!h)XdH?Kvb(~x?EoK4C~qodMJvZthcog_PcEnpJbLAYvTPZ2IxP6upL)RG{0 zG(R-+#FzpbGFn>I-WC2!V%j~ozV%e(wkXXba05B3N*0;T&XbSow{8x~IXnhi6N<^Z z{_8J;vMaMUu{qTL9inrm7Y=0b7mbRz$ya01Ln}pmBPTc9;^yS}dh}-fKOxZ49~Hj5 zaae?l0@exmgO8Mf8?Nk4;$X;w>&+lD)m81_*3%ZDqqh1Bg@uU8T04~W<`&emQa+mZ*4Mw_lwOIYB<0KU!}9gt)4;V z@Ng)SU5WGlbC_2|*MFI?(PDBiPeGfw$6kQ4QpRPhx={idN;+`{S6U&5bU{-N zOMA-$8B}XtUOU~uA8;hnR32v%nzs0%trY_+54R1hw)Hc-}is6Vi{zxWC+;Q~e9NGSrt;jP@O^Y5OgBy{vtX6@>e_sFaF8Rh0qn2YgYXc>e`Y4UpchFA)D`Lzz|#(vRsxt)n5_ z{R|)ZS8azxx$VA$(lV&sm}|1QnSZ-yi&+We+hoQASiixMdgu=LAhWeoy{=_r2R-L! zA+e=eVu6c)LmXWdm2kEtS(7zBVUvBL_p1C5rKc7jDQkR-Bcy8Xzdn%&+5&?{7e?U2 zU%^|!zLcV@$MfWxxcSX|^5=m_kt@{VGi?{S+MD0C%af&eQt4COu3!+!fe~dby+HgP zMS@SNZTN5U%f-IV1!$+pI~g18hWD+2Qkp33`8osVm#k{_FRm#Hw$IPHDAC+8*r{Pm zycPPr-25aB^5NXKj1P`6m?wf=aEnD0GTX}7Br(eES6Vm`${U>H|CV_e9~6*G|AcnE z19;;H3w3s6#|E%yO!FLC{j>vaKMt3>3$D-E60z0UNUOX68Jdy=udZ3&Qaam}8CJTM z3IPD`mM#AO1Pmu2VX5;wVWuPDG32)X18=*->TQdZa$Lau)wMUmqC*AKu%IsI@(>{) z1to~7^)ZTfHW^62=I%$N8ce3*%9gFQEYB26=<9ejcx5kUCa;Ng^DPkLK`vXdG+qMx zs{bFfAqOGU5zXR2sL`M${gGaW(m|4yl#ZRt3W<^VA@))335E4cc_}J1yz=HH6c(4k z_KT>9Z}^2Y-XZz>!s+~3 zqCY@j%U)h347*r_sq)0!iA)P9<@Xo>TCw35M=#?8QdKo7{+oGUud24NCY*alb)KET7xG5xd(M`Hi^n=qF{ yUxcJfq`OL?dv8#Z4s-g*Ft6V;g`nI4C{;}?)Ioq+m^$Dbh58il(Y7ps+KX+xXT`Yy From c9df1810fdc841eed716159fccc0e0bddbd1996f Mon Sep 17 00:00:00 2001 From: Anatoli Babenia Date: Fri, 4 Jan 2019 13:54:16 +0300 Subject: [PATCH 108/196] Remove unused secrets --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index c7ca4ad..5aa579b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,9 +31,6 @@ jobs: before_install: skip install: skip script: snapcraft - after_success: - - openssl aes-256-cbc -K $encrypted_8b01c2e263fa_key -iv $encrypted_8b01c2e263fa_iv - -in .snapcraft/travis_snapcraft.cfg -out .snapcraft/snapcraft.cfg -d deploy: on: branch: master From 4dff6177226fa10d7e68c909bddabc0ae3db7e2d Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 8 Feb 2019 00:12:23 +0300 Subject: [PATCH 109/196] Build snap on a newer Ubuntu base --- snap/snapcraft.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index a7e32e8..739b905 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -3,6 +3,7 @@ name: gitless version: git summary: A simple version control system built on top of Git +license: MIT description: | Gitless is an experimental version control system built on top of Git. Many people complain that Git is hard to use. We think the problem lies @@ -13,6 +14,8 @@ description: | Git), you can always fall back on Git. And of course your coworkers you share a repo with need never know that you're not a Git aficionado. +base: core18 + grade: devel # 'stable' for stable/candidate upload confinement: devmode # 'strict' after right plugs and slots From a9bc1a37ee479c416c82f3bd87770a1fb38b0efb Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Thu, 7 Feb 2019 17:17:33 -0800 Subject: [PATCH 110/196] remove license field in snapcraft to prevent error --- snap/snapcraft.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 739b905..612735f 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -3,7 +3,6 @@ name: gitless version: git summary: A simple version control system built on top of Git -license: MIT description: | Gitless is an experimental version control system built on top of Git. Many people complain that Git is hard to use. We think the problem lies From 21f4be68784ce640ddf127bb9ebe73cb3b264367 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Thu, 7 Feb 2019 21:32:37 -0800 Subject: [PATCH 111/196] Update README.md --- README.md | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0a82051..4f19242 100644 --- a/README.md +++ b/README.md @@ -99,18 +99,9 @@ Documentation Contribute ---------- -There are several ways you can contribute to the project: - -- Bugs: did you find a bug? create an issue for it and we'll fix it -ASAP -- Code: you can browse through the open issues and see if there's something -there you would like to work on. Is something missing? feel free to propose it! -- Design: if you have any feedback about Gitless's design we would love to -hear from you. You can create an issue in the project with your -feedback/questions/suggestions or shoot us an email - - -If you're planning on submitting code here are some useful things to know: +If you find a bug, you can help us by submitting an issue to our +GitHub Repository. If you'd like to contribute +code, here are some useful things to know: - We follow (to some extent) the [Google Python Style Guide]( https://google.github.io/styleguide/pyguide.html @@ -120,7 +111,7 @@ Gitless's code so that your edits are consistent with the codebase - Finally, if you don't want [Travis]( https://travis-ci.org/sdg-mit/gitless "Travis") to -be mad at you, check that tests pass in Python 2.7 and 3.2+. Tests can be run with +be mad at you, check that tests pass in Python 2.7 and 3.2+. Tests can be run with: ``` pip install nose nosetests # run tests other than end-to-end tests From e9aa1f70a816719996852bb15efa1c44a3b8d432 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sat, 9 Feb 2019 20:48:17 +0300 Subject: [PATCH 112/196] Install latest snapcraft with snap To reenable license field https://github.com/sdg-mit/gitless/pull/202#issuecomment-461655961 --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5aa579b..6e6e87e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,5 @@ language: python dist: xenial -addons: - apt: - packages: - - snapcraft python: - '2.7' - '3.4' @@ -29,7 +25,7 @@ jobs: - stage: Pack snap env: EMPTY before_install: skip - install: skip + install: sudo snap install snapcraft --classic script: snapcraft deploy: on: From ef1ab82a5854099e05ae803a49e74d9fa4dc5d24 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sat, 9 Feb 2019 21:35:06 +0300 Subject: [PATCH 113/196] Install multipass for snapcraft You need multipass installed to build snaps (https://github.com/CanonicalLtd/multipass). Would you like to install it now? [y/N]: --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6e6e87e..b10fecd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,9 @@ jobs: - stage: Pack snap env: EMPTY before_install: skip - install: sudo snap install snapcraft --classic + install: + - sudo snap install snapcraft --classic + - sudo snap install multipass --classic --beta script: snapcraft deploy: on: From 1044b1ce1f02fc7ea5d7eb2e2721c24f529ce887 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sat, 9 Feb 2019 22:08:40 +0300 Subject: [PATCH 114/196] Found another way to install snaps https://docs.travis-ci.com/user/installing-dependencies/#installing-snap-packages-with-the-snaps-addon --- .travis.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index b10fecd..2b21718 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,11 +23,16 @@ branches: jobs: include: - stage: Pack snap + addons: + snaps: + - name: snapcraft + classic: true + - name: multipass + classic: true + channel: beta env: EMPTY before_install: skip - install: - - sudo snap install snapcraft --classic - - sudo snap install multipass --classic --beta + install: skip script: snapcraft deploy: on: From fd76f6e6cc6a31e9bc0c499709af9c3d105e8c15 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sat, 9 Feb 2019 22:11:29 +0300 Subject: [PATCH 115/196] Link to pygit2 from README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f19242..f27ad23 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Note that the installation **won't interfere** with your Git installation in any way, you can keep using Git, and switch between Git and Gitless seamlessly. We currently require Git (1.7.12+) to be installed (but this requirement is -going to disappear soon once we finish with our migration to pygit2). +going to disappear soon once we finish with our migration to [pygit2](https://github.com/libgit2/pygit2)). ### Binary releases (macOS and Linux only) From f21192372ee89751b41907cc3a22269aaa674281 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sat, 9 Feb 2019 22:15:30 +0300 Subject: [PATCH 116/196] Use recommended 0.26.x version of libgit2 pygit2 0.26.4 needs at 0.26.x branch of libgit2 https://www.pygit2.org/install.html#version-numbers --- snap/snapcraft.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 612735f..9d827d2 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -27,7 +27,8 @@ apps: parts: libgit2: plugin: cmake - source: https://github.com/libgit2/libgit2/archive/v0.27.0.tar.gz + # https://www.pygit2.org/install.html#version-numbers + source: https://github.com/libgit2/libgit2/archive/v0.26.8.tar.gz build-packages: - libssl-dev From f85f93ceba0257934f7d58095dba763b96e21298 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sat, 9 Feb 2019 22:32:27 +0300 Subject: [PATCH 117/196] Clarify `gl init` message It creates normal git repo --- gitless/cli/gl_init.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gitless/cli/gl_init.py b/gitless/cli/gl_init.py index eb6bbde..9f5121b 100644 --- a/gitless/cli/gl_init.py +++ b/gitless/cli/gl_init.py @@ -17,8 +17,7 @@ def parser(subparsers, _): """Adds the init parser to the given subparsers object.""" desc = ( - 'create an empty Gitless\'s repository or create one from an existing ' - 'remote repository') + 'create an empty git repository or clone remote') init_parser = subparsers.add_parser( 'init', help=desc, description=desc.capitalize()) init_parser.add_argument( From 576ac779069f31b6a95641d2ad6b6bff66bfe5d9 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sat, 9 Feb 2019 22:39:34 +0300 Subject: [PATCH 118/196] Sync setup.py install_requires with requirements.txt --- setup.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 2a16dce..f37d3b2 100755 --- a/setup.py +++ b/setup.py @@ -67,9 +67,10 @@ url='http://gitless.com', packages=['gitless', 'gitless.cli'], install_requires=[ - 'pygit2>=0.24.0', - 'clint>=0.3.6', - 'sh>=1.11' if sys.platform != 'win32' else 'pbs>=0.11' + # make sure it matches requirements.txt + 'pygit2==0.26.4', # requires libgit2 0.26 + 'clint==0.5.1', + 'sh==1.12.14' if sys.platform != 'win32' else 'pbs==0.110' ], license='MIT', classifiers=( From 3489a7c62681e1280412fd142c17affad4acf355 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sat, 9 Feb 2019 22:40:37 +0300 Subject: [PATCH 119/196] Add reminder to update setup.py --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements.txt b/requirements.txt index 5de1a5a..3a3d10b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ +# make sure to update setup.py + pygit2==0.26.4 # requires libgit2 0.26 clint==0.5.1 sh==1.12.14;sys_platform!='win32' From f5c9345f73716705d341e8ecea6b6f26b9c61232 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sat, 9 Feb 2019 22:54:48 +0300 Subject: [PATCH 120/196] Try snapcraft with sudo for multipass --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2b21718..8d53faa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ jobs: env: EMPTY before_install: skip install: skip - script: snapcraft + script: sudo snapcraft deploy: on: branch: master From 2bf2cccf7e4f15f57e095b90d6f5fa9973ce5f57 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 10 Feb 2019 21:19:15 +0300 Subject: [PATCH 121/196] Patch test_e2e.py for easier command override Binary name in snap is now `gitless.gl` and to run e2e tests with, the `sh` invocation syntax should be changed for dot https://amoffat.github.io/sh/sections/faq.html#how-do-i-execute-a-program-with-a-special-character-in-its-name --- gitless/tests/test_e2e.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gitless/tests/test_e2e.py b/gitless/tests/test_e2e.py index 9a9333b..c478143 100755 --- a/gitless/tests/test_e2e.py +++ b/gitless/tests/test_e2e.py @@ -14,11 +14,12 @@ import sys if sys.platform != 'win32': - from sh import ErrorReturnCode, gl, git + from sh import ErrorReturnCode, Command else: from pbs import ErrorReturnCode, Command - gl = Command('gl') - git = Command('git') + +gl = Command('gl') +git = Command('git') from gitless.tests import utils From f7559207586aa0d5ad6b79694bd30355353173c4 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 22 Mar 2019 07:54:32 +0300 Subject: [PATCH 122/196] Appveyor: Update pip and run `gl` as a smoke test This removes red warning on Appveyor https://ci.appveyor.com/project/spderosso/gitless/build/job/jru3ntgukwtkun4g#L59 --- .appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index aa0f705..4bd2c7b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,6 +7,7 @@ environment: PYTHON: 'C:\Python27-x64\python.exe' init: + - cmd: '%PYTHON% -m pip install -U pip' - cmd: '%PYTHON% -m pip install -U nose wheel' build: off @@ -16,6 +17,7 @@ before_test: - cmd: git config --global user.email "appveyor@test.com" test_script: + - cmd: gl - ps: | # e2e tests require `gl` binary &$env:PYTHON -m pip install -r requirements.txt . From 500b4cc99b95aff473ce721e9e572cfc6415717d Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 22 Mar 2019 08:01:03 +0300 Subject: [PATCH 123/196] Build gitless as a separate step wheel is also installed by default --- .appveyor.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4bd2c7b..c419070 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -8,9 +8,11 @@ environment: init: - cmd: '%PYTHON% -m pip install -U pip' - - cmd: '%PYTHON% -m pip install -U nose wheel' + - cmd: '%PYTHON% -m pip install -U nose' -build: off +build: + # build and install `gl` binary (end to end test also use it) + - cmd: '%PYTHON% -m pip install -r requirements.txt .' before_test: - cmd: git config --global user.name "appveyor-test" @@ -19,8 +21,6 @@ before_test: test_script: - cmd: gl - ps: | - # e2e tests require `gl` binary - &$env:PYTHON -m pip install -r requirements.txt . # 'gl' is installed in Python Scripts directory $env:PATH += ";$(Split-Path $env:PYTHON)\Scripts" &$env:PYTHON setup.py nosetests --logging-level=WARN --with-xunit From 4e380097dc574f86cfc4b396353572c73798a466 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 22 Mar 2019 08:02:47 +0300 Subject: [PATCH 124/196] build_script: is the right build: --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index c419070..71e3001 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -10,7 +10,7 @@ init: - cmd: '%PYTHON% -m pip install -U pip' - cmd: '%PYTHON% -m pip install -U nose' -build: +build_script: # build and install `gl` binary (end to end test also use it) - cmd: '%PYTHON% -m pip install -r requirements.txt .' From 592f6b69277f9058f505abac9ec9b61fdcfc376a Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 22 Mar 2019 08:07:28 +0300 Subject: [PATCH 125/196] Try dir to see what is going on --- .appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.appveyor.yml b/.appveyor.yml index 71e3001..115315a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,6 +19,7 @@ before_test: - cmd: git config --global user.email "appveyor@test.com" test_script: + - cmd: dir - cmd: gl - ps: | # 'gl' is installed in Python Scripts directory From 1c1cb88a49d99b3938fbc2e9344ca8b238d38fa7 Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Fri, 22 Mar 2019 08:10:49 +0300 Subject: [PATCH 126/196] Show hidden files --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 115315a..4fe9b32 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,7 +19,7 @@ before_test: - cmd: git config --global user.email "appveyor@test.com" test_script: - - cmd: dir + - cmd: dir /a:h - cmd: gl - ps: | # 'gl' is installed in Python Scripts directory From ce3a5d713a672090223b8cdb9a595b382db8eddd Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 24 May 2019 10:50:25 -0700 Subject: [PATCH 127/196] Update setup.py --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index f37d3b2..e6116c3 100755 --- a/setup.py +++ b/setup.py @@ -69,8 +69,8 @@ install_requires=[ # make sure it matches requirements.txt 'pygit2==0.26.4', # requires libgit2 0.26 - 'clint==0.5.1', - 'sh==1.12.14' if sys.platform != 'win32' else 'pbs==0.110' + 'clint>=0.3.6', + 'sh>=1.11' if sys.platform != 'win32' else 'pbs>=0.11' ], license='MIT', classifiers=( From 0eaf72ef7c629e23ac9ea1bee62252ff636a38db Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 24 May 2019 11:32:16 -0700 Subject: [PATCH 128/196] update brew url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f27ad23..ecacab8 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Gitless [![PyPI version](https://badge.fury.io/py/gitless.png)]( http://badge.fury.io/py/gitless "PyPI version") -[![Homebrew Formula](https://img.shields.io/homebrew/v/gitless.svg)](http://braumeister.org/formula/gitless "Homebrew Formula") +[![Homebrew Formula](https://img.shields.io/homebrew/v/gitless.svg)](https://formulae.brew.sh/formula/gitless "Homebrew Formula") [![Travis Build Status](https://travis-ci.org/sdg-mit/gitless.png?branch=master)](https://travis-ci.org/sdg-mit/gitless "Travis Build Status") [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/sdg-mit/gitless?svg=true)](https://ci.appveyor.com/project/spderosso/gitless "AppVeyor Build Status") From 9d1e2891c4c8163c4da98ae728f95dc6069c8f2d Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 24 May 2019 12:54:37 -0700 Subject: [PATCH 129/196] prep for 0.8.7 and bump py/libgit2 to 0.27 --- .travis.sh | 2 +- gitless/cli/gl.py | 2 +- requirements.txt | 2 +- setup.py | 10 +++++----- snap/snapcraft.yaml | 3 +-- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.travis.sh b/.travis.sh index 185b179..9d0f2e7 100755 --- a/.travis.sh +++ b/.travis.sh @@ -2,7 +2,7 @@ cd ~ -git clone --depth=1 -b maint/v0.26 https://github.com/libgit2/libgit2.git +git clone --depth=1 -b maint/v0.27 https://github.com/libgit2/libgit2.git cd libgit2/ mkdir build && cd build diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index e5be6c7..1c1e6af 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -34,7 +34,7 @@ INTERNAL_ERROR = 3 NOT_IN_GL_REPO = 4 -__version__ = '0.8.6' +__version__ = '0.8.7' URL = 'http://gitless.com' diff --git a/requirements.txt b/requirements.txt index 3a3d10b..32282b7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ # make sure to update setup.py -pygit2==0.26.4 # requires libgit2 0.26 +pygit2==0.27.4 # requires libgit2 0.27 clint==0.5.1 sh==1.12.14;sys_platform!='win32' pbs==0.110;sys_platform=='win32' diff --git a/setup.py b/setup.py index e6116c3..a648bb2 100755 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ print('creating tar.gz file') shutil.copy('README.md', rel) shutil.copy('LICENSE.md', rel) - + with tarfile.open(rel + '.tar.gz', 'w:gz') as tar: tar.add(rel) print('success!! binary release at {0}'.format(rel + '.tar.gz')) @@ -67,13 +67,13 @@ url='http://gitless.com', packages=['gitless', 'gitless.cli'], install_requires=[ - # make sure it matches requirements.txt - 'pygit2==0.26.4', # requires libgit2 0.26 + # make sure it matches requirements.txt + 'pygit2==0.27.4', # requires libgit2 0.27 'clint>=0.3.6', 'sh>=1.11' if sys.platform != 'win32' else 'pbs>=0.11' ], license='MIT', - classifiers=( + classifiers=[ 'Development Status :: 2 - Pre-Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', @@ -81,7 +81,7 @@ 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 3', - 'Topic :: Software Development :: Version Control'), + 'Topic :: Software Development :: Version Control'], entry_points={ 'console_scripts': [ 'gl = gitless.cli.gl:main' diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 9d827d2..cd37741 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -28,7 +28,7 @@ parts: libgit2: plugin: cmake # https://www.pygit2.org/install.html#version-numbers - source: https://github.com/libgit2/libgit2/archive/v0.26.8.tar.gz + source: https://github.com/libgit2/libgit2/archive/v0.27.8.tar.gz build-packages: - libssl-dev @@ -41,4 +41,3 @@ parts: - git build-packages: - git - From b5e88c08d6c3be75af08824fa9364f27424cc481 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 24 May 2019 13:17:07 -0700 Subject: [PATCH 130/196] fix pyinstaller issue --- gl.spec | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gl.spec b/gl.spec index dfdee1f..4cdd71b 100644 --- a/gl.spec +++ b/gl.spec @@ -3,6 +3,9 @@ import os a = Analysis(['gl.py'], pathex=[os.getcwd()], + # https://github.com/pyinstaller/pyinstaller/issues/3198 + # remove this when dropping support for Python < 3.7 + hiddenimports=['_sysconfigdata'], hookspath=None, runtime_hooks=None) From 7c1364199d1cadaf03242922265fbe103bdefba1 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 24 May 2019 15:33:07 -0700 Subject: [PATCH 131/196] Update README.md --- README.md | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index ecacab8..43a71c4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,10 @@ Gitless [![PyPI version](https://badge.fury.io/py/gitless.png)]( http://badge.fury.io/py/gitless "PyPI version") -[![Homebrew Formula](https://img.shields.io/homebrew/v/gitless.svg)](https://formulae.brew.sh/formula/gitless "Homebrew Formula") +[![Homebrew Formula](https://img.shields.io/homebrew/v/gitless.svg)](https://formulae.brew.sh/formula/gitless "Homebrew Formula") +[![Snap Package](https://img.shields.io/badge/snap%20store-v0.8.7-yellowgreen.svg)](https://snapcraft.io/gitless) + + [![Travis Build Status](https://travis-ci.org/sdg-mit/gitless.png?branch=master)](https://travis-ci.org/sdg-mit/gitless "Travis Build Status") [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/sdg-mit/gitless?svg=true)](https://ci.appveyor.com/project/spderosso/gitless "AppVeyor Build Status") @@ -28,24 +31,6 @@ We currently require Git (1.7.12+) to be installed (but this requirement is going to disappear soon once we finish with our migration to [pygit2](https://github.com/libgit2/pygit2)). -### Binary releases (macOS and Linux only) - -Binary releases for macOS and Linux are available from the -[Gitless website](http://gitless.com "Gitless's website"). - -If you've downloaded a binary release of Gitless everything is contained in the -gl binary, so to install simply do: - - $ cp path-to-downloaded-gl-binary /usr/local/bin/gl - -You can put the binary in other locations as well, just be sure to update your -`PATH`. - -If for some reason this doesn't work (maybe you are running an old version of -your OS?), try one of the other options (installing from source or via -the Python Package Index). - - ### Installing from source To install from source you need to have Python (2.7, 3.2+ or PyPy) @@ -89,6 +74,32 @@ brew update brew install gitless ``` +### Binary release (macOS only) + +A binary release for macOS is available from the +[Gitless website](http://gitless.com "Gitless's website"). + +If you've downloaded a binary release of Gitless everything is contained in the +gl binary, so to install simply do: + + $ cp path-to-downloaded-gl-binary /usr/local/bin/gl + +You can put the binary in other locations as well, just be sure to update your +`PATH`. + +If for some reason this doesn't work (maybe you are running an old version of +your OS?), try one of the other options (installing from source or via +the Python Package Index). + +### Installing via Snapcraft (Linux only) + +If you are using [Snapcraft](https://snapcraft.io/ "Snapcraft"), a +package manager for Linux, you can install Gitless with: + +``` +snap install gitless +``` + Documentation ------------- From 343253b11e1d40f86bd9f11ebf94caf33511c277 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 24 May 2019 15:46:22 -0700 Subject: [PATCH 132/196] update badges --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 43a71c4..4cfd5f0 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ Gitless ======= -[![PyPI version](https://badge.fury.io/py/gitless.png)]( - http://badge.fury.io/py/gitless "PyPI version") +[![PyPI version](https://img.shields.io/pypi/v/gitless.svg)](https://pypi.org/project/gitless "PyPI version") [![Homebrew Formula](https://img.shields.io/homebrew/v/gitless.svg)](https://formulae.brew.sh/formula/gitless "Homebrew Formula") -[![Snap Package](https://img.shields.io/badge/snap%20store-v0.8.7-yellowgreen.svg)](https://snapcraft.io/gitless) +[![Snap Package](https://img.shields.io/badge/snap%20store-v0.8.7-orange.svg)](https://snapcraft.io/gitless) -[![Travis Build Status](https://travis-ci.org/sdg-mit/gitless.png?branch=master)](https://travis-ci.org/sdg-mit/gitless "Travis Build Status") +[![Travis Build Status](https://img.shields.io/travis/sdg-mit/gitless/master.svg)](https://travis-ci.org/sdg-mit/gitless "Travis Build Status") [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/sdg-mit/gitless?svg=true)](https://ci.appveyor.com/project/spderosso/gitless "AppVeyor Build Status") [Gitless](http://gitless.com "Gitless's website") is an experimental version From f3a44c831a81a6c61837274f81a711362d3fd57e Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Fri, 24 May 2019 17:15:46 -0700 Subject: [PATCH 133/196] update snap instructions --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4cfd5f0..f8023a7 100644 --- a/README.md +++ b/README.md @@ -93,12 +93,15 @@ the Python Package Index). ### Installing via Snapcraft (Linux only) If you are using [Snapcraft](https://snapcraft.io/ "Snapcraft"), a -package manager for Linux, you can install Gitless with: +package manager for Linux, you can install the most recent release +of Gitless with: ``` -snap install gitless +snap install --channel=beta gitless ``` +You can also use the `edge` channel to install the most recent build. + Documentation ------------- From ab88661da1f57d3d2de101b0782c9afaf41282f4 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Tue, 28 May 2019 13:05:04 -0700 Subject: [PATCH 134/196] bump libgit2, cut new release --- .travis.sh | 2 +- gitless/cli/gl.py | 2 +- requirements.txt | 2 +- setup.py | 2 +- snap/snapcraft.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.sh b/.travis.sh index 9d0f2e7..199ccab 100755 --- a/.travis.sh +++ b/.travis.sh @@ -2,7 +2,7 @@ cd ~ -git clone --depth=1 -b maint/v0.27 https://github.com/libgit2/libgit2.git +git clone --depth=1 -b maint/v0.28 https://github.com/libgit2/libgit2.git cd libgit2/ mkdir build && cd build diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 1c1e6af..95eae4e 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -34,7 +34,7 @@ INTERNAL_ERROR = 3 NOT_IN_GL_REPO = 4 -__version__ = '0.8.7' +__version__ = '0.8.8' URL = 'http://gitless.com' diff --git a/requirements.txt b/requirements.txt index 32282b7..05f190a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ # make sure to update setup.py -pygit2==0.27.4 # requires libgit2 0.27 +pygit2==0.28.2 # requires libgit2 0.28 clint==0.5.1 sh==1.12.14;sys_platform!='win32' pbs==0.110;sys_platform=='win32' diff --git a/setup.py b/setup.py index a648bb2..68a3a87 100755 --- a/setup.py +++ b/setup.py @@ -68,7 +68,7 @@ packages=['gitless', 'gitless.cli'], install_requires=[ # make sure it matches requirements.txt - 'pygit2==0.27.4', # requires libgit2 0.27 + 'pygit2==0.28.2', # requires libgit2 0.28 'clint>=0.3.6', 'sh>=1.11' if sys.platform != 'win32' else 'pbs>=0.11' ], diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index cd37741..4c37cf1 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -28,7 +28,7 @@ parts: libgit2: plugin: cmake # https://www.pygit2.org/install.html#version-numbers - source: https://github.com/libgit2/libgit2/archive/v0.27.8.tar.gz + source: https://github.com/libgit2/libgit2/archive/v0.28.2.tar.gz build-packages: - libssl-dev From ec9edd1cae7bd99d3a82f4578c9b994604ea64cd Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Tue, 28 May 2019 13:38:04 -0700 Subject: [PATCH 135/196] fix in pyinstaller spec --- gl.spec | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gl.spec b/gl.spec index 4cdd71b..b19c465 100644 --- a/gl.spec +++ b/gl.spec @@ -3,9 +3,11 @@ import os a = Analysis(['gl.py'], pathex=[os.getcwd()], - # https://github.com/pyinstaller/pyinstaller/issues/3198 - # remove this when dropping support for Python < 3.7 - hiddenimports=['_sysconfigdata'], + hiddenimports=[ + # https://github.com/pyinstaller/pyinstaller/issues/3198 + # remove this when dropping support for Python < 3.7 + '_sysconfigdata', + '_cffi_backend'], hookspath=None, runtime_hooks=None) From 08a64a3941f832b5d290155539b5bfe0728c5c61 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Tue, 28 May 2019 13:58:36 -0700 Subject: [PATCH 136/196] rm snap badge better to wait until shields.io officially supports it --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index f8023a7..d4b6887 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,6 @@ Gitless [![PyPI version](https://img.shields.io/pypi/v/gitless.svg)](https://pypi.org/project/gitless "PyPI version") [![Homebrew Formula](https://img.shields.io/homebrew/v/gitless.svg)](https://formulae.brew.sh/formula/gitless "Homebrew Formula") -[![Snap Package](https://img.shields.io/badge/snap%20store-v0.8.7-orange.svg)](https://snapcraft.io/gitless) - [![Travis Build Status](https://img.shields.io/travis/sdg-mit/gitless/master.svg)](https://travis-ci.org/sdg-mit/gitless "Travis Build Status") [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/sdg-mit/gitless?svg=true)](https://ci.appveyor.com/project/spderosso/gitless "AppVeyor Build Status") From 29fb46313a1b1d76bb937a1c45b62eeae19394ca Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Tue, 28 May 2019 16:43:57 -0700 Subject: [PATCH 137/196] update readme to include linux binary --- README.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index d4b6887..2f91b0f 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,23 @@ We currently require Git (1.7.12+) to be installed (but this requirement is going to disappear soon once we finish with our migration to [pygit2](https://github.com/libgit2/pygit2)). +### Binary release (macOS and Linux only) + +Binary releases for macOS and Linux are available from the +[Gitless website](http://gitless.com "Gitless's website"). + +If you've downloaded a binary release of Gitless everything is contained in the +gl binary, so to install simply do: + + $ cp path-to-downloaded-gl-binary /usr/local/bin/gl + +You can put the binary in other locations as well, just be sure to update your +`PATH`. + +If for some reason this doesn't work (maybe you are running an old version of +your OS?), try one of the other options (installing from source or via +the Python Package Index). + ### Installing from source To install from source you need to have Python (2.7, 3.2+ or PyPy) @@ -71,23 +88,6 @@ brew update brew install gitless ``` -### Binary release (macOS only) - -A binary release for macOS is available from the -[Gitless website](http://gitless.com "Gitless's website"). - -If you've downloaded a binary release of Gitless everything is contained in the -gl binary, so to install simply do: - - $ cp path-to-downloaded-gl-binary /usr/local/bin/gl - -You can put the binary in other locations as well, just be sure to update your -`PATH`. - -If for some reason this doesn't work (maybe you are running an old version of -your OS?), try one of the other options (installing from source or via -the Python Package Index). - ### Installing via Snapcraft (Linux only) If you are using [Snapcraft](https://snapcraft.io/ "Snapcraft"), a From a68aed4522f7d4b85897f840704cb04937665fe8 Mon Sep 17 00:00:00 2001 From: Santiago P De Rosso Date: Wed, 4 Sep 2019 10:21:02 -0400 Subject: [PATCH 138/196] update instructions for development --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 2f91b0f..8b63295 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,11 @@ If you find a bug, you can help us by submitting an issue to our GitHub Repository. If you'd like to contribute code, here are some useful things to know: +- To install gitless for development, [install pygit2]( + http://www.pygit2.org/install.html "pygit2 install"), clone the repo, + `cd` to the repo root and do `./setup.py develop`. This will install + the `gl` command with a symlink to your source files. You can make + changes to your code and run `gl` to test them. - We follow (to some extent) the [Google Python Style Guide]( https://google.github.io/styleguide/pyguide.html "Google Python Style Guide"). From 09d803522e8cfc425931c9f31e1834d1ecfe148c Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Tue, 24 Sep 2019 21:21:37 -0400 Subject: [PATCH 139/196] Added the -o and -e flags for the gl init command. --- gitless/cli/gl_init.py | 9 ++++++++- gitless/core.py | 12 +++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/gitless/cli/gl_init.py b/gitless/cli/gl_init.py index 9f5121b..7c2996e 100644 --- a/gitless/cli/gl_init.py +++ b/gitless/cli/gl_init.py @@ -25,6 +25,13 @@ def parser(subparsers, _): help=( 'an optional remote repo address from where to read to create the ' 'local repo')) + init_parser.add_argument( + '-o', '--only', nargs='*', + help='use only files given (tracked modified or untracked)', dest='only') + init_parser.add_argument( + '-e', '--exclude', nargs='+', + help = 'use everything but these branches', dest='exclude') + init_parser.set_defaults(func=main) @@ -32,7 +39,7 @@ def main(args, repo): if repo: pprint.err('You are already in a Gitless repository') return False - core.init_repository(url=args.repo) + core.init_repository(url=args.repo, exclude=frozenset(args.exclude if args.exclude else []), only=frozenset(args.only if args.only else [])) pprint.ok('Local repo created in {0}'.format(os.getcwd())) if args.repo: pprint.ok('Initialized from remote {0}'.format(args.repo)) diff --git a/gitless/core.py b/gitless/core.py index a6a1780..a81fa6b 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -65,7 +65,7 @@ def error_on_none(path): return path -def init_repository(url=None): +def init_repository(url=None, exclude=None, only=None): """Creates a new Gitless's repository in the cwd. Args: @@ -73,6 +73,8 @@ def init_repository(url=None): given by this url. """ cwd = os.getcwd() + branches_only = only + branches_exclude = exclude try: error_on_none(pygit2.discover_repository(cwd)) raise GlError('You are already in a Gitless repository') @@ -89,11 +91,19 @@ def init_repository(url=None): raise GlError(stderr(e)) # We get all remote branches as well and create local equivalents + #Flags: only branches take precedence over exclude branches. If user selected branches as only, will not look at exclude + #If only empty, will look at exclude + #If both empty, will grab all branches repo = Repository() remote = repo.remotes['origin'] for rb in (remote.lookup_branch(bn) for bn in remote.listall_branches()): if rb.branch_name == 'master': continue + if branches_only: + if rb.branch_name not in branches_only: + continue + elif branches_exclude and rb.branch_name in branches_exclude: + continue new_b = repo.create_branch(rb.branch_name, rb.head) new_b.upstream = rb return repo From d5e2d69f4083a7ee4c2be7e666612fa56fa5a5d6 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Wed, 25 Sep 2019 09:38:23 -0400 Subject: [PATCH 140/196] Made pull request changes to the code --- gitless/cli/gl_init.py | 8 +++++--- gitless/core.py | 21 ++++++++++----------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/gitless/cli/gl_init.py b/gitless/cli/gl_init.py index 7c2996e..87bd473 100644 --- a/gitless/cli/gl_init.py +++ b/gitless/cli/gl_init.py @@ -27,10 +27,10 @@ def parser(subparsers, _): 'local repo')) init_parser.add_argument( '-o', '--only', nargs='*', - help='use only files given (tracked modified or untracked)', dest='only') + help='use only branches given from remote repo', dest='only') init_parser.add_argument( '-e', '--exclude', nargs='+', - help = 'use everything but these branches', dest='exclude') + help = 'use everything but this branches from remote repo', dest='exclude') init_parser.set_defaults(func=main) @@ -39,7 +39,9 @@ def main(args, repo): if repo: pprint.err('You are already in a Gitless repository') return False - core.init_repository(url=args.repo, exclude=frozenset(args.exclude if args.exclude else []), only=frozenset(args.only if args.only else [])) + core.init_repository(url=args.repo, + exclude=frozenset(args.exclude if args.exclude else []), + only=frozenset(args.only if args.only else [])) pprint.ok('Local repo created in {0}'.format(os.getcwd())) if args.repo: pprint.ok('Initialized from remote {0}'.format(args.repo)) diff --git a/gitless/core.py b/gitless/core.py index a81fa6b..736da59 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -65,16 +65,18 @@ def error_on_none(path): return path -def init_repository(url=None, exclude=None, only=None): +def init_repository(url=None, only=None, exclude=None): """Creates a new Gitless's repository in the cwd. Args: url: if given the local repository will be a clone of the remote repository given by this url. + only: if given, this local repository will consist only of the branches + in this set + exclude: if given, and only is not given, this local repository will + consistent of all branches not in this set """ cwd = os.getcwd() - branches_only = only - branches_exclude = exclude try: error_on_none(pygit2.discover_repository(cwd)) raise GlError('You are already in a Gitless repository') @@ -91,19 +93,16 @@ def init_repository(url=None, exclude=None, only=None): raise GlError(stderr(e)) # We get all remote branches as well and create local equivalents - #Flags: only branches take precedence over exclude branches. If user selected branches as only, will not look at exclude - #If only empty, will look at exclude - #If both empty, will grab all branches + #Flags: only branches take precedence over exclude branches. repo = Repository() remote = repo.remotes['origin'] for rb in (remote.lookup_branch(bn) for bn in remote.listall_branches()): if rb.branch_name == 'master': continue - if branches_only: - if rb.branch_name not in branches_only: - continue - elif branches_exclude and rb.branch_name in branches_exclude: - continue + if only and rb.branch_name not in branches_only: + continue + elif not only and exclude and rb.branch_name in branches_exclude: + continue new_b = repo.create_branch(rb.branch_name, rb.head) new_b.upstream = rb return repo From 1584fcbdc2c3d2e5f5fb64b6754a5e5b705dcd9e Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Wed, 25 Sep 2019 10:05:56 -0400 Subject: [PATCH 141/196] Fixed some variable names and the ordering of only and exclude --- gitless/cli/gl_init.py | 6 +++--- gitless/core.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gitless/cli/gl_init.py b/gitless/cli/gl_init.py index 87bd473..88d9722 100644 --- a/gitless/cli/gl_init.py +++ b/gitless/cli/gl_init.py @@ -39,9 +39,9 @@ def main(args, repo): if repo: pprint.err('You are already in a Gitless repository') return False - core.init_repository(url=args.repo, - exclude=frozenset(args.exclude if args.exclude else []), - only=frozenset(args.only if args.only else [])) + core.init_repository(url=args.repo, + only=frozenset(args.only if args.only else []), + exclude=frozenset(args.exclude if args.exclude else [])) pprint.ok('Local repo created in {0}'.format(os.getcwd())) if args.repo: pprint.ok('Initialized from remote {0}'.format(args.repo)) diff --git a/gitless/core.py b/gitless/core.py index 736da59..8e36829 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -93,15 +93,15 @@ def init_repository(url=None, only=None, exclude=None): raise GlError(stderr(e)) # We get all remote branches as well and create local equivalents - #Flags: only branches take precedence over exclude branches. + #Flags: only branches take precedence over exclude branches. repo = Repository() remote = repo.remotes['origin'] for rb in (remote.lookup_branch(bn) for bn in remote.listall_branches()): if rb.branch_name == 'master': continue - if only and rb.branch_name not in branches_only: + if only and rb.branch_name not in only: continue - elif not only and exclude and rb.branch_name in branches_exclude: + elif not only and exclude and rb.branch_name in exclude: continue new_b = repo.create_branch(rb.branch_name, rb.head) new_b.upstream = rb From 5994f456664590599bc30fdac77c1fb272675f1c Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Wed, 25 Sep 2019 13:14:14 -0400 Subject: [PATCH 142/196] Have made the requested changes in the code format, as well as the '+' instead of '*' for the args. --- gitless/cli/gl_init.py | 4 ++-- gitless/core.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gitless/cli/gl_init.py b/gitless/cli/gl_init.py index 88d9722..977f6fd 100644 --- a/gitless/cli/gl_init.py +++ b/gitless/cli/gl_init.py @@ -26,11 +26,11 @@ def parser(subparsers, _): 'an optional remote repo address from where to read to create the ' 'local repo')) init_parser.add_argument( - '-o', '--only', nargs='*', + '-o', '--only', nargs='+', help='use only branches given from remote repo', dest='only') init_parser.add_argument( '-e', '--exclude', nargs='+', - help = 'use everything but this branches from remote repo', dest='exclude') + help='use everything but this branches from remote repo', dest='exclude') init_parser.set_defaults(func=main) diff --git a/gitless/core.py b/gitless/core.py index 8e36829..f4114dc 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -93,7 +93,7 @@ def init_repository(url=None, only=None, exclude=None): raise GlError(stderr(e)) # We get all remote branches as well and create local equivalents - #Flags: only branches take precedence over exclude branches. + # Flags: only branches take precedence over exclude branches. repo = Repository() remote = repo.remotes['origin'] for rb in (remote.lookup_branch(bn) for bn in remote.listall_branches()): From 6b31df80021a7d781fddcaece109dc3d1ab72c2c Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Wed, 25 Sep 2019 13:16:59 -0400 Subject: [PATCH 143/196] Made a grammar change: 'this branches' -> 'these branches' --- gitless/cli/gl_init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/cli/gl_init.py b/gitless/cli/gl_init.py index 977f6fd..5caeae9 100644 --- a/gitless/cli/gl_init.py +++ b/gitless/cli/gl_init.py @@ -30,7 +30,7 @@ def parser(subparsers, _): help='use only branches given from remote repo', dest='only') init_parser.add_argument( '-e', '--exclude', nargs='+', - help='use everything but this branches from remote repo', dest='exclude') + help='use everything but these branches from remote repo', dest='exclude') init_parser.set_defaults(func=main) From 0056dc669959431a55b568ca32a076e4499ff82e Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Mon, 30 Sep 2019 12:53:06 -0400 Subject: [PATCH 144/196] Fixed the issue None attributed noted by a user on GitHub. Also, added the ability to rename branches and remotes by using the -rn command. --- gitless/cli/gl_branch.py | 29 ++++++++++++++++++++++++++++- gitless/cli/gl_remote.py | 21 +++++++++++++++++++++ gitless/core.py | 12 ++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index f5032a0..2267dc8 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -55,6 +55,11 @@ def parser(subparsers, _): '-uu', '--unset-upstream', help='unset the upstream branch of the current branch', action='store_true') + edit_group.add_argument( + '-rn', '--rename-branch', nargs='+', + help='renames this branch or another specified branch', + dest='rename_b' + ) branch_parser.set_defaults(func=main) @@ -63,7 +68,7 @@ def main(args, repo): is_list = bool(args.verbose or args.remote) is_create = bool(args.create_b or args.dp) is_delete = bool(args.delete_b) - is_edit = bool(args.new_head or args.upstream_b or args.unset_upstream) + is_edit = bool(args.new_head or args.upstream_b or args.unset_upstream or args.rename_b) if is_list + is_create + is_delete + is_edit > 1: pprint.err('Invalid flag combination') @@ -82,6 +87,8 @@ def main(args, repo): ret = _do_unset_upstream(repo) elif args.new_head: ret = _do_set_head(args.new_head, repo) + elif args.rename_b: + ret = _do_rename(args.rename_b, repo) else: _do_list(repo, args.remote, v=args.verbose) @@ -203,3 +210,23 @@ def _do_set_head(commit_id, repo): pprint.ok( 'Head of current branch {0} is now {1}'.format(curr_b, pprint.commit_str(commit))) return True + + +def _do_rename(rename_b, repo): + ret = True + if len(rename_b) == 1 : + # Renaming this current branch + curr_b = repo.current_branch + curr_b.rename(rename_b[0]) + pprint.ok('Renamed this branch to {0}'.format(rename_b[0])) + elif len(rename_b) == 2: + # Renaming a specified branch to a new name + b = helpers.get_branch(rename_b[0], repo) + b.rename(rename_b[1]) + pprint.ok('Renamed branch {0} to {1}'.format(rename_b[0], rename_b[1])) + else : + # Gave more than 2 arguments + pprint.err( + 'Too many arguments given') + ret = False + return ret diff --git a/gitless/cli/gl_remote.py b/gitless/cli/gl_remote.py index 4957f97..536abd0 100644 --- a/gitless/cli/gl_remote.py +++ b/gitless/cli/gl_remote.py @@ -24,6 +24,9 @@ def parser(subparsers, _): remote_parser.add_argument( '-d', '--delete', nargs='+', help='delete remote(es)', dest='delete_r', metavar='remote') + remote_parser.add_argument( + '-rn', '--rename', nargs='+', + help='rename the specified remote', dest='rename_r') remote_parser.set_defaults(func=main) @@ -36,6 +39,8 @@ def main(args, repo): ret = _do_create(args.remote_name, args.remote_url, remotes) elif args.delete_r: ret = _do_delete(args.delete_r, remotes) + elif args.rename_r: + ret = _do_rename(args.rename_r, remotes) else: ret = _do_list(remotes) @@ -76,3 +81,19 @@ def _do_delete(delete_r, remotes): pprint.err('Remote \'{0}\' doesn\'t exist'.format(r)) errors_found = True return not errors_found + + +def _do_rename(rename_r, remotes): + errors_found = False + if len(rename_r) != 2: + pprint.err( + 'Expected 2 arguments to gl remote -rn') + errors_found = True + else: + try: + remotes.rename(rename_r[0], rename_r[1]) + pprint.ok('Renamed remote {0} to {1}'.format(rename_r[0], rename_r[1])) + except KeyError: + pprint.err('Remote \'{0}\' doesn\'t exist'.format(rename_r[0])) + errors_found = True + return not errors_found diff --git a/gitless/core.py b/gitless/core.py index f4114dc..bfdcad8 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -453,6 +453,9 @@ def create(self, name, url): def delete(self, name): self.git_remote_collection.delete(name) + def rename(self, name, new_name): + self.git_remote_collection.rename(name, new_name) + class Remote(object): """Tracked remote repository. @@ -505,6 +508,12 @@ def lookup_branch(self, branch_name): git.fetch(self.git_remote.name, branch_name) git_branch = self.gl_repo.git_repo.lookup_branch( self.git_remote.name + '/' + branch_name, pygit2.GIT_BRANCH_REMOTE) + # Make another check for the branch being None + # As observed in issue : https://github.com/sdg-mit/gitless/issues/211 + if git_branch is None: + git.fetch(self.git_remote.name) + git_branch = self.gl_repo.git_repo.lookup_branch( + self.git_remote.name + '/' + branch_name, pygit2.GIT_BRANCH_REMOTE) return RemoteBranch(git_branch, self.gl_repo) @@ -653,6 +662,9 @@ def delete(self): if s_id: git.stash.drop(s_id) + def rename(self, new_name): + self.git_branch.rename(new_name) + @property def upstream(self): git_upstream = self.git_branch.upstream From 9f14527c2b59248cf31650f444a418ab86e27710 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Mon, 30 Sep 2019 16:31:28 -0400 Subject: [PATCH 145/196] Made some of the requested changes, including making the help messages more clear. --- gitless/cli/gl_branch.py | 17 ++++++++++------- gitless/cli/gl_remote.py | 7 +++++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index 2267dc8..d58ce5e 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -43,21 +43,24 @@ def parser(subparsers, _): '-d', '--delete', nargs='+', help='delete branch(es)', dest='delete_b', metavar='branch') - edit_group = branch_parser.add_argument_group('edit the current branch') - edit_group.add_argument( + edit_current_branch_group = branch_parser.add_argument_group('edit the current branch') + edit_current_branch_group.add_argument( '-sh', '--set-head', help='set the head of the current branch', dest='new_head', metavar='commit_id') - edit_group.add_argument( + edit_current_branch_group.add_argument( '-su', '--set-upstream', help='set the upstream branch of the current branch', dest='upstream_b', metavar='branch') - edit_group.add_argument( + edit_current_branch_group.add_argument( '-uu', '--unset-upstream', help='unset the upstream branch of the current branch', action='store_true') + + edit_group = branch_parser.add_argument_group('edit branches') edit_group.add_argument( '-rn', '--rename-branch', nargs='+', - help='renames this branch or another specified branch', + help='renames the current branch (gl branch -rn new_name) ' + 'or another specified branch (gl branch -rn branch_name new_name)', dest='rename_b' ) @@ -215,7 +218,7 @@ def _do_set_head(commit_id, repo): def _do_rename(rename_b, repo): ret = True if len(rename_b) == 1 : - # Renaming this current branch + # Renaming the current branch curr_b = repo.current_branch curr_b.rename(rename_b[0]) pprint.ok('Renamed this branch to {0}'.format(rename_b[0])) @@ -227,6 +230,6 @@ def _do_rename(rename_b, repo): else : # Gave more than 2 arguments pprint.err( - 'Too many arguments given') + 'Too many arguments given. Expected 1 or 2 arguments.') ret = False return ret diff --git a/gitless/cli/gl_remote.py b/gitless/cli/gl_remote.py index 536abd0..3e77aab 100644 --- a/gitless/cli/gl_remote.py +++ b/gitless/cli/gl_remote.py @@ -26,7 +26,9 @@ def parser(subparsers, _): metavar='remote') remote_parser.add_argument( '-rn', '--rename', nargs='+', - help='rename the specified remote', dest='rename_r') + help='renames the specified remote: accepts two arguments ' + '(current remote name and new remote name)', + dest='rename_r') remote_parser.set_defaults(func=main) @@ -87,7 +89,8 @@ def _do_rename(rename_r, remotes): errors_found = False if len(rename_r) != 2: pprint.err( - 'Expected 2 arguments to gl remote -rn') + 'Expected 2 arguments in the folllowing format: ' + 'gl remote -rn current_remote_name new_remote_name') errors_found = True else: try: From 7f057643685015050190ee9f1297dff4b4765e1a Mon Sep 17 00:00:00 2001 From: Darcy Coleman Date: Sat, 5 Oct 2019 16:24:29 -0400 Subject: [PATCH 146/196] Enable commands for .gitignore Allow gitless to track, untrack and resolve on files that start with .git EXCEPT for the very specific directory at the top level of the repo .git. For example, `gl track .gitignore` is fine, `gl track .git/HEAD` is not allowed. Another, `gl track .gitdir/some_file` is allowed, `gl track .git` will not be allowed. --- gitless/cli/gl.py | 12 ++++++-- gitless/cli/helpers.py | 4 +-- gitless/tests/test_core.py | 57 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 95eae4e..b462df7 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -67,7 +67,7 @@ def print_help(parser): for choice in subparsers_action._choices_actions: print(' {:<19} {}'.format(choice.dest, choice.help)) -def main(): +def build_parser(subcommands, repo): parser = argparse.ArgumentParser( description=( 'Gitless: a version control system built on top of Git.\nMore info, ' @@ -80,12 +80,18 @@ def main(): subparsers = parser.add_subparsers(title='subcommands', dest='subcmd_name') subparsers.required = True + for sub_cmd in subcommands: + sub_cmd.parser(subparsers, repo) + + return parser + +def main(): sub_cmds = [ gl_track, gl_untrack, gl_status, gl_diff, gl_commit, gl_branch, gl_tag, gl_checkout, gl_merge, gl_resolve, gl_fuse, gl_remote, gl_publish, gl_switch, gl_init, gl_history] - for sub_cmd in sub_cmds: - sub_cmd.parser(subparsers, repo) + + parser = build_parser(sub_cmds, repo) if len(sys.argv) == 1: print_help(parser) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index dc7e34c..0c90f5e 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -112,7 +112,7 @@ def __init__( def __call__(self, parser, namespace, paths, option_string=None): root = self.repo.root if self.repo else '' - repo_dir = self.repo.path[:-1] if self.repo else '' # strip trailing / + repo_dir = self.repo.path if self.repo else '' # Don't strip trailing / def process_paths(): for path in paths: path = os.path.abspath(path) @@ -133,8 +133,6 @@ def process_paths(): else: if not path.startswith(repo_dir): yield os.path.relpath(path, root) - else: - yield path setattr(namespace, self.dest, process_paths()) diff --git a/gitless/tests/test_core.py b/gitless/tests/test_core.py index 8037446..943171b 100644 --- a/gitless/tests/test_core.py +++ b/gitless/tests/test_core.py @@ -11,6 +11,8 @@ import os import shutil import tempfile +import unittest +import argparse import sys if sys.platform != 'win32': @@ -20,6 +22,7 @@ git = Command('git') from gitless import core +from gitless.cli import gl, helpers, gl_track import gitless.tests.utils as utils_lib @@ -34,7 +37,12 @@ IGNORED_FP_WITH_SPACE = 'f3 space' NONEXISTENT_FP = 'nonexistent' NONEXISTENT_FP_WITH_SPACE = 'nonexistent space' +GITIGNORE_FP = '.gitignore' DIR = 'dir' +REPO_DIR = '.git' +REPO_FP = os.path.join(REPO_DIR, 'HEAD') +GITTEST_DIR = '.gittest' +GITTEST_FP = os.path.join(GITTEST_DIR, 'fp') 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') @@ -49,12 +57,12 @@ 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'] + TRACKED_DIR_DIR_FP_WITH_SPACE, GITIGNORE_FP, GITTEST_FP] 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] + UNTRACKED_DIR_DIR_FP_WITH_SPACE, GITTEST_DIR] BRANCH = 'b1' REMOTE_BRANCH = 'rb' FP_IN_CONFLICT = 'f_conflict' @@ -164,10 +172,11 @@ def setUp(self): utils_lib.write_file(UNTRACKED_DIR_DIR_FP) utils_lib.write_file(UNTRACKED_DIR_DIR_FP_WITH_SPACE) utils_lib.write_file( - '.gitignore', contents='{0}\n{1}'.format( + GITIGNORE_FP, contents='{0}\n{1}'.format( IGNORED_FP, IGNORED_FP_WITH_SPACE)) utils_lib.write_file(IGNORED_FP) utils_lib.write_file(IGNORED_FP_WITH_SPACE) + utils_lib.write_file(GITTEST_FP) self.curr_b = self.repo.current_branch @@ -259,6 +268,10 @@ def __assert_track_ignored(self, *fps): def test_track_ignored(self): self.__assert_track_ignored(IGNORED_FP, IGNORED_FP_WITH_SPACE) + @assert_contents_unchanged(GITIGNORE_FP) + def test_track_gitignore(self): + self.__assert_track_untracked(GITIGNORE_FP) + class TestFileUntrack(TestFile): @@ -745,6 +758,44 @@ def test_resolve_relative(self): ValueError, 'no conflicts', self.curr_b.resolve_file, DIR_FP_IN_CONFLICT) +class TestFilePathProcessor(TestFile): + + def setUp(self): + super(TestFilePathProcessor, self).setUp() + self.parser = gl.build_parser([gl_track], self.repo) + + def test_path_processor_track_git(self): + argv = ['track', REPO_DIR] + args = self.parser.parse_args(argv) + files = [fp for fp in args.files] + # Should be empty in this case + self.assertFalse(files) + + @assert_contents_unchanged(REPO_FP) + def test_path_processor_track_git_file(self): + argv = ['track', REPO_FP] + args = self.parser.parse_args(argv) + files = [fp for fp in args.files] + self.assertFalse(files) + + @assert_no_side_effects(GITIGNORE_FP) + def test_path_processor_track_gitignore(self): + argv = ['track', GITIGNORE_FP] + args = self.parser.parse_args(argv) + files = [fp for fp in args.files] + + self.assertEqual(len(files), 1) + self.assertTrue(GITIGNORE_FP in files) + + @assert_no_side_effects(GITTEST_FP) + def test_path_processor_track_gittest_dir(self): + argv = ['track', GITTEST_DIR] + args = self.parser.parse_args(argv) + files = [fp for fp in args.files] + + self.assertEqual(len(files), 1) + self.assertTrue(GITTEST_FP in files) + # Unit tests for branch related operations From 79ba9c5be445af06a89bbf85eb0424f57a2e4bf6 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Tue, 8 Oct 2019 13:49:48 -0400 Subject: [PATCH 147/196] Added standard short commands for branch, checkout, commit, and status by using aliasing. More short commands can be added easily. --- gitless/cli/gl_branch.py | 2 +- gitless/cli/gl_checkout.py | 2 +- gitless/cli/gl_commit.py | 2 +- gitless/cli/gl_status.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index d58ce5e..f6544bf 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -18,7 +18,7 @@ def parser(subparsers, _): """Adds the branch parser to the given subparsers object.""" desc = 'list, create, delete, or edit branches' branch_parser = subparsers.add_parser( - 'branch', help=desc, description=desc.capitalize()) + 'branch', help=desc, description=desc.capitalize(), aliases=['br']) list_group = branch_parser.add_argument_group('list branches') list_group.add_argument( diff --git a/gitless/cli/gl_checkout.py b/gitless/cli/gl_checkout.py index 74141da..5d39a98 100644 --- a/gitless/cli/gl_checkout.py +++ b/gitless/cli/gl_checkout.py @@ -16,7 +16,7 @@ def parser(subparsers, repo): """Adds the checkout parser to the given subparsers object.""" desc = 'checkout committed versions of files' checkout_parser = subparsers.add_parser( - 'checkout', help=desc, description=desc.capitalize()) + 'checkout', help=desc, description=desc.capitalize(), aliases=['co']) checkout_parser.add_argument( '-cp', '--commit-point', help=( 'the commit point to checkout the files at. Defaults to HEAD.'), diff --git a/gitless/cli/gl_commit.py b/gitless/cli/gl_commit.py index df39901..222a7a9 100644 --- a/gitless/cli/gl_commit.py +++ b/gitless/cli/gl_commit.py @@ -30,7 +30,7 @@ def parser(subparsers, repo): desc.capitalize() + '. ' + 'By default all tracked modified files are committed. To customize the' ' set of files to be committed use the only, exclude, and include ' - 'flags')) + 'flags'), aliases=['ci']) commit_parser.add_argument( '-m', '--message', help='Commit message', dest='m') commit_parser.add_argument( diff --git a/gitless/cli/gl_status.py b/gitless/cli/gl_status.py index 2524ef2..ea4667c 100644 --- a/gitless/cli/gl_status.py +++ b/gitless/cli/gl_status.py @@ -20,7 +20,7 @@ def parser(subparsers, repo): """Adds the status parser to the given subparsers object.""" desc = 'show status of the repo' status_parser = subparsers.add_parser( - 'status', help=desc, description=desc.capitalize()) + 'status', help=desc, description=desc.capitalize(), aliases=['st']) status_parser.add_argument( 'paths', nargs='*', help='the specific path(s) to status', action=helpers.PathProcessor, repo=repo) From 44f58f5f393e4aa5602f7e1cd0befe888727f9b2 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Tue, 8 Oct 2019 18:46:16 -0700 Subject: [PATCH 148/196] fix windows bug in path processor --- gitless/cli/helpers.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 0c90f5e..cd52c7c 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -112,13 +112,18 @@ def __init__( def __call__(self, parser, namespace, paths, option_string=None): root = self.repo.root if self.repo else '' - repo_dir = self.repo.path if self.repo else '' # Don't strip trailing / + repo_path = self.repo.path if self.repo else '' + # We add the sep so that we can use `startswith` to determine if a file + # is inside the .git folder + # `normpath` is important because libgit2 returns the repo_path with forward + # slashes on Windows + normalized_repo_path = os.path.normpath(repo_path) + os.path.sep def process_paths(): for path in paths: path = os.path.abspath(path) if self.recursive and os.path.isdir(path): for curr_dir, dirs, fps in os.walk(path, topdown=True): - if curr_dir.startswith(repo_dir): + if curr_dir.startswith(normalized_repo_path): dirs[:] = [] continue curr_dir_rel = os.path.relpath(curr_dir, root) @@ -131,7 +136,7 @@ def process_paths(): for fp in fps: yield os.path.join(curr_dir_rel, fp) else: - if not path.startswith(repo_dir): + if not path.startswith(normalized_repo_path): yield os.path.relpath(path, root) setattr(namespace, self.dest, process_paths()) From 9297275cc742b564a96154769ae49f1defceffeb Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Tue, 8 Oct 2019 21:56:42 -0400 Subject: [PATCH 149/196] Added a new short command for switch --- gitless/cli/gl_switch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/cli/gl_switch.py b/gitless/cli/gl_switch.py index a2ef0ce..79cf632 100644 --- a/gitless/cli/gl_switch.py +++ b/gitless/cli/gl_switch.py @@ -14,7 +14,7 @@ def parser(subparsers, _): """Adds the switch parser to the given subparsers object.""" desc = 'switch branches' switch_parser = subparsers.add_parser( - 'switch', help=desc, description=desc.capitalize()) + 'switch', help=desc, description=desc.capitalize(), aliases=['sw']) switch_parser.add_argument('branch', help='switch to branch') switch_parser.add_argument( '-mo', '--move-over', From ffcf0d1a4850192a04ad9c226f3ecc203447ec16 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Tue, 8 Oct 2019 23:45:24 -0400 Subject: [PATCH 150/196] Setting the upstream branch automatically, with cases considering if it is remote or local --- gitless/cli/gl_branch.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index f6544bf..107c963 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -149,8 +149,18 @@ def _do_create(create_b, dp, repo): continue remote_str = ' in remote repository {0}'.format(maybe_remote) try: - r.create_branch(b_name, target) + new_branch = r.create_branch(b_name, target) pprint.ok('Created new branch {0}{1}'.format(b_name, remote_str)) + if '/' in dp: + # Remote branch + remote, branch = dp.split('/', 1) + if branch in repo.remotes[remote].listall_branches(): + new_branch.upstream = helpers.get_branch(branch, repo.remotes[remote]) + pprint.ok('Upstream of {0} set to {1}'.format(b_name, dp)) + elif dp in repo.listall_branches(): + # Local branch + new_branch.upstream = helpers.get_branch(dp, repo) + pprint.ok('Upstream of {0} set to {1}'.format(b_name, dp)) except ValueError as e: pprint.err(e) errors_found = True From 06a55965ec60c84a06a0acc3f3880f1d03c123d7 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Wed, 9 Oct 2019 19:53:01 -0400 Subject: [PATCH 151/196] Added short commands for each gl command, and refectored the code for automatically setting upstream branch --- gitless/cli/file_cmd.py | 4 ++-- gitless/cli/gl_branch.py | 16 +++++++--------- gitless/cli/gl_diff.py | 2 +- gitless/cli/gl_fuse.py | 2 +- gitless/cli/gl_history.py | 2 +- gitless/cli/gl_init.py | 2 +- gitless/cli/gl_merge.py | 2 +- gitless/cli/gl_publish.py | 2 +- gitless/cli/gl_remote.py | 2 +- gitless/cli/gl_resolve.py | 2 +- gitless/cli/gl_tag.py | 2 +- gitless/cli/gl_track.py | 2 +- gitless/cli/gl_untrack.py | 2 +- 13 files changed, 20 insertions(+), 22 deletions(-) diff --git a/gitless/cli/file_cmd.py b/gitless/cli/file_cmd.py index f5f3120..9e633b0 100644 --- a/gitless/cli/file_cmd.py +++ b/gitless/cli/file_cmd.py @@ -13,10 +13,10 @@ VOWELS = ('a', 'e', 'i', 'o', 'u') -def parser(help_msg, subcmd): +def parser(help_msg, subcmd, subcmd_aliases=[]): def f(subparsers, repo): p = subparsers.add_parser( - subcmd, help=help_msg, description=help_msg.capitalize()) + subcmd, help=help_msg, description=help_msg.capitalize(), aliases=subcmd_aliases) p.add_argument( 'files', nargs='+', help='the file(s) to {0}'.format(subcmd), action=helpers.PathProcessor, repo=repo, diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index 107c963..cbd9744 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -151,16 +151,14 @@ def _do_create(create_b, dp, repo): try: new_branch = r.create_branch(b_name, target) pprint.ok('Created new branch {0}{1}'.format(b_name, remote_str)) - if '/' in dp: - # Remote branch - remote, branch = dp.split('/', 1) - if branch in repo.remotes[remote].listall_branches(): - new_branch.upstream = helpers.get_branch(branch, repo.remotes[remote]) + try: + remote, branch = dp.split('/', 1) if '/' in dp else ('' , '') + upstream_branch = helpers.get_branch(dp, repo) or helpers.get_branch(branch, repo.remotes[remote]) + new_branch.upstream = upstream_branch pprint.ok('Upstream of {0} set to {1}'.format(b_name, dp)) - elif dp in repo.listall_branches(): - # Local branch - new_branch.upstream = helpers.get_branch(dp, repo) - pprint.ok('Upstream of {0} set to {1}'.format(b_name, dp)) + except: + # Not a branch + continue except ValueError as e: pprint.err(e) errors_found = True diff --git a/gitless/cli/gl_diff.py b/gitless/cli/gl_diff.py index 169c0f0..fdc2132 100644 --- a/gitless/cli/gl_diff.py +++ b/gitless/cli/gl_diff.py @@ -20,7 +20,7 @@ def parser(subparsers, repo): 'diff', help=desc, description=( desc.capitalize() + '. ' + 'By default all tracked modified files are diffed. To customize the ' - ' set of files to diff use the only, exclude, and include flags')) + ' set of files to diff use the only, exclude, and include flags'), aliases=['df']) helpers.oei_flags(diff_parser, repo) diff_parser.set_defaults(func=main) diff --git a/gitless/cli/gl_fuse.py b/gitless/cli/gl_fuse.py index 3863320..5dffc35 100644 --- a/gitless/cli/gl_fuse.py +++ b/gitless/cli/gl_fuse.py @@ -19,7 +19,7 @@ def parser(subparsers, repo): desc.capitalize() + '. ' + 'By default all divergent changes from the given source branch are ' 'fused. To customize the set of commits to fuse use the only and ' - 'exclude flags')) + 'exclude flags'), aliases=['fs']) fuse_parser.add_argument( 'src', nargs='?', help=( diff --git a/gitless/cli/gl_history.py b/gitless/cli/gl_history.py index 9c648d8..a1be6ab 100644 --- a/gitless/cli/gl_history.py +++ b/gitless/cli/gl_history.py @@ -17,7 +17,7 @@ def parser(subparsers, _): """Adds the history parser to the given subparsers object.""" desc = 'show commit history' history_parser = subparsers.add_parser( - 'history', help=desc, description=desc.capitalize()) + 'history', help=desc, description=desc.capitalize(), aliases=['hs']) history_parser.add_argument( '-v', '--verbose', help='be verbose, will output the diffs of the commit', action='store_true') diff --git a/gitless/cli/gl_init.py b/gitless/cli/gl_init.py index 5caeae9..9efc4af 100644 --- a/gitless/cli/gl_init.py +++ b/gitless/cli/gl_init.py @@ -19,7 +19,7 @@ def parser(subparsers, _): desc = ( 'create an empty git repository or clone remote') init_parser = subparsers.add_parser( - 'init', help=desc, description=desc.capitalize()) + 'init', help=desc, description=desc.capitalize(), aliases=['in']) init_parser.add_argument( 'repo', nargs='?', help=( diff --git a/gitless/cli/gl_merge.py b/gitless/cli/gl_merge.py index a37ad49..63cb1a3 100644 --- a/gitless/cli/gl_merge.py +++ b/gitless/cli/gl_merge.py @@ -15,7 +15,7 @@ def parser(subparsers, repo): desc = 'merge the divergent changes of one branch onto another' merge_parser = subparsers.add_parser( - 'merge', help=desc, description=desc.capitalize()) + 'merge', help=desc, description=desc.capitalize(), aliases=['mg']) group = merge_parser.add_mutually_exclusive_group() group.add_argument( 'src', nargs='?', help='the source branch to read changes from') diff --git a/gitless/cli/gl_publish.py b/gitless/cli/gl_publish.py index f99bdb9..a968b15 100644 --- a/gitless/cli/gl_publish.py +++ b/gitless/cli/gl_publish.py @@ -14,7 +14,7 @@ def parser(subparsers, _): """Adds the publish parser to the given subparsers object.""" desc = 'publish commits upstream' publish_parser = subparsers.add_parser( - 'publish', help=desc, description=desc.capitalize()) + 'publish', help=desc, description=desc.capitalize(), aliases=['pb']) publish_parser.add_argument( 'dst', nargs='?', help='the branch where to publish commits') publish_parser.set_defaults(func=main) diff --git a/gitless/cli/gl_remote.py b/gitless/cli/gl_remote.py index 3e77aab..0a08921 100644 --- a/gitless/cli/gl_remote.py +++ b/gitless/cli/gl_remote.py @@ -14,7 +14,7 @@ def parser(subparsers, _): """Adds the remote parser to the given subparsers object.""" desc = 'list, create, edit or delete remotes' remote_parser = subparsers.add_parser( - 'remote', help=desc, description=desc.capitalize()) + 'remote', help=desc, description=desc.capitalize(), aliases=['rt']) remote_parser.add_argument( '-c', '--create', nargs='?', help='create remote', dest='remote_name', metavar='remote') diff --git a/gitless/cli/gl_resolve.py b/gitless/cli/gl_resolve.py index 213df43..bbbb6e8 100644 --- a/gitless/cli/gl_resolve.py +++ b/gitless/cli/gl_resolve.py @@ -10,4 +10,4 @@ from . import file_cmd -parser = file_cmd.parser('mark files with conflicts as resolved', 'resolve') +parser = file_cmd.parser('mark files with conflicts as resolved', 'resolve', ['rs']) diff --git a/gitless/cli/gl_tag.py b/gitless/cli/gl_tag.py index 4035caa..ecb407b 100644 --- a/gitless/cli/gl_tag.py +++ b/gitless/cli/gl_tag.py @@ -16,7 +16,7 @@ def parser(subparsers, _): """Adds the tag parser to the given subparsers object.""" desc = 'list, create, or delete tags' tag_parser = subparsers.add_parser( - 'tag', help=desc, description=desc.capitalize()) + 'tag', help=desc, description=desc.capitalize(), aliases=['tg']) list_group = tag_parser.add_argument_group('list tags') list_group.add_argument( diff --git a/gitless/cli/gl_track.py b/gitless/cli/gl_track.py index afcfd0d..801cf43 100644 --- a/gitless/cli/gl_track.py +++ b/gitless/cli/gl_track.py @@ -10,4 +10,4 @@ from . import file_cmd -parser = file_cmd.parser('start tracking changes to files', 'track') +parser = file_cmd.parser('start tracking changes to files', 'track', ['tr']) diff --git a/gitless/cli/gl_untrack.py b/gitless/cli/gl_untrack.py index 2f2d2d7..124d4ca 100644 --- a/gitless/cli/gl_untrack.py +++ b/gitless/cli/gl_untrack.py @@ -10,4 +10,4 @@ from . import file_cmd -parser = file_cmd.parser('stop tracking changes to files', 'untrack') +parser = file_cmd.parser('stop tracking changes to files', 'untrack', ['un']) From 79d573ae92b596c57b19e65729fc3ec3f52f18ca Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Wed, 9 Oct 2019 22:00:21 -0400 Subject: [PATCH 152/196] Changed the create code for branch by not splitting and instead calling get_branch --- gitless/cli/gl_branch.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index cbd9744..58a1089 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -152,9 +152,7 @@ def _do_create(create_b, dp, repo): new_branch = r.create_branch(b_name, target) pprint.ok('Created new branch {0}{1}'.format(b_name, remote_str)) try: - remote, branch = dp.split('/', 1) if '/' in dp else ('' , '') - upstream_branch = helpers.get_branch(dp, repo) or helpers.get_branch(branch, repo.remotes[remote]) - new_branch.upstream = upstream_branch + new_branch.upstream = helpers.get_branch(dp, repo) pprint.ok('Upstream of {0} set to {1}'.format(b_name, dp)) except: # Not a branch From ee01cc636eac2ec5013d2fe97dce55519166e140 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Thu, 10 Oct 2019 14:16:29 -0400 Subject: [PATCH 153/196] Added aliasing for python2, such that we check if the system uses python2, and if so we change the parser --- aliases.py | 34 ++++++++++++++++++++++++++++++++++ gitless/cli/gl.py | 4 ++++ 2 files changed, 38 insertions(+) create mode 100644 aliases.py diff --git a/aliases.py b/aliases.py new file mode 100644 index 0000000..bd1beca --- /dev/null +++ b/aliases.py @@ -0,0 +1,34 @@ +"""Aliases for argparse positional arguments.""" + +import argparse + +class AliasedSubParsersAction(argparse._SubParsersAction): + + class _AliasedPseudoAction(argparse.Action): + def __init__(self, name, aliases, help): + dest = name + if aliases: + dest += ' (%s)' % ','.join(aliases) + sup = super(AliasedSubParsersAction._AliasedPseudoAction, self) + sup.__init__(option_strings=[], dest=dest, help=help) + + def add_parser(self, name, **kwargs): + if 'aliases' in kwargs: + aliases = kwargs['aliases'] + del kwargs['aliases'] + else: + aliases = [] + + parser = super(AliasedSubParsersAction, self).add_parser(name, **kwargs) + + # Make the aliases work. + for alias in aliases: + self._name_parser_map[alias] = parser + # Make the help text reflect them, first removing old help entry. + if 'help' in kwargs: + help = kwargs.pop('help') + self._choices_actions.pop() + pseudo_action = self._AliasedPseudoAction(name, aliases, help) + self._choices_actions.append(pseudo_action) + + return parser diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index b462df7..1c49a22 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -21,6 +21,8 @@ from gitless import core +from aliases import AliasedSubParsersAction + from . import ( gl_track, gl_untrack, gl_status, gl_diff, gl_commit, gl_branch, gl_tag, gl_checkout, gl_merge, gl_resolve, gl_fuse, gl_remote, gl_publish, @@ -73,6 +75,8 @@ def build_parser(subcommands, repo): 'Gitless: a version control system built on top of Git.\nMore info, ' 'downloads and documentation at {0}'.format(URL)), formatter_class=argparse.RawDescriptionHelpFormatter) + if sys.version_info[0] < 3: + parser.register('action', 'parsers', AliasedSubParsersAction) parser.add_argument( '--version', action='version', version=( 'GL Version: {0}\nYou can check if there\'s a new version of Gitless ' From 336eb5aa4cd38d5ba878a44e3d4e61e6273c86ed Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Thu, 10 Oct 2019 17:21:26 -0400 Subject: [PATCH 154/196] Moved the aliasing classes from the root folder into the helpers.py --- aliases.py | 34 ---------------------------------- gitless/cli/gl.py | 4 ++-- gitless/cli/helpers.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 36 deletions(-) delete mode 100644 aliases.py diff --git a/aliases.py b/aliases.py deleted file mode 100644 index bd1beca..0000000 --- a/aliases.py +++ /dev/null @@ -1,34 +0,0 @@ -"""Aliases for argparse positional arguments.""" - -import argparse - -class AliasedSubParsersAction(argparse._SubParsersAction): - - class _AliasedPseudoAction(argparse.Action): - def __init__(self, name, aliases, help): - dest = name - if aliases: - dest += ' (%s)' % ','.join(aliases) - sup = super(AliasedSubParsersAction._AliasedPseudoAction, self) - sup.__init__(option_strings=[], dest=dest, help=help) - - def add_parser(self, name, **kwargs): - if 'aliases' in kwargs: - aliases = kwargs['aliases'] - del kwargs['aliases'] - else: - aliases = [] - - parser = super(AliasedSubParsersAction, self).add_parser(name, **kwargs) - - # Make the aliases work. - for alias in aliases: - self._name_parser_map[alias] = parser - # Make the help text reflect them, first removing old help entry. - if 'help' in kwargs: - help = kwargs.pop('help') - self._choices_actions.pop() - pseudo_action = self._AliasedPseudoAction(name, aliases, help) - self._choices_actions.append(pseudo_action) - - return parser diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 1c49a22..be2a531 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -21,13 +21,13 @@ from gitless import core -from aliases import AliasedSubParsersAction from . import ( gl_track, gl_untrack, gl_status, gl_diff, gl_commit, gl_branch, gl_tag, gl_checkout, gl_merge, gl_resolve, gl_fuse, gl_remote, gl_publish, gl_switch, gl_init, gl_history) from . import pprint +from . import helpers SUCCESS = 0 @@ -76,7 +76,7 @@ def build_parser(subcommands, repo): 'downloads and documentation at {0}'.format(URL)), formatter_class=argparse.RawDescriptionHelpFormatter) if sys.version_info[0] < 3: - parser.register('action', 'parsers', AliasedSubParsersAction) + parser.register('action', 'parsers', helpers.AliasedSubParsersAction) parser.add_argument( '--version', action='version', version=( 'GL Version: {0}\nYou can check if there\'s a new version of Gitless ' diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index cd52c7c..e16e6da 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -251,3 +251,36 @@ def validate(fps, check_fn, msg): for e in err: pprint.err(e) return False + +"""Aliases for argparse positional arguments.""" + +class AliasedSubParsersAction(argparse._SubParsersAction): + + class _AliasedPseudoAction(argparse.Action): + def __init__(self, name, aliases, help): + dest = name + if aliases: + dest += ' (%s)' % ','.join(aliases) + sup = super(AliasedSubParsersAction._AliasedPseudoAction, self) + sup.__init__(option_strings=[], dest=dest, help=help) + + def add_parser(self, name, **kwargs): + if 'aliases' in kwargs: + aliases = kwargs['aliases'] + del kwargs['aliases'] + else: + aliases = [] + + parser = super(AliasedSubParsersAction, self).add_parser(name, **kwargs) + + # Make the aliases work. + for alias in aliases: + self._name_parser_map[alias] = parser + # Make the help text reflect them, first removing old help entry. + if 'help' in kwargs: + help = kwargs.pop('help') + self._choices_actions.pop() + pseudo_action = self._AliasedPseudoAction(name, aliases, help) + self._choices_actions.append(pseudo_action) + + return parser From 33d3a94f3b2f9f95dbf1639c8959024295b86d2c Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Thu, 10 Oct 2019 17:40:46 -0400 Subject: [PATCH 155/196] Removed a space from gl.py --- gitless/cli/gl.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index be2a531..d17f31c 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -21,7 +21,6 @@ from gitless import core - from . import ( gl_track, gl_untrack, gl_status, gl_diff, gl_commit, gl_branch, gl_tag, gl_checkout, gl_merge, gl_resolve, gl_fuse, gl_remote, gl_publish, From 0c4fa3924592b5d2a2c8c3495823788eb6b247fd Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Mon, 21 Oct 2019 09:06:53 +0200 Subject: [PATCH 156/196] The Windows console (Win10) needs to be told to accept ANSI color codes --- gitless/cli/gl.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index d17f31c..071c121 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -88,6 +88,12 @@ def build_parser(subcommands, repo): return parser +def setup_windows_console(): + if sys.platform == 'win32': + import ctypes + kernel32 = ctypes.windll.kernel32 + kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7) + def main(): sub_cmds = [ gl_track, gl_untrack, gl_status, gl_diff, gl_commit, gl_branch, gl_tag, @@ -105,6 +111,7 @@ def main(): if args.subcmd_name != 'init' and not repo: raise core.NotInRepoError('You are not in a Gitless\'s repository') + setup_windows_console() return SUCCESS if args.func(args, repo) else ERRORS_FOUND except KeyboardInterrupt: pprint.puts('\n') From c9a39d62ffbfed3bc45e5c2f6a45c99a6605dd80 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Wed, 30 Oct 2019 09:53:28 -0400 Subject: [PATCH 157/196] Fixed issues with git track . --- gitless/cli/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index e16e6da..dd29d90 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -134,7 +134,7 @@ def process_paths(): dirs[:] = [] continue for fp in fps: - yield os.path.join(curr_dir_rel, fp) + yield fp if curr_dir_rel == '.' else os.path.join(curr_dir_rel, fp) else: if not path.startswith(normalized_repo_path): yield os.path.relpath(path, root) From f049860bec9e1ff5fc86b32c44a8192eb7f60738 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Mon, 11 Nov 2019 00:58:05 -0500 Subject: [PATCH 158/196] Added total diff added and removed messages to git diff and to git commit --- gitless/cli/gl_commit.py | 16 +++++++++++++++- gitless/cli/gl_diff.py | 12 ++++++++++-- gitless/cli/pprint.py | 16 +++++++++++++++- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/gitless/cli/gl_commit.py b/gitless/cli/gl_commit.py index 222a7a9..c339d52 100644 --- a/gitless/cli/gl_commit.py +++ b/gitless/cli/gl_commit.py @@ -50,6 +50,20 @@ def main(args, repo): return False curr_b = repo.current_branch + total_additions = 0 + total_deletions = 0 + for fp in commit_files: + try: + patch = curr_b.diff_file(fp) + except KeyError: + continue + + if patch.delta.is_binary: + continue + + total_additions += patch.line_stats[1] + total_deletions += patch.line_stats[2] + partials = None if args.p: partials = _do_partial_selection(commit_files, curr_b) @@ -68,7 +82,7 @@ def main(args, repo): pprint.ok('Commit on branch {0} succeeded'.format(repo.current_branch)) pprint.blank() - pprint.commit(ci) + pprint.commit(ci, line_additions=total_additions, line_deletions=total_deletions) if curr_b.fuse_in_progress: _op_continue(curr_b.fuse_continue, 'Fuse') diff --git a/gitless/cli/gl_diff.py b/gitless/cli/gl_diff.py index fdc2132..4268ead 100644 --- a/gitless/cli/gl_diff.py +++ b/gitless/cli/gl_diff.py @@ -33,6 +33,9 @@ def main(args, repo): success = True curr_b = repo.current_branch with tempfile.NamedTemporaryFile(mode='w', delete=False) as tf: + total_additions = 0 + total_deletions = 0 + patches = [] for fp in files: try: patch = curr_b.diff_file(fp) @@ -47,11 +50,16 @@ def main(args, repo): additions = patch.line_stats[1] deletions = patch.line_stats[2] + total_additions += additions + total_deletions += deletions if (not additions) and (not deletions): pprint.warn('No diffs to output for {0}'.format(fp)) continue - - pprint.diff(patch, stream=tf.write) + patches.append(patch) + if patches: + pprint.diff_totals(total_additions, total_deletions, stream=tf.write) + for patch in patches: + pprint.diff(patch, stream=tf.write) if os.path.getsize(tf.name) > 0: helpers.page(tf.name, repo) diff --git a/gitless/cli/pprint.py b/gitless/cli/pprint.py index 8faa349..4503bc2 100644 --- a/gitless/cli/pprint.py +++ b/gitless/cli/pprint.py @@ -135,7 +135,7 @@ def commit_str(ci): return ci_str.getvalue().strip() -def commit(ci, compact=False, stream=sys.stdout.write): +def commit(ci, compact=False, stream=sys.stdout.write, line_additions=0, line_deletions=0): merge_commit = len(ci.parent_ids) > 1 color = colored.magenta if merge_commit else colored.yellow if compact: @@ -152,6 +152,10 @@ def commit(ci, compact=False, stream=sys.stdout.write): ci_author_dt = datetime.fromtimestamp( ci.author.time, FixedOffset(ci.author.offset)) puts(color('Date: {0:%c %z}'.format(ci_author_dt)), stream=stream) + put_s = lambda num: '' if num == 1 else 's' + puts(color('Stats: {0} line{1} added, {2} line{3} removed' + .format(line_additions, put_s(line_additions), + line_deletions, put_s(line_deletions))), stream=stream) puts(stream=stream) with indent(4): puts(ci.message, stream=stream) @@ -226,6 +230,16 @@ def diff(patch, stream=sys.stdout.write): puts(stream=stream) puts(stream=stream) +def diff_totals(total_additions, total_deletions, stream=sys.stdout.write): + + put_s = lambda num: '' if num == 1 else 's' + puts('Diff summary', stream=stream) + puts('Total of {0} line{1} added' + .format(total_additions, put_s(total_additions)), stream=stream) + puts('Total of {0} line{1} removed' + .format(total_deletions, put_s(total_deletions)), stream=stream) + puts(stream=stream) + def _hunk(hunk, stream=sys.stdout.write): puts(colored.cyan('@@ -{0},{1} +{2},{3} @@'.format( From 7029300e25a9a3d7c49db8d541242589e8f74fe6 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Tue, 12 Nov 2019 19:05:46 -0500 Subject: [PATCH 159/196] Added lookup_branches in core to make gl branch -r faster --- gitless/cli/gl_branch.py | 2 +- gitless/core.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index 58a1089..29c5409 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -118,7 +118,7 @@ def _do_list(repo, list_remote, v=False): if list_remote: for r in sorted(repo.remotes, key=lambda r: r.name): - for b in (r.lookup_branch(n) for n in sorted(r.listall_branches())): + for b in r.lookup_branches(sorted(r.listall_branches())): pprint.item(' {0}'.format(colored.yellow(str(b)))) if v: pprint.item(' ➜ head is {0}'.format(pprint.commit_str(b.head))) diff --git a/gitless/core.py b/gitless/core.py index bfdcad8..53e074e 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -516,6 +516,23 @@ def lookup_branch(self, branch_name): self.git_remote.name + '/' + branch_name, pygit2.GIT_BRANCH_REMOTE) return RemoteBranch(git_branch, self.gl_repo) + def lookup_branches(self, branch_names): + if not stdout(git('ls-remote', '--heads', self.name, branch_names)): + return None + # The branch exists in the remote + git.fetch(self.git_remote.name, branch_names) + remote_branches = [] + for branch_name in branch_names: + git_branch = self.gl_repo.git_repo.lookup_branch( + self.git_remote.name + '/' + branch_name, pygit2.GIT_BRANCH_REMOTE) + # Make another check for the branch being None + # As observed in issue : https://github.com/sdg-mit/gitless/issues/211 + if git_branch is None: + git.fetch(self.git_remote.name) + git_branch = self.gl_repo.git_repo.lookup_branch( + self.git_remote.name + '/' + branch_name, pygit2.GIT_BRANCH_REMOTE) + remote_branches.append(RemoteBranch(git_branch, self.gl_repo)) + return remote_branches # Tag-related methods From 7e6c7a47faf1a91e56263e01a4c506ceb5a360e3 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Tue, 12 Nov 2019 22:00:24 -0500 Subject: [PATCH 160/196] Updated the check so that it filters the input to only contain branches that exist in the remote. If no branches from the input exist in remote, it returns None, as lookup_branch would. --- gitless/core.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/gitless/core.py b/gitless/core.py index 53e074e..98199cb 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -502,24 +502,15 @@ def listall_branches(self): yield regex.match(head).group(1) def lookup_branch(self, branch_name): - if not stdout(git('ls-remote', '--heads', self.name, branch_name)): - return None - # The branch exists in the remote - git.fetch(self.git_remote.name, branch_name) - git_branch = self.gl_repo.git_repo.lookup_branch( - self.git_remote.name + '/' + branch_name, pygit2.GIT_BRANCH_REMOTE) - # Make another check for the branch being None - # As observed in issue : https://github.com/sdg-mit/gitless/issues/211 - if git_branch is None: - git.fetch(self.git_remote.name) - git_branch = self.gl_repo.git_repo.lookup_branch( - self.git_remote.name + '/' + branch_name, pygit2.GIT_BRANCH_REMOTE) - return RemoteBranch(git_branch, self.gl_repo) + return self.lookup_branches([branch_name])[0] def lookup_branches(self, branch_names): - if not stdout(git('ls-remote', '--heads', self.name, branch_names)): + all_branches = self.listall_branches() + branch_names = [branch_name for branch_name in all_branches if branch_name in branch_names] + if not branch_names: return None - # The branch exists in the remote + + # The branches exist in the remote git.fetch(self.git_remote.name, branch_names) remote_branches = [] for branch_name in branch_names: From 6e42741759f0382644923a3efc3f98da8cd8a5b2 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Tue, 12 Nov 2019 22:06:21 -0500 Subject: [PATCH 161/196] Removed the bug that would occur if lookup_branches returned None. Changed the code so lookup_branches returns an empty list if no branches exist in the remote, and lookup_branch returns None --- gitless/core.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gitless/core.py b/gitless/core.py index 98199cb..df9615a 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -502,13 +502,15 @@ def listall_branches(self): yield regex.match(head).group(1) def lookup_branch(self, branch_name): - return self.lookup_branches([branch_name])[0] + branches = self.lookup_branches([branch_name]) + if not branches: + return None + else: + return branches[0] def lookup_branches(self, branch_names): all_branches = self.listall_branches() branch_names = [branch_name for branch_name in all_branches if branch_name in branch_names] - if not branch_names: - return None # The branches exist in the remote git.fetch(self.git_remote.name, branch_names) From b59da1c0e283b0ced67885ec62af931fb6557411 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Tue, 12 Nov 2019 22:13:45 -0500 Subject: [PATCH 162/196] Changed the formatting so that the lines aren't too long --- gitless/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gitless/core.py b/gitless/core.py index df9615a..3c4f008 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -510,7 +510,8 @@ def lookup_branch(self, branch_name): def lookup_branches(self, branch_names): all_branches = self.listall_branches() - branch_names = [branch_name for branch_name in all_branches if branch_name in branch_names] + branch_names = [branch_name for branch_name in all_branches + if branch_name in branch_names] # The branches exist in the remote git.fetch(self.git_remote.name, branch_names) From db2d36141625b6f28da757ca6e1e43f0c5d67ec9 Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Tue, 12 Nov 2019 23:06:21 -0500 Subject: [PATCH 163/196] Added a new lookupall_branches function, and changed the behavior of lookup_branches to just return None if git.fetch returns an error. --- gitless/cli/gl_branch.py | 2 +- gitless/core.py | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index 29c5409..9fbffd6 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -118,7 +118,7 @@ def _do_list(repo, list_remote, v=False): if list_remote: for r in sorted(repo.remotes, key=lambda r: r.name): - for b in r.lookup_branches(sorted(r.listall_branches())): + for b in r.lookupall_branches(): pprint.item(' {0}'.format(colored.yellow(str(b)))) if v: pprint.item(' ➜ head is {0}'.format(pprint.commit_str(b.head))) diff --git a/gitless/core.py b/gitless/core.py index 3c4f008..0510672 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -146,6 +146,8 @@ def revparse_single(self, revision): return self.remotes[remote].lookup_branch(remote_branch).head except KeyError: pass + except AttributeError: + pass try: return self.git_repo.revparse_single(revision) except (KeyError, ValueError): @@ -503,18 +505,13 @@ def listall_branches(self): def lookup_branch(self, branch_name): branches = self.lookup_branches([branch_name]) - if not branches: - return None - else: - return branches[0] + return branches[0] if branches else None def lookup_branches(self, branch_names): - all_branches = self.listall_branches() - branch_names = [branch_name for branch_name in all_branches - if branch_name in branch_names] - - # The branches exist in the remote - git.fetch(self.git_remote.name, branch_names) + try: + git.fetch(self.git_remote.name, branch_names) + except: + return None remote_branches = [] for branch_name in branch_names: git_branch = self.gl_repo.git_repo.lookup_branch( @@ -528,6 +525,9 @@ def lookup_branches(self, branch_names): remote_branches.append(RemoteBranch(git_branch, self.gl_repo)) return remote_branches + def lookupall_branches(self): + return self.lookup_branches(sorted(self.listall_branches())) + # Tag-related methods def create_tag(self, name, commit): From 4e567c33ccd09423ac24dc9efa286e9c5e032f2f Mon Sep 17 00:00:00 2001 From: Steven Diaz Date: Tue, 3 Dec 2019 13:28:58 -0500 Subject: [PATCH 164/196] Increased the performance speed of gl branch -r by using listall_branches() when the user does not input the -v flag, since we don't need to do the extra fetching work. When the user does input the -v flag, we still use lookupall_branches(), which will do the fetching and get the head. --- gitless/cli/gl_branch.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index 9fbffd6..c976ad4 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -118,8 +118,10 @@ def _do_list(repo, list_remote, v=False): if list_remote: for r in sorted(repo.remotes, key=lambda r: r.name): - for b in r.lookupall_branches(): - pprint.item(' {0}'.format(colored.yellow(str(b)))) + branches = r.lookupall_branches() if v else r.listall_branches() + b_remote = '' if v else r.name + '/' + for b in branches: + pprint.item(' {0}'.format(colored.yellow(b_remote + str(b)))) if v: pprint.item(' ➜ head is {0}'.format(pprint.commit_str(b.head))) From 1231e936c21d5b873061e0546a00cfb993fb0bc9 Mon Sep 17 00:00:00 2001 From: Darcy Coleman Date: Sat, 7 Dec 2019 14:45:48 -0500 Subject: [PATCH 165/196] Prevent gitless from following symlinks Add a check for symlinks when we check if a path is a directory and treat the symlink as a normal file. Gitless will NOT follow the symlinks, because it could pull in the .git/ directory, files outside of the repository or, in the worst case, the entire filesystem. This follows the behavior of git. Git will commit symlinks into the repository and recreate the links on filesystems that support it when the file is downloaded. --- gitless/cli/helpers.py | 5 +++- gitless/tests/test_core.py | 49 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index dd29d90..8ea3caf 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -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[:] = [] diff --git a/gitless/tests/test_core.py b/gitless/tests/test_core.py index 943171b..78438d1 100644 --- a/gitless/tests/test_core.py +++ b/gitless/tests/test_core.py @@ -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') @@ -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' @@ -178,6 +188,12 @@ def setUp(self): utils_lib.write_file(IGNORED_FP_WITH_SPACE) utils_lib.write_file(GITTEST_FP) + # Testing with symlinks! + utils_lib.write_file(SYMLINK_TARGET_FP, contents=SYMLINK_TARGET_FP_CONTENTS) + os.symlink(REPO_DIR, SYMLINK_GIT) + os.mkdir(SYMLINK_DIR) + os.symlink(SYMLINK_TARGET, SYMLINK_FP) + self.curr_b = self.repo.current_branch @@ -796,6 +812,35 @@ 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] + + 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] + + self.assertEqual(len(files), 1) + self.assertTrue(SYMLINK_FP in files) + self.assertFalse(SYMLINK_TARGET_FP in files) + # Unit tests for branch related operations From 5fece7766e0a270facb356a24756eb18daa1f23a Mon Sep 17 00:00:00 2001 From: Darcy Coleman Date: Sun, 8 Dec 2019 17:47:12 -0500 Subject: [PATCH 166/196] Update symlinks to not break on windows --- gitless/tests/test_core.py | 20 +++++++++++--------- gitless/tests/utils.py | 10 ++++++++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/gitless/tests/test_core.py b/gitless/tests/test_core.py index 78438d1..37df619 100644 --- a/gitless/tests/test_core.py +++ b/gitless/tests/test_core.py @@ -188,11 +188,11 @@ def setUp(self): utils_lib.write_file(IGNORED_FP_WITH_SPACE) utils_lib.write_file(GITTEST_FP) - # Testing with symlinks! + # Testing with symlinks! The symlink calls will be no ops on Windows utils_lib.write_file(SYMLINK_TARGET_FP, contents=SYMLINK_TARGET_FP_CONTENTS) - os.symlink(REPO_DIR, SYMLINK_GIT) + utils_lib.symlink(REPO_DIR, SYMLINK_GIT) os.mkdir(SYMLINK_DIR) - os.symlink(SYMLINK_TARGET, SYMLINK_FP) + utils_lib.symlink(SYMLINK_TARGET, SYMLINK_FP) self.curr_b = self.repo.current_branch @@ -823,20 +823,22 @@ def test_path_processor_track_gittest_fp(self): @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] + 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] + 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) diff --git a/gitless/tests/utils.py b/gitless/tests/utils.py index 30602d0..90f15a6 100644 --- a/gitless/tests/utils.py +++ b/gitless/tests/utils.py @@ -82,6 +82,16 @@ def onerror(func, path, unused_exc_info): # error handler for rmtree logging.debug('Removed dir {0}'.format(path)) +def symlink(src, dst, target_is_directory=False, *, dir_fd=None): + try: + os.symlink(src, dst, target_is_directory, dir_fd=dir_fd) + except OSError: + # Swallow the OSError, because Windows is very weird about creating + # symlinks. Technically, python supports this if it is run with the right + # permissions. In that case, this will just work. + pass + + def write_file(fp, contents=''): _x_file('w', fp, contents=contents) From a34f4ec5823f054ae942bf728b85db6806ef6d44 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Sun, 2 Feb 2020 22:00:21 -0500 Subject: [PATCH 167/196] lets see if removing `*` works --- gitless/tests/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/tests/utils.py b/gitless/tests/utils.py index 90f15a6..db91663 100644 --- a/gitless/tests/utils.py +++ b/gitless/tests/utils.py @@ -82,7 +82,7 @@ def onerror(func, path, unused_exc_info): # error handler for rmtree logging.debug('Removed dir {0}'.format(path)) -def symlink(src, dst, target_is_directory=False, *, dir_fd=None): +def symlink(src, dst, target_is_directory=False, dir_fd=None): try: os.symlink(src, dst, target_is_directory, dir_fd=dir_fd) except OSError: From 00226034a0a577741392546415c74b29bd18e726 Mon Sep 17 00:00:00 2001 From: Darcy Coleman Date: Sun, 9 Feb 2020 10:41:23 -0500 Subject: [PATCH 168/196] Add additional symlink error handling Catch AttributeError for os module missing symlink method in Python 2 implementations on Windows. All the flavors of error that could happen in a symlink call should be handled now. --- gitless/tests/utils.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/gitless/tests/utils.py b/gitless/tests/utils.py index db91663..4f70cab 100644 --- a/gitless/tests/utils.py +++ b/gitless/tests/utils.py @@ -85,10 +85,16 @@ def onerror(func, path, unused_exc_info): # error handler for rmtree def symlink(src, dst, target_is_directory=False, dir_fd=None): try: os.symlink(src, dst, target_is_directory, dir_fd=dir_fd) - except OSError: - # Swallow the OSError, because Windows is very weird about creating - # symlinks. Technically, python supports this if it is run with the right - # permissions. In that case, this will just work. + 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 From 6f2bcbe6d79d240092e1667f8efa76f8faca4a2a Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Mon, 10 Feb 2020 12:01:03 -0800 Subject: [PATCH 169/196] add parens in except --- gitless/tests/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/tests/utils.py b/gitless/tests/utils.py index 4f70cab..2d4187e 100644 --- a/gitless/tests/utils.py +++ b/gitless/tests/utils.py @@ -85,7 +85,7 @@ def onerror(func, path, unused_exc_info): # error handler for rmtree def symlink(src, dst, target_is_directory=False, dir_fd=None): try: os.symlink(src, dst, target_is_directory, dir_fd=dir_fd) - except AttributeError, NotImplementedError, OSError: + 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 From 98f14e1538d29c5af8231d5720b46415cb4805bb Mon Sep 17 00:00:00 2001 From: Darcy Coleman Date: Wed, 12 Feb 2020 17:28:39 -0500 Subject: [PATCH 170/196] Update symlink method signature to python 2 Make the os.symlink method call signature the same as python 2. The arguments and parameters for symlinking to directories and for the file descriptor of the directory were removed. Those were added in python 3 causing tests to fail in python 2. --- gitless/tests/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gitless/tests/utils.py b/gitless/tests/utils.py index 2d4187e..d4d676c 100644 --- a/gitless/tests/utils.py +++ b/gitless/tests/utils.py @@ -82,9 +82,9 @@ def onerror(func, path, unused_exc_info): # error handler for rmtree logging.debug('Removed dir {0}'.format(path)) -def symlink(src, dst, target_is_directory=False, dir_fd=None): +def symlink(src, dst): try: - os.symlink(src, dst, target_is_directory, dir_fd=dir_fd) + 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, From daf352cae1f830bd4ca9adc949884b606cccdf49 Mon Sep 17 00:00:00 2001 From: Alexander Bayandin Date: Sun, 15 Mar 2020 09:44:51 +0000 Subject: [PATCH 171/196] Update libgit2 --- .travis.sh | 2 +- requirements.txt | 2 +- setup.py | 2 +- snap/snapcraft.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.sh b/.travis.sh index 199ccab..f262871 100755 --- a/.travis.sh +++ b/.travis.sh @@ -2,7 +2,7 @@ cd ~ -git clone --depth=1 -b maint/v0.28 https://github.com/libgit2/libgit2.git +git clone --depth=1 -b maint/v0.99 https://github.com/libgit2/libgit2.git cd libgit2/ mkdir build && cd build diff --git a/requirements.txt b/requirements.txt index 05f190a..4146764 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ # make sure to update setup.py -pygit2==0.28.2 # requires libgit2 0.28 +pygit2==1.1.1 # requires libgit2 0.99 or 1.0 clint==0.5.1 sh==1.12.14;sys_platform!='win32' pbs==0.110;sys_platform=='win32' diff --git a/setup.py b/setup.py index 68a3a87..12448c8 100755 --- a/setup.py +++ b/setup.py @@ -68,7 +68,7 @@ packages=['gitless', 'gitless.cli'], install_requires=[ # make sure it matches requirements.txt - 'pygit2==0.28.2', # requires libgit2 0.28 + 'pygit2==1.1.1', # requires libgit2 0.99 or 1.0 'clint>=0.3.6', 'sh>=1.11' if sys.platform != 'win32' else 'pbs>=0.11' ], diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 4c37cf1..68d352f 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -28,7 +28,7 @@ parts: libgit2: plugin: cmake # https://www.pygit2.org/install.html#version-numbers - source: https://github.com/libgit2/libgit2/archive/v0.28.2.tar.gz + source: https://github.com/libgit2/libgit2/archive/v0.99.0.tar.gz build-packages: - libssl-dev From 22823953a604b97e8c47777f478d259b872098ad Mon Sep 17 00:00:00 2001 From: Kerkko Pelttari Date: Tue, 31 Mar 2020 13:02:25 +0300 Subject: [PATCH 172/196] Add tab completion support with argcomplete --- gitless/cli/gl.py | 3 ++- requirements.txt | 1 + setup.py | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 071c121..b39ac46 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -9,6 +9,7 @@ import sys import argparse +import argcomplete import traceback import pygit2 @@ -101,7 +102,7 @@ def main(): gl_switch, gl_init, gl_history] parser = build_parser(sub_cmds, repo) - + argcomplete.autocomplete(parser) if len(sys.argv) == 1: print_help(parser) return SUCCESS diff --git a/requirements.txt b/requirements.txt index 4146764..dcb9374 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ # make sure to update setup.py +argcomplete>=1.11.1 pygit2==1.1.1 # requires libgit2 0.99 or 1.0 clint==0.5.1 sh==1.12.14;sys_platform!='win32' diff --git a/setup.py b/setup.py index 12448c8..d25f6ef 100755 --- a/setup.py +++ b/setup.py @@ -70,7 +70,8 @@ # make sure it matches requirements.txt 'pygit2==1.1.1', # requires libgit2 0.99 or 1.0 'clint>=0.3.6', - 'sh>=1.11' if sys.platform != 'win32' else 'pbs>=0.11' + 'sh>=1.11' if sys.platform != 'win32' else 'pbs>=0.11', + 'argcomplete>=1.11.1' ], license='MIT', classifiers=[ From 4885e6d8e8dfea420226e717fde341b5ea6ef97c Mon Sep 17 00:00:00 2001 From: Kerkko Pelttari Date: Tue, 31 Mar 2020 19:19:36 +0300 Subject: [PATCH 173/196] Add mostly-autogenerated man pages --- gitless.1 | 664 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 664 insertions(+) create mode 100644 gitless.1 diff --git a/gitless.1 b/gitless.1 new file mode 100644 index 0000000..3ebc661 --- /dev/null +++ b/gitless.1 @@ -0,0 +1,664 @@ +.TH gitless "1" Manual +.SH NAME +gl +.SH SYNOPSIS +.B gl +[-h] [--version] {track,tr,untrack,un,status,st,diff,df,commit,ci,branch,br,tag,tg,checkout,co,merge,mg,resolve,rs,fuse,fs,remote,rt,publish,pb,switch,sw,init,in,history,hs} ... +.SH DESCRIPTION +Gitless: a version control system built on top of Git. +More info, downloads and documentation at http://gitless.com +.SH OPTIONS + +.TP +\fB\-\-version\fR +show program's version number and exit + +.SS +\fBSub-commands\fR +.TP +\fBgl\fR \fI\,track\/\fR +start tracking changes to files +.TP +\fBgl\fR \fI\,untrack\/\fR +stop tracking changes to files +.TP +\fBgl\fR \fI\,status\/\fR +show status of the repo +.TP +\fBgl\fR \fI\,diff\/\fR +show changes to files +.TP +\fBgl\fR \fI\,commit\/\fR +save changes to the local repository +.TP +\fBgl\fR \fI\,branch\/\fR +list, create, delete, or edit branches +.TP +\fBgl\fR \fI\,tag\/\fR +list, create, or delete tags +.TP +\fBgl\fR \fI\,checkout\/\fR +checkout committed versions of files +.TP +\fBgl\fR \fI\,merge\/\fR +merge the divergent changes of one branch onto another +.TP +\fBgl\fR \fI\,resolve\/\fR +mark files with conflicts as resolved +.TP +\fBgl\fR \fI\,fuse\/\fR +fuse the divergent changes of a branch onto the current branch +.TP +\fBgl\fR \fI\,remote\/\fR +list, create, edit or delete remotes +.TP +\fBgl\fR \fI\,publish\/\fR +publish commits upstream +.TP +\fBgl\fR \fI\,switch\/\fR +switch branches +.TP +\fBgl\fR \fI\,init\/\fR +create an empty git repository or clone remote +.TP +\fBgl\fR \fI\,history\/\fR +show commit history +.SH OPTIONS 'gl track' +usage: gl track [-h] files [files ...] + +Start tracking changes to files + +.TP +\fBfiles\fR +the file(s) to track + + +.SH OPTIONS 'gl tr' +usage: gl track [-h] files [files ...] + +Start tracking changes to files + +.TP +\fBfiles\fR +the file(s) to track + + +.SH OPTIONS 'gl untrack' +usage: gl untrack [-h] files [files ...] + +Stop tracking changes to files + +.TP +\fBfiles\fR +the file(s) to untrack + + +.SH OPTIONS 'gl un' +usage: gl untrack [-h] files [files ...] + +Stop tracking changes to files + +.TP +\fBfiles\fR +the file(s) to untrack + + +.SH OPTIONS 'gl status' +usage: gl status [-h] [paths [paths ...]] + +Show status of the repo + +.TP +\fBpaths\fR +the specific path(s) to status + + +.SH OPTIONS 'gl st' +usage: gl status [-h] [paths [paths ...]] + +Show status of the repo + +.TP +\fBpaths\fR +the specific path(s) to status + + +.SH OPTIONS 'gl diff' +usage: gl diff [-h] [-e file [file ...]] [-i file [file ...]] + [file [file ...]] + +Show changes to files. By default all tracked modified files are diffed. To customize the set of files to diff use the only, exclude, and include flags + +.TP +\fBfile\fR +use only files given (tracked modified or untracked) + +.TP +\fB\-e\fR file [file ...], \fB\-\-exclude\fR file [file ...] +exclude files given (files must be tracked modified) + +.TP +\fB\-i\fR file [file ...], \fB\-\-include\fR file [file ...] +include files given (files must be untracked) + +.SH OPTIONS 'gl df' +usage: gl diff [-h] [-e file [file ...]] [-i file [file ...]] + [file [file ...]] + +Show changes to files. By default all tracked modified files are diffed. To customize the set of files to diff use the only, exclude, and include flags + +.TP +\fBfile\fR +use only files given (tracked modified or untracked) + +.TP +\fB\-e\fR file [file ...], \fB\-\-exclude\fR file [file ...] +exclude files given (files must be tracked modified) + +.TP +\fB\-i\fR file [file ...], \fB\-\-include\fR file [file ...] +include files given (files must be untracked) + +.SH OPTIONS 'gl commit' +usage: gl commit [-h] [-m M] [-p] [-e file [file ...]] + [-i file [file ...]] + [file [file ...]] + +Save changes to the local repository. By default all tracked modified files are committed. To customize the set of files to be committed use the only, exclude, and include flags + +.TP +\fBfile\fR +use only files given (tracked modified or untracked) + +.TP +\fB\-m\fR \fI\,M\/\fR, \fB\-\-message\fR \fI\,M\/\fR +Commit message + +.TP +\fB\-p\fR, \fB\-\-partial\fR +Interactively select segments of files to commit + +.TP +\fB\-e\fR file [file ...], \fB\-\-exclude\fR file [file ...] +exclude files given (files must be tracked modified) + +.TP +\fB\-i\fR file [file ...], \fB\-\-include\fR file [file ...] +include files given (files must be untracked) + +.SH OPTIONS 'gl ci' +usage: gl commit [-h] [-m M] [-p] [-e file [file ...]] + [-i file [file ...]] + [file [file ...]] + +Save changes to the local repository. By default all tracked modified files are committed. To customize the set of files to be committed use the only, exclude, and include flags + +.TP +\fBfile\fR +use only files given (tracked modified or untracked) + +.TP +\fB\-m\fR \fI\,M\/\fR, \fB\-\-message\fR \fI\,M\/\fR +Commit message + +.TP +\fB\-p\fR, \fB\-\-partial\fR +Interactively select segments of files to commit + +.TP +\fB\-e\fR file [file ...], \fB\-\-exclude\fR file [file ...] +exclude files given (files must be tracked modified) + +.TP +\fB\-i\fR file [file ...], \fB\-\-include\fR file [file ...] +include files given (files must be untracked) + +.SH OPTIONS 'gl branch' +usage: gl branch [-h] [-r] [-v] [-c branch [branch ...]] + [-dp DP] [-d branch [branch ...]] + [-sh commit_id] [-su branch] [-uu] + [-rn RENAME_B [RENAME_B ...]] + +List, create, delete, or edit branches + + + +.TP +\fB\-r\fR, \fB\-\-remote\fR +list remote branches in addition to local branches + +.TP +\fB\-v\fR, \fB\-\-verbose\fR +be verbose, will output the head of each branch + +.TP +\fB\-c\fR branch [branch ...], \fB\-\-create\fR branch [branch ...] +create branch(es) + +.TP +\fB\-dp\fR \fI\,DP\/\fR, \fB\-\-divergent\-point\fR \fI\,DP\/\fR +the commit from where to 'branch out' (only relevant if a new branch is created; defaults to HEAD) + +.TP +\fB\-d\fR branch [branch ...], \fB\-\-delete\fR branch [branch ...] +delete branch(es) + +.TP +\fB\-sh\fR commit_id, \fB\-\-set\-head\fR commit_id +set the head of the current branch + +.TP +\fB\-su\fR branch, \fB\-\-set\-upstream\fR branch +set the upstream branch of the current branch + +.TP +\fB\-uu\fR, \fB\-\-unset\-upstream\fR +unset the upstream branch of the current branch + +.TP +\fB\-rn\fR \fI\,RENAME_B\/\fR [\fI\,RENAME_B\/\fR ...], \fB\-\-rename\-branch\fR \fI\,RENAME_B\/\fR [\fI\,RENAME_B\/\fR ...] +renames the current branch (gl branch \-rn new_name) or another specified branch (gl branch \-rn branch_name new_name) + +.SH OPTIONS 'gl br' +usage: gl branch [-h] [-r] [-v] [-c branch [branch ...]] + [-dp DP] [-d branch [branch ...]] + [-sh commit_id] [-su branch] [-uu] + [-rn RENAME_B [RENAME_B ...]] + +List, create, delete, or edit branches + + + +.TP +\fB\-r\fR, \fB\-\-remote\fR +list remote branches in addition to local branches + +.TP +\fB\-v\fR, \fB\-\-verbose\fR +be verbose, will output the head of each branch + +.TP +\fB\-c\fR branch [branch ...], \fB\-\-create\fR branch [branch ...] +create branch(es) + +.TP +\fB\-dp\fR \fI\,DP\/\fR, \fB\-\-divergent\-point\fR \fI\,DP\/\fR +the commit from where to 'branch out' (only relevant if a new branch is created; defaults to HEAD) + +.TP +\fB\-d\fR branch [branch ...], \fB\-\-delete\fR branch [branch ...] +delete branch(es) + +.TP +\fB\-sh\fR commit_id, \fB\-\-set\-head\fR commit_id +set the head of the current branch + +.TP +\fB\-su\fR branch, \fB\-\-set\-upstream\fR branch +set the upstream branch of the current branch + +.TP +\fB\-uu\fR, \fB\-\-unset\-upstream\fR +unset the upstream branch of the current branch + +.TP +\fB\-rn\fR \fI\,RENAME_B\/\fR [\fI\,RENAME_B\/\fR ...], \fB\-\-rename\-branch\fR \fI\,RENAME_B\/\fR [\fI\,RENAME_B\/\fR ...] +renames the current branch (gl branch \-rn new_name) or another specified branch (gl branch \-rn branch_name new_name) + +.SH OPTIONS 'gl tag' +usage: gl tag [-h] [-r] [-c tag [tag ...]] [-ci CI] + [-d tag [tag ...]] + +List, create, or delete tags + + + +.TP +\fB\-r\fR, \fB\-\-remote\fR +list remote tags in addition to local tags + +.TP +\fB\-c\fR tag [tag ...], \fB\-\-create\fR tag [tag ...] +create tag(s) + +.TP +\fB\-ci\fR \fI\,CI\/\fR, \fB\-\-commit\fR \fI\,CI\/\fR +the commit to tag (only relevant if a new tag is created; defaults to the HEAD commit) + +.TP +\fB\-d\fR tag [tag ...], \fB\-\-delete\fR tag [tag ...] +delete tag(s) + +.SH OPTIONS 'gl tg' +usage: gl tag [-h] [-r] [-c tag [tag ...]] [-ci CI] + [-d tag [tag ...]] + +List, create, or delete tags + + + +.TP +\fB\-r\fR, \fB\-\-remote\fR +list remote tags in addition to local tags + +.TP +\fB\-c\fR tag [tag ...], \fB\-\-create\fR tag [tag ...] +create tag(s) + +.TP +\fB\-ci\fR \fI\,CI\/\fR, \fB\-\-commit\fR \fI\,CI\/\fR +the commit to tag (only relevant if a new tag is created; defaults to the HEAD commit) + +.TP +\fB\-d\fR tag [tag ...], \fB\-\-delete\fR tag [tag ...] +delete tag(s) + +.SH OPTIONS 'gl checkout' +usage: gl checkout [-h] [-cp CP] files [files ...] + +Checkout committed versions of files + +.TP +\fBfiles\fR +the file(s) to checkout + +.TP +\fB\-cp\fR \fI\,CP\/\fR, \fB\-\-commit\-point\fR \fI\,CP\/\fR +the commit point to checkout the files at. Defaults to HEAD. + +.SH OPTIONS 'gl co' +usage: gl checkout [-h] [-cp CP] files [files ...] + +Checkout committed versions of files + +.TP +\fBfiles\fR +the file(s) to checkout + +.TP +\fB\-cp\fR \fI\,CP\/\fR, \fB\-\-commit\-point\fR \fI\,CP\/\fR +the commit point to checkout the files at. Defaults to HEAD. + +.SH OPTIONS 'gl merge' +usage: gl merge [-h] [-a] [src] + +Merge the divergent changes of one branch onto another + +.TP +\fBsrc\fR +the source branch to read changes from + +.TP +\fB\-a\fR, \fB\-\-abort\fR +abort the merge in progress + +.SH OPTIONS 'gl mg' +usage: gl merge [-h] [-a] [src] + +Merge the divergent changes of one branch onto another + +.TP +\fBsrc\fR +the source branch to read changes from + +.TP +\fB\-a\fR, \fB\-\-abort\fR +abort the merge in progress + +.SH OPTIONS 'gl resolve' +usage: gl resolve [-h] files [files ...] + +Mark files with conflicts as resolved + +.TP +\fBfiles\fR +the file(s) to resolve + + +.SH OPTIONS 'gl rs' +usage: gl resolve [-h] files [files ...] + +Mark files with conflicts as resolved + +.TP +\fBfiles\fR +the file(s) to resolve + + +.SH OPTIONS 'gl fuse' +usage: gl fuse [-h] [-o commit_id [commit_id ...]] + [-e commit_id [commit_id ...]] [-ip [commit_id]] + [-a] + [src] + +Fuse the divergent changes of a branch onto the current branch. By default all divergent changes from the given source branch are fused. To customize the set of commits to fuse use the only and exclude flags + +.TP +\fBsrc\fR +the source branch to read changes from. If none is given the upstream branch of the current branch is used as the source + +.TP +\fB\-o\fR commit_id [commit_id ...], \fB\-\-only\fR commit_id [commit_id ...] +fuse only the commits given (commits must belong to the set of divergent commits from the given src branch) + +.TP +\fB\-e\fR commit_id [commit_id ...], \fB\-\-exclude\fR commit_id [commit_id ...] +exclude from the fuse the commits given (commits must belong to the set of divergent commits from the given src branch) + +.TP +\fB\-ip\fR [commit_id], \fB\-\-insertion\-point\fR [commit_id] +the divergent changes will be inserted after the commit given, dp for divergent point is the default + +.TP +\fB\-a\fR, \fB\-\-abort\fR +abort the fuse in progress + +.SH OPTIONS 'gl fs' +usage: gl fuse [-h] [-o commit_id [commit_id ...]] + [-e commit_id [commit_id ...]] [-ip [commit_id]] + [-a] + [src] + +Fuse the divergent changes of a branch onto the current branch. By default all divergent changes from the given source branch are fused. To customize the set of commits to fuse use the only and exclude flags + +.TP +\fBsrc\fR +the source branch to read changes from. If none is given the upstream branch of the current branch is used as the source + +.TP +\fB\-o\fR commit_id [commit_id ...], \fB\-\-only\fR commit_id [commit_id ...] +fuse only the commits given (commits must belong to the set of divergent commits from the given src branch) + +.TP +\fB\-e\fR commit_id [commit_id ...], \fB\-\-exclude\fR commit_id [commit_id ...] +exclude from the fuse the commits given (commits must belong to the set of divergent commits from the given src branch) + +.TP +\fB\-ip\fR [commit_id], \fB\-\-insertion\-point\fR [commit_id] +the divergent changes will be inserted after the commit given, dp for divergent point is the default + +.TP +\fB\-a\fR, \fB\-\-abort\fR +abort the fuse in progress + +.SH OPTIONS 'gl remote' +usage: gl remote [-h] [-c [remote]] [-d remote [remote ...]] + [-rn RENAME_R [RENAME_R ...]] + [remote_url] + +List, create, edit or delete remotes + +.TP +\fBremote_url\fR +the url of the remote (only relevant if a new remote is created) + +.TP +\fB\-c\fR [remote], \fB\-\-create\fR [remote] +create remote + +.TP +\fB\-d\fR remote [remote ...], \fB\-\-delete\fR remote [remote ...] +delete remote(es) + +.TP +\fB\-rn\fR \fI\,RENAME_R\/\fR [\fI\,RENAME_R\/\fR ...], \fB\-\-rename\fR \fI\,RENAME_R\/\fR [\fI\,RENAME_R\/\fR ...] +renames the specified remote: accepts two arguments (current remote name and new remote name) + +.SH OPTIONS 'gl rt' +usage: gl remote [-h] [-c [remote]] [-d remote [remote ...]] + [-rn RENAME_R [RENAME_R ...]] + [remote_url] + +List, create, edit or delete remotes + +.TP +\fBremote_url\fR +the url of the remote (only relevant if a new remote is created) + +.TP +\fB\-c\fR [remote], \fB\-\-create\fR [remote] +create remote + +.TP +\fB\-d\fR remote [remote ...], \fB\-\-delete\fR remote [remote ...] +delete remote(es) + +.TP +\fB\-rn\fR \fI\,RENAME_R\/\fR [\fI\,RENAME_R\/\fR ...], \fB\-\-rename\fR \fI\,RENAME_R\/\fR [\fI\,RENAME_R\/\fR ...] +renames the specified remote: accepts two arguments (current remote name and new remote name) + +.SH OPTIONS 'gl publish' +usage: gl publish [-h] [dst] + +Publish commits upstream + +.TP +\fBdst\fR +the branch where to publish commits + + +.SH OPTIONS 'gl pb' +usage: gl publish [-h] [dst] + +Publish commits upstream + +.TP +\fBdst\fR +the branch where to publish commits + + +.SH OPTIONS 'gl switch' +usage: gl switch [-h] [-mo] branch + +Switch branches + +.TP +\fBbranch\fR +switch to branch + +.TP +\fB\-mo\fR, \fB\-\-move\-over\fR +move uncomitted changes made in the current branch to the destination branch + +.SH OPTIONS 'gl sw' +usage: gl switch [-h] [-mo] branch + +Switch branches + +.TP +\fBbranch\fR +switch to branch + +.TP +\fB\-mo\fR, \fB\-\-move\-over\fR +move uncomitted changes made in the current branch to the destination branch + +.SH OPTIONS 'gl init' +usage: gl init [-h] [-o ONLY [ONLY ...]] + [-e EXCLUDE [EXCLUDE ...]] + [repo] + +Create an empty git repository or clone remote + +.TP +\fBrepo\fR +an optional remote repo address from where to read to create the local repo + +.TP +\fB\-o\fR \fI\,ONLY\/\fR [\fI\,ONLY\/\fR ...], \fB\-\-only\fR \fI\,ONLY\/\fR [\fI\,ONLY\/\fR ...] +use only branches given from remote repo + +.TP +\fB\-e\fR \fI\,EXCLUDE\/\fR [\fI\,EXCLUDE\/\fR ...], \fB\-\-exclude\fR \fI\,EXCLUDE\/\fR [\fI\,EXCLUDE\/\fR ...] +use everything but these branches from remote repo + +.SH OPTIONS 'gl in' +usage: gl init [-h] [-o ONLY [ONLY ...]] + [-e EXCLUDE [EXCLUDE ...]] + [repo] + +Create an empty git repository or clone remote + +.TP +\fBrepo\fR +an optional remote repo address from where to read to create the local repo + +.TP +\fB\-o\fR \fI\,ONLY\/\fR [\fI\,ONLY\/\fR ...], \fB\-\-only\fR \fI\,ONLY\/\fR [\fI\,ONLY\/\fR ...] +use only branches given from remote repo + +.TP +\fB\-e\fR \fI\,EXCLUDE\/\fR [\fI\,EXCLUDE\/\fR ...], \fB\-\-exclude\fR \fI\,EXCLUDE\/\fR [\fI\,EXCLUDE\/\fR ...] +use everything but these branches from remote repo + +.SH OPTIONS 'gl history' +usage: gl history [-h] [-v] [-l LIMIT] [-c] [-b [branch_name]] + +Show commit history + + +.TP +\fB\-v\fR, \fB\-\-verbose\fR +be verbose, will output the diffs of the commit + +.TP +\fB\-l\fR \fI\,LIMIT\/\fR, \fB\-\-limit\fR \fI\,LIMIT\/\fR +limit number of commits displayed + +.TP +\fB\-c\fR, \fB\-\-compact\fR +output history in a compact format + +.TP +\fB\-b\fR [branch_name], \fB\-\-branch\fR [branch_name] +the branch to show history of (defaults to the current branch) + +.SH OPTIONS 'gl hs' +usage: gl history [-h] [-v] [-l LIMIT] [-c] [-b [branch_name]] + +Show commit history + + +.TP +\fB\-v\fR, \fB\-\-verbose\fR +be verbose, will output the diffs of the commit + +.TP +\fB\-l\fR \fI\,LIMIT\/\fR, \fB\-\-limit\fR \fI\,LIMIT\/\fR +limit number of commits displayed + +.TP +\fB\-c\fR, \fB\-\-compact\fR +output history in a compact format + +.TP +\fB\-b\fR [branch_name], \fB\-\-branch\fR [branch_name] +the branch to show history of (defaults to the current branch) + +.SH AUTHORS +.B gitless +was written by Santiago Perez De Rosso . +.SH DISTRIBUTION +The latest version of gitless may be downloaded from +.UR http://gitless.com +.UE From 470d5603fcd25f54fe6b23534b033cf50e633272 Mon Sep 17 00:00:00 2001 From: Clement Cherlin <1463364+Mooninaut@users.noreply.github.com> Date: Tue, 31 Mar 2020 15:12:06 -0400 Subject: [PATCH 174/196] Add --no-stash-ignored / -ni flag to "gl switch". --- gitless/cli/gl_switch.py | 5 ++++- gitless/core.py | 10 ++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gitless/cli/gl_switch.py b/gitless/cli/gl_switch.py index 79cf632..71182c2 100644 --- a/gitless/cli/gl_switch.py +++ b/gitless/cli/gl_switch.py @@ -21,6 +21,9 @@ def parser(subparsers, _): help='move uncomitted changes made in the current branch to the ' 'destination branch', action='store_true') + switch_parser.add_argument('-ni', '--no-stash-ignored', + help='do not stash ignored files, has no effect if --move-over is also set', + action='store_true') switch_parser.set_defaults(func=main) @@ -33,6 +36,6 @@ def main(args, repo): pprint.err_exp('to create a new branch do gl branch -c {0}'.format(args.branch)) return False - repo.switch_current_branch(b, move_over=args.move_over) + repo.switch_current_branch(b, move_over=args.move_over, no_stash_ignored=args.no_stash_ignored) pprint.ok('Switched to branch {0}'.format(args.branch)) return True diff --git a/gitless/core.py b/gitless/core.py index 0510672..acd17c7 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -256,13 +256,16 @@ def listall_branches(self): """ return self.git_repo.listall_branches(pygit2.GIT_BRANCH_LOCAL) - def switch_current_branch(self, dst_b, move_over=False): + def switch_current_branch(self, dst_b, move_over=False, no_stash_ignored=False): """Switches to the given branch. Args: dst_b: the destination branch. move_over: if True, then uncommitted changes made in the current branch are moved to the destination branch (defaults to False). + no_stash_ignored: if move_over is False and no_stash_ignored is True, then + stash only non-ignored files. If both move_over and + no_stash_ignored are False, then stash all files, including ignored files. """ if dst_b.is_current: raise ValueError( @@ -346,7 +349,10 @@ def save(b): if not move_over: # Stash - git.stash.save('--all', '--', msg) + if no_stash_ignored: + git.stash.save('--include-untracked', '--', msg) + else: + git.stash.save('--all', '--', msg) def restore(b): s_id, msg = _stash(_stash_msg(b.branch_name)) From 799ce696a056ef44cf04473654cc2ecd03898ec2 Mon Sep 17 00:00:00 2001 From: Clement Cherlin <1463364+Mooninaut@users.noreply.github.com> Date: Wed, 1 Apr 2020 15:51:11 -0400 Subject: [PATCH 175/196] Rename no-stash-ignored to move-ignored for consistency with gitless terminology --- gitless/cli/gl_switch.py | 7 ++++--- gitless/core.py | 9 ++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gitless/cli/gl_switch.py b/gitless/cli/gl_switch.py index 71182c2..aca85bc 100644 --- a/gitless/cli/gl_switch.py +++ b/gitless/cli/gl_switch.py @@ -21,8 +21,9 @@ def parser(subparsers, _): help='move uncomitted changes made in the current branch to the ' 'destination branch', action='store_true') - switch_parser.add_argument('-ni', '--no-stash-ignored', - help='do not stash ignored files, has no effect if --move-over is also set', + switch_parser.add_argument('-mi', '--move-ignored', + help='move ignored files to the destination branch, ' + 'has no effect if --move-over is also set', action='store_true') switch_parser.set_defaults(func=main) @@ -36,6 +37,6 @@ def main(args, repo): pprint.err_exp('to create a new branch do gl branch -c {0}'.format(args.branch)) return False - repo.switch_current_branch(b, move_over=args.move_over, no_stash_ignored=args.no_stash_ignored) + repo.switch_current_branch(b, move_over=args.move_over, move_ignored=args.move_ignored) pprint.ok('Switched to branch {0}'.format(args.branch)) return True diff --git a/gitless/core.py b/gitless/core.py index acd17c7..e0bc323 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -256,16 +256,15 @@ def listall_branches(self): """ return self.git_repo.listall_branches(pygit2.GIT_BRANCH_LOCAL) - def switch_current_branch(self, dst_b, move_over=False, no_stash_ignored=False): + def switch_current_branch(self, dst_b, move_over=False, move_ignored=False): """Switches to the given branch. Args: dst_b: the destination branch. move_over: if True, then uncommitted changes made in the current branch are moved to the destination branch (defaults to False). - no_stash_ignored: if move_over is False and no_stash_ignored is True, then - stash only non-ignored files. If both move_over and - no_stash_ignored are False, then stash all files, including ignored files. + move_ignored: if True, and move_over is False, then ignored files are moved + to the destination branch, but uncommitted changes are not (defaults to False). """ if dst_b.is_current: raise ValueError( @@ -349,7 +348,7 @@ def save(b): if not move_over: # Stash - if no_stash_ignored: + if move_ignored: git.stash.save('--include-untracked', '--', msg) else: git.stash.save('--all', '--', msg) From 516d96187cad6f1e4c5dea6861e625c15be41ca5 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Thu, 6 Aug 2020 16:27:14 -0700 Subject: [PATCH 176/196] remove clint dependency The package is not maintained anymore and we were barely using it --- gitless/cli/gl.py | 6 +-- gitless/cli/gl_branch.py | 6 +-- gitless/cli/gl_status.py | 18 +++---- gitless/cli/pprint.py | 110 +++++++++++++++++++++++++-------------- requirements.txt | 1 - setup.py | 1 - 6 files changed, 83 insertions(+), 59 deletions(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index b39ac46..a7f543f 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -18,8 +18,6 @@ else: from pbs import ErrorReturnCode -from clint.textui import colored - from gitless import core from . import ( @@ -44,9 +42,9 @@ try: repo = core.Repository() try: - colored.DISABLE_COLOR = not repo.config.get_bool('color.ui') + pprint.DISABLE_COLOR = not repo.config.get_bool('color.ui') except pygit2.GitError: - colored.DISABLE_COLOR = ( + prrint.DISABLE_COLOR = ( repo.config['color.ui'] in ['no', 'never']) except (core.NotInRepoError, KeyError): pass diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index c976ad4..90924b9 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -7,8 +7,6 @@ from __future__ import unicode_literals -from clint.textui import colored - from gitless import core from . import helpers, pprint @@ -110,7 +108,7 @@ def _do_list(repo, list_remote, v=False): for b in (repo.lookup_branch(n) for n in sorted(repo.listall_branches())): current_str = '*' if b.is_current else ' ' upstream_str = '(upstream is {0})'.format(b.upstream) if b.upstream else '' - color = colored.green if b.is_current else colored.yellow + color = pprint.green if b.is_current else pprint.yellow pprint.item( '{0} {1} {2}'.format(current_str, color(b.branch_name), upstream_str)) if v: @@ -121,7 +119,7 @@ def _do_list(repo, list_remote, v=False): branches = r.lookupall_branches() if v else r.listall_branches() b_remote = '' if v else r.name + '/' for b in branches: - pprint.item(' {0}'.format(colored.yellow(b_remote + str(b)))) + pprint.item(' {0}'.format(pprint.yellow(b_remote + str(b)))) if v: pprint.item(' ➜ head is {0}'.format(pprint.commit_str(b.head))) diff --git a/gitless/cli/gl_status.py b/gitless/cli/gl_status.py index ea4667c..a6bc69b 100644 --- a/gitless/cli/gl_status.py +++ b/gitless/cli/gl_status.py @@ -9,8 +9,6 @@ import os -from clint.textui import colored - from gitless import core from . import helpers, pprint @@ -30,7 +28,7 @@ def parser(subparsers, repo): def main(args, repo): curr_b = repo.current_branch pprint.msg('On branch {0}, repo-directory {1}'.format( - colored.green(curr_b.branch_name), colored.green('//' + repo.cwd))) + pprint.green(curr_b.branch_name), pprint.green('//' + repo.cwd))) if curr_b.merge_in_progress: pprint.blank() @@ -83,16 +81,16 @@ def _print_tracked_mod_files(tracked_mod_list, relative_paths, repo): root = repo.root for f in tracked_mod_list: exp = '' - color = colored.yellow + color = pprint.yellow if not f.exists_at_head: exp = ' (new file)' - color = colored.green + color = pprint.green elif not f.exists_in_wd: exp = ' (deleted)' - color = colored.red + color = pprint.red elif f.in_conflict: exp = ' (with conflicts)' - color = colored.cyan + color = pprint.cyan fp = os.path.relpath(os.path.join(root, f.fp)) if relative_paths else f.fp if fp == '.': @@ -114,12 +112,12 @@ def _print_untracked_files(untracked_list, relative_paths, repo): root = repo.root for f in untracked_list: exp = '' - color = colored.blue + color = pprint.blue if f.in_conflict: exp = ' (with conflicts)' - color = colored.cyan + color = pprint.cyan elif f.exists_at_head: - color = colored.magenta + color = pprint.magenta if f.exists_in_wd: exp = ' (exists at head)' else: diff --git a/gitless/cli/pprint.py b/gitless/cli/pprint.py index 4503bc2..e91e0e9 100644 --- a/gitless/cli/pprint.py +++ b/gitless/cli/pprint.py @@ -17,8 +17,7 @@ import re import sys -from clint.textui import colored, indent -from clint.textui import puts as clint_puts +DISABLE_COLOR = False from gitless import core @@ -33,23 +32,62 @@ def puts(s='', newline=True, stream=sys.stdout.write): - assert not IS_PY2 or ( - isinstance(s, unicode) or isinstance(s, colored.ColoredString)) + assert not IS_PY2 or isinstance(s, unicode) if IS_PY2: s = s.encode(ENCODING, errors='ignore') - clint_puts(s, newline=newline, stream=stream) + if newline: + s = s + '\n' + stream(s) + + +# Colored strings +RED = '\033[31m' +RED_BOLD = '\033[1;31m' +GREEN = '\033[32m' +GREEN_BOLD = '\033[1;32m' +YELLOW = '\033[33m' +BLUE = '\033[34m' +MAGENTA = '\033[35m' +CYAN = '\033[36m' +CLEAR = '\033[0m' + +def _color(color_code, text): + return '{0}{1}{2}'.format(color_code, text, CLEAR) if should_color() else text + +def should_color(): + # We only output colored lines if the coloring is enabled and we are not being + # piped or redirected + return not DISABLE_COLOR and sys.stdout.isatty() + +def red(text): + return _color(RED, text) + +def green(text): + return _color(GREEN, text) + +def yellow(text): + return _color(YELLOW, text) + +def blue(text): + return _color(BLUE, text) + +def magenta(text): + return _color(MAGENTA, text) + +def cyan(text): + return _color(CYAN, text) # Stdout def ok(text): - puts(colored.green('✔ {0}'.format(text))) + puts(green('✔ {0}'.format(text))) def warn(text): - puts(colored.yellow('! {0}'.format(text))) + puts(yellow('! {0}'.format(text))) def msg(text, stream=sys.stdout.write): @@ -57,13 +95,11 @@ def msg(text, stream=sys.stdout.write): def exp(text, stream=sys.stdout.write): - with indent(2): - puts('➜ {0}'.format(text), stream=stream) + puts(' ➜ {0}'.format(text), stream=stream) def item(i, opt_text='', stream=sys.stdout.write): - with indent(4): - puts('{0}{1}'.format(i, opt_text), stream=stream) + puts(' {0}{1}'.format(i, opt_text), stream=stream) def blank(stream=sys.stdout.write): @@ -77,7 +113,7 @@ def sep(stream=sys.stdout.write): # Err def err(text): - puts(colored.red('✘ {0}'.format(text)), stream=sys.stderr.write) + puts(red('✘ {0}'.format(text)), stream=sys.stderr.write) def err_msg(text): @@ -137,7 +173,7 @@ def commit_str(ci): def commit(ci, compact=False, stream=sys.stdout.write, line_additions=0, line_deletions=0): merge_commit = len(ci.parent_ids) > 1 - color = colored.magenta if merge_commit else colored.yellow + color = magenta if merge_commit else yellow if compact: title = ci.message.splitlines()[0] puts('{0} {1}'.format(color(str(ci.id)[:7]), title), stream=stream) @@ -154,11 +190,10 @@ def commit(ci, compact=False, stream=sys.stdout.write, line_additions=0, line_de puts(color('Date: {0:%c %z}'.format(ci_author_dt)), stream=stream) put_s = lambda num: '' if num == 1 else 's' puts(color('Stats: {0} line{1} added, {2} line{3} removed' - .format(line_additions, put_s(line_additions), + .format(line_additions, put_s(line_additions), line_deletions, put_s(line_deletions))), stream=stream) puts(stream=stream) - with indent(4): - puts(ci.message, stream=stream) + puts(' {0}'.format(ci.message), stream=stream) # Op Callbacks @@ -203,7 +238,7 @@ def diff(patch, stream=sys.stdout.write): new_fp = patch.delta.new_file.path puts('Diff of file "{0}"'.format(old_fp), stream=stream) if old_fp != new_fp: - puts(colored.cyan(' (renamed to {0})'.format(new_fp)), stream=stream) + puts(cyan(' (renamed to {0})'.format(new_fp)), stream=stream) puts(stream=stream) if patch.delta.is_binary: @@ -242,7 +277,7 @@ def diff_totals(total_additions, total_deletions, stream=sys.stdout.write): def _hunk(hunk, stream=sys.stdout.write): - puts(colored.cyan('@@ -{0},{1} +{2},{3} @@'.format( + puts(cyan('@@ -{0},{1} +{2},{3} @@'.format( hunk.old_start, hunk.old_lines, hunk.new_start, hunk.new_lines)), stream=stream) padding = _padding(hunk) @@ -305,21 +340,18 @@ def _format_line(diff_line, padding, bold_delim=None): Returns: a padded and colored version of the diff line with line numbers """ - # Color constants - # We only output colored lines if the coloring is enabled and we are not being - # piped or redirected - if colored.DISABLE_COLOR or not sys.stdout.isatty(): - GREEN = '' - GREEN_BOLD = '' - RED = '' - RED_BOLD = '' - CLEAR = '' + if should_color(): + green = GREEN + green_bold = GREEN_BOLD + red = RED + red_bold = RED_BOLD + clear = CLEAR else: - GREEN = '\033[32m' - GREEN_BOLD = '\033[1;32m' - RED = '\033[31m' - RED_BOLD = '\033[1;31m' - CLEAR = '\033[0m' + green = '' + green_bold = '' + red = '' + red_bold = '' + clear = '' formatted = '' st = diff_line.origin @@ -331,25 +363,25 @@ def _format_line(diff_line, padding, bold_delim=None): formatted = ( str(old_lineno).ljust(padding) + str(new_lineno).ljust(padding) + line) elif st == '+': - formatted = ' ' * padding + GREEN + str(new_lineno).ljust(padding) + formatted = ' ' * padding + green + str(new_lineno).ljust(padding) if not bold_delim: formatted += line else: bold_start, bold_end = bold_delim formatted += ( - line[:bold_start] + GREEN_BOLD + line[bold_start:bold_end] + CLEAR + - GREEN + line[bold_end:]) + line[:bold_start] + green_bold + line[bold_start:bold_end] + clear + + green + line[bold_end:]) elif st == '-': - formatted = RED + str(old_lineno).ljust(padding) + ' ' * padding + formatted = red + str(old_lineno).ljust(padding) + ' ' * padding if not bold_delim: formatted += line else: bold_start, bold_end = bold_delim formatted += ( - line[:bold_start] + RED_BOLD + line[bold_start:bold_end] + CLEAR + - RED + line[bold_end:]) + line[:bold_start] + red_bold + line[bold_start:bold_end] + clear + + red + line[bold_end:]) - return formatted + CLEAR + return formatted + clear def _highlight(line1, line2): diff --git a/requirements.txt b/requirements.txt index dcb9374..f8fbbe5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,5 @@ argcomplete>=1.11.1 pygit2==1.1.1 # requires libgit2 0.99 or 1.0 -clint==0.5.1 sh==1.12.14;sys_platform!='win32' pbs==0.110;sys_platform=='win32' diff --git a/setup.py b/setup.py index d25f6ef..34b7fbf 100755 --- a/setup.py +++ b/setup.py @@ -69,7 +69,6 @@ install_requires=[ # make sure it matches requirements.txt 'pygit2==1.1.1', # requires libgit2 0.99 or 1.0 - 'clint>=0.3.6', 'sh>=1.11' if sys.platform != 'win32' else 'pbs>=0.11', 'argcomplete>=1.11.1' ], From b4755d742084ab553292a51a19f922665e645c5a Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Mon, 10 Aug 2020 21:15:50 -0700 Subject: [PATCH 177/196] remove sh/pbs dependency sh doesn't work on Windows and pbs is no longer supported and doesn't work on Python 3 --- gitless/cli/gl.py | 7 +- gitless/cli/gl_commit.py | 13 +- gitless/core.py | 162 ++++++------- gitless/tests/test_core.py | 76 ++++--- gitless/tests/test_e2e.py | 456 ++++++++++++++++++++----------------- gitless/tests/utils.py | 26 ++- requirements.txt | 2 - setup.py | 8 +- 8 files changed, 379 insertions(+), 371 deletions(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index a7f543f..c5c2fb0 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -13,10 +13,7 @@ import traceback import pygit2 -if sys.platform != 'win32': - from sh import ErrorReturnCode -else: - from pbs import ErrorReturnCode +from subprocess import CalledProcessError from gitless import core @@ -124,7 +121,7 @@ def main(): except (ValueError, pygit2.GitError, core.GlError) as e: pprint.err(e) return ERRORS_FOUND - except ErrorReturnCode as e: + except CalledProcessError as e: pprint.err(e.stderr) return ERRORS_FOUND except: diff --git a/gitless/cli/gl_commit.py b/gitless/cli/gl_commit.py index c339d52..65ea855 100644 --- a/gitless/cli/gl_commit.py +++ b/gitless/cli/gl_commit.py @@ -7,15 +7,6 @@ from __future__ import unicode_literals -import subprocess - -import sys -if sys.platform != 'win32': - from sh import git -else: - from pbs import Command - git = Command('git') - from gitless import core from . import commit_dialog @@ -74,7 +65,7 @@ def main(args, repo): msg = args.m if args.m else commit_dialog.show(commit_files, repo) if not msg.strip(): if partials: - git.reset('HEAD', partials) + core.git('reset', 'HEAD', partials) raise ValueError('Missing commit message') _auto_track(commit_files, curr_b) @@ -121,7 +112,7 @@ def _do_partial_selection(files, curr_b): pprint.warn('Can\'t select segments for deleted file {0}'.format(fp)) continue - subprocess.call(['git', 'add', '-p', fp]) + core.git('add', '-p', fp) # TODO: check that at least one hunk was staged partials.append(fp) diff --git a/gitless/core.py b/gitless/core.py index e0bc323..3f4e318 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -21,19 +21,11 @@ import os import re import shutil - -import pygit2 - - import sys -if sys.platform != 'win32': - from sh import git, ErrorReturnCode -else: - from pbs import Command, ErrorReturnCode - git = Command('git') -git = git.bake('--no-pager') +import pygit2 +from subprocess import run, CalledProcessError ENCODING = getpreferredencoding() or 'utf-8' @@ -84,13 +76,13 @@ def init_repository(url=None, only=None, exclude=None): if not url: repo = pygit2.init_repository(cwd) # We also create an initial root commit - git.commit(allow_empty=True, m='Initialize repository') + git('commit', '--allow-empty', '-m', 'Initialize repository') return repo try: - git.clone(url, cwd) - except ErrorReturnCode as e: - raise GlError(stderr(e)) + git('clone', url, cwd) + except CalledProcessError as e: + raise GlError(e.stderr) # We get all remote branches as well and create local equivalents # Flags: only branches take precedence over exclude branches. @@ -282,17 +274,16 @@ def switch_current_branch(self, dst_b, move_over=False, move_ignored=False): git_repo = self.git_repo au_fp = lambda b: os.path.join( self.path, 'GL_AU_{0}'.format(b.branch_name.replace('/', '_'))) - update_index = git.bake('update-index', _cwd=self.root) def save(b): msg = _stash_msg(b.branch_name) # Save assumed unchanged info - au_fps = ' '.join(b._au_files()) + au_fps = list(b._au_files()) if au_fps: with io.open(au_fp(b), mode='w', encoding=ENCODING) as f: - f.write(au_fps) - update_index('--no-assume-unchanged', au_fps) + f.write(' '.join(au_fps)) + git('update-index', '--no-assume-unchanged', *au_fps, cwd=self.root) if b.merge_in_progress or b.fuse_in_progress: body = {} @@ -349,9 +340,9 @@ def save(b): if not move_over: # Stash if move_ignored: - git.stash.save('--include-untracked', '--', msg) + git('stash', 'save', '--include-untracked', '--', msg) else: - git.stash.save('--all', '--', msg) + git('stash', 'save', '--all', '--', msg) def restore(b): s_id, msg = _stash(_stash_msg(b.branch_name)) @@ -363,14 +354,14 @@ def restore_au_info(): if os.path.exists(au): with io.open(au, mode='r', encoding=ENCODING) as f: au_fps = f.read() - update_index('--assume-unchanged', au_fps) + git('update-index', '--assume-unchanged', *au_fps.split()) os.remove(au) split_msg = msg.split(INFO_SEP) if len(split_msg) == 1: # No op to restore # Pop - git.stash.pop(s_id) + git('stash', 'pop', s_id) # Restore assumed unchanged info restore_au_info() else: # Restore op @@ -387,7 +378,7 @@ def restore_au_info(): self._ref_create('MERGE_HEAD', ref_info['MERGE_HEAD']) # Pop - git.stash.pop(s_id) + git('stash', 'pop', s_id) # Restore conflict info conf_info = body[CONF_INFO] @@ -404,8 +395,8 @@ def restore_au_info(): if index_e[THEIRS]: index_info.append(build_entry(index_e[THEIRS], 3)) - update_index('--unresolve', _in=' '.join(conf_info.keys())) - update_index('--index-info', _in='\n'.join(index_info)) + git('update-index', '--unresolve', _in=' '.join(conf_info.keys())) + git('update-index', '--index-info', _in='\n'.join(index_info)) # Restore msg info merge_msg_fp = os.path.join(self.path, 'MERGE_MSG') @@ -452,8 +443,8 @@ def create(self, name, url): # Check that the given url corresponds to a git repo try: git('ls-remote', '--heads', url) - except ErrorReturnCode as e: - raise ValueError(stderr(e)) + except CalledProcessError as e: + raise ValueError(e.stderr) self.git_remote_collection.create(name, url) @@ -491,10 +482,10 @@ def create_branch(self, name, head): # push tmp_b = self.gl_repo.create_branch('gl_tmp_ref', head) try: - git.push(self.name, '{0}:{1}'.format(tmp_b, name)) + git('push', self.name, '{0}:{1}'.format(tmp_b, name)) return self.lookup_branch(name) - except ErrorReturnCode as e: - raise GlError(stderr(e)) + except CalledProcessError as e: + raise GlError(e.stderr) finally: tmp_b.delete() @@ -505,7 +496,7 @@ def listall_branches(self): to each name. """ regex = re.compile(r'.*\trefs/heads/(.*)') - for head in stdout(git('ls-remote', '--heads', self.name)).splitlines(): + for head in git('ls-remote', '--heads', self.name).splitlines(): yield regex.match(head).group(1) def lookup_branch(self, branch_name): @@ -514,7 +505,7 @@ def lookup_branch(self, branch_name): def lookup_branches(self, branch_names): try: - git.fetch(self.git_remote.name, branch_names) + git('fetch', self.git_remote.name, *branch_names) except: return None remote_branches = [] @@ -524,7 +515,7 @@ def lookup_branches(self, branch_names): # Make another check for the branch being None # As observed in issue : https://github.com/sdg-mit/gitless/issues/211 if git_branch is None: - git.fetch(self.git_remote.name) + git('fetch', self.git_remote.name) git_branch = self.gl_repo.git_repo.lookup_branch( self.git_remote.name + '/' + branch_name, pygit2.GIT_BRANCH_REMOTE) remote_branches.append(RemoteBranch(git_branch, self.gl_repo)) @@ -545,10 +536,10 @@ def create_tag(self, name, commit): # push tmp_t = self.gl_repo.create_tag('gl_tmp_ref', commit) try: - git.push(self.name, 'refs/tags/{0}:refs/tags/{1}'.format(tmp_t, name)) + git('push', self.name, 'refs/tags/{0}:refs/tags/{1}'.format(tmp_t, name)) return self.lookup_tag(name) - except ErrorReturnCode as e: - raise GlError(stderr(e)) + except CalledProcessError as e: + raise GlError(e.stderr) finally: tmp_t.delete() @@ -559,18 +550,18 @@ def listall_tags(self): to each name. """ regex = re.compile(r'.*\trefs/tags/(.*)') - for head in stdout(git('ls-remote', '--tags', self.name)).splitlines(): + for head in git('ls-remote', '--tags', self.name).splitlines(): tag_name = regex.match(head).group(1) if tag_name.endswith('^{}'): continue yield tag_name def lookup_tag(self, tag_name): - tag_info = stdout(git('ls-remote', '--tags', self.name, tag_name)) + tag_info = git('ls-remote', '--tags', self.name, tag_name) if not tag_info: return None # The tag exists in the remote - git.fetch(self.git_remote.name, tag_name) + git('fetch', self.git_remote.name, tag_name) regex = re.compile(r'(.*)\trefs/tags/.*') commit_id = regex.match(tag_info).group(1) @@ -596,9 +587,9 @@ def __init__(self, remote_name, tag_name, commit): def delete(self): try: - git.push(self.remote_name, ':{0}'.format(self.tag_name)) - except ErrorReturnCode as e: - raise GlError(stderr(e)) + git('push', self.remote_name, ':{0}'.format(self.tag_name)) + except CalledProcessError as e: + raise GlError(e.stderr) def __str__(self): return self.remote_name + '/' + self.tag_name @@ -622,9 +613,9 @@ def __init__(self, git_branch, gl_repo): def delete(self): try: - git.push(self.remote_name, ':{0}'.format(self.branch_name)) - except ErrorReturnCode as e: - raise GlError(stderr(e)) + git('push', self.remote_name, ':{0}'.format(self.branch_name)) + except CalledProcessError as e: + raise GlError(e.stderr) @property def target(self): @@ -641,7 +632,7 @@ def history(self, reverse=False): return walker(self.gl_repo.git_repo, self.target, reverse=reverse) def _update(self): - git.fetch(self.remote_name, self.branch_name) + git('fetch', self.remote_name, self.branch_name) self.git_branch = self.gl_repo.git_repo.lookup_branch( self.remote_name + '/' + self.branch_name, pygit2.GIT_BRANCH_REMOTE) @@ -676,7 +667,7 @@ def delete(self): # We also cleanup any stash left s_id, _ = _stash(_stash_msg(self.branch_name)) if s_id: - git.stash.drop(s_id) + git('stash', 'drop', s_id) def rename(self, new_name): self.git_branch.rename(new_name) @@ -794,8 +785,7 @@ def __getattr__(self, name): 'in_conflict']) def _au_files(self): - for f_out in stdout( - git('ls-files', '-v', _cwd=self.gl_repo.root)).splitlines(): + for f_out in git('ls-files', '-v', cwd=self.gl_repo.root).splitlines(): if f_out[0] == 'h': yield f_out[2:].strip() @@ -809,7 +799,7 @@ def status(self): yield self.FileStatus(fp, *self._st_map[git_s]) # status doesn't report au files - au_files = self._au_files() + au_files = list(self._au_files()) if au_files: for fp in au_files: exists_in_wd = os.path.exists(os.path.join(self.gl_repo.root, fp)) @@ -825,7 +815,7 @@ def _status_file(self, path): git_st = self.gl_repo.git_repo.status_file(_get_git_path(path)) root = self.gl_repo.root - cmd_out = stdout(git('ls-files', '-v', '--full-name', path, _cwd=root)) + cmd_out = git('ls-files', '-v', '--full-name', path, cwd=root) is_au = cmd_out and cmd_out[0] == 'h' if is_au: exists_in_wd = os.path.exists(os.path.join(root, path)) @@ -866,8 +856,7 @@ def track_file(self, path): git_path = _get_git_path(path) index.add(git_path) elif is_au: # Case (ii) - git('update-index', '--no-assume-unchanged', path, - _cwd=self.gl_repo.root) + git('update-index', '--no-assume-unchanged', path, cwd=self.gl_repo.root) else: raise GlError('File {0} in unknown status {1}'.format(path, git_st)) @@ -897,8 +886,7 @@ def untrack_file(self, path): git_path = _get_git_path(path) index.remove(git_path) elif not is_au: # Case (ii) - git('update-index', '--assume-unchanged', path, - _cwd=self.gl_repo.root) + git('update-index', '--assume-unchanged', path, cwd=self.gl_repo.root) else: raise GlError('File {0} in unknown status {1}'.format(path, git_st)) @@ -1000,18 +988,18 @@ def merge(self, src, op_cb=None): if result & pygit2.GIT_MERGE_ANALYSIS_UP_TO_DATE: raise GlError('No commits to merge') try: - git.merge(src, '--no-ff') - except ErrorReturnCode as e: - err = stderr(e) + git('merge', str(src), '--no-ff') + except CalledProcessError as e: + err = e.stderr if not 'stash' in err: - raise GlError(stdout(e) + err) + raise GlError(e.stdout + err) if op_cb and op_cb.save: op_cb.save() - git.stash.save('--', _stash_msg_merge(self)) + git('stash', 'save', '--', _stash_msg_merge(self)) try: - git.merge(src, '--no-ff') - except ErrorReturnCode as e: - raise GlError(stdout(e) + stderr(e)) + git('merge', str(src), '--no-ff') + except CalledProcessError as e: + raise GlError(e.stdout + e.stderr) self._state_cleanup() restore_fn = op_cb.restore_ok if op_cb else None @@ -1031,7 +1019,7 @@ def merge_in_progress(self): def abort_merge(self): if not self.merge_in_progress: raise GlError('No merge in progress, nothing to abort') - git.merge(abort=True) + git('merge', '--abort') # Fuse-related methods @@ -1197,7 +1185,7 @@ def _safe_reset(self, cid, msg_fn, save_fn=None): # case either so we need to find an alternative way of doing this) if save_fn: save_fn() - git.stash.save('--', msg_fn(self)) + git('stash', 'save', '--', msg_fn(self)) git_repo.checkout_tree(tree) git_repo.reset(cid, pygit2.GIT_RESET_SOFT) @@ -1205,10 +1193,10 @@ def _safe_restore(self, msg_fn, restore_fn=None): s_id, _ = _stash(msg_fn(self)) if s_id: try: - git.stash.pop(s_id) + git('stash', 'pop', s_id) if restore_fn: restore_fn() - except ErrorReturnCode: + except CalledProcessError: raise ApplyFailedError( 'Uncommitted changes failed to apply onto the new head of the ' 'branch') @@ -1302,13 +1290,14 @@ def publish(self, branch): assert branch.branch_name in self.gl_repo.remotes[ branch.remote_name].listall_branches() - cmd = git.push( - branch.remote_name, - '{0}:{1}'.format(self.branch_name, branch.branch_name)) - if 'Everything up-to-date' in stderr(cmd): + cmd = git_p( + 'push', + branch.remote_name, + '{0}:{1}'.format(self.branch_name, branch.branch_name)) + if 'Everything up-to-date' in cmd.stderr: raise GlError('No commits to publish') - except ErrorReturnCode as e: - err_msg = stderr(e) + except CalledProcessError as e: + err_msg = e.stderr if 'Updates were rejected' in err_msg: raise GlError('There are changes you need to fuse/merge') raise GlError(err_msg) @@ -1341,7 +1330,7 @@ def __init__(self, tag_name, commit): self.commit = commit def delete(self): - git.tag('-d', self.tag_name) + git('tag', '-d', self.tag_name) def __str__(self): return self.tag_name @@ -1351,18 +1340,18 @@ def __str__(self): def _stash(pattern): """Returns the id and msg of the stash that matches the given pattern.""" - out = stdout(git.stash.list(grep=pattern, format='|*|%gd|*|%B|*|')) + out = git('stash', 'list', '--grep', pattern, '--format=|%gd|%s|') if not out: return None, None - result = re.match(r'\|\*\|(stash@\{.+\})\|\*\|(.*)\|\*\|', out, re.DOTALL) + result = re.match(r'\|(stash@\{.+\})\|(.*)\|', out, re.DOTALL) if not result: raise GlError('Unexpected output of git stash: {0}'.format(out)) return result.group(1).strip(), result.group(2).strip() def _stash_msg(name): - return '---gl-{0}---'.format(name) + return 'gl-{0}'.format(name) def _stash_msg_fuse(name): return _stash_msg('fuse-{0}'.format(name)) @@ -1376,19 +1365,14 @@ def _stash_msg_merge(name): OpCb = collections.namedtuple( 'OpCb', ['apply_ok', 'apply_err', 'save', 'restore_ok']) -def stdout(p): - try: - pstdout = p.stdout.decode(ENCODING) - except AttributeError: - pstdout = p.stdout - return pstdout +def git(*args, cwd=None, _in=None): + return git_p(*args, cwd=cwd, _in=_in).stdout -def stderr(p): - try: - pstderr = p.stderr.decode(ENCODING) - except AttributeError: - pstderr = p.stderr - return pstderr +def git_p(*args, cwd=None, _in=None): + p = run( + ['git', '--no-pager', *args], check=True, capture_output=True, cwd=cwd, + input=_in, encoding=ENCODING) + return p def walker(git_repo, target, reverse): flags = pygit2.GIT_SORT_TOPOLOGICAL | pygit2.GIT_SORT_TIME diff --git a/gitless/tests/test_core.py b/gitless/tests/test_core.py index 37df619..3b6a7f8 100644 --- a/gitless/tests/test_core.py +++ b/gitless/tests/test_core.py @@ -13,13 +13,8 @@ import tempfile import unittest import argparse - import sys -if sys.platform != 'win32': - from sh import git -else: - from pbs import Command - git = Command('git') +from subprocess import CalledProcessError from gitless import core from gitless.cli import gl, helpers, gl_track @@ -86,7 +81,7 @@ class TestCore(utils_lib.TestBase): def setUp(self): super(TestCore, self).setUp('gl-core-test') - git.init() + utils_lib.git('init') utils_lib.set_test_config() self.repo = core.Repository() @@ -155,14 +150,16 @@ def setUp(self): utils_lib.write_file(TRACKED_DIR_DIR_FP, contents=TRACKED_FP_CONTENTS_1) utils_lib.write_file( TRACKED_DIR_DIR_FP_WITH_SPACE, contents=TRACKED_FP_CONTENTS_1) - git.add( - TRACKED_FP, TRACKED_FP_WITH_SPACE, - TRACKED_DIR_FP, TRACKED_DIR_FP_WITH_SPACE, - TRACKED_DIR_DIR_FP, TRACKED_DIR_DIR_FP_WITH_SPACE) - git.commit( - TRACKED_FP, TRACKED_FP_WITH_SPACE, - TRACKED_DIR_FP, TRACKED_DIR_FP_WITH_SPACE, - TRACKED_DIR_DIR_FP, TRACKED_DIR_DIR_FP_WITH_SPACE, m='1') + utils_lib.git( + 'add', + TRACKED_FP, TRACKED_FP_WITH_SPACE, + TRACKED_DIR_FP, TRACKED_DIR_FP_WITH_SPACE, + TRACKED_DIR_DIR_FP, TRACKED_DIR_DIR_FP_WITH_SPACE) + utils_lib.git( + 'commit', + TRACKED_FP, TRACKED_FP_WITH_SPACE, + TRACKED_DIR_FP, TRACKED_DIR_FP_WITH_SPACE, + TRACKED_DIR_DIR_FP, TRACKED_DIR_DIR_FP_WITH_SPACE, '-m', '1') utils_lib.write_file(TRACKED_FP, contents=TRACKED_FP_CONTENTS_2) utils_lib.write_file(TRACKED_FP_WITH_SPACE, contents=TRACKED_FP_CONTENTS_2) utils_lib.write_file(TRACKED_DIR_FP, contents=TRACKED_FP_CONTENTS_2) @@ -171,10 +168,11 @@ def setUp(self): utils_lib.write_file(TRACKED_DIR_DIR_FP, contents=TRACKED_FP_CONTENTS_2) utils_lib.write_file( TRACKED_DIR_DIR_FP_WITH_SPACE, contents=TRACKED_FP_CONTENTS_2) - git.commit( - TRACKED_FP, TRACKED_FP_WITH_SPACE, - TRACKED_DIR_FP, TRACKED_DIR_FP_WITH_SPACE, - TRACKED_DIR_DIR_FP, TRACKED_DIR_DIR_FP_WITH_SPACE, m='2') + utils_lib.git( + 'commit', + TRACKED_FP, TRACKED_FP_WITH_SPACE, + TRACKED_DIR_FP, TRACKED_DIR_FP_WITH_SPACE, + TRACKED_DIR_DIR_FP, TRACKED_DIR_DIR_FP_WITH_SPACE, '-m', '2') utils_lib.write_file(UNTRACKED_FP) utils_lib.write_file(UNTRACKED_FP_WITH_SPACE) utils_lib.write_file(UNTRACKED_DIR_FP) @@ -738,17 +736,23 @@ def setUp(self): super(TestFileResolve, self).setUp() # Generate a conflict - git.checkout(b='branch') - utils_lib.write_file(FP_IN_CONFLICT, contents='branch') - utils_lib.write_file(DIR_FP_IN_CONFLICT, contents='branch') - git.add(FP_IN_CONFLICT, DIR_FP_IN_CONFLICT) - git.commit(FP_IN_CONFLICT, DIR_FP_IN_CONFLICT, m='branch') - git.checkout('master') + bname = 'branch' + utils_lib.git('checkout', '-b', bname) + utils_lib.write_file(FP_IN_CONFLICT, contents=bname) + utils_lib.write_file(DIR_FP_IN_CONFLICT, contents=bname) + utils_lib.git('add', FP_IN_CONFLICT, DIR_FP_IN_CONFLICT) + utils_lib.git('commit', FP_IN_CONFLICT, DIR_FP_IN_CONFLICT, '-m', bname) + utils_lib.git('checkout', 'master') utils_lib.write_file(FP_IN_CONFLICT, contents='master') utils_lib.write_file(DIR_FP_IN_CONFLICT, contents='master') - git.add(FP_IN_CONFLICT, DIR_FP_IN_CONFLICT) - git.commit(FP_IN_CONFLICT, DIR_FP_IN_CONFLICT, m='master') - git.merge('branch', _ok_code=[1]) + utils_lib.git('add', FP_IN_CONFLICT, DIR_FP_IN_CONFLICT) + utils_lib.git('commit', FP_IN_CONFLICT, DIR_FP_IN_CONFLICT, '-m', 'master') + try: + utils_lib.git('merge', bname) + raise Exception('The merge should have failed') + except CalledProcessError as e: + # we expect the merge to fail + pass @assert_no_side_effects(TRACKED_FP) def test_resolve_fp_with_no_conflicts(self): @@ -854,14 +858,14 @@ def setUp(self): # Build up an interesting mock repo. utils_lib.write_file(TRACKED_FP, contents=TRACKED_FP_CONTENTS_1) - git.add(TRACKED_FP) - git.commit(TRACKED_FP, m='1') + utils_lib.git('add', TRACKED_FP) + utils_lib.git('commit', TRACKED_FP, '-m', '1') utils_lib.write_file(TRACKED_FP, contents=TRACKED_FP_CONTENTS_2) - git.commit(TRACKED_FP, m='2') + utils_lib.git('commit', TRACKED_FP, '-m', '2') utils_lib.write_file(UNTRACKED_FP, contents=UNTRACKED_FP_CONTENTS) utils_lib.write_file('.gitignore', contents='{0}'.format(IGNORED_FP)) utils_lib.write_file(IGNORED_FP) - git.branch(BRANCH) + utils_lib.git('branch', BRANCH) self.curr_b = self.repo.current_branch @@ -939,7 +943,7 @@ def test_switch_contents_still_there_ignored(self): def test_switch_contents_still_there_tracked_commit(self): utils_lib.write_file(TRACKED_FP, contents='commit') - git.commit(TRACKED_FP, m='comment') + utils_lib.git('commit', TRACKED_FP, '-m', 'comment') self.repo.switch_current_branch(self.repo.lookup_branch(BRANCH)) self.assertEqual(TRACKED_FP_CONTENTS_2, utils_lib.read_file(TRACKED_FP)) self.repo.switch_current_branch(self.repo.lookup_branch('master')) @@ -1038,8 +1042,8 @@ def setUp(self): super(TestRemoteSync, self).setUp() utils_lib.write_file('foo', contents='foo') - git.add('foo') - git.commit('foo', m='msg') + utils_lib.git('add', 'foo') + utils_lib.git('commit', 'foo', '-m', 'msg') self.repo.remotes.create('remote', self.remote_path) self.remote = self.repo.remotes['remote'] @@ -1053,7 +1057,7 @@ def test_sync_changes(self): # It is not a ff so it should fail self.assertRaises(core.GlError, current_b.publish, remote_branch) # Get the changes - git.rebase(remote_branch) + utils_lib.git('rebase', str(remote_branch)) # Retry (this time it should work) current_b.publish(remote_branch) diff --git a/gitless/tests/test_e2e.py b/gitless/tests/test_e2e.py index c478143..17deaf2 100755 --- a/gitless/tests/test_e2e.py +++ b/gitless/tests/test_e2e.py @@ -11,16 +11,8 @@ import os import re import time - +from subprocess import CalledProcessError import sys -if sys.platform != 'win32': - from sh import ErrorReturnCode, Command -else: - from pbs import ErrorReturnCode, Command - -gl = Command('gl') -git = Command('git') - from gitless.tests import utils @@ -34,18 +26,18 @@ class TestEndToEnd(utils.TestBase): def setUp(self): super(TestEndToEnd, self).setUp('gl-e2e-test') - gl.init() + utils.gl('init') # Disable colored output so that we don't need to worry about ANSI escape # codes - git.config('color.ui', False) + utils.git('config', 'color.ui', 'False') # Disable paging so that we don't have to use sh's _tty_out option, which is # not available on pbs if sys.platform != 'win32': - git.config('core.pager', 'cat') + utils.git('config', 'core.pager', 'cat') else: # On Windows, we need to call 'type' through cmd.exe (with 'cmd'). The /C # is so that the command window gets closed after 'type' finishes - git.config('core.pager', 'cmd /C type') + utils.git('config', 'core.pager', 'cmd /C type') utils.set_test_config() @@ -58,11 +50,11 @@ def test_not_in_repo(self): def assert_not_in_repo(*cmds): for cmd in cmds: self.assertRaisesRegexp( - ErrorReturnCode, 'not in a Gitless\'s repository', cmd) + CalledProcessError, 'not in a Gitless\'s repository', utils.gl, cmd) assert_not_in_repo( - gl.status, gl.diff, gl.commit, gl.branch, gl.merge, gl.fuse, gl.remote, - gl.publish, gl.history) + 'status', 'diff', 'commit', 'branch', 'merge', 'fuse', 'remote', + 'publish', 'history') class TestBasic(TestEndToEnd): @@ -70,91 +62,104 @@ class TestBasic(TestEndToEnd): def test_basic_functionality(self): utils.write_file('file1', 'Contents of file1') # Track - gl.track('file1') - self.assertRaises(ErrorReturnCode, gl.track, 'file1') - self.assertRaises(ErrorReturnCode, gl.track, 'non-existent') + utils.gl('track', 'file1') + self.assertRaises(CalledProcessError, utils.gl, 'track', 'file1') + self.assertRaises(CalledProcessError, utils.gl, 'track', 'non-existent') # Untrack - gl.untrack('file1') - self.assertRaises(ErrorReturnCode, gl.untrack, 'file1') - self.assertRaises(ErrorReturnCode, gl.untrack, 'non-existent') + utils.gl('untrack', 'file1') + self.assertRaises(CalledProcessError, utils.gl, 'untrack', 'file1') + self.assertRaises(CalledProcessError, utils.gl, 'untrack', 'non-existent') # Commit - gl.track('file1') - gl.commit(m='file1 commit') - self.assertRaises(ErrorReturnCode, gl.commit, m='nothing to commit') + utils.gl('track', 'file1') + utils.gl('commit', '-m', 'file1 commit') + self.assertRaises( + CalledProcessError, utils.gl, 'commit', '-m', 'nothing to commit') # History - if 'file1 commit' not in utils.stdout(gl.history()): + if 'file1 commit' not in utils.gl('history'): self.fail('Commit didn\'t appear in history') # Branch # Make some changes to file1 and branch out utils.write_file('file1', 'New contents of file1') - gl.branch(c='branch1') - gl.switch('branch1') + utils.gl('branch', '-c', 'branch1') + utils.gl('switch', 'branch1') if 'New' in utils.read_file('file1'): self.fail('Branch not independent!') # Switch back to master branch, check that contents are the same as before. - gl.switch('master') + utils.gl('switch', 'master') if 'New' not in utils.read_file('file1'): self.fail('Branch not independent!') - out = utils.stdout(gl.branch()) + out = utils.gl('branch') if '* master' not in out: self.fail('Branch status output wrong: {0}'.format(out)) if 'branch1' not in out: self.fail('Branch status output wrong: {0}'.format(out)) - gl.branch(c='branch2') - gl.branch(c='branch-conflict1') - gl.branch(c='branch-conflict2') - gl.commit(m='New contents commit') + utils.gl('branch', '-c', 'branch2') + utils.gl('branch', '-c', 'branch-conflict1') + utils.gl('branch', '-c', 'branch-conflict2') + utils.gl('commit', '-m', 'New contents commit') # Fuse - gl.switch('branch1') - self.assertRaises(ErrorReturnCode, gl.fuse) # no upstream set + utils.gl('switch', 'branch1') + self.assertRaises(CalledProcessError, utils.gl, 'fuse') # no upstream set try: - gl.fuse('master') - except ErrorReturnCode as e: + utils.gl('fuse', 'master') + except CalledProcessError as e: self.fail(utils.stderr(e)) - out = utils.stdout(gl.history()) + out = utils.gl('history') if 'file1 commit' not in out: self.fail(out) # Merge - gl.switch('branch2') - self.assertRaises(ErrorReturnCode, gl.merge) # no upstream set - gl.merge('master') - out = utils.stdout(gl.history()) + utils.gl('switch', 'branch2') + self.assertRaises(CalledProcessError, utils.gl, 'merge') # no upstream set + utils.gl('merge', 'master') + out = utils.gl('history') if 'file1 commit' not in out: self.fail(out) # Conflicting fuse - gl.switch('branch-conflict1') + utils.gl('switch', 'branch-conflict1') utils.write_file('file1', 'Conflicting changes to file1') - gl.commit(m='changes in branch-conflict1') - err = utils.stderr(gl.fuse('master', _ok_code=[1])) - if 'conflict' not in err: - self.fail(err) - out = utils.stdout(gl.status()) + utils.gl('commit', '-m', 'changes in branch-conflict1') + try: + utils.gl('fuse', 'master') + except CalledProcessError as e: + # expected + err = e.stderr + if 'conflict' not in err: + self.fail(err) + + out = utils.gl('status') if 'file1 (with conflicts)' not in out: self.fail(out) # Try aborting - gl.fuse('--abort') - out = utils.stdout(gl.status()) + utils.gl('fuse', '--abort') + out = utils.gl('status') if 'file1' in out: self.fail(out) # Ok, now let's fix the conflicts - err = utils.stderr(gl.fuse('master', _ok_code=[1])) - if 'conflict' not in err: - self.fail(err) - out = utils.stdout(gl.status()) + try: + utils.gl('fuse', 'master') + except CalledProcessError as e: + # expected + err = e.stderr + if 'conflict' not in err: + self.fail(err) + + out = utils.gl('status') if 'file1 (with conflicts)' not in out: self.fail(out) utils.write_file('file1', 'Fixed conflicts!') - self.assertRaises(ErrorReturnCode, gl.commit, m='resolve not called') - self.assertRaises(ErrorReturnCode, gl.resolve, 'non-existent') - gl.resolve('file1') - gl.commit(m='fixed conflicts') + self.assertRaises( + CalledProcessError, utils.gl, 'commit', '-m', 'resolve not called') + self.assertRaises( + CalledProcessError, utils.gl, 'resolve', 'non-existent') + utils.gl('resolve', 'file1') + utils.gl('commit', '-m', 'fixed conflicts') class TestCommit(TestEndToEnd): @@ -170,64 +175,71 @@ def setUp(self): utils.write_file(self.TRACKED_FP) utils.write_file(self.DIR_TRACKED_FP) utils.write_file(self.UNTRACKED_FP) - gl.track(self.TRACKED_FP, self.DIR_TRACKED_FP) + utils.gl('track', self.TRACKED_FP, self.DIR_TRACKED_FP) def test_commit(self): - gl.commit(m='msg') + utils.gl('commit', '-m', 'msg') self.__assert_commit(self.TRACKED_FP, self.DIR_TRACKED_FP) def test_commit_relative(self): os.chdir(self.DIR) - gl.commit(m='msg') + utils.gl('commit', '-m', 'msg') self.__assert_commit(self.TRACKED_FP, self.DIR_TRACKED_FP) def test_commit_only(self): - gl.commit(self.TRACKED_FP, m="msg") + utils.gl('commit', self.TRACKED_FP, '-m', 'msg') self.__assert_commit(self.TRACKED_FP) def test_commit_only_relative(self): os.chdir(self.DIR) - self.assertRaises(ErrorReturnCode, gl.commit, self.TRACKED_FP, "-m='msg'") - gl.commit('../' + self.TRACKED_FP, m='msg') + self.assertRaises( + CalledProcessError, utils.gl, 'commit', self.TRACKED_FP, '-m', 'msg') + utils.gl('commit', '../' + self.TRACKED_FP, '-m', 'msg') self.__assert_commit(self.TRACKED_FP) def test_commit_only_untrack(self): - gl.commit("-m='msg'", self.UNTRACKED_FP) + utils.gl('commit', '-m', 'msg', self.UNTRACKED_FP) self.__assert_commit(self.UNTRACKED_FP) def test_commit_only_untrack_relative(self): os.chdir(self.DIR) - self.assertRaises(ErrorReturnCode, gl.commit, self.UNTRACKED_FP, m='msg') - gl.commit('../' + self.UNTRACKED_FP, m='msg') + self.assertRaises( + CalledProcessError, utils.gl, 'commit', self.UNTRACKED_FP, '-m', 'msg') + utils.gl('commit', '../' + self.UNTRACKED_FP, '-m', 'msg') self.__assert_commit(self.UNTRACKED_FP) def test_commit_include(self): - gl.commit("-m='msg'", include=self.UNTRACKED_FP) + utils.gl('commit', '-m', 'msg', '--include', self.UNTRACKED_FP) self.__assert_commit( self.TRACKED_FP, self.DIR_TRACKED_FP, self.UNTRACKED_FP) def test_commit_exclude_include(self): - gl.commit("-m='msg'", include=self.UNTRACKED_FP, exclude=self.TRACKED_FP) + utils.gl( + 'commit', '-m', 'msg', + '--include', self.UNTRACKED_FP, '--exclude', self.TRACKED_FP) self.__assert_commit(self.UNTRACKED_FP, self.DIR_TRACKED_FP) def test_commit_no_files(self): self.assertRaises( - ErrorReturnCode, gl.commit, '--exclude', - self.TRACKED_FP, self.DIR_TRACKED_FP, m='msg') - self.assertRaises(ErrorReturnCode, gl.commit, 'non-existent', m='msg') + CalledProcessError, utils.gl, 'commit', '--exclude', + self.TRACKED_FP, self.DIR_TRACKED_FP, '-m', 'msg') + self.assertRaises( + CalledProcessError, utils.gl, 'commit', 'non-existent', '-m', 'msg') self.assertRaises( - ErrorReturnCode, gl.commit, m='msg', exclude='non-existent') + CalledProcessError, utils.gl, 'commit', '-m', 'msg', + '--exclude', 'non-existent') self.assertRaises( - ErrorReturnCode, gl.commit, m='msg', include='non-existent') + CalledProcessError, utils.gl, 'commit', '-m', 'msg', + '--include', 'non-existent') def test_commit_dir(self): fp = 'dir/f' utils.write_file(fp) - gl.commit(fp, m='msg') + utils.gl('commit', fp, '-m', 'msg') self.__assert_commit('dir/f') def __assert_commit(self, *expected_committed): - h = utils.stdout(gl.history(v=True)) + h = utils.gl('history', '-v') for fp in expected_committed: if fp not in h: self.fail('{0} was apparently not committed!'.format(fp)) @@ -248,11 +260,11 @@ def setUp(self): super(TestStatus, self).setUp() utils.write_file(self.TRACKED_DIR_FP) utils.write_file(self.UNTRACKED_DIR_FP) - gl.commit(self.TRACKED_DIR_FP, m='commit') + utils.gl('commit', self.TRACKED_DIR_FP, '-m', 'commit') def test_status_relative(self): utils.write_file(self.TRACKED_DIR_FP, contents='some modifications') - st = utils.stdout(gl.status()) + st = utils.gl('status') if self.TRACKED_DIR_FP not in st: self.fail() if self.UNTRACKED_DIR_FP not in st: @@ -260,7 +272,7 @@ def test_status_relative(self): os.chdir(self.DIR) - st = utils.stdout(gl.status()) + st = utils.gl('status') rel_tracked = os.path.relpath(self.TRACKED_DIR_FP, self.DIR) rel_untracked = os.path.relpath(self.UNTRACKED_DIR_FP, self.DIR) if (self.TRACKED_DIR_FP in st) or (rel_tracked not in st): @@ -277,36 +289,40 @@ class TestBranch(TestEndToEnd): def setUp(self): super(TestBranch, self).setUp() utils.write_file('f') - gl.commit('f', m='commit') + utils.gl('commit', 'f', '-m', 'commit') def test_create(self): - gl.branch(c=self.BRANCH_1) - self.assertRaises(ErrorReturnCode, gl.branch, c=self.BRANCH_1) - self.assertRaises(ErrorReturnCode, gl.branch, c='evil*named*branch') - if self.BRANCH_1 not in utils.stdout(gl.branch()): + utils.gl('branch', '-c', self.BRANCH_1) + self.assertRaises( + CalledProcessError, utils.gl, 'branch', '-c', self.BRANCH_1) + self.assertRaises( + CalledProcessError, utils.gl, 'branch', '-c', 'evil*named*branch') + if self.BRANCH_1 not in utils.gl('branch'): self.fail() def test_remove(self): - gl.branch(c=self.BRANCH_1) - gl.switch(self.BRANCH_1) - self.assertRaises(ErrorReturnCode, gl.branch, d=self.BRANCH_1, _in='y') - gl.branch(c=self.BRANCH_2) - gl.switch(self.BRANCH_2) - gl.branch(d=self.BRANCH_1, _in='n') - gl.branch(d=self.BRANCH_1, _in='y') - if self.BRANCH_1 in utils.stdout(gl.branch()): + utils.gl('branch', '-c', self.BRANCH_1) + utils.gl('switch', self.BRANCH_1) + self.assertRaises( + CalledProcessError, utils.gl, 'branch', '-d', self.BRANCH_1, _in='y') + utils.gl('branch', '-c', self.BRANCH_2) + utils.gl('switch', self.BRANCH_2) + utils.gl('branch', '-d', self.BRANCH_1, _in='n') + utils.gl('branch', '-d', self.BRANCH_1, _in='y') + if self.BRANCH_1 in utils.gl('branch'): self.fail() def test_upstream(self): - self.assertRaises(ErrorReturnCode, gl.branch, '-uu') - self.assertRaises(ErrorReturnCode, gl.branch, '-su', 'non-existent') + self.assertRaises(CalledProcessError, utils.gl, 'branch', '-uu') + self.assertRaises( + CalledProcessError, utils.gl, 'branch', '-su', 'non-existent') self.assertRaises( - ErrorReturnCode, gl.branch, '-su', 'non-existent/non-existent') + CalledProcessError, utils.gl, 'branch', '-su', 'non-existent/non-existent') def test_list(self): - gl.branch(c=self.BRANCH_1) - gl.branch(c=self.BRANCH_2) - branch_out = utils.stdout(gl.branch()) + utils.gl('branch', '-c', self.BRANCH_1) + utils.gl('branch', '-c', self.BRANCH_2) + branch_out = utils.gl('branch') self.assertTrue( branch_out.find(self.BRANCH_1) < branch_out.find(self.BRANCH_2)) @@ -319,26 +335,27 @@ class TestTag(TestEndToEnd): def setUp(self): super(TestTag, self).setUp() utils.write_file('f') - gl.commit('f', m='commit') + utils.gl('commit', 'f', '-m', 'commit') def test_create(self): - gl.tag(c=self.TAG_1) - self.assertRaises(ErrorReturnCode, gl.tag, c=self.TAG_1) - self.assertRaises(ErrorReturnCode, gl.tag, c='evil*named*tag') - if self.TAG_1 not in utils.stdout(gl.tag()): + utils.gl('tag', '-c', self.TAG_1) + self.assertRaises(CalledProcessError, utils.gl, 'tag', '-c', self.TAG_1) + self.assertRaises( + CalledProcessError, utils.gl, 'tag', '-c', 'evil*named*tag') + if self.TAG_1 not in utils.gl('tag'): self.fail() def test_remove(self): - gl.tag(c=self.TAG_1) - gl.tag(d=self.TAG_1, _in='n') - gl.tag(d=self.TAG_1, _in='y') - if self.TAG_1 in utils.stdout(gl.tag()): + utils.gl('tag', '-c', self.TAG_1) + utils.gl('tag', '-d', self.TAG_1, _in='n') + utils.gl('tag', '-d', self.TAG_1, _in='y') + if self.TAG_1 in utils.gl('tag'): self.fail() def test_list(self): - gl.tag(c=self.TAG_1) - gl.tag(c=self.TAG_2) - tag_out = utils.stdout(gl.tag()) + utils.gl('tag', '-c', self.TAG_1) + utils.gl('tag', '-c', self.TAG_2) + tag_out = utils.gl('tag') self.assertTrue( tag_out.find(self.TAG_1) < tag_out.find(self.TAG_2)) @@ -354,24 +371,28 @@ def setUp(self): super(TestDiffFile, self).setUp() utils.write_file(self.TRACKED_FP) utils.write_file(self.DIR_TRACKED_FP) - gl.commit(self.TRACKED_FP, self.DIR_TRACKED_FP, m='commit') + utils.gl('commit', self.TRACKED_FP, self.DIR_TRACKED_FP, '-m', 'commit') utils.write_file(self.UNTRACKED_FP) def test_empty_diff(self): - if 'No files to diff' not in utils.stdout(gl.diff()): + if 'No files to diff' not in utils.gl('diff'): self.fail() def test_diff_nonexistent_fp(self): - err = utils.stderr(gl.diff('file', _ok_code=[1])) - if 'doesn\'t exist' not in err: - self.fail() + try: + utils.gl('diff', 'file') + except CalledProcessError as e: + # expected + err = e.stderr + if 'doesn\'t exist' not in err: + self.fail() def test_basic_diff(self): utils.write_file(self.TRACKED_FP, contents='contents') - out1 = utils.stdout(gl.diff()) + out1 = utils.gl('diff') if '+contents' not in out1: self.fail() - out2 = utils.stdout(gl.diff(self.TRACKED_FP)) + out2 = utils.gl('diff', self.TRACKED_FP) if '+contents' not in out2: self.fail() self.assertEqual(out1, out2) @@ -380,20 +401,20 @@ def test_basic_diff_relative(self): utils.write_file(self.TRACKED_FP, contents='contents_tracked') utils.write_file(self.DIR_TRACKED_FP, contents='contents_dir_tracked') os.chdir(self.DIR) - out1 = utils.stdout(gl.diff()) + out1 = utils.gl('diff') if '+contents_tracked' not in out1: self.fail() if '+contents_dir_tracked' not in out1: self.fail() rel_dir_tracked_fp = os.path.relpath(self.DIR_TRACKED_FP, self.DIR) - out2 = utils.stdout(gl.diff(rel_dir_tracked_fp)) + out2 = utils.gl('diff', rel_dir_tracked_fp) if '+contents_dir_tracked' not in out2: self.fail() def test_diff_dir(self): fp = 'dir/dir/f' utils.write_file(fp, contents='contents') - out = utils.stdout(gl.diff(fp)) + out = utils.gl('diff', fp) if '+contents' not in out: self.fail() @@ -403,10 +424,10 @@ def test_diff_non_ascii(self): return contents = '’◕‿◕’©Ä☺’ಠ_ಠ’' utils.write_file(self.TRACKED_FP, contents=contents) - out1 = utils.stdout(gl.diff()) + out1 = utils.gl('diff') if '+' + contents not in out1: self.fail('out is ' + out1) - out2 = utils.stdout(gl.diff(self.TRACKED_FP)) + out2 = utils.gl('diff', self.TRACKED_FP) if '+' + contents not in out2: self.fail('out is ' + out2) self.assertEqual(out1, out2) @@ -426,31 +447,35 @@ def setUp(self): def create_commits(branch_name, fp): self.commits[branch_name] = [] utils.append_to_file(fp, contents='contents {0}\n'.format(0)) - out = utils.stdout(gl.commit(m='ci 0 in {0}'.format(branch_name), inc=fp)) + out = utils.gl( + 'commit', '-m', 'ci 0 in {0}'.format(branch_name), '--include', fp) self.commits[branch_name].append( re.search(r'Commit Id: (\S*)', out, re.UNICODE).group(1)) for i in range(1, self.COMMITS_NUMBER): utils.append_to_file(fp, contents='contents {0}\n'.format(i)) - out = utils.stdout(gl.commit(m='ci {0} in {1}'.format(i, branch_name))) + out = utils.gl('commit', '-m', 'ci {0} in {1}'.format(i, branch_name)) self.commits[branch_name].append( re.search(r'Commit Id: (\S*)', out, re.UNICODE).group(1)) - gl.branch(c=self.OTHER) + utils.gl('branch', '-c', self.OTHER) create_commits('master', self.MASTER_FILE) - gl.switch(self.OTHER) + try: + utils.gl('switch', self.OTHER) + except CalledProcessError as e: + raise Exception(e.stderr) create_commits(self.OTHER, self.OTHER_FILE) - gl.switch('master') + utils.gl('switch', 'master') class TestFuse(TestOp): def __assert_history(self, expected): - out = utils.stdout(gl.history()) + out = utils.gl('history') cids = list(reversed(re.findall(r'ci (.*) in (\S*)', out, re.UNICODE))) self.assertItemsEqual( cids, expected, 'cids is ' + text(cids) + ' exp ' + text(expected)) - st_out = utils.stdout(gl.status()) + st_out = utils.gl('status') self.assertFalse('fuse' in st_out) def __build(self, branch_name, cids=None): @@ -459,50 +484,54 @@ def __build(self, branch_name, cids=None): return [(text(ci), branch_name) for ci in cids] def test_basic(self): - gl.fuse(self.OTHER) + utils.gl('fuse', self.OTHER) self.__assert_history(self.__build(self.OTHER) + self.__build('master')) def test_only_errors(self): - self.assertRaises(ErrorReturnCode, gl.fuse, self.OTHER, o='non-existent-id') self.assertRaises( - ErrorReturnCode, gl.fuse, self.OTHER, o=self.commits['master'][1]) + CalledProcessError, utils.gl, 'fuse', self.OTHER, '-o', 'non-existent-id') + self.assertRaises( + CalledProcessError, utils.gl, 'fuse', self.OTHER, + '-o', self.commits['master'][1]) def test_only_one(self): - gl.fuse(self.OTHER, o=self.commits[self.OTHER][0]) + utils.gl('fuse', self.OTHER, '-o', self.commits[self.OTHER][0]) self.__assert_history( self.__build(self.OTHER, cids=[0]) + self.__build('master')) def test_only_some(self): - gl.fuse(self.OTHER, '-o', self.commits[self.OTHER][:2]) + utils.gl('fuse', self.OTHER, '-o', *self.commits[self.OTHER][:2]) self.__assert_history( self.__build(self.OTHER, [0, 1]) + self.__build('master')) def test_exclude_errors(self): - self.assertRaises(ErrorReturnCode, gl.fuse, self.OTHER, e='non-existent-id') self.assertRaises( - ErrorReturnCode, gl.fuse, self.OTHER, e=self.commits['master'][1]) + CalledProcessError, utils.gl, 'fuse', self.OTHER, '-e', 'non-existent-id') + self.assertRaises( + CalledProcessError, utils.gl, 'fuse', self.OTHER, + '-e', self.commits['master'][1]) def test_exclude_one(self): last_ci = self.COMMITS_NUMBER - 1 - gl.fuse(self.OTHER, e=self.commits[self.OTHER][last_ci]) + utils.gl('fuse', self.OTHER, '-e', self.commits[self.OTHER][last_ci]) self.__assert_history( self.__build(self.OTHER, range(0, last_ci)) + self.__build('master')) def test_exclude_some(self): - gl.fuse(self.OTHER, '-e', self.commits[self.OTHER][1:]) + utils.gl('fuse', self.OTHER, '-e', *self.commits[self.OTHER][1:]) self.__assert_history( self.__build(self.OTHER, cids=[0]) + self.__build('master')) def test_ip_dp(self): - gl.fuse(self.OTHER, insertion_point='dp') + utils.gl('fuse', self.OTHER, '--insertion-point', 'dp') self.__assert_history(self.__build(self.OTHER) + self.__build('master')) def test_ip_head(self): - gl.fuse(self.OTHER, insertion_point='HEAD') + utils.gl('fuse', self.OTHER, '--insertion-point', 'HEAD') self.__assert_history(self.__build('master') + self.__build(self.OTHER)) def test_ip_commit(self): - gl.fuse(self.OTHER, insertion_point=self.commits['master'][1]) + utils.gl('fuse', self.OTHER, '--insertion-point', self.commits['master'][1]) self.__assert_history( self.__build('master', [0, 1]) + self.__build(self.OTHER) + self.__build('master', range(2, self.COMMITS_NUMBER))) @@ -510,88 +539,91 @@ def test_ip_commit(self): def test_conflicts(self): def trigger_conflicts(): self.assertRaisesRegexp( - ErrorReturnCode, 'conflicts', gl.fuse, - self.OTHER, e=self.commits[self.OTHER][0]) + CalledProcessError, 'conflicts', utils.gl, 'fuse', + self.OTHER, '-e', self.commits[self.OTHER][0]) # Abort trigger_conflicts() - gl.fuse('-a') + utils.gl('fuse', '-a') self.__assert_history(self.__build('master')) # Fix conflicts trigger_conflicts() - gl.resolve(self.OTHER_FILE) - gl.commit(m='ci 1 in other') + utils.gl('resolve', self.OTHER_FILE) + utils.gl('commit', '-m', 'ci 1 in other') self.__assert_history( self.__build(self.OTHER, range(1, self.COMMITS_NUMBER)) + self.__build('master')) def test_conflicts_switch(self): - gl.switch('other') + utils.gl('switch', 'other') utils.write_file(self.OTHER_FILE, contents='uncommitted') - gl.switch('master') + utils.gl('switch', 'master') try: - gl.fuse(self.OTHER, e=self.commits[self.OTHER][0]) + utils.gl('fuse', self.OTHER, '-e', self.commits[self.OTHER][0]) self.fail() - except ErrorReturnCode: + except CalledProcessError: pass # Switch - gl.switch('other') + utils.gl('switch', 'other') self.__assert_history(self.__build('other')) - st_out = utils.stdout(gl.status()) + st_out = utils.gl('status') self.assertTrue('fuse' not in st_out) self.assertTrue('conflict' not in st_out) - gl.switch('master') - st_out = utils.stdout(gl.status()) + utils.gl('switch', 'master') + st_out = utils.gl('status') self.assertTrue('fuse' in st_out) self.assertTrue('conflict' in st_out) # Check that we are able to complete the fuse after switch - gl.resolve(self.OTHER_FILE) - gl.commit(m='ci 1 in other') + utils.gl('resolve', self.OTHER_FILE) + utils.gl('commit', '-m', 'ci 1 in other') self.__assert_history( self.__build(self.OTHER, range(1, self.COMMITS_NUMBER)) + self.__build('master')) - gl.switch('other') + utils.gl('switch', 'other') self.assertEqual('uncommitted', utils.read_file(self.OTHER_FILE)) def test_conflicts_multiple(self): - gl.branch(c='tmp', divergent_point='HEAD~2') - gl.switch('tmp') + utils.gl('branch', '-c', 'tmp', '--divergent-point', 'HEAD~2') + utils.gl('switch', 'tmp') utils.append_to_file(self.MASTER_FILE, contents='conflict') - gl.commit(m='will conflict 0') + utils.gl('commit', '-m', 'will conflict 0') utils.append_to_file(self.MASTER_FILE, contents='conflict') - gl.commit(m='will conflict 1') + utils.gl('commit', '-m', 'will conflict 1') - self.assertRaisesRegexp(ErrorReturnCode, 'conflicts', gl.fuse, 'master') - gl.resolve(self.MASTER_FILE) self.assertRaisesRegexp( - ErrorReturnCode, 'conflicts', gl.commit, m='ci 0 in tmp') - gl.resolve(self.MASTER_FILE) - gl.commit(m='ci 1 in tmp') # this one should finalize the fuse + CalledProcessError, 'conflicts', utils.gl, 'fuse', 'master') + utils.gl('resolve', self.MASTER_FILE) + self.assertRaisesRegexp( + CalledProcessError, 'conflicts', utils.gl, 'commit', '-m', 'ci 0 in tmp') + utils.gl('resolve', self.MASTER_FILE) + utils.gl('commit', '-m', 'ci 1 in tmp') # this one should finalize the fuse self.__assert_history( self.__build('master') + self.__build('tmp', range(2))) def test_conflicts_multiple_uncommitted_changes(self): - gl.branch(c='tmp', divergent_point='HEAD~2') - gl.switch('tmp') + utils.gl('branch', '-c', 'tmp', '--divergent-point', 'HEAD~2') + utils.gl('switch', 'tmp') utils.append_to_file(self.MASTER_FILE, contents='conflict') - gl.commit(m='will conflict 0') + utils.gl('commit', '-m', 'will conflict 0') utils.append_to_file(self.MASTER_FILE, contents='conflict') - gl.commit(m='will conflict 1') + utils.gl('commit', '-m', 'will conflict 1') utils.write_file(self.MASTER_FILE, contents='uncommitted') - self.assertRaisesRegexp(ErrorReturnCode, 'conflicts', gl.fuse, 'master') - gl.resolve(self.MASTER_FILE) self.assertRaisesRegexp( - ErrorReturnCode, 'conflicts', gl.commit, m='ci 0 in tmp') - gl.resolve(self.MASTER_FILE) + CalledProcessError, 'conflicts', utils.gl, 'fuse', 'master') + utils.gl('resolve', self.MASTER_FILE) + self.assertRaisesRegexp( + CalledProcessError, 'conflicts', utils.gl, 'commit', '-m', 'ci 0 in tmp') + utils.gl('resolve', self.MASTER_FILE) self.assertRaisesRegexp( - ErrorReturnCode, 'failed to apply', gl.commit, m='ci 1 in tmp') + CalledProcessError, 'failed to apply', utils.gl, + 'commit', '-m', 'ci 1 in tmp') self.__assert_history( self.__build('master') + self.__build('tmp', range(2))) @@ -599,48 +631,48 @@ def test_conflicts_multiple_uncommitted_changes(self): def test_nothing_to_fuse(self): self.assertRaisesRegexp( - ErrorReturnCode, 'No commits to fuse', gl.fuse, - self.OTHER, '-e', *self.commits[self.OTHER]) + CalledProcessError, 'No commits to fuse', utils.gl, 'fuse', + self.OTHER, '-e', *self.commits[self.OTHER]) def test_ff(self): - gl.branch(c='tmp', divergent_point='HEAD~2') - gl.switch('tmp') + utils.gl('branch', '-c', 'tmp', '--divergent-point', 'HEAD~2') + utils.gl('switch', 'tmp') - gl.fuse('master') + utils.gl('fuse', 'master') self.__assert_history(self.__build('master')) def test_ff_ip_head(self): - gl.branch(c='tmp', divergent_point='HEAD~2') - gl.switch('tmp') + utils.gl('branch', '-c', 'tmp', '--divergent-point', 'HEAD~2') + utils.gl('switch', 'tmp') - gl.fuse('master', insertion_point='HEAD') + utils.gl('fuse', 'master', '--insertion-point', 'HEAD') self.__assert_history(self.__build('master')) def test_uncommitted_changes(self): utils.write_file(self.MASTER_FILE, contents='uncommitted') utils.write_file('master_untracked', contents='uncommitted') - gl.fuse(self.OTHER) + utils.gl('fuse', self.OTHER) self.assertEqual('uncommitted', utils.read_file(self.MASTER_FILE)) self.assertEqual('uncommitted', utils.read_file('master_untracked')) def test_uncommitted_tracked_changes_that_conflict(self): - gl.branch(c='tmp', divergent_point='HEAD~1') - gl.switch('tmp') + utils.gl('branch', '-c', 'tmp', '--divergent-point', 'HEAD~1') + utils.gl('switch', 'tmp') utils.write_file(self.MASTER_FILE, contents='uncommitted') self.assertRaisesRegexp( - ErrorReturnCode, 'failed to apply', gl.fuse, - 'master', insertion_point='HEAD') + CalledProcessError, 'failed to apply', utils.gl, 'fuse', + 'master', '--insertion-point', 'HEAD') contents = utils.read_file(self.MASTER_FILE) self.assertTrue('uncommitted' in contents) self.assertTrue('contents 2' in contents) def test_uncommitted_tracked_changes_that_conflict_append(self): - gl.branch(c='tmp', divergent_point='HEAD~1') - gl.switch('tmp') + utils.gl('branch', '-c', 'tmp', '--divergent-point', 'HEAD~1') + utils.gl('switch', 'tmp') utils.append_to_file(self.MASTER_FILE, contents='uncommitted') self.assertRaisesRegexp( - ErrorReturnCode, 'failed to apply', gl.fuse, - 'master', insertion_point='HEAD') + CalledProcessError, 'failed to apply', utils.gl, 'fuse', + 'master', '--insertion-point', 'HEAD') contents = utils.read_file(self.MASTER_FILE) self.assertTrue('uncommitted' in contents) self.assertTrue('contents 2' in contents) @@ -648,9 +680,9 @@ def test_uncommitted_tracked_changes_that_conflict_append(self): # def test_uncommitted_untracked_changes_that_conflict(self): # utils.write_file(self.OTHER_FILE, contents='uncommitted in master') # try: -# gl.fuse(self.OTHER) +# utils.gl('fuse', self.OTHER) # self.fail() -# except ErrorReturnCode as e: +# except CalledProcessError as e: # self.assertTrue('failed to apply' in utils.stderr(e)) @@ -659,26 +691,26 @@ class TestMerge(TestOp): def test_uncommitted_changes(self): utils.write_file(self.MASTER_FILE, contents='uncommitted') utils.write_file('master_untracked', contents='uncommitted') - gl.merge(self.OTHER) + utils.gl('merge', self.OTHER) self.assertEqual('uncommitted', utils.read_file(self.MASTER_FILE)) self.assertEqual('uncommitted', utils.read_file('master_untracked')) def test_uncommitted_tracked_changes_that_conflict(self): - gl.branch(c='tmp', divergent_point='HEAD~1') - gl.switch('tmp') + utils.gl('branch', '-c', 'tmp', '--divergent-point', 'HEAD~1') + utils.gl('switch', 'tmp') utils.write_file(self.MASTER_FILE, contents='uncommitted') self.assertRaisesRegexp( - ErrorReturnCode, 'failed to apply', gl.merge, 'master') + CalledProcessError, 'failed to apply', utils.gl, 'merge', 'master') contents = utils.read_file(self.MASTER_FILE) self.assertTrue('uncommitted' in contents) self.assertTrue('contents 2' in contents) def test_uncommitted_tracked_changes_that_conflict_append(self): - gl.branch(c='tmp', divergent_point='HEAD~1') - gl.switch('tmp') + utils.gl('branch', '-c', 'tmp', '--divergent-point', 'HEAD~1') + utils.gl('switch', 'tmp') utils.append_to_file(self.MASTER_FILE, contents='uncommitted') self.assertRaisesRegexp( - ErrorReturnCode, 'failed to apply', gl.merge, 'master') + CalledProcessError, 'failed to apply', utils.gl, 'merge', 'master') contents = utils.read_file(self.MASTER_FILE) self.assertTrue('uncommitted' in contents) self.assertTrue('contents 2' in contents) @@ -701,11 +733,11 @@ def assert_status_performance(): MAX_TOLERANCE = 100 t = time.time() - gl.status() + utils.gl('status') gl_t = time.time() - t t = time.time() - git.status() + utils.git('status') git_t = time.time() - t self.assertTrue( @@ -716,28 +748,28 @@ def assert_status_performance(): assert_status_performance() # Track all files, repeat logging.info('Doing a massive git add, this might take a while') - git.add('.') + utils.git('add', '.') logging.info('Done') assert_status_performance() def test_branch_switch_performance(self): MAX_TOLERANCE = 100 - gl.commit('f1', m='commit') + utils.gl('commit', 'f1', '-m', 'commit') t = time.time() - gl.branch(c='develop') - gl.switch('develop') + utils.gl('branch', '-c', 'develop') + utils.gl('switch', 'develop') gl_t = time.time() - t # go back to previous state - gl.switch('master') + utils.gl('switch', 'master') # do the same for git t = time.time() - git.branch('gitdev') - git.stash.save('--all') - git.checkout('gitdev') + utils.git('branch', 'gitdev') + utils.git('stash', 'save', '--all') + utils.git('checkout', 'gitdev') git_t = time.time() - t self.assertTrue( diff --git a/gitless/tests/utils.py b/gitless/tests/utils.py index d4d676c..cf3ef5a 100644 --- a/gitless/tests/utils.py +++ b/gitless/tests/utils.py @@ -18,11 +18,7 @@ import tempfile import unittest -if sys.platform != 'win32': - from sh import git, ErrorReturnCode -else: - from pbs import ErrorReturnCode, Command - git = Command('git') +from subprocess import run, CalledProcessError IS_PY2 = sys.version_info[0] == 2 @@ -59,7 +55,7 @@ def assertRaisesRegexp(self, exc, r, fun, *args, **kwargs): fun(*args, **kwargs) self.fail('Exception not raised') except exc as e: - msg = stderr(e) if isinstance(e, ErrorReturnCode) else str(e) + msg = e.stderr if isinstance(e, CalledProcessError) else str(e) if not re.search(r, msg): self.fail('No "{0}" found in "{1}"'.format(r, msg)) @@ -107,8 +103,8 @@ def append_to_file(fp, contents=''): def set_test_config(): - git.config('user.name', 'test') - git.config('user.email', 'test@test.com') + git('config', 'user.name', 'test') + git('config', 'user.email', 'test@test.com') def read_file(fp): @@ -117,12 +113,18 @@ def read_file(fp): return ret -def stdout(p): - return p.stdout.decode(ENCODING) +def git(*args, cwd=None, _in=None): + p = run( + ['git', '--no-pager', *args], capture_output=True, check=True, cwd=cwd, + input=_in, encoding=ENCODING) + return p.stdout -def stderr(p): - return p.stderr.decode(ENCODING) +def gl(*args, cwd=None, _in=None): + p = run( + ['gl', *args], capture_output=True, check=True, cwd=cwd, + input=_in, encoding=ENCODING) + return p.stdout # Private functions diff --git a/requirements.txt b/requirements.txt index f8fbbe5..8785d99 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,5 +2,3 @@ argcomplete>=1.11.1 pygit2==1.1.1 # requires libgit2 0.99 or 1.0 -sh==1.12.14;sys_platform!='win32' -pbs==0.110;sys_platform=='win32' diff --git a/setup.py b/setup.py index 34b7fbf..95c099f 100755 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ # Build helper if sys.argv[-1] == 'gl-build': - from sh import pyinstaller + from subprocess import run import shutil import tarfile import platform @@ -28,8 +28,9 @@ version, platform.system().lower(), platform.machine()) print('running pyinstaller...') - pyinstaller( - 'gl.spec', clean=True, distpath=rel, _out=sys.stdout, _err=sys.stderr) + run( + ['pyinstaller', 'gl.spec', '--clean', '--distpath', rel], + stdout=sys.stdout, stderr=sys.stderr) print('success!! gl binary should be at {0}/gl'.format(rel)) print('creating tar.gz file') @@ -69,7 +70,6 @@ install_requires=[ # make sure it matches requirements.txt 'pygit2==1.1.1', # requires libgit2 0.99 or 1.0 - 'sh>=1.11' if sys.platform != 'win32' else 'pbs>=0.11', 'argcomplete>=1.11.1' ], license='MIT', From c211e240c3f2d789b08b7984336752180e045017 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Wed, 12 Aug 2020 11:49:56 -0700 Subject: [PATCH 178/196] drop support for Python 2 --- .appveyor.yml | 18 +++++++++++++----- .travis.yml | 6 ++---- README.md | 23 +++++++---------------- gitless/cli/commit_dialog.py | 9 +-------- gitless/cli/file_cmd.py | 2 -- gitless/cli/gl.py | 2 -- gitless/cli/gl_branch.py | 2 -- gitless/cli/gl_checkout.py | 2 -- gitless/cli/gl_commit.py | 2 -- gitless/cli/gl_diff.py | 2 -- gitless/cli/gl_fuse.py | 2 -- gitless/cli/gl_history.py | 2 -- gitless/cli/gl_init.py | 2 -- gitless/cli/gl_merge.py | 2 -- gitless/cli/gl_publish.py | 2 -- gitless/cli/gl_remote.py | 2 -- gitless/cli/gl_resolve.py | 2 -- gitless/cli/gl_status.py | 2 -- gitless/cli/gl_switch.py | 2 -- gitless/cli/gl_tag.py | 2 -- gitless/cli/gl_track.py | 2 -- gitless/cli/gl_untrack.py | 2 -- gitless/cli/helpers.py | 2 -- gitless/cli/pprint.py | 8 -------- gitless/core.py | 6 ------ gitless/tests/test_core.py | 6 ++---- gitless/tests/test_e2e.py | 4 +--- gitless/tests/utils.py | 17 ----------------- setup.py | 2 -- tox.ini | 7 ------- 30 files changed, 26 insertions(+), 118 deletions(-) delete mode 100644 tox.ini diff --git a/.appveyor.yml b/.appveyor.yml index aa0f705..8c965d5 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,10 +1,18 @@ # Based on pygit2's appveyor config environment: matrix: - - GENERATOR: 'Visual Studio 10' - PYTHON: 'C:\Python27\python.exe' - - GENERATOR: 'Visual Studio 10 Win64' - PYTHON: 'C:\Python27-x64\python.exe' + - GENERATOR: 'Visual Studio 14' + PYTHON: 'C:\Python36\python.exe' + - GENERATOR: 'Visual Studio 14 Win64' + PYTHON: 'C:\Python36-x64\python.exe' + - GENERATOR: 'Visual Studio 14' + PYTHON: 'C:\Python37\python.exe' + - GENERATOR: 'Visual Studio 14 Win64' + PYTHON: 'C:\Python37-x64\python.exe' + - GENERATOR: 'Visual Studio 14' + PYTHON: 'C:\Python38\python.exe' + - GENERATOR: 'Visual Studio 14 Win64' + PYTHON: 'C:\Python38-x64\python.exe' init: - cmd: '%PYTHON% -m pip install -U nose wheel' @@ -21,7 +29,7 @@ test_script: &$env:PYTHON -m pip install -r requirements.txt . # 'gl' is installed in Python Scripts directory $env:PATH += ";$(Split-Path $env:PYTHON)\Scripts" - &$env:PYTHON setup.py nosetests --logging-level=WARN --with-xunit + &$env:PYTHON setup.py nosetests --logging-level=WARN --with-xunit if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) } # upload results to AppVeyor $wc = New-Object 'System.Net.WebClient' diff --git a/.travis.yml b/.travis.yml index 5aa579b..851161e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,10 @@ addons: packages: - snapcraft python: -- '2.7' -- '3.4' -- '3.5' - '3.6' - '3.7' -- 'pypy3.5' +- '3.8' +- 'pypy3.6' env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib before_install: ./.travis.sh install: pip install -r requirements.txt . diff --git a/README.md b/README.md index 8b63295..ce1e5b2 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ Install Note that the installation **won't interfere** with your Git installation in any way, you can keep using Git, and switch between Git and Gitless seamlessly. -We currently require Git (1.7.12+) to be installed (but this requirement is -going to disappear soon once we finish with our migration to [pygit2](https://github.com/libgit2/pygit2)). +We currently require Git (1.7.12+) to be installed, but this requirement is +going to disappear soon once we finish with our migration to [pygit2](https://github.com/libgit2/pygit2). ### Binary release (macOS and Linux only) @@ -47,11 +47,7 @@ the Python Package Index). ### Installing from source -To install from source you need to have Python (2.7, 3.2+ or PyPy) -installed. - -Note to Windows users: Python 3 is not supported yet, -see [#146](https://github.com/sdg-mit/gitless/issues/146) for more info. +To install from source you need to have Python 3.6+ installed. Additionally, you need to [install pygit2]( http://www.pygit2.org/install.html "pygit2 install"). @@ -66,10 +62,7 @@ and do: If you are a Python fan you might find it easier to install Gitless via the Python Package Index. To do this, you need to have -Python (2.7, 3.2+ or PyPy) installed. - -Note to Windows users: Python 3 is not supported yet, -see [#146](https://github.com/sdg-mit/gitless/issues/146) for more info. +Python 3.6+ installed. Additionally, you need to [install pygit2]( http://www.pygit2.org/install.html "pygit2 install"). @@ -119,7 +112,7 @@ code, here are some useful things to know: `cd` to the repo root and do `./setup.py develop`. This will install the `gl` command with a symlink to your source files. You can make changes to your code and run `gl` to test them. -- We follow (to some extent) the [Google Python Style Guide]( +- We follow, to some extent, the [Google Python Style Guide]( https://google.github.io/styleguide/pyguide.html "Google Python Style Guide"). Before submitting code, take a few seconds to look at the style guide and the @@ -127,9 +120,7 @@ Gitless's code so that your edits are consistent with the codebase - Finally, if you don't want [Travis]( https://travis-ci.org/sdg-mit/gitless "Travis") to -be mad at you, check that tests pass in Python 2.7 and 3.2+. Tests can be run with: +be mad at you, check that tests pass in Python 3.6+. Tests can be run with: ``` - pip install nose - nosetests # run tests other than end-to-end tests - nosetests ./gitless/tests/test_e2e.py # run end-to-end tests + python -m unittest discover gitless/tests ``` diff --git a/gitless/cli/commit_dialog.py b/gitless/cli/commit_dialog.py index 891fd42..872f6ce 100644 --- a/gitless/cli/commit_dialog.py +++ b/gitless/cli/commit_dialog.py @@ -5,8 +5,6 @@ """Gitless's commit dialog.""" -from __future__ import unicode_literals - import io from locale import getpreferredencoding import os @@ -18,7 +16,6 @@ from . import pprint -IS_PY2 = sys.version_info[0] == 2 ENCODING = getpreferredencoding() or 'utf-8' _COMMIT_FILE = 'GL_COMMIT_EDIT_MSG' @@ -35,11 +32,7 @@ def show(files, repo): Returns: The commit msg. """ - if IS_PY2: - # wb because we use pprint to write - cf = io.open(_commit_file(repo), mode='wb') - else: - cf = io.open(_commit_file(repo), mode='w', encoding=ENCODING) + cf = io.open(_commit_file(repo), mode='w', encoding=ENCODING) curr_b = repo.current_branch if curr_b.merge_in_progress or curr_b.fuse_in_progress: diff --git a/gitless/cli/file_cmd.py b/gitless/cli/file_cmd.py index 9e633b0..d184319 100644 --- a/gitless/cli/file_cmd.py +++ b/gitless/cli/file_cmd.py @@ -5,8 +5,6 @@ """Helper module for gl_{track, untrack, resolve}.""" -from __future__ import unicode_literals - from . import helpers, pprint diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index c5c2fb0..3723ac3 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -5,8 +5,6 @@ """gl - Main Gitless's command. Dispatcher to the other cmds.""" -from __future__ import unicode_literals - import sys import argparse import argcomplete diff --git a/gitless/cli/gl_branch.py b/gitless/cli/gl_branch.py index 90924b9..bd3b2bb 100644 --- a/gitless/cli/gl_branch.py +++ b/gitless/cli/gl_branch.py @@ -5,8 +5,6 @@ """gl branch - List, create, edit or delete branches.""" -from __future__ import unicode_literals - from gitless import core from . import helpers, pprint diff --git a/gitless/cli/gl_checkout.py b/gitless/cli/gl_checkout.py index 5d39a98..b0c143b 100644 --- a/gitless/cli/gl_checkout.py +++ b/gitless/cli/gl_checkout.py @@ -5,8 +5,6 @@ """gl checkout - Checkout committed versions of files.""" -from __future__ import unicode_literals - from gitless import core from . import helpers, pprint diff --git a/gitless/cli/gl_commit.py b/gitless/cli/gl_commit.py index 65ea855..58798da 100644 --- a/gitless/cli/gl_commit.py +++ b/gitless/cli/gl_commit.py @@ -5,8 +5,6 @@ """gl commit - Record changes in the local repository.""" -from __future__ import unicode_literals - from gitless import core from . import commit_dialog diff --git a/gitless/cli/gl_diff.py b/gitless/cli/gl_diff.py index 4268ead..36346d0 100644 --- a/gitless/cli/gl_diff.py +++ b/gitless/cli/gl_diff.py @@ -5,8 +5,6 @@ """gl diff - Show changes in files.""" -from __future__ import unicode_literals - import os import tempfile diff --git a/gitless/cli/gl_fuse.py b/gitless/cli/gl_fuse.py index 5dffc35..864f2c9 100644 --- a/gitless/cli/gl_fuse.py +++ b/gitless/cli/gl_fuse.py @@ -5,8 +5,6 @@ """gl fuse - Fuse the divergent changes of a branch onto the current branch.""" -from __future__ import unicode_literals - from gitless import core from . import helpers, pprint diff --git a/gitless/cli/gl_history.py b/gitless/cli/gl_history.py index a1be6ab..a2a1108 100644 --- a/gitless/cli/gl_history.py +++ b/gitless/cli/gl_history.py @@ -5,8 +5,6 @@ """gl history - Show commit history.""" -from __future__ import unicode_literals - import os import tempfile diff --git a/gitless/cli/gl_init.py b/gitless/cli/gl_init.py index 9efc4af..a248f62 100644 --- a/gitless/cli/gl_init.py +++ b/gitless/cli/gl_init.py @@ -5,8 +5,6 @@ """gl init - Create an empty repo or make a clone.""" -from __future__ import unicode_literals - import os from gitless import core diff --git a/gitless/cli/gl_merge.py b/gitless/cli/gl_merge.py index 63cb1a3..118de4d 100644 --- a/gitless/cli/gl_merge.py +++ b/gitless/cli/gl_merge.py @@ -5,8 +5,6 @@ """gl merge - Merge the divergent changes of one branch onto another.""" -from __future__ import unicode_literals - from gitless import core from . import helpers, pprint diff --git a/gitless/cli/gl_publish.py b/gitless/cli/gl_publish.py index a968b15..19b6227 100644 --- a/gitless/cli/gl_publish.py +++ b/gitless/cli/gl_publish.py @@ -5,8 +5,6 @@ """gl publish - Publish commits upstream.""" -from __future__ import unicode_literals - from . import helpers, pprint diff --git a/gitless/cli/gl_remote.py b/gitless/cli/gl_remote.py index 0a08921..bb549f9 100644 --- a/gitless/cli/gl_remote.py +++ b/gitless/cli/gl_remote.py @@ -5,8 +5,6 @@ """gl remote - List, create, edit or delete remotes.""" -from __future__ import unicode_literals - from . import pprint diff --git a/gitless/cli/gl_resolve.py b/gitless/cli/gl_resolve.py index bbbb6e8..742182e 100644 --- a/gitless/cli/gl_resolve.py +++ b/gitless/cli/gl_resolve.py @@ -5,8 +5,6 @@ """gl resolve - Mark a file with conflicts as resolved.""" -from __future__ import unicode_literals - from . import file_cmd diff --git a/gitless/cli/gl_status.py b/gitless/cli/gl_status.py index a6bc69b..1be3398 100644 --- a/gitless/cli/gl_status.py +++ b/gitless/cli/gl_status.py @@ -5,8 +5,6 @@ """gl status - Show the status of files in the repo.""" -from __future__ import unicode_literals - import os from gitless import core diff --git a/gitless/cli/gl_switch.py b/gitless/cli/gl_switch.py index aca85bc..01a09a7 100644 --- a/gitless/cli/gl_switch.py +++ b/gitless/cli/gl_switch.py @@ -5,8 +5,6 @@ """gl switch - Switch branches.""" -from __future__ import unicode_literals - from . import pprint diff --git a/gitless/cli/gl_tag.py b/gitless/cli/gl_tag.py index ecb407b..789a7b6 100644 --- a/gitless/cli/gl_tag.py +++ b/gitless/cli/gl_tag.py @@ -5,8 +5,6 @@ """gl tag - List, create, edit or delete tags.""" -from __future__ import unicode_literals - from gitless import core from . import helpers, pprint diff --git a/gitless/cli/gl_track.py b/gitless/cli/gl_track.py index 801cf43..c22b8f8 100644 --- a/gitless/cli/gl_track.py +++ b/gitless/cli/gl_track.py @@ -5,8 +5,6 @@ """gl track - Start tracking changes to files.""" -from __future__ import unicode_literals - from . import file_cmd diff --git a/gitless/cli/gl_untrack.py b/gitless/cli/gl_untrack.py index 124d4ca..670db33 100644 --- a/gitless/cli/gl_untrack.py +++ b/gitless/cli/gl_untrack.py @@ -5,8 +5,6 @@ """gl untrack - Stop tracking changes to files.""" -from __future__ import unicode_literals - from . import file_cmd diff --git a/gitless/cli/helpers.py b/gitless/cli/helpers.py index 8ea3caf..61efd63 100644 --- a/gitless/cli/helpers.py +++ b/gitless/cli/helpers.py @@ -5,8 +5,6 @@ """Some helpers for commands.""" -from __future__ import unicode_literals - import argparse import os import subprocess diff --git a/gitless/cli/pprint.py b/gitless/cli/pprint.py index e91e0e9..1c84766 100644 --- a/gitless/cli/pprint.py +++ b/gitless/cli/pprint.py @@ -5,8 +5,6 @@ """Module for pretty printing Gitless output.""" -from __future__ import unicode_literals - try: from StringIO import StringIO except ImportError: @@ -27,15 +25,10 @@ '######') -IS_PY2 = sys.version_info[0] == 2 ENCODING = getpreferredencoding() or 'utf-8' def puts(s='', newline=True, stream=sys.stdout.write): - assert not IS_PY2 or isinstance(s, unicode) - - if IS_PY2: - s = s.encode(ENCODING, errors='ignore') if newline: s = s + '\n' stream(s) @@ -284,7 +277,6 @@ def _hunk(hunk, stream=sys.stdout.write): del_line, add_line, maybe_bold, saw_add = None, None, False, False for diff_line in hunk.lines: - assert not IS_PY2 or isinstance(diff_line.content, unicode) st = diff_line.origin if st == '-' and not maybe_bold: diff --git a/gitless/core.py b/gitless/core.py index 3f4e318..258d887 100644 --- a/gitless/core.py +++ b/gitless/core.py @@ -5,15 +5,9 @@ """Gitless's library.""" -from __future__ import unicode_literals - import collections import errno import io -try: - from itertools import izip as zip -except ImportError: - pass import itertools import json diff --git a/gitless/tests/test_core.py b/gitless/tests/test_core.py index 3b6a7f8..8002018 100644 --- a/gitless/tests/test_core.py +++ b/gitless/tests/test_core.py @@ -5,8 +5,6 @@ """Core unit tests.""" -from __future__ import unicode_literals - from functools import wraps import os import shutil @@ -1019,7 +1017,7 @@ class TestRemoteList(TestRemote): def test_list_all(self): self.remotes.create('remote1', self.remote_path) self.remotes.create('remote2', self.remote_path) - self.assertItemsEqual( + self.assertCountEqual( ['remote1', 'remote2'], [r.name for r in self.remotes]) @@ -1061,7 +1059,7 @@ def test_sync_changes(self): # Retry (this time it should work) current_b.publish(remote_branch) - self.assertItemsEqual( + self.assertCountEqual( ['master', REMOTE_BRANCH], self.remote.listall_branches()) self.assertEqual( master_head_before.id, self.remote.lookup_branch('master').head.id) diff --git a/gitless/tests/test_e2e.py b/gitless/tests/test_e2e.py index 17deaf2..a2daeb3 100755 --- a/gitless/tests/test_e2e.py +++ b/gitless/tests/test_e2e.py @@ -5,8 +5,6 @@ """End-to-end test.""" -from __future__ import unicode_literals - import logging import os import re @@ -472,7 +470,7 @@ class TestFuse(TestOp): def __assert_history(self, expected): out = utils.gl('history') cids = list(reversed(re.findall(r'ci (.*) in (\S*)', out, re.UNICODE))) - self.assertItemsEqual( + self.assertCountEqual( cids, expected, 'cids is ' + text(cids) + ' exp ' + text(expected)) st_out = utils.gl('status') diff --git a/gitless/tests/utils.py b/gitless/tests/utils.py index cf3ef5a..a1d9d28 100644 --- a/gitless/tests/utils.py +++ b/gitless/tests/utils.py @@ -5,8 +5,6 @@ """Utility library for tests.""" -from __future__ import unicode_literals - import io from locale import getpreferredencoding import logging @@ -21,7 +19,6 @@ from subprocess import run, CalledProcessError -IS_PY2 = sys.version_info[0] == 2 ENCODING = getpreferredencoding() or 'utf-8' @@ -38,18 +35,6 @@ def tearDown(self): """Removes the temporary dir.""" rmtree(self.path) - # Python 2/3 compatibility - def assertItemsEqual(self, actual, expected, msg=None): - try: - return super(TestBase, self).assertItemsEqual(actual, expected, msg=msg) - except AttributeError: - try: - # Checks that actual and expected have the same elements in the same - # number, regardless of their order - return super(TestBase, self).assertCountEqual(actual, expected, msg=msg) - except AttributeError: - return self.assertEqual(sorted(actual), sorted(expected), msg=msg) - def assertRaisesRegexp(self, exc, r, fun, *args, **kwargs): try: fun(*args, **kwargs) @@ -131,8 +116,6 @@ def gl(*args, cwd=None, _in=None): def _x_file(x, fp, contents=''): - assert not IS_PY2 or isinstance(contents, unicode) - if not contents: contents = fp dirs, _ = os.path.split(fp) diff --git a/setup.py b/setup.py index 95c099f..5e3c0e7 100755 --- a/setup.py +++ b/setup.py @@ -79,8 +79,6 @@ 'License :: OSI Approved :: MIT License', 'Natural Language :: English', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Version Control'], entry_points={ 'console_scripts': [ diff --git a/tox.ini b/tox.ini deleted file mode 100644 index d3ee346..0000000 --- a/tox.ini +++ /dev/null @@ -1,7 +0,0 @@ -[tox] -envlist = py27, py34 -[testenv] -deps=nose -commands= - nosetests - nosetests gitless/tests/test_e2e.py From a877cd4665125f0cea8d33617fbf66adf83a16f2 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Wed, 12 Aug 2020 12:16:45 -0700 Subject: [PATCH 179/196] drop support for python 3.6 --- .appveyor.yml | 4 ---- .travis.yml | 2 -- README.md | 6 +++--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 8c965d5..fe09e13 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,10 +1,6 @@ # Based on pygit2's appveyor config environment: matrix: - - GENERATOR: 'Visual Studio 14' - PYTHON: 'C:\Python36\python.exe' - - GENERATOR: 'Visual Studio 14 Win64' - PYTHON: 'C:\Python36-x64\python.exe' - GENERATOR: 'Visual Studio 14' PYTHON: 'C:\Python37\python.exe' - GENERATOR: 'Visual Studio 14 Win64' diff --git a/.travis.yml b/.travis.yml index 851161e..4038b57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,10 +5,8 @@ addons: packages: - snapcraft python: -- '3.6' - '3.7' - '3.8' -- 'pypy3.6' env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib before_install: ./.travis.sh install: pip install -r requirements.txt . diff --git a/README.md b/README.md index ce1e5b2..792016d 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ the Python Package Index). ### Installing from source -To install from source you need to have Python 3.6+ installed. +To install from source you need to have Python 3.7+ installed. Additionally, you need to [install pygit2]( http://www.pygit2.org/install.html "pygit2 install"). @@ -62,7 +62,7 @@ and do: If you are a Python fan you might find it easier to install Gitless via the Python Package Index. To do this, you need to have -Python 3.6+ installed. +Python 3.7+ installed. Additionally, you need to [install pygit2]( http://www.pygit2.org/install.html "pygit2 install"). @@ -120,7 +120,7 @@ Gitless's code so that your edits are consistent with the codebase - Finally, if you don't want [Travis]( https://travis-ci.org/sdg-mit/gitless "Travis") to -be mad at you, check that tests pass in Python 3.6+. Tests can be run with: +be mad at you, check that tests pass in Python 3.7+. Tests can be run with: ``` python -m unittest discover gitless/tests ``` From d3cbce238f5c81790d8def2f7e23747b2319e794 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Wed, 12 Aug 2020 13:31:45 -0700 Subject: [PATCH 180/196] drop develop branch from CI files we don't use a dev branch anymore --- .appveyor.yml | 1 - .travis.yml | 4 +--- requirements.txt | 2 +- snap/snapcraft.yaml | 1 + 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index fe09e13..a2ce2b9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -34,4 +34,3 @@ test_script: branches: only: - master - - develop diff --git a/.travis.yml b/.travis.yml index 4038b57..d4b05c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,12 +14,10 @@ before_script: - git config --global user.name "travis-test" - git config --global user.email "travis@test.com" script: -- nosetests --logging-level=WARN -- nosetests gitless/tests/test_e2e.py --logging-level=WARN +- python -m unittest discover gitless/tests branches: only: - master - - develop jobs: include: - stage: Pack snap diff --git a/requirements.txt b/requirements.txt index 8785d99..86362d4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -# make sure to update setup.py +# make sure to update setup.py if you make any changes to this file argcomplete>=1.11.1 pygit2==1.1.1 # requires libgit2 0.99 or 1.0 diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 68d352f..e23fb19 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -13,6 +13,7 @@ description: | Git), you can always fall back on Git. And of course your coworkers you share a repo with need never know that you're not a Git aficionado. +# Base snap for snapd that is based on Ubuntu 18.04 base: core18 grade: devel # 'stable' for stable/candidate upload From c0994843bcd33cf29a3c43b614adcfa565ff1ac8 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Wed, 12 Aug 2020 13:52:48 -0700 Subject: [PATCH 181/196] bump libgit2/pygit2 versions let's see if this fixes the snap build --- .travis.sh | 2 +- requirements.txt | 2 +- setup.py | 4 ++-- snap/snapcraft.yaml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.sh b/.travis.sh index f262871..e95df82 100755 --- a/.travis.sh +++ b/.travis.sh @@ -2,7 +2,7 @@ cd ~ -git clone --depth=1 -b maint/v0.99 https://github.com/libgit2/libgit2.git +git clone --depth=1 -b maint/v1.0.1 https://github.com/libgit2/libgit2.git cd libgit2/ mkdir build && cd build diff --git a/requirements.txt b/requirements.txt index 86362d4..86b228a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ # make sure to update setup.py if you make any changes to this file argcomplete>=1.11.1 -pygit2==1.1.1 # requires libgit2 0.99 or 1.0 +pygit2==1.2.0 # requires libgit2 1.0.x diff --git a/setup.py b/setup.py index 5e3c0e7..d00a03c 100755 --- a/setup.py +++ b/setup.py @@ -68,8 +68,8 @@ url='http://gitless.com', packages=['gitless', 'gitless.cli'], install_requires=[ - # make sure it matches requirements.txt - 'pygit2==1.1.1', # requires libgit2 0.99 or 1.0 + # make sure install_requires is consistent with requirements.txt + 'pygit2==1.2.0', # requires libgit2 1.0.x 'argcomplete>=1.11.1' ], license='MIT', diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index e23fb19..e3c30bc 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -29,7 +29,7 @@ parts: libgit2: plugin: cmake # https://www.pygit2.org/install.html#version-numbers - source: https://github.com/libgit2/libgit2/archive/v0.99.0.tar.gz + source: https://github.com/libgit2/libgit2/archive/v1.0.1.tar.gz build-packages: - libssl-dev From 613eb373212ccca64457ee531e0270e5604f8916 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Wed, 12 Aug 2020 16:36:59 -0700 Subject: [PATCH 182/196] update badges --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 792016d..07d6fef 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ Gitless [![PyPI version](https://img.shields.io/pypi/v/gitless.svg)](https://pypi.org/project/gitless "PyPI version") [![Homebrew Formula](https://img.shields.io/homebrew/v/gitless.svg)](https://formulae.brew.sh/formula/gitless "Homebrew Formula") -[![Travis Build Status](https://img.shields.io/travis/sdg-mit/gitless/master.svg)](https://travis-ci.org/sdg-mit/gitless "Travis Build Status") -[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/sdg-mit/gitless?svg=true)](https://ci.appveyor.com/project/spderosso/gitless "AppVeyor Build Status") +[![Travis Build Status](https://img.shields.io/travis/gitless-vcs/gitless/master.svg)](https://travis-ci.org/gitless-vcs/gitless "Travis Build Status") +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/gitless-vcs/gitless?svg=true)](https://ci.appveyor.com/project/spderosso/gitless-11bfm "AppVeyor Build Status") [Gitless](http://gitless.com "Gitless's website") is an experimental version control system built on top of Git. Many @@ -119,7 +119,7 @@ Before submitting code, take a few seconds to look at the style guide and the Gitless's code so that your edits are consistent with the codebase - Finally, if you don't want [Travis]( - https://travis-ci.org/sdg-mit/gitless "Travis") to + https://travis-ci.org/gitless-vcs/gitless "Travis") to be mad at you, check that tests pass in Python 3.7+. Tests can be run with: ``` python -m unittest discover gitless/tests From 032f3ac8144ada46736dbbf0a73d7e5c5b4bba87 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Thu, 13 Aug 2020 13:10:28 -0700 Subject: [PATCH 183/196] update the project description on the readme file --- README.md | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 07d6fef..3eab9f7 100644 --- a/README.md +++ b/README.md @@ -7,22 +7,27 @@ Gitless [![Travis Build Status](https://img.shields.io/travis/gitless-vcs/gitless/master.svg)](https://travis-ci.org/gitless-vcs/gitless "Travis Build Status") [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/gitless-vcs/gitless?svg=true)](https://ci.appveyor.com/project/spderosso/gitless-11bfm "AppVeyor Build Status") -[Gitless](http://gitless.com "Gitless's website") is an experimental version -control system built on top of Git. Many -people complain that Git is hard to use. We think the problem lies deeper than -the user interface, in the concepts underlying Git. Gitless is an experiment to -see what happens if you put a simple veneer on an app that changes the -underlying concepts. Because Gitless is implemented on top of Git (could be -considered what Git pros call a "porcelain" of Git), you can always fall -back on Git. And of course your coworkers you share a repository with need never -know that you're not a Git aficionado. +[Gitless](http://gitless.com "Gitless's website") is a version control system built on top of Git, that is easy to learn and use: + +- **Simple commit workflow** + + Track or untrack files to control what changes to commit. Changes to tracked files are committed by default, but you can easily customize the set of files to commit using flags +- **Independent branches** + + Branches in Gitless include your working changes, so you can switch between branches without having to worry about conflicting uncommitted changes +- **Friendly command-line interface** + + Gitless commands will give you good feedback and help you figure out what to do next +- **Compatible with Git** + + Because Gitless is implemented on top of Git, you can always fall back on Git. And your coworkers you share a repo with need never know that you're not a Git aficionado. Moreover, you can use Gitless with GitHub or with any Git hosting service Install ------- -Note that the installation **won't interfere** with your Git installation in any -way, you can keep using Git, and switch between Git and Gitless seamlessly. +Installing Gitless won't interfere with your Git installation in any +way. You can keep using Git and switch between Git and Gitless seamlessly. We currently require Git (1.7.12+) to be installed, but this requirement is going to disappear soon once we finish with our migration to [pygit2](https://github.com/libgit2/pygit2). @@ -104,7 +109,7 @@ Contribute ---------- If you find a bug, you can help us by submitting an issue to our -GitHub Repository. If you'd like to contribute +GitHub repository. If you'd like to contribute code, here are some useful things to know: - To install gitless for development, [install pygit2]( From 1ffeab0ef602e87b34d3460b1b75869bd1a03a66 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Thu, 13 Aug 2020 19:23:42 -0700 Subject: [PATCH 184/196] update project descriptions --- setup.py | 17 +++++++---------- snap/snapcraft.yaml | 14 ++++++-------- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/setup.py b/setup.py index d00a03c..dbf3e65 100755 --- a/setup.py +++ b/setup.py @@ -45,14 +45,11 @@ ld = """ -Gitless is an experimental version control system built on top of Git. -Many people complain that Git is hard to use. We think the problem lies -deeper than the user interface, in the concepts underlying Git. Gitless -is an experiment to see what happens if you put a simple veneer on an -app that changes the underlying concepts. Because Gitless is implemented -on top of Git (could be considered what Git pros call a \"porcelain\" of -Git), you can always fall back on Git. And of course your coworkers you -share a repo with need never know that you're not a Git aficionado. +Gitless is a version control system built on top of Git, that is easy to learn +and use. It features a simple commit workflow, independent branches, and +a friendly command-line interface. Because Gitless is implemented on top of +Git, you can always fall back on Git. And your coworkers you share a repo with +need never know that you're not a Git aficionado. More info, downloads and documentation @ `Gitless's website `__. @@ -61,11 +58,11 @@ setup( name='gitless', version=version, - description='A version control system built on top of Git', + description='A simple version control system built on top of Git', long_description=ld, author='Santiago Perez De Rosso', author_email='sperezde@csail.mit.edu', - url='http://gitless.com', + url='https://gitless.com', packages=['gitless', 'gitless.cli'], install_requires=[ # make sure install_requires is consistent with requirements.txt diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index e3c30bc..b7e037b 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -4,14 +4,12 @@ name: gitless version: git summary: A simple version control system built on top of Git description: | - Gitless is an experimental version control system built on top of Git. - Many people complain that Git is hard to use. We think the problem lies - deeper than the user interface, in the concepts underlying Git. Gitless - is an experiment to see what happens if you put a simple veneer on an - app that changes the underlying concepts. Because Gitless is implemented - on top of Git (could be considered what Git pros call a "porcelain" of - Git), you can always fall back on Git. And of course your coworkers you - share a repo with need never know that you're not a Git aficionado. + Gitless is a version control system built on top of Git, that is easy to learn + and use. It features a simple commit workflow, independent branches, and + a friendly command-line interface. Because Gitless is implemented on top of + Git, you can always fall back on Git. And your coworkers you share a repo with + need never know that you're not a Git aficionado. + # Base snap for snapd that is based on Ubuntu 18.04 base: core18 From 68be717f54156c0b31113ab93a583a4a2e35e28a Mon Sep 17 00:00:00 2001 From: Ma'or Kadosh <4103412+it-is-wednesday@users.noreply.github.com> Date: Mon, 12 Oct 2020 11:47:26 +0300 Subject: [PATCH 185/196] add AUR packages to readme --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 3eab9f7..414057b 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,16 @@ snap install --channel=beta gitless You can also use the `edge` channel to install the most recent build. +### Installing via the Arch User Repository + +If you are using [Arch Linux](https://www.archlinux.org/) or any of +its derivatives, you can use your favorite +[AUR Helper](https://wiki.archlinux.org/index.php/AUR_helpers) and install: +- [gitless](https://aur.archlinux.org/packages/gitless/) for the latest + released version +- [gitless-git](https://aur.archlinux.org/packages/gitless-git/) to + build the latest version straight from this repo + Documentation ------------- From 6b85540e57afb8780d8596a615b4e534fa1e691a Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Thu, 26 Nov 2020 16:43:38 -0500 Subject: [PATCH 186/196] deps: update libgit2 to 1.4.0 previous update, #230 relates to https://github.com/Homebrew/homebrew-core/pull/65706 Signed-off-by: Rui Chen --- .travis.sh | 2 +- requirements.txt | 2 +- setup.py | 2 +- snap/snapcraft.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.sh b/.travis.sh index e95df82..fdf241c 100755 --- a/.travis.sh +++ b/.travis.sh @@ -2,7 +2,7 @@ cd ~ -git clone --depth=1 -b maint/v1.0.1 https://github.com/libgit2/libgit2.git +git clone --depth=1 -b ethomson/v1.1 https://github.com/libgit2/libgit2.git cd libgit2/ mkdir build && cd build diff --git a/requirements.txt b/requirements.txt index 86b228a..2c21c81 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ # make sure to update setup.py if you make any changes to this file argcomplete>=1.11.1 -pygit2==1.2.0 # requires libgit2 1.0.x +pygit2==1.4.0 # requires libgit2 1.1.x diff --git a/setup.py b/setup.py index dbf3e65..4c4081b 100755 --- a/setup.py +++ b/setup.py @@ -66,7 +66,7 @@ packages=['gitless', 'gitless.cli'], install_requires=[ # make sure install_requires is consistent with requirements.txt - 'pygit2==1.2.0', # requires libgit2 1.0.x + 'pygit2==1.4.0', # requires libgit2 1.1.x 'argcomplete>=1.11.1' ], license='MIT', diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index b7e037b..dba4c8d 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -27,7 +27,7 @@ parts: libgit2: plugin: cmake # https://www.pygit2.org/install.html#version-numbers - source: https://github.com/libgit2/libgit2/archive/v1.0.1.tar.gz + source: https://github.com/libgit2/libgit2/archive/v1.1.0.tar.gz build-packages: - libssl-dev From f3269f63f70e5415e2d441c57fd2d178b8c9ae61 Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Thu, 26 Nov 2020 16:46:15 -0500 Subject: [PATCH 187/196] ci: add python 3.9 --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d4b05c3..7659629 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,10 @@ addons: packages: - snapcraft python: -- '3.7' -- '3.8' + - '3.7' + - '3.8' + - '3.9' + env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib before_install: ./.travis.sh install: pip install -r requirements.txt . From 569b91785201b8cbfcd741e8bb275241a6a54b94 Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Thu, 26 Nov 2020 16:52:46 -0500 Subject: [PATCH 188/196] ci: add python39 for appveyor Signed-off-by: Rui Chen --- .appveyor.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index a2ce2b9..c245501 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -9,6 +9,10 @@ environment: PYTHON: 'C:\Python38\python.exe' - GENERATOR: 'Visual Studio 14 Win64' PYTHON: 'C:\Python38-x64\python.exe' + - GENERATOR: 'Visual Studio 14' + PYTHON: 'C:\Python39\python.exe' + - GENERATOR: 'Visual Studio 14 Win64' + PYTHON: 'C:\Python39-x64\python.exe' init: - cmd: '%PYTHON% -m pip install -U nose wheel' From 3889c75a10a60127e0d8d5b393f19c66e2f46980 Mon Sep 17 00:00:00 2001 From: Rui Chen Date: Thu, 26 Nov 2020 17:08:22 -0500 Subject: [PATCH 189/196] drop python 3.7 ``` pygit2<=0.28.2; python_version < '3.8' pygit2>=1.2.0; python_version >= '3.8' ``` --- .appveyor.yml | 4 ---- .travis.yml | 1 - 2 files changed, 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index a2ce2b9..00b1a19 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,10 +1,6 @@ # Based on pygit2's appveyor config environment: matrix: - - GENERATOR: 'Visual Studio 14' - PYTHON: 'C:\Python37\python.exe' - - GENERATOR: 'Visual Studio 14 Win64' - PYTHON: 'C:\Python37-x64\python.exe' - GENERATOR: 'Visual Studio 14' PYTHON: 'C:\Python38\python.exe' - GENERATOR: 'Visual Studio 14 Win64' diff --git a/.travis.yml b/.travis.yml index d4b05c3..e6d9220 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ addons: packages: - snapcraft python: -- '3.7' - '3.8' env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib before_install: ./.travis.sh From 1c7be09889d8b04e18c99a9db1b847677b4142fb Mon Sep 17 00:00:00 2001 From: Piotr Gorski Date: Tue, 26 Jan 2021 03:01:10 +0100 Subject: [PATCH 190/196] Fix gitless error Signed-off-by: Piotr Gorski --- gitless/cli/gl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gitless/cli/gl.py b/gitless/cli/gl.py index 3723ac3..67bed8a 100644 --- a/gitless/cli/gl.py +++ b/gitless/cli/gl.py @@ -39,7 +39,7 @@ try: pprint.DISABLE_COLOR = not repo.config.get_bool('color.ui') except pygit2.GitError: - prrint.DISABLE_COLOR = ( + pprint.DISABLE_COLOR = ( repo.config['color.ui'] in ['no', 'never']) except (core.NotInRepoError, KeyError): pass From 225f23632ccc5afc9f70abd623ec70e1256c93a1 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Tue, 26 Jan 2021 22:12:55 -0800 Subject: [PATCH 191/196] Add `image` to appveyor config --- .appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.appveyor.yml b/.appveyor.yml index 11f72aa..957e74d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,5 @@ # Based on pygit2's appveyor config +image: Visual Studio 2019 environment: matrix: - GENERATOR: 'Visual Studio 14' From 124e6bb8a077bfa32d83fb2bd58f2ebafe340b7b Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Tue, 26 Jan 2021 22:36:59 -0800 Subject: [PATCH 192/196] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 414057b..e60c92e 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ snap install --channel=beta gitless You can also use the `edge` channel to install the most recent build. -### Installing via the Arch User Repository +### Installing via the Arch User Repository (Arch Linux only) If you are using [Arch Linux](https://www.archlinux.org/) or any of its derivatives, you can use your favorite @@ -118,7 +118,7 @@ Documentation Contribute ---------- -If you find a bug, you can help us by submitting an issue to our +If you find a bug, create an issue in our GitHub repository. If you'd like to contribute code, here are some useful things to know: @@ -131,7 +131,7 @@ code, here are some useful things to know: https://google.github.io/styleguide/pyguide.html "Google Python Style Guide"). Before submitting code, take a few seconds to look at the style guide and the -Gitless's code so that your edits are consistent with the codebase +Gitless code so that your edits are consistent with the codebase. - Finally, if you don't want [Travis]( https://travis-ci.org/gitless-vcs/gitless "Travis") to From 982e47a65cf62682d1bb53eb7b30cda8b772f50e Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Tue, 26 Jan 2021 22:53:22 -0800 Subject: [PATCH 193/196] Update travis.sh --- .travis.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.travis.sh b/.travis.sh index fdf241c..c6bb06e 100755 --- a/.travis.sh +++ b/.travis.sh @@ -1,8 +1,19 @@ #!/bin/sh +# Based on pygit2's .travis.sh +PREFIX=/home/travis/install + +# Build libssh2 1.9.0 (Ubuntu only has 1.8.0, which doesn't work) cd ~ +wget https://www.libssh2.org/download/libssh2-1.9.0.tar.gz +tar xf libssh2-1.9.0.tar.gz +cd libssh2-1.9.0 +./configure --prefix=/usr --disable-static && make +sudo make install -git clone --depth=1 -b ethomson/v1.1 https://github.com/libgit2/libgit2.git +# Build libgit2 +cd ~ +git clone --depth=1 -b "maint/v1.1" https://github.com/libgit2/libgit2.git cd libgit2/ mkdir build && cd build From 74e610620a1bc79de752e682dbdf82830567a18f Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Fri, 29 Jan 2021 19:09:54 -0800 Subject: [PATCH 194/196] Try to fix snapcraft packaging --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1653ec2..6ab7a17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ jobs: env: EMPTY before_install: skip install: skip - script: sudo snapcraft + script: sudo snapcraft --destructive-mode deploy: on: branch: master From 5aefa26ec673b5248754ba5d9d030af0c2f0921b Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Sat, 30 Jan 2021 12:57:10 -0800 Subject: [PATCH 195/196] Remove command in appveyor --- .appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index e28bf61..1148976 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -25,7 +25,6 @@ before_test: test_script: - cmd: dir /a:h - - cmd: gl - ps: | # 'gl' is installed in Python Scripts directory $env:PATH += ";$(Split-Path $env:PYTHON)\Scripts" From 3ac28e39e170acdcd1590e0a25a06790ae0e6922 Mon Sep 17 00:00:00 2001 From: Santiago Perez De Rosso Date: Tue, 2 Feb 2021 22:53:34 -0800 Subject: [PATCH 196/196] Update ubuntu distribution used in travis May fix snapcraft packaging --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6ab7a17..2736397 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: python -dist: xenial +dist: focal python: - '3.8' - '3.9'