Show NoUpstream error in checkup output.
This commit is contained in:
parent
e557c1a64f
commit
015957f72d
1 changed files with 63 additions and 61 deletions
124
gitcheckup.py
124
gitcheckup.py
|
@ -4,6 +4,7 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
from voussoirkit import dotdict
|
||||||
from voussoirkit import winwhich
|
from voussoirkit import winwhich
|
||||||
|
|
||||||
GIT = winwhich.which('git')
|
GIT = winwhich.which('git')
|
||||||
|
@ -17,19 +18,22 @@ GIT = winwhich.which('git')
|
||||||
# ?? file3
|
# ?? file3
|
||||||
|
|
||||||
class NoUpstreamBranch(Exception):
|
class NoUpstreamBranch(Exception):
|
||||||
pass
|
def __str__(self):
|
||||||
|
return f'No upstream branch for {self.args[0]}'
|
||||||
|
|
||||||
def check_output(command):
|
def check_output(command):
|
||||||
output = subprocess.check_output(command, stderr=subprocess.STDOUT)
|
output = subprocess.check_output(command, stderr=subprocess.STDOUT)
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def checkup_committed():
|
def checkup_committed():
|
||||||
|
details = dotdict.DotDict(default=None)
|
||||||
|
|
||||||
command = [GIT, 'status', '--short', '--untracked-files=all']
|
command = [GIT, 'status', '--short', '--untracked-files=all']
|
||||||
output = check_output(command)
|
output = check_output(command)
|
||||||
|
|
||||||
added = 0
|
details.added = 0
|
||||||
modified = 0
|
details.modified = 0
|
||||||
deleted = 0
|
details.deleted = 0
|
||||||
for line in output.splitlines():
|
for line in output.splitlines():
|
||||||
status = line.split()[0].strip().decode('ascii')
|
status = line.split()[0].strip().decode('ascii')
|
||||||
|
|
||||||
|
@ -37,18 +41,19 @@ def checkup_committed():
|
||||||
# added in the index but deleted on disk, etc. Anyway these numbers
|
# added in the index but deleted on disk, etc. Anyway these numbers
|
||||||
# don't need to be super accurate, just enough to remind you to commit.
|
# don't need to be super accurate, just enough to remind you to commit.
|
||||||
if {'A', '?'}.intersection(status):
|
if {'A', '?'}.intersection(status):
|
||||||
added += 1
|
details.added += 1
|
||||||
if {'M', 'R', '!'}.intersection(status):
|
if {'M', 'R', '!'}.intersection(status):
|
||||||
modified += 1
|
details.modified += 1
|
||||||
if {'D'}.intersection(status):
|
if {'D'}.intersection(status):
|
||||||
deleted += 1
|
details.deleted += 1
|
||||||
|
|
||||||
committed = (added, modified, deleted) == (0, 0, 0)
|
details.committed = (details.added, details.modified, details.deleted) == (0, 0, 0)
|
||||||
details = types.SimpleNamespace(added=added, deleted=deleted, modified=modified)
|
|
||||||
|
|
||||||
return (committed, details)
|
return details
|
||||||
|
|
||||||
def checkup_pushed():
|
def checkup_pushed():
|
||||||
|
details = dotdict.DotDict(default=None)
|
||||||
|
|
||||||
command = [GIT, 'rev-parse', '@']
|
command = [GIT, 'rev-parse', '@']
|
||||||
my_head = check_output(command).strip().decode()
|
my_head = check_output(command).strip().decode()
|
||||||
|
|
||||||
|
@ -58,33 +63,28 @@ def checkup_pushed():
|
||||||
except subprocess.CalledProcessError as exc:
|
except subprocess.CalledProcessError as exc:
|
||||||
command = [GIT, 'rev-parse', '--abbrev-ref', 'HEAD']
|
command = [GIT, 'rev-parse', '--abbrev-ref', 'HEAD']
|
||||||
current_branch = check_output(command).strip().decode()
|
current_branch = check_output(command).strip().decode()
|
||||||
raise NoUpstreamBranch(current_branch)
|
details.error = NoUpstreamBranch(current_branch)
|
||||||
|
return details
|
||||||
|
|
||||||
if my_head == remote_head:
|
if my_head == remote_head:
|
||||||
to_push = 0
|
details.to_push = 0
|
||||||
to_pull = 0
|
details.to_pull = 0
|
||||||
else:
|
else:
|
||||||
command = [GIT, 'merge-base', '@', '@{u}']
|
command = [GIT, 'merge-base', '@', '@{u}']
|
||||||
merge_base = check_output(command)
|
merge_base = check_output(command).strip().decode()
|
||||||
merge_base = merge_base.strip().decode()
|
|
||||||
|
|
||||||
if my_head == merge_base:
|
if my_head == merge_base:
|
||||||
to_push = 0
|
details.to_push = 0
|
||||||
to_pull = len(git_commits_between(merge_base, remote_head))
|
details.to_pull = len(git_commits_between(merge_base, remote_head))
|
||||||
elif remote_head == merge_base:
|
elif remote_head == merge_base:
|
||||||
to_push = len(git_commits_between(merge_base, my_head))
|
details.to_push = len(git_commits_between(merge_base, my_head))
|
||||||
to_pull = 0
|
details.to_pull = 0
|
||||||
else:
|
else:
|
||||||
to_push = len(git_commits_between(merge_base, my_head))
|
details.to_push = len(git_commits_between(merge_base, my_head))
|
||||||
to_pull = len(git_commits_between(merge_base, remote_head))
|
details.to_pull = len(git_commits_between(merge_base, remote_head))
|
||||||
|
|
||||||
pushed = (to_push, to_pull) == (0, 0)
|
details.pushed = (details.to_push, details.to_pull) == (0, 0)
|
||||||
details = types.SimpleNamespace(
|
return details
|
||||||
to_push=to_push,
|
|
||||||
to_pull=to_pull,
|
|
||||||
)
|
|
||||||
|
|
||||||
return (pushed, details)
|
|
||||||
|
|
||||||
def git_commits_between(a, b):
|
def git_commits_between(a, b):
|
||||||
command = [GIT, 'log', '--oneline', f'{a}..{b}']
|
command = [GIT, 'log', '--oneline', f'{a}..{b}']
|
||||||
|
@ -100,12 +100,10 @@ def checkup(directory, do_fetch=False):
|
||||||
os.chdir(directory)
|
os.chdir(directory)
|
||||||
if do_fetch:
|
if do_fetch:
|
||||||
git_fetch()
|
git_fetch()
|
||||||
(committed, commit_details) = checkup_committed()
|
commit_details = checkup_committed()
|
||||||
(pushed, push_details) = checkup_pushed()
|
push_details = checkup_pushed()
|
||||||
return types.SimpleNamespace(
|
return dotdict.DotDict(
|
||||||
committed=committed,
|
|
||||||
commit_details=commit_details,
|
commit_details=commit_details,
|
||||||
pushed=pushed,
|
|
||||||
push_details=push_details,
|
push_details=push_details,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -121,7 +119,36 @@ def read_directories_file():
|
||||||
|
|
||||||
return directories
|
return directories
|
||||||
|
|
||||||
def gitcheckup(do_fetch=False):
|
def gitcheckup_one(directory, do_fetch=False):
|
||||||
|
try:
|
||||||
|
result = checkup(directory, do_fetch=do_fetch)
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
raise Exception(exc.output)
|
||||||
|
|
||||||
|
committed = 'C' if result.commit_details.committed else ' '
|
||||||
|
pushed = 'P' if result.push_details.pushed else ' '
|
||||||
|
|
||||||
|
details = []
|
||||||
|
|
||||||
|
commit_details = []
|
||||||
|
if result.commit_details.added: commit_details.append(f'+{result.commit_details.added}')
|
||||||
|
if result.commit_details.deleted: commit_details.append(f'-{result.commit_details.deleted}')
|
||||||
|
if result.commit_details.modified: commit_details.append(f'~{result.commit_details.modified}')
|
||||||
|
commit_details = ', '.join(commit_details)
|
||||||
|
if commit_details: details.append(f'({commit_details})')
|
||||||
|
|
||||||
|
push_details = []
|
||||||
|
if result.push_details.to_push: push_details.append(f'↑{result.push_details.to_push}')
|
||||||
|
if result.push_details.to_pull: push_details.append(f'↓{result.push_details.to_pull}')
|
||||||
|
if result.push_details.error: push_details.append(f'!{result.push_details.error}')
|
||||||
|
push_details = ', '.join(push_details)
|
||||||
|
if push_details: details.append(f'({push_details})')
|
||||||
|
|
||||||
|
details = ' '.join(details)
|
||||||
|
details = (' ' + details).rstrip()
|
||||||
|
print(f'[{committed}][{pushed}] {directory}{details}')
|
||||||
|
|
||||||
|
def gitcheckup_all(do_fetch=False):
|
||||||
try:
|
try:
|
||||||
directories = read_directories_file()
|
directories = read_directories_file()
|
||||||
except FileNotFoundError as exc:
|
except FileNotFoundError as exc:
|
||||||
|
@ -129,35 +156,10 @@ def gitcheckup(do_fetch=False):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
for directory in directories:
|
for directory in directories:
|
||||||
try:
|
gitcheckup_one(directory, do_fetch=do_fetch)
|
||||||
result = checkup(directory, do_fetch=do_fetch)
|
|
||||||
except subprocess.CalledProcessError as exc:
|
|
||||||
raise Exception(exc.output)
|
|
||||||
|
|
||||||
committed = 'C' if result.committed else ' '
|
|
||||||
pushed = 'P' if result.pushed else ' '
|
|
||||||
|
|
||||||
details = []
|
|
||||||
|
|
||||||
commit_details = []
|
|
||||||
if result.commit_details.added: commit_details.append(f'+{result.commit_details.added}')
|
|
||||||
if result.commit_details.deleted: commit_details.append(f'-{result.commit_details.deleted}')
|
|
||||||
if result.commit_details.modified: commit_details.append(f'~{result.commit_details.modified}')
|
|
||||||
commit_details = ', '.join(commit_details)
|
|
||||||
if commit_details: details.append(f'({commit_details})')
|
|
||||||
|
|
||||||
push_details = []
|
|
||||||
if result.push_details.to_push: push_details.append(f'↑{result.push_details.to_push}')
|
|
||||||
if result.push_details.to_pull: push_details.append(f'↓{result.push_details.to_pull}')
|
|
||||||
push_details = ', '.join(push_details)
|
|
||||||
if push_details: details.append(f'({push_details})')
|
|
||||||
|
|
||||||
details = ' '.join(details)
|
|
||||||
details = (' ' + details).rstrip()
|
|
||||||
print(f'[{committed}][{pushed}] {directory}{details}')
|
|
||||||
|
|
||||||
def gitcheckup_argparse(args):
|
def gitcheckup_argparse(args):
|
||||||
return gitcheckup(do_fetch=args.do_fetch)
|
return gitcheckup_all(do_fetch=args.do_fetch)
|
||||||
|
|
||||||
def main(argv):
|
def main(argv):
|
||||||
parser = argparse.ArgumentParser(description=__doc__)
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
|
Loading…
Reference in a new issue