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.
Files changed (39) hide show
  1. skilleter_thingy/__init__.py +0 -0
  2. skilleter_thingy/addpath.py +107 -0
  3. skilleter_thingy/console_colours.py +63 -0
  4. skilleter_thingy/ffind.py +535 -0
  5. skilleter_thingy/ggit.py +88 -0
  6. skilleter_thingy/ggrep.py +155 -0
  7. skilleter_thingy/git_br.py +186 -0
  8. skilleter_thingy/git_ca.py +147 -0
  9. skilleter_thingy/git_cleanup.py +297 -0
  10. skilleter_thingy/git_co.py +227 -0
  11. skilleter_thingy/git_common.py +68 -0
  12. skilleter_thingy/git_hold.py +162 -0
  13. skilleter_thingy/git_parent.py +84 -0
  14. skilleter_thingy/git_retag.py +67 -0
  15. skilleter_thingy/git_review.py +1450 -0
  16. skilleter_thingy/git_update.py +398 -0
  17. skilleter_thingy/git_wt.py +72 -0
  18. skilleter_thingy/gitcmp_helper.py +328 -0
  19. skilleter_thingy/gitprompt.py +293 -0
  20. skilleter_thingy/linecount.py +154 -0
  21. skilleter_thingy/multigit.py +915 -0
  22. skilleter_thingy/py_audit.py +133 -0
  23. skilleter_thingy/remdir.py +127 -0
  24. skilleter_thingy/rpylint.py +98 -0
  25. skilleter_thingy/strreplace.py +82 -0
  26. skilleter_thingy/test.py +34 -0
  27. skilleter_thingy/tfm.py +948 -0
  28. skilleter_thingy/tfparse.py +101 -0
  29. skilleter_thingy/trimpath.py +82 -0
  30. skilleter_thingy/venv_create.py +47 -0
  31. skilleter_thingy/venv_template.py +47 -0
  32. skilleter_thingy/xchmod.py +124 -0
  33. skilleter_thingy/yamlcheck.py +89 -0
  34. skilleter_thingy-0.3.14.dist-info/METADATA +606 -0
  35. skilleter_thingy-0.3.14.dist-info/RECORD +39 -0
  36. skilleter_thingy-0.3.14.dist-info/WHEEL +5 -0
  37. skilleter_thingy-0.3.14.dist-info/entry_points.txt +31 -0
  38. skilleter_thingy-0.3.14.dist-info/licenses/LICENSE +619 -0
  39. skilleter_thingy-0.3.14.dist-info/top_level.txt +1 -0
@@ -0,0 +1,328 @@
1
+ #! /usr/bin/env python3
2
+
3
+ ################################################################################
4
+ """ Script invoked via the 'git cmp' alias, which sets GIT_EXTERNAL_DIFF so that
5
+ this is called instead of using git diff.
6
+
7
+ Copyright (C) 2017-18 John Skilleter
8
+
9
+ Parameters passed by git are:
10
+
11
+ For a normal diff between two versions of a file in Git:
12
+
13
+ N MEANING EXAMPLE
14
+ 1 file path tgy_git.py
15
+
16
+ 2 tmp old file /tmp/OjfLZ8_tgy_git.py
17
+ 3 old SHA1 027422b8b6e945227b27abf4161ad38c5b6e9ff9
18
+ 4 old perm 100644
19
+
20
+ 5 tmp new file tgy_git.py
21
+ 6 new SHA1 0000000000000000000000000000000000000000
22
+ 7 new perm 100644
23
+
24
+ If the path is unmerged, only parameter #1 is passed
25
+
26
+ Also sets:
27
+
28
+ GIT_DIFF_PATH_COUNTER - incremented for each file compared
29
+ GIT_DIFF_PATH_TOTAL - total number of paths to be compared
30
+
31
+ If GIT_SUBDIR is set in the environment it indicates the relative
32
+ path of the current directory from the top-level directory of the
33
+ working tree.
34
+ """
35
+ ################################################################################
36
+
37
+ ################################################################################
38
+ # Imports
39
+
40
+ import sys
41
+ import os
42
+ import argparse
43
+ import filecmp
44
+ import re
45
+ import logging
46
+ import subprocess
47
+
48
+ from skilleter_modules import colour
49
+ from skilleter_modules import files
50
+ from skilleter_modules import git
51
+ from skilleter_modules import dircolors
52
+
53
+ ################################################################################
54
+ # Constants
55
+
56
+ # A file must be at least this size to be considered binary - if it is smaller
57
+ # we give it the benefit of the doubt.
58
+
59
+ MIN_BINARY_SIZE = 8
60
+
61
+ ################################################################################
62
+
63
+ def report_permissions(perm):
64
+ """ Convert an octal value in a string to a description of file permissions
65
+ e.g. given '644' it will return 'rw-r--r--' """
66
+
67
+ mask_chars = ('r', 'w', 'x', 'r', 'w', 'x', 'r', 'w', 'x')
68
+
69
+ # Convert the permissions from an octal string to an integer
70
+
71
+ permissions = int(perm, 8)
72
+
73
+ # Start at the topmost bit and work downwards adding the mask character
74
+ # for bits that are set and '-' for ones that aren't.
75
+
76
+ mask = 1 << (len(mask_chars) - 1)
77
+
78
+ permtext = []
79
+
80
+ for mask_char in mask_chars:
81
+ permtext.append(mask_char if permissions & mask else '-')
82
+ mask >>= 1
83
+
84
+ return ''.join(permtext)
85
+
86
+ ################################################################################
87
+
88
+ def main():
89
+ """ Main function - does everything """
90
+
91
+ # Allow the log level to be configured in git config, as well as via the
92
+ # GITCMP_DEBUG
93
+
94
+ txt_debug = git.config_get('cmp', 'debug')
95
+ env_debug = os.getenv('GITCMP_DEBUG', '0')
96
+
97
+ if txt_debug.lower() in ('true', '1') or env_debug.lower() in ('true', '1'):
98
+ logging.basicConfig(level=logging.INFO)
99
+
100
+ # Parse the command line
101
+
102
+ parser = argparse.ArgumentParser(description='Invoked via the "git cmp" alias. Works as an enhanced version of "git difftool"')
103
+
104
+ parser.add_argument('file_path', nargs='?', help='File name and path')
105
+
106
+ parser.add_argument('old_file', nargs='?', help='Name of temporary copy of old version')
107
+ parser.add_argument('old_sha1', nargs='?', help='SHA1 of the old version')
108
+ parser.add_argument('old_perm', nargs='?', help='Permissions for the old version')
109
+
110
+ parser.add_argument('new_file', nargs='?', help='Name of temporary copy of the new version')
111
+ parser.add_argument('new_sha1', nargs='?', help='SHA1 of the new version')
112
+ parser.add_argument('new_perm', nargs='?', help='Permissions for the new version')
113
+
114
+ parser.add_argument('new_name', nargs='?', help='New name (if file has been renamed)')
115
+ parser.add_argument('rename', nargs='?', help='Description of rename')
116
+
117
+ args = parser.parse_args()
118
+
119
+ # Get configuration from the environment
120
+
121
+ path_count = int(os.getenv('GIT_DIFF_PATH_COUNTER', '0'))
122
+ path_total = int(os.getenv('GIT_DIFF_PATH_TOTAL', '0'))
123
+ diff_binaries = int(os.getenv('GIT_DIFF_BINARIES', '0'))
124
+ skip_deleted = int(os.getenv('GIT_IGNORE_DELETED', '0'))
125
+
126
+ # Debug output
127
+
128
+ logging.info('Parameters to gitcmp-helper:')
129
+ logging.info('1: path: %s', args.file_path)
130
+ logging.info('2: old file: %s', args.old_file)
131
+ logging.info('3: old sha1: %s', args.old_sha1)
132
+ logging.info('4: old perm: %s', args.old_perm)
133
+ logging.info('5: new file: %s', args.new_file)
134
+ logging.info('6: new sha1: %s', args.new_sha1)
135
+ logging.info('7: new perm: %s', args.new_perm)
136
+ logging.info('8: new name: %s', args.new_name)
137
+ logging.info('9: rename : %s', args.rename)
138
+ logging.info('path count: %d/%d', path_count, path_total)
139
+
140
+ # Sanity checks
141
+
142
+ if args.file_path is None:
143
+ sys.stderr.write('At least one parameter must be specified\n')
144
+ sys.exit(1)
145
+
146
+ # Check and handle for the simple case of an unmerged file
147
+
148
+ if args.old_file is None:
149
+ colour.write(f'[CYAN:{args.file_path}] is not merged')
150
+ sys.exit(0)
151
+
152
+ # Make sure that we have all the expected parameters
153
+
154
+ if args.new_perm is None:
155
+ sys.stderr.write('Either 1 or 7 parameters must be specified\n')
156
+ sys.exit(1)
157
+
158
+ # Make sure we can access the temporary files supplied
159
+
160
+ if not os.access(args.old_file, os.R_OK):
161
+ sys.stderr.write(f'Unable to read temporary old file: {args.old_file}\n')
162
+ sys.exit(2)
163
+
164
+ if not os.access(args.new_file, os.R_OK):
165
+ sys.stderr.write(f'Unable to read temporary new file: {args.new_file}\n')
166
+ sys.exit(2)
167
+
168
+ dc = dircolors.Dircolors()
169
+
170
+ # Determine the best way of reporting the path to the file
171
+
172
+ try:
173
+ working_tree_path = os.getcwd()
174
+ except FileNotFoundError:
175
+ sys.stderr.write('Unable to get current working directory')
176
+ sys.exit(2)
177
+
178
+ current_path = os.path.join(working_tree_path, os.getenv('GIT_SUBDIR', ''))
179
+
180
+ current_file_path = os.path.relpath(args.file_path if args.new_name is None else args.new_name, current_path)
181
+
182
+ logging.info('file path: %s', current_file_path)
183
+
184
+ # Heading printed first
185
+
186
+ heading = ['[BOLD]Changes in [NORMAL]%s' % dc.format(current_file_path)]
187
+
188
+ # If file was renamed, append the old name and the degree of similarity
189
+
190
+ if args.new_name:
191
+ similarity = re.sub(r'(similarity index) (.*)', r'\1 [CYAN:\2]', args.rename.split('\n')[0])
192
+
193
+ heading.append('(rename from %s with %s)' % (dc.format(os.path.relpath(args.file_path, current_path)), similarity))
194
+
195
+ # If processing more than one file, append he index and total number of files
196
+
197
+ if path_total > 0:
198
+ heading.append(f'({path_count}/{path_total})')
199
+
200
+ # Check for newly created/deleted files (other version will be '/dev/null')
201
+
202
+ created_file = args.old_file == '/dev/null'
203
+ deleted_file = args.new_file == '/dev/null'
204
+
205
+ if created_file:
206
+ heading.append('(new file)')
207
+
208
+ if deleted_file:
209
+ heading.append('(deleted file)')
210
+
211
+ colour.write(' '.join(heading))
212
+
213
+ # Report permission(s) / permissions changes
214
+
215
+ permissions_changed = not (created_file or deleted_file) and args.old_perm != args.new_perm
216
+
217
+ if deleted_file:
218
+ colour.write(' Old permissions: [CYAN:%s]' % report_permissions(args.old_perm))
219
+ elif created_file:
220
+ colour.write(' New permissions: [CYAN:%s]' % report_permissions(args.new_perm))
221
+ elif permissions_changed:
222
+ colour.write(' Changed permissions: [CYAN:%s] -> [CYAN:%s]' % (report_permissions(args.old_perm), report_permissions(args.new_perm)))
223
+ else:
224
+ colour.write(' Permissions: [CYAN:%s]' % report_permissions(args.new_perm))
225
+
226
+ # Report size changes
227
+
228
+ old_size = os.stat(args.old_file).st_size
229
+ new_size = os.stat(args.new_file).st_size
230
+
231
+ formatted_old_size = files.format_size(old_size, always_suffix=True)
232
+ formatted_new_size = files.format_size(new_size, always_suffix=True)
233
+
234
+ if created_file:
235
+ colour.write(f' New size: [CYAN:{formatted_new_size}]')
236
+ elif deleted_file:
237
+ colour.write(f' Original size: [CYAN:{formatted_old_size}]')
238
+ elif new_size == old_size:
239
+ colour.write(f' Size: [CYAN]{formatted_new_size}[NORMAL] (no change)')
240
+ else:
241
+ formatted_delta_size = files.format_size(abs(new_size - old_size), always_suffix=True)
242
+
243
+ delta = '%s %s' % (formatted_delta_size, 'larger' if new_size > old_size else 'smaller')
244
+
245
+ if formatted_old_size == formatted_new_size:
246
+ colour.write(' Size: [CYAN:%s] (%s)' % (formatted_new_size, delta))
247
+ else:
248
+ colour.write(' Size: [CYAN:%s] -> [CYAN:%s] (%s)' %
249
+ (formatted_old_size, formatted_new_size, delta))
250
+
251
+ # Report file type
252
+
253
+ if created_file:
254
+ old_type = None
255
+ else:
256
+ old_type = files.file_type(args.old_file)
257
+
258
+ if deleted_file:
259
+ new_type = None
260
+ else:
261
+ new_type = files.file_type(args.new_file)
262
+
263
+ if created_file:
264
+ colour.write(' File type: [CYAN:%s]' % new_type)
265
+ elif deleted_file:
266
+ colour.write(' Original file type: [CYAN:%s]' % old_type)
267
+ elif old_type != new_type:
268
+ colour.write(' File type: [CYAN:%s] (previously [CYAN:%s)]' % (new_type, old_type))
269
+ else:
270
+ colour.write(' File type: [CYAN:%s]' % new_type)
271
+
272
+ # Report permissions and type
273
+
274
+ if filecmp.cmp(args.old_file, args.new_file, shallow=False):
275
+ # If the file is unchanged, just report the permissions change (if any)
276
+
277
+ if permissions_changed:
278
+ colour.write(' Revisions are identical with changes to permissions')
279
+ else:
280
+ colour.write(' Revisions are identical')
281
+ else:
282
+ # Check if the file is/was a binary
283
+
284
+ old_binary = not created_file and old_size > MIN_BINARY_SIZE and files.is_binary_file(args.old_file)
285
+ new_binary = not deleted_file and new_size > MIN_BINARY_SIZE and files.is_binary_file(args.new_file)
286
+
287
+ # If both versions are binary and we're not risking diffing binaries, report it
288
+ # otherwise, issue a warning if one version is binary then do the diff
289
+
290
+ if (old_binary or new_binary) and not diff_binaries:
291
+ colour.write(' Cannot diff binary files')
292
+ else:
293
+ difftool = git.config_get('cmp', 'difftool', defaultvalue='diffuse')
294
+
295
+ if old_binary or new_binary:
296
+ colour.write(' [BOLD:WARNING]: One or both files may be binaries')
297
+
298
+ if not deleted_file or not skip_deleted:
299
+ try:
300
+ subprocess.run([difftool, args.old_file, args.new_file], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=True)
301
+
302
+ except subprocess.CalledProcessError as exc:
303
+ print(f'WARNING: Diff failed - status = {exc.returncode}')
304
+
305
+ except FileNotFoundError:
306
+ print(f'ERROR: Unable to locate diff tool {difftool}')
307
+ sys.exit(1)
308
+
309
+ # Separate reports with a blank line
310
+
311
+ print('')
312
+
313
+ ################################################################################
314
+
315
+ def gitcmp_helper():
316
+ """Entry point"""
317
+
318
+ try:
319
+ main()
320
+ except KeyboardInterrupt:
321
+ sys.exit(1)
322
+ except BrokenPipeError:
323
+ sys.exit(2)
324
+
325
+ ################################################################################
326
+
327
+ if __name__ == '__main__':
328
+ gitcmp_helper()
@@ -0,0 +1,293 @@
1
+ #! /usr/bin/env python3
2
+
3
+ """ Thingy gitprompt command
4
+
5
+ Copyright (C) 2017 John Skilleter
6
+
7
+ Used to create the portion of the shell prompt that optionally shows
8
+ the current git repo name and branch and to output a colour code indicating
9
+ the status of the current working tree.
10
+
11
+ Normally used in the shell setup scripts (e.g. ~/.bashrc) as:
12
+
13
+ export PS1=$(gitprompt OPTIONS)
14
+
15
+ Command line options:
16
+
17
+ '--colour'
18
+
19
+ Output a background colour code indicating the status of the
20
+ current tree, rather than the repo name and branch.
21
+
22
+ Colours used are:
23
+
24
+ Green - Clean repo, no local changes
25
+ Cyan - Clean repo with untracked file(s)
26
+ Yellow - Uncommitted local changes (added, copied or renamed files)
27
+ Red - Local changes that have not been added (files modified or deleted)
28
+ Magenta - Unmerged files
29
+
30
+ Other options are set via the Git configuration:
31
+
32
+ prompt.prefix: 0 - No prefix
33
+ 1 - Single letter indications of git status (untracked, modified, etc)
34
+ 2 - One word indications (untracked, modified, etc)
35
+
36
+ TODO: Limit the total prompt length more 'intelligently', rather than just bits of it.
37
+ TODO: Indicate whether current directory is writeable and/or put current owner in prompt if no the current user
38
+ """
39
+
40
+ ################################################################################
41
+
42
+ # Try and reduce the scope for an auto-repeating ^C to screw up the shell prompt
43
+
44
+ import signal
45
+
46
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
47
+
48
+ import os
49
+ import sys
50
+ import argparse
51
+
52
+ from skilleter_modules import git
53
+ from skilleter_modules import colour
54
+
55
+ ################################################################################
56
+ # Constants
57
+
58
+ # Prefix text used when showing git status in the prompt - first entry is the
59
+ # abbreviated form and the second is the verbose.
60
+
61
+ STATUS_PREFIX = \
62
+ {
63
+ 'untracked': ('u', 'untracked'),
64
+ 'added': ('A', 'added'),
65
+ 'modified': ('M', 'modified'),
66
+ 'unmerged': ('U', 'unmerged'),
67
+ 'deleted': ('D', 'deleted'),
68
+ 'copied': ('C', 'copied'),
69
+ 'renamed': ('R', 'renamed'),
70
+ 'stash': ('S', 'stashed')
71
+ }
72
+
73
+ MAX_BRANCH_NAME_LENGTH = int(os.environ.get('COLUMNS', 96)) / 3
74
+
75
+ ################################################################################
76
+
77
+ def colour_prompt(gitstate: dict):
78
+ """ Return the colour for the prompt, according to the current state of the
79
+ working tree. """
80
+
81
+ output = []
82
+
83
+ output.append('[NORMAL]')
84
+
85
+ if gitstate['modified'] or gitstate['deleted']:
86
+ output.append('[REVERSE][RED]')
87
+
88
+ elif gitstate['added'] or gitstate['copied'] or gitstate['renamed']:
89
+ output.append('[REVERSE][YELLOW]')
90
+
91
+ elif gitstate['unmerged']:
92
+ output.append('[REVERSE][MAGENTA]')
93
+
94
+ elif gitstate['untracked']:
95
+ output.append('[REVERSE][CYAN]')
96
+
97
+ elif gitstate['merging'] or gitstate['bisecting'] or gitstate['rebasing']:
98
+ output.append('[REVERSE][BLACK]')
99
+
100
+ else:
101
+ output.append('[REVERSE][GREEN]')
102
+
103
+ if output:
104
+ output.append(' ')
105
+
106
+ return output
107
+
108
+ ################################################################################
109
+
110
+ def prompt_prefix(gitstate: dict):
111
+ """ Build a prompt prefix containing the type and number
112
+ of changes in the repo. """
113
+
114
+ prefix = []
115
+
116
+ # Get the status configuration from gitconfig and restrict it to the
117
+ # range 0..2
118
+
119
+ try:
120
+ status_prefix = int(git.config_get('prompt', 'prefix', defaultvalue='0'))
121
+ except ValueError:
122
+ status_prefix = 0
123
+ else:
124
+ status_prefix = max(min(status_prefix, 2), 0)
125
+
126
+ # Only output the status information if the prefix is non-zero
127
+
128
+ if status_prefix > 0:
129
+ i = status_prefix - 1
130
+
131
+ stashed = len(git.stash())
132
+
133
+ if stashed:
134
+ prefix.append('%s:%d' % (STATUS_PREFIX['stash'][i], stashed))
135
+
136
+ if gitstate['untracked']:
137
+ prefix.append('%s:%d' % (STATUS_PREFIX['untracked'][i], gitstate['untracked']))
138
+
139
+ if gitstate['added']:
140
+ prefix.append('%s:%d' % (STATUS_PREFIX['added'][i], gitstate['added']))
141
+
142
+ if gitstate['modified']:
143
+ prefix.append('%s:%d' % (STATUS_PREFIX['modified'][i], gitstate['modified']))
144
+
145
+ if gitstate['unmerged']:
146
+ prefix.append('%s:%d' % (STATUS_PREFIX['unmerged'][i], gitstate['unmerged']))
147
+
148
+ if gitstate['deleted']:
149
+ prefix.append('%s:%d' % (STATUS_PREFIX['deleted'][i], gitstate['deleted']))
150
+
151
+ if gitstate['copied']:
152
+ prefix.append('%s:%d' % (STATUS_PREFIX['copied'][i], gitstate['copied']))
153
+
154
+ if gitstate['renamed']:
155
+ prefix.append('%s:%d' % (STATUS_PREFIX['renamed'][i], gitstate['renamed']))
156
+
157
+ if prefix:
158
+ prefix = ['[' + ' '.join(prefix) + ']']
159
+
160
+ # Get the current branch, tag or commit
161
+
162
+ branch = git.branch() or git.tag() or git.current_commit(short=True)
163
+
164
+ # TODO: More intelligent branch name pruning - currently just trims it if longer than limit
165
+ # TODO: Keep branch name up to minimum characters long - use more components if still shorter
166
+
167
+ if len(branch) > MAX_BRANCH_NAME_LENGTH:
168
+ truncated_name = None
169
+
170
+ for sep in (' ', '-', '_', '/'):
171
+ shortname = sep.join(branch.split(sep)[0:2])
172
+ if (truncated_name and len(truncated_name) > len(shortname)) or not truncated_name:
173
+ truncated_name = shortname
174
+
175
+ if truncated_name:
176
+ branch = '%s...' % truncated_name
177
+
178
+ if gitstate['rebasing']:
179
+ prefix.append('(rebasing)')
180
+ elif gitstate['bisecting']:
181
+ prefix.append('(bisecting)')
182
+ elif gitstate['merging']:
183
+ prefix.append('(merging)')
184
+
185
+ project = git.project(short=True)
186
+
187
+ if project:
188
+ prefix.append(project + ':')
189
+
190
+ prefix.append(branch)
191
+
192
+ return ' '.join(prefix)
193
+
194
+ ################################################################################
195
+
196
+ def git_status(colour_output: str, prompt_output: str):
197
+ """ Catalogue the current state of the working tree then call the function
198
+ to either output a suitable colour or the prompt text or both """
199
+
200
+ # Get the working tree, just return if there's an error
201
+
202
+ try:
203
+ working_tree = git.working_tree()
204
+ except git.GitError:
205
+ return None
206
+
207
+ # Return if we are not in a working tree
208
+
209
+ if not working_tree:
210
+ return None
211
+
212
+ # gitstate contains counters for numbers of modified (etc.) elements in the tree and flags to indicate
213
+ # whether we're currently in a merge/rebase/bisect state.
214
+
215
+ gitstate = {'modified': 0, 'added': 0, 'untracked': 0, 'unmerged': 0, 'deleted': 0, 'renamed': 0, 'copied': 0}
216
+
217
+ # Set flags if we are currently merging/rebasing/bisecting and get the current status
218
+
219
+ try:
220
+ gitstate['merging'] = git.merging()
221
+ gitstate['rebasing'] = git.rebasing()
222
+ gitstate['bisecting'] = git.bisecting()
223
+
224
+ status = git.status(untracked=True)
225
+ except git.GitError as exc:
226
+ # Major failure of gitness - report the error and quit
227
+
228
+ msg = exc.msg.split('\n')[0]
229
+
230
+ if colour_output:
231
+ return f'[WHITE][BRED] {msg}'
232
+
233
+ return f' ERROR: {msg} '
234
+
235
+ # Count the number of files in each state
236
+
237
+ for st in status:
238
+ gitstate['untracked'] += '?' in st[0]
239
+ gitstate['added'] += 'A' in st[0]
240
+ gitstate['modified'] += 'M' in st[0]
241
+ gitstate['unmerged'] += 'U' in st[0]
242
+ gitstate['deleted'] += 'D' in st[0]
243
+ gitstate['copied'] += 'C' in st[0]
244
+ gitstate['renamed'] += 'R' in st[0]
245
+
246
+ # Set the output colour or output the prompt prefix
247
+
248
+ output = []
249
+
250
+ if colour_output:
251
+ output += colour_prompt(gitstate)
252
+
253
+ if prompt_output or not colour_output:
254
+ output.append(prompt_prefix(gitstate))
255
+
256
+ if output:
257
+ output.append(' ')
258
+
259
+ return ''.join(output)
260
+
261
+ ################################################################################
262
+
263
+ def main():
264
+ """ Parse the command line and output colour or status """
265
+
266
+ parser = argparse.ArgumentParser(description='Report current branch and, optionally, git repo name to be embedded in shell prompt')
267
+ parser.add_argument('--colour', action='store_true', help='Output colour code indicating working tree status')
268
+ parser.add_argument('--prompt', action='store_true', help='Output the prompt (default if --colour not specified)')
269
+
270
+ args = parser.parse_args()
271
+
272
+ output = git_status(args.colour, args.prompt)
273
+
274
+ if output:
275
+ colour.write(output, newline=False)
276
+
277
+ ################################################################################
278
+
279
+ def gitprompt():
280
+ """Entry point"""
281
+
282
+ try:
283
+ main()
284
+
285
+ except KeyboardInterrupt:
286
+ sys.exit(1)
287
+ except BrokenPipeError:
288
+ sys.exit(2)
289
+
290
+ ################################################################################
291
+
292
+ if __name__ == '__main__':
293
+ gitprompt()