| #!/usr/bin/env python |
| import argparse |
| import subprocess |
| import sys |
| |
| def call_process(*args, **kwargs): |
| _result = subprocess.check_output(*args, **kwargs) |
| return _result.decode("utf-8") if sys.version_info.major > 2 else _result |
| |
| def parse_args(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument("--git-dir", default="/srv/salt/reclass") |
| parser.add_argument("--remote", default="") |
| parser.add_argument("--branch") |
| return parser.parse_args() |
| |
| CHANGES_FORMAT = '''reclass_staged_changes,directory={dir} value={staged} |
| reclass_unstaged_changes,directory={dir} value={unstaged}''' |
| |
| if __name__ == "__main__": |
| args = parse_args() |
| git_dir = args.git_dir.strip() |
| |
| staged, unstaged = [], [] |
| for file_status in call_process( |
| str.split('git status --porcelain'), cwd=git_dir |
| ).splitlines(): |
| if file_status[0] not in (' ', '?'): |
| staged.append(file_status[3:].strip()) |
| if file_status[1] != ' ': |
| unstaged.append(file_status[3:].strip()) |
| |
| print(CHANGES_FORMAT.format( |
| dir=git_dir, staged=len(staged), unstaged=len(unstaged) |
| )) |
| |
| # if no branch provided, default to current local branch |
| if not args.branch: |
| args.branch = call_process(str.split( |
| 'git rev-parse --abbrev-ref HEAD' |
| ), cwd=git_dir).strip().lstrip('heads/') # branch and tag share name |
| if args.branch == 'HEAD': # detached head, any assumption is bad |
| args.branch = 'master' |
| local_branch = args.branch.strip() |
| |
| # remote handling |
| remotes = call_process(str.split('git remote show'), cwd=git_dir).splitlines() |
| remote_ref = '{}/{}'.format(args.remote.strip() or 'origin', local_branch) |
| |
| # if no remote provided, try figuring out upstream tracking branch |
| if not args.remote: |
| upstream_ref = call_process(str.split( |
| 'git for-each-ref --format=%(upstream:short) refs/heads/{}'.format(local_branch) |
| ), cwd=git_dir).strip() |
| if upstream_ref and upstream_ref.split('/')[0] in remotes: |
| args.remote = upstream_ref.split('/')[0] # breaks on remotes with slashes |
| remote_ref = upstream_ref |
| else: |
| args.remote = 'origin' |
| |
| if args.remote.strip() in remotes: |
| known_refs = call_process(str.split( |
| 'git for-each-ref --format=%(refname:short)' |
| ), cwd=git_dir).splitlines() |
| |
| if all([ # check whether we have the local and remote branch with the same name |
| local_branch in known_refs, |
| remote_ref in known_refs |
| ]): |
| # 0 if local branch is synced with remote, 1 otherwise |
| print('reclass_remote_desync,directory={dir} value={val}'.format( |
| dir=git_dir, val=int(bool(call_process( |
| str.split("git diff {local_ref}..{remote_ref}".format( |
| local_ref=local_branch, remote_ref=remote_ref |
| )), cwd=git_dir |
| ))) |
| )) |