skilleter-thingy 0.3.14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- skilleter_thingy/__init__.py +0 -0
- skilleter_thingy/addpath.py +107 -0
- skilleter_thingy/console_colours.py +63 -0
- skilleter_thingy/ffind.py +535 -0
- skilleter_thingy/ggit.py +88 -0
- skilleter_thingy/ggrep.py +155 -0
- skilleter_thingy/git_br.py +186 -0
- skilleter_thingy/git_ca.py +147 -0
- skilleter_thingy/git_cleanup.py +297 -0
- skilleter_thingy/git_co.py +227 -0
- skilleter_thingy/git_common.py +68 -0
- skilleter_thingy/git_hold.py +162 -0
- skilleter_thingy/git_parent.py +84 -0
- skilleter_thingy/git_retag.py +67 -0
- skilleter_thingy/git_review.py +1450 -0
- skilleter_thingy/git_update.py +398 -0
- skilleter_thingy/git_wt.py +72 -0
- skilleter_thingy/gitcmp_helper.py +328 -0
- skilleter_thingy/gitprompt.py +293 -0
- skilleter_thingy/linecount.py +154 -0
- skilleter_thingy/multigit.py +915 -0
- skilleter_thingy/py_audit.py +133 -0
- skilleter_thingy/remdir.py +127 -0
- skilleter_thingy/rpylint.py +98 -0
- skilleter_thingy/strreplace.py +82 -0
- skilleter_thingy/test.py +34 -0
- skilleter_thingy/tfm.py +948 -0
- skilleter_thingy/tfparse.py +101 -0
- skilleter_thingy/trimpath.py +82 -0
- skilleter_thingy/venv_create.py +47 -0
- skilleter_thingy/venv_template.py +47 -0
- skilleter_thingy/xchmod.py +124 -0
- skilleter_thingy/yamlcheck.py +89 -0
- skilleter_thingy-0.3.14.dist-info/METADATA +606 -0
- skilleter_thingy-0.3.14.dist-info/RECORD +39 -0
- skilleter_thingy-0.3.14.dist-info/WHEEL +5 -0
- skilleter_thingy-0.3.14.dist-info/entry_points.txt +31 -0
- skilleter_thingy-0.3.14.dist-info/licenses/LICENSE +619 -0
- skilleter_thingy-0.3.14.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Archive one or more branches by tagging the branch then deleting it
|
|
3
|
+
The branch tag is 'archive/BRANCH_NAME'"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
import argparse
|
|
8
|
+
import fnmatch
|
|
9
|
+
|
|
10
|
+
from skilleter_modules import colour
|
|
11
|
+
from skilleter_modules import git
|
|
12
|
+
|
|
13
|
+
################################################################################
|
|
14
|
+
# Prefix for tags representing archived branches
|
|
15
|
+
|
|
16
|
+
ARCHIVE_PREFIX = 'archive/'
|
|
17
|
+
|
|
18
|
+
################################################################################
|
|
19
|
+
|
|
20
|
+
def archive_tag_name(branch):
|
|
21
|
+
"""Return the tag name for an archive branch"""
|
|
22
|
+
|
|
23
|
+
return f'{ARCHIVE_PREFIX}{branch}'
|
|
24
|
+
|
|
25
|
+
################################################################################
|
|
26
|
+
|
|
27
|
+
def archive_branch_name(tag):
|
|
28
|
+
"""Return the branch name for an archive tag"""
|
|
29
|
+
|
|
30
|
+
if not tag.startswith(ARCHIVE_PREFIX):
|
|
31
|
+
raise git.GitError(f'{tag} is not an archive tag')
|
|
32
|
+
|
|
33
|
+
return tag[len(ARCHIVE_PREFIX):]
|
|
34
|
+
|
|
35
|
+
################################################################################
|
|
36
|
+
|
|
37
|
+
def archive_tags():
|
|
38
|
+
"""Return the list of current archive tags"""
|
|
39
|
+
|
|
40
|
+
return [tag for tag in git.tags() if tag.startswith(ARCHIVE_PREFIX)]
|
|
41
|
+
|
|
42
|
+
################################################################################
|
|
43
|
+
|
|
44
|
+
def archive_branches(branches):
|
|
45
|
+
"""Archive one or more branches"""
|
|
46
|
+
|
|
47
|
+
tags = archive_tags()
|
|
48
|
+
current_branch = git.branch()
|
|
49
|
+
|
|
50
|
+
for branch in branches:
|
|
51
|
+
if not git.isbranch(branch):
|
|
52
|
+
colour.error(f'Branch {branch} does not exist', prefix=True)
|
|
53
|
+
|
|
54
|
+
if archive_tag_name(branch) in tags:
|
|
55
|
+
colour.error(f'An archive tag already exists for branch {branch}', prefix=True)
|
|
56
|
+
|
|
57
|
+
if branch == current_branch:
|
|
58
|
+
colour.error('Cannot archive the current branch', prefix=True)
|
|
59
|
+
|
|
60
|
+
for branch in branches:
|
|
61
|
+
tag_name = archive_tag_name(branch)
|
|
62
|
+
|
|
63
|
+
git.tag_apply(tag_name, branch)
|
|
64
|
+
git.delete_branch(branch, force=True)
|
|
65
|
+
|
|
66
|
+
for remote in git.remotes():
|
|
67
|
+
git.push(repository=remote, tags=True)
|
|
68
|
+
|
|
69
|
+
################################################################################
|
|
70
|
+
|
|
71
|
+
def list_archive_branches(branches):
|
|
72
|
+
"""List archive branches, optionally only those matching entries in the
|
|
73
|
+
branches parameter"""
|
|
74
|
+
|
|
75
|
+
tags = archive_tags()
|
|
76
|
+
|
|
77
|
+
if branches:
|
|
78
|
+
report = set()
|
|
79
|
+
|
|
80
|
+
for branch in branches:
|
|
81
|
+
for tag in tags:
|
|
82
|
+
branch_name = archive_branch_name(tag)
|
|
83
|
+
if branch_name not in report and fnmatch.fnmatch(branch_name, branch):
|
|
84
|
+
report.add(branch_name)
|
|
85
|
+
else:
|
|
86
|
+
report = set(tags)
|
|
87
|
+
|
|
88
|
+
for branch_name in sorted(report):
|
|
89
|
+
print(branch_name)
|
|
90
|
+
|
|
91
|
+
################################################################################
|
|
92
|
+
|
|
93
|
+
def restore_archive_branches(branches):
|
|
94
|
+
"""Restore archived branches"""
|
|
95
|
+
|
|
96
|
+
tags = archive_tags()
|
|
97
|
+
|
|
98
|
+
for branch in branches:
|
|
99
|
+
if archive_tag_name(branch) not in tags:
|
|
100
|
+
colour.error(f'Archive branch {branch} does not exist', prefix=True)
|
|
101
|
+
|
|
102
|
+
archive_tag_names = []
|
|
103
|
+
|
|
104
|
+
for branch in branches:
|
|
105
|
+
archive_tag = archive_tag_name(branch)
|
|
106
|
+
archive_tag_names.append(archive_tag)
|
|
107
|
+
|
|
108
|
+
git.checkout(branch, commit=archive_tag)
|
|
109
|
+
git.tag_delete(archive_tag)
|
|
110
|
+
|
|
111
|
+
for remote in git.remotes():
|
|
112
|
+
git.push(repository=remote, delete=True, refspec=archive_tag_names)
|
|
113
|
+
|
|
114
|
+
################################################################################
|
|
115
|
+
|
|
116
|
+
def main():
|
|
117
|
+
"""Main function"""
|
|
118
|
+
|
|
119
|
+
parser = argparse.ArgumentParser(description='Archive, list or recover one or more Git branches')
|
|
120
|
+
parser.add_argument('--list', '-l', action='store_true', help='List archived branches')
|
|
121
|
+
parser.add_argument('--restore', '-r', action='store_true', help='Restore archived branches')
|
|
122
|
+
parser.add_argument('--path', '-C', nargs=1, type=str, default=None,
|
|
123
|
+
help='Run the command in the specified directory')
|
|
124
|
+
parser.add_argument('branches', nargs='*', help='Branches')
|
|
125
|
+
|
|
126
|
+
args = parser.parse_args()
|
|
127
|
+
|
|
128
|
+
if args.list and args.restore:
|
|
129
|
+
colour.error('The list and restore options cannot be specified together', prefix=True)
|
|
130
|
+
|
|
131
|
+
if not args.branches and not args.list:
|
|
132
|
+
colour.error('No branches specified', prefix=True)
|
|
133
|
+
|
|
134
|
+
if args.path:
|
|
135
|
+
os.chdir(args.path[0])
|
|
136
|
+
|
|
137
|
+
if args.list:
|
|
138
|
+
list_archive_branches(args.branches)
|
|
139
|
+
elif args.restore:
|
|
140
|
+
restore_archive_branches(args.branches)
|
|
141
|
+
else:
|
|
142
|
+
archive_branches(args.branches)
|
|
143
|
+
|
|
144
|
+
################################################################################
|
|
145
|
+
|
|
146
|
+
def git_hold():
|
|
147
|
+
"""Entry point"""
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
main()
|
|
151
|
+
|
|
152
|
+
except KeyboardInterrupt:
|
|
153
|
+
sys.exit(1)
|
|
154
|
+
except BrokenPipeError:
|
|
155
|
+
sys.exit(2)
|
|
156
|
+
except git.GitError as exc:
|
|
157
|
+
colour.error(exc.msg, status=exc.status, prefix=True)
|
|
158
|
+
|
|
159
|
+
################################################################################
|
|
160
|
+
|
|
161
|
+
if __name__ == '__main__':
|
|
162
|
+
git_hold()
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Attempt to determine the parent branch of a commit by tracking down
|
|
5
|
+
the branch commit history and looking for other branches that share
|
|
6
|
+
the same commit. Can optionally ignore feature branches and/or report
|
|
7
|
+
the distance to the potential parent.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
import argparse
|
|
12
|
+
import sys
|
|
13
|
+
|
|
14
|
+
from skilleter_modules import git
|
|
15
|
+
from skilleter_modules import colour
|
|
16
|
+
|
|
17
|
+
################################################################################
|
|
18
|
+
|
|
19
|
+
def main():
|
|
20
|
+
""" Main function """
|
|
21
|
+
|
|
22
|
+
current_branch = git.branch()
|
|
23
|
+
|
|
24
|
+
parser = argparse.ArgumentParser(description='Attempt to determine the parent branch for the specified branch (defaulting to the current one)')
|
|
25
|
+
parser.add_argument('--all', '-a', action='store_true', help='Include feature branches as possible parents')
|
|
26
|
+
parser.add_argument('--verbose', '-v', action='store_true', help='Report verbose results (includes number of commits between branch and parent)')
|
|
27
|
+
parser.add_argument('--path', '-C', nargs=1, type=str, default=None,
|
|
28
|
+
help='Run the command in the specified directory')
|
|
29
|
+
parser.add_argument('branch', action='store', nargs='?', type=str, default=current_branch,
|
|
30
|
+
help=f'Branch, commit or commit (defaults to current branch; {current_branch})')
|
|
31
|
+
|
|
32
|
+
args = parser.parse_args()
|
|
33
|
+
|
|
34
|
+
if args.path:
|
|
35
|
+
os.chdir(args.path[0])
|
|
36
|
+
|
|
37
|
+
if args.all:
|
|
38
|
+
any_parents, any_distance = git.parents(args.branch)
|
|
39
|
+
else:
|
|
40
|
+
any_parents = []
|
|
41
|
+
|
|
42
|
+
parents, distance = git.parents(args.branch, ignore='feature/*')
|
|
43
|
+
|
|
44
|
+
# If we have feature and non-feature branch candidates, decide which to report
|
|
45
|
+
# (one or both) based on distance.
|
|
46
|
+
|
|
47
|
+
if parents and any_parents:
|
|
48
|
+
if any_distance < distance:
|
|
49
|
+
parents = any_parents
|
|
50
|
+
distance = any_distance
|
|
51
|
+
elif any_distance == distance:
|
|
52
|
+
for more in any_parents:
|
|
53
|
+
if more not in parents:
|
|
54
|
+
parents.append(more)
|
|
55
|
+
|
|
56
|
+
if parents:
|
|
57
|
+
if args.verbose:
|
|
58
|
+
if len(parents) == 1:
|
|
59
|
+
colour.write(f'Parent branch [BLUE:{parents[0]}] is [BLUE:{distance}] commits away from [BLUE:{args.branch}]')
|
|
60
|
+
else:
|
|
61
|
+
colour.write(f'Parent branches [BLUE:%s] are [BLUE:{distance}] commits away from [BLUE:{args.branch}]' % (', '.join(parents)))
|
|
62
|
+
else:
|
|
63
|
+
print(', '.join(parents))
|
|
64
|
+
else:
|
|
65
|
+
colour.error('Could not determine parent branch\n', prefix=True)
|
|
66
|
+
|
|
67
|
+
################################################################################
|
|
68
|
+
|
|
69
|
+
def git_parent():
|
|
70
|
+
"""Entry point"""
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
main()
|
|
74
|
+
except KeyboardInterrupt:
|
|
75
|
+
sys.exit(1)
|
|
76
|
+
except BrokenPipeError:
|
|
77
|
+
sys.exit(2)
|
|
78
|
+
except git.GitError as exc:
|
|
79
|
+
colour.error(exc.msg, status=exc.status, prefix=True)
|
|
80
|
+
|
|
81
|
+
################################################################################
|
|
82
|
+
|
|
83
|
+
if __name__ == '__main__':
|
|
84
|
+
git_parent()
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#! /usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
################################################################################
|
|
4
|
+
""" Apply or update a tag, optionally updating it on the remote as well.
|
|
5
|
+
|
|
6
|
+
Copyright (C) 2025 John Skilleter
|
|
7
|
+
|
|
8
|
+
Licence: GPL v3 or later
|
|
9
|
+
"""
|
|
10
|
+
################################################################################
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
import argparse
|
|
15
|
+
|
|
16
|
+
from skilleter_modules import git
|
|
17
|
+
from skilleter_modules import colour
|
|
18
|
+
|
|
19
|
+
################################################################################
|
|
20
|
+
|
|
21
|
+
def main():
|
|
22
|
+
""" Main function """
|
|
23
|
+
|
|
24
|
+
# Command line parameters
|
|
25
|
+
|
|
26
|
+
parser = argparse.ArgumentParser(description='Apply or update a tag, optionally updating it on the remote as well.')
|
|
27
|
+
parser.add_argument('--push', '-p', action='store_true', help='Push the tag to the remote')
|
|
28
|
+
parser.add_argument('--path', '-C', nargs=1, type=str, default=None,
|
|
29
|
+
help='Run the command in the specified directory')
|
|
30
|
+
parser.add_argument('tag', nargs=1, help='The tag')
|
|
31
|
+
|
|
32
|
+
args = parser.parse_args()
|
|
33
|
+
|
|
34
|
+
# Change directory, if specified
|
|
35
|
+
|
|
36
|
+
if args.path:
|
|
37
|
+
os.chdir(args.path[0])
|
|
38
|
+
|
|
39
|
+
tag = args.tag[0]
|
|
40
|
+
|
|
41
|
+
# Delete the tag if it currently exists, optionally pushing the deletion
|
|
42
|
+
|
|
43
|
+
if tag in git.tags():
|
|
44
|
+
git.tag_delete(tag, push=args.push)
|
|
45
|
+
|
|
46
|
+
# Apply the tag
|
|
47
|
+
|
|
48
|
+
git.tag_apply(tag, 'HEAD', push=args.push)
|
|
49
|
+
|
|
50
|
+
################################################################################
|
|
51
|
+
|
|
52
|
+
def git_retag():
|
|
53
|
+
"""Entry point"""
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
main()
|
|
57
|
+
except KeyboardInterrupt:
|
|
58
|
+
sys.exit(1)
|
|
59
|
+
except BrokenPipeError:
|
|
60
|
+
sys.exit(2)
|
|
61
|
+
except git.GitError as exc:
|
|
62
|
+
colour.error(exc.msg, status=exc.status, prefix=True)
|
|
63
|
+
|
|
64
|
+
################################################################################
|
|
65
|
+
|
|
66
|
+
if __name__ == '__main__':
|
|
67
|
+
git_retag()
|