skilleter-thingy 0.0.48__tar.gz → 0.0.50__tar.gz

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.

Potentially problematic release.


This version of skilleter-thingy might be problematic. Click here for more details.

Files changed (74) hide show
  1. {skilleter_thingy-0.0.48/skilleter_thingy.egg-info → skilleter_thingy-0.0.50}/PKG-INFO +1 -1
  2. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/pyproject.toml +1 -1
  3. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/box.py +0 -2
  4. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/git_hold.py +2 -2
  5. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/git_review.py +2 -2
  6. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/git_update.py +1 -1
  7. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/gphotosync.py +10 -4
  8. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/photodupe.py +0 -1
  9. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/py_audit.py +1 -2
  10. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/readable.py +21 -1
  11. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/git2.py +0 -9
  12. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/tidy.py +18 -3
  13. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/venv_create.py +1 -0
  14. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50/skilleter_thingy.egg-info}/PKG-INFO +1 -1
  15. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/LICENSE +0 -0
  16. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/README.md +0 -0
  17. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/setup.cfg +0 -0
  18. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/__init__.py +0 -0
  19. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/addpath.py +0 -0
  20. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/borger.py +0 -0
  21. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/console_colours.py +0 -0
  22. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/diskspacecheck.py +0 -0
  23. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/docker_purge.py +0 -0
  24. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/ffind.py +0 -0
  25. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/ggit.py +0 -0
  26. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/ggrep.py +0 -0
  27. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/git_br.py +0 -0
  28. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/git_ca.py +0 -0
  29. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/git_cleanup.py +0 -0
  30. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/git_co.py +0 -0
  31. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/git_common.py +0 -0
  32. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/git_mr.py +0 -0
  33. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/git_parent.py +0 -0
  34. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/git_wt.py +0 -0
  35. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/gitcmp_helper.py +0 -0
  36. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/gitprompt.py +0 -0
  37. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/gl.py +0 -0
  38. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/linecount.py +0 -0
  39. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/moviemover.py +0 -0
  40. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/phototidier.py +0 -0
  41. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/remdir.py +0 -0
  42. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/rmdupe.py +0 -0
  43. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/rpylint.py +0 -0
  44. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/splitpics.py +0 -0
  45. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/strreplace.py +0 -0
  46. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/sysmon.py +0 -0
  47. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/tfm.py +0 -0
  48. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/tfparse.py +0 -0
  49. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/__init__.py +0 -0
  50. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/colour.py +0 -0
  51. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/dc_curses.py +0 -0
  52. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/dc_defaults.py +0 -0
  53. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/dc_util.py +0 -0
  54. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/dircolors.py +0 -0
  55. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/docker.py +0 -0
  56. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/files.py +0 -0
  57. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/git.py +0 -0
  58. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/gitlab.py +0 -0
  59. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/logger.py +0 -0
  60. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/path.py +0 -0
  61. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/popup.py +0 -0
  62. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/process.py +0 -0
  63. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/run.py +0 -0
  64. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/tfm_pane.py +0 -0
  65. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/thingy/venv_template.py +0 -0
  66. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/trimpath.py +0 -0
  67. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/window_rename.py +0 -0
  68. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/xchmod.py +0 -0
  69. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy/yamlcheck.py +0 -0
  70. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy.egg-info/SOURCES.txt +0 -0
  71. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy.egg-info/dependency_links.txt +0 -0
  72. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy.egg-info/entry_points.txt +0 -0
  73. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy.egg-info/requires.txt +0 -0
  74. {skilleter_thingy-0.0.48 → skilleter_thingy-0.0.50}/skilleter_thingy.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: skilleter_thingy
3
- Version: 0.0.48
3
+ Version: 0.0.50
4
4
  Summary: A collection of useful utilities, mainly aimed at making Git more friendly
5
5
  Author-email: John Skilleter <john@skilleter.org.uk>
6
6
  Project-URL: Home, https://skilleter.org.uk
@@ -7,7 +7,7 @@ name = "skilleter_thingy"
7
7
 
8
8
  # Version must be incremented to install updated Thingy
9
9
 
10
- version = "0.0.48"
10
+ version = "0.0.50"
11
11
 
12
12
  authors = [
13
13
  {name="John Skilleter", email="john@skilleter.org.uk"},
@@ -5,9 +5,7 @@
5
5
  """
6
6
  ################################################################################
7
7
 
8
- import os
9
8
  import sys
10
- import argparse
11
9
  import thingy.colour as colour
12
10
 
13
11
  ################################################################################
@@ -54,7 +54,7 @@ def archive_branches(branches):
54
54
  colour.error(f'[RED:ERROR:] An archive tag already exists for branch {branch}')
55
55
 
56
56
  if branch == current_branch:
57
- colour.error(f'[RED:ERROR:] Cannot archive the current branch')
57
+ colour.error('[RED:ERROR:] Cannot archive the current branch')
58
58
 
59
59
  for branch in branches:
60
60
  tag_name = archive_tag_name(branch)
@@ -95,7 +95,7 @@ def restore_archive_branches(branches):
95
95
  tags = archive_tags()
96
96
 
97
97
  for branch in branches:
98
- if not archive_tag_name(branch) in tags:
98
+ if archive_tag_name(branch) not in tags:
99
99
  colour.error(f'[RED:ERROR:] Archive branch {branch} does not exist')
100
100
 
101
101
  archive_tag_names = []
@@ -1299,13 +1299,13 @@ def parse_command_line():
1299
1299
  # Make sure that we're actually in a git working tree
1300
1300
 
1301
1301
  if not git.working_tree():
1302
- colour.error(f'[RED:ERROR] Not a git repository')
1302
+ colour.error('[RED:ERROR] Not a git repository')
1303
1303
 
1304
1304
  # -C/--change is shorthand for '--commit HEAD^'
1305
1305
 
1306
1306
  if args.change:
1307
1307
  if args.commits:
1308
- colour.error(f'[RED:ERROR] The -C/--change option does not take parameters')
1308
+ colour.error('[RED:ERROR] The -C/--change option does not take parameters')
1309
1309
 
1310
1310
  args.commits = ['HEAD^']
1311
1311
 
@@ -195,7 +195,7 @@ def branch_pull(args, results, branch, fail=True):
195
195
  fail = False
196
196
 
197
197
  elif exc.msg.startswith('Your configuration specifies to merge with the ref'):
198
- colour.write(f'[RED:WARNING]: The upstream branch no longer exists', indent=4)
198
+ colour.write('[RED:WARNING]: The upstream branch no longer exists', indent=4)
199
199
  fail = False
200
200
 
201
201
  elif 'no such ref was fetched' in exc.msg:
@@ -120,6 +120,7 @@ def parse_command_line():
120
120
  parser.add_argument('--rclone', '-r', action='store', default=DEFAULT_RCLONE_REMOTE, help=f'rclone remote name for Google photos (defaults to {DEFAULT_RCLONE_REMOTE})')
121
121
  parser.add_argument('--no-update', '-N', action='store_true', help='Do not update local cache')
122
122
  parser.add_argument('--keep', '-k', action='store', type=int, default=DEFAULT_KEEP, help=f'Keep this number of months before the start date in the cache (defaults to {DEFAULT_KEEP})')
123
+ parser.add_argument('--skip-no-day', '-z', action='store_true', help='Don\'t sync files where the day of the month could not be determined')
123
124
  parser.add_argument('action', nargs='*', help='Actions to perform (report or sync)')
124
125
 
125
126
  args = parser.parse_args()
@@ -319,7 +320,7 @@ def get_media_date(name, info):
319
320
 
320
321
  ################################################################################
321
322
 
322
- def sync_media_local(dryrun, media_files, destination_dir):
323
+ def sync_media_local(dryrun, skip_no_day, media_files, destination_dir):
323
324
  """Sync files from the cache to local storage"""
324
325
 
325
326
  # Iterate through the list of remote media_files to try work out the date and
@@ -328,6 +329,11 @@ def sync_media_local(dryrun, media_files, destination_dir):
328
329
  for media_file in media_files:
329
330
  year, month, day = get_media_date(media_file, media_files[media_file])
330
331
 
332
+ # If specified, skip files where the day of the month could not be determined
333
+
334
+ if skip_no_day and day == '00':
335
+ day = None
336
+
331
337
  if year and month and day:
332
338
  destination_media_file_path = os.path.join(destination_dir, year, f'{year}-{month}-{day}', os.path.basename(media_file))
333
339
 
@@ -385,7 +391,7 @@ def update_cache(args, year, month):
385
391
 
386
392
  ################################################################################
387
393
 
388
- def media_sync(dryrun, media, media_files, local_dir):
394
+ def media_sync(dryrun, skip_no_day, media, media_files, local_dir):
389
395
  """Given a media type and list of local and remote files of the type, check
390
396
  for out-of-sync files and sync any missing remote files to local storage"""
391
397
 
@@ -422,7 +428,7 @@ def media_sync(dryrun, media, media_files, local_dir):
422
428
 
423
429
  if media_files['remote']:
424
430
  colour.write(f' [BOLD:{len(media_files["remote"])} remote {media} files are out of sync]')
425
- sync_media_local(dryrun, media_files['remote'], local_dir)
431
+ sync_media_local(dryrun, skip_no_day, media_files['remote'], local_dir)
426
432
  else:
427
433
  colour.write(f' [BOLD:No remote {media} files are out of sync]')
428
434
 
@@ -542,7 +548,7 @@ def gphoto_sync(args, year, month):
542
548
  colour.write(f'[BOLD:Syncing files for {month:02}/{year}]')
543
549
 
544
550
  for media in ('photo', 'video'):
545
- media_sync(args.dryrun, media, media_files[media], args.local_dir[media])
551
+ media_sync(args.dryrun, args.skip_no_day, media, media_files[media], args.local_dir[media])
546
552
 
547
553
  ################################################################################
548
554
 
@@ -3,7 +3,6 @@
3
3
 
4
4
  import sys
5
5
  import os
6
- import sys
7
6
  import pickle
8
7
  import argparse
9
8
 
@@ -5,7 +5,6 @@
5
5
 
6
6
  ################################################################################
7
7
 
8
- import os
9
8
  import sys
10
9
  import requests
11
10
  import subprocess
@@ -64,7 +63,7 @@ def audit(package, version):
64
63
  print()
65
64
  print(v['details'])
66
65
  else:
67
- print(f'No known vulnerabilities')
66
+ print('No known vulnerabilities')
68
67
 
69
68
  ################################################################################
70
69
 
@@ -29,7 +29,7 @@ import thingy.files as files
29
29
  TF_OBJECTS_CHANGED_END = 'Terraform detected the following changes made outside of Terraform since the last "terraform apply":'
30
30
  TF_IGNORE_MSG = 'Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan may include actions to undo or respond to these changes.'
31
31
 
32
- TF_REFRESHING_AND_READING = re.compile(r'.*: (?:Refreshing state\.\.\.|Reading\.\.\.|Read complete after |Preparing import\.\.\.).*')
32
+ TF_REFRESHING_AND_READING = re.compile(r'.*: (?:Refreshing state\.\.\.|Reading\.\.\.|Still reading\.\.\.|Read complete after |Preparing import\.\.\.).*')
33
33
  TF_FINDING_AND_INSTALLING = re.compile(r'- (?:Finding .*[.]{3}|Installing .*[.]{3}|Installed .*)')
34
34
 
35
35
  TF_HAS_CHANGED = re.compile(r' # .* has changed')
@@ -62,6 +62,7 @@ def parse_command_line():
62
62
  parser.add_argument('-O', '--dir', action='store', default=None, help='Store output files in the specified directory (creating it if it doesn\'t exist)')
63
63
  parser.add_argument('-a', '--aws', action='store_true', help='Remove AWS resource IDs')
64
64
  parser.add_argument('-T', '--terraform', action='store_true', help='Clean Terraform plan/apply log files')
65
+ parser.add_argument('-R', '--replace', action='append', default=None, help='Additional regex replacements in the form "REGEX=REPLACEMENT"')
65
66
  parser.add_argument('files', nargs='*', default=None, help='The files to convert (use stdin/stout if no input files are specified)')
66
67
 
67
68
  args = parser.parse_args()
@@ -91,6 +92,18 @@ def parse_command_line():
91
92
  if args.dir and not os.path.isdir(args.dir):
92
93
  os.mkdir(args.dir)
93
94
 
95
+ # Handle additional regex replacements
96
+
97
+ if args.replace:
98
+ args.regex_replace = []
99
+ for entry in args.replace:
100
+ regex, replace = entry.split('=')
101
+ try:
102
+ args.regex_replace.append({'regex': re.compile(regex), 'replace':replace})
103
+ except re.error as exc:
104
+ print(f'ERROR in regular expression {regex}: {exc}')
105
+ sys.exit(1)
106
+
94
107
  return args
95
108
 
96
109
  ################################################################################
@@ -139,6 +152,7 @@ def cleanfile(args, infile, outfile):
139
152
  clean = tidy.remove_sha256(clean)
140
153
  clean = tidy.remove_sha1(clean)
141
154
  clean = tidy.remove_times(clean)
155
+ clean = tidy.remove_speeds(clean)
142
156
 
143
157
  if not args.light and not args.dark:
144
158
  clean = tidy.remove_ansi(clean)
@@ -148,6 +162,12 @@ def cleanfile(args, infile, outfile):
148
162
  if args.aws:
149
163
  clean = tidy.remove_aws_ids(clean)
150
164
 
165
+ # Additional custom regex replacements
166
+
167
+ if args.replace:
168
+ for entry in args.regex_replace:
169
+ clean = entry['regex'].sub(entry['replace'], clean)
170
+
151
171
  # Do things with Terraform log data
152
172
 
153
173
  if args.terraform:
@@ -216,15 +216,6 @@ def merge(branch):
216
216
 
217
217
  ################################################################################
218
218
 
219
- def merging():
220
- """ Return True if a merge is in progress, False otherwise """
221
-
222
- merge_check = git_run_status(['rev-parse', '-q', '--verify', 'MERGE_HEAD'])
223
-
224
- return merge_check[1] == 0
225
-
226
- ################################################################################
227
-
228
219
  def abort_merge():
229
220
  """ Abort the current merge """
230
221
 
@@ -50,16 +50,16 @@ RE_TIME = [
50
50
  {'regex': re.compile(r'[1-9][0-9]{3}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}[.][0-9]+Z?'), 'replace': '{DATE+TIME}'},
51
51
  {'regex': re.compile(r'[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}(Z|,[0-9]+)'), 'replace': '{TIME}'},
52
52
  {'regex': re.compile(r'[0-9]{1,2}:[0-9]{2}:[0-9]{2}(\.[0-9]{1,6})?([+][0-9]{2}:[0-9]{2})?'), 'replace': '{TIME}'},
53
-
54
-
53
+
55
54
  {'regex': re.compile(r'[1-9][0-9]{3}/[0-9][0-9]?/[1-9][0-9]'), 'replace': '{DATE}'},
56
55
  {'regex': re.compile(r'[1-9][0-9]/[0-9][0-9]?/[1-9][0-9]{3}'), 'replace': '{DATE}'},
57
56
  {'regex': re.compile(r'[0-9]{4}-[0-9]{2}-[0-9]{2}'), 'replace': '{DATE}'},
58
57
  {'regex': re.compile(r'[0-9]{2}-[0-9]{2}-[0-9]{4}'), 'replace': '{DATE}'},
59
58
 
60
59
  {'regex': re.compile(r'[0-9]([.][0-9]*)*\s*(second[s]?)'), 'replace': '{ELAPSED}'},
61
-
60
+
62
61
  {'find': r'{DATE} {TIME}', 'replace': '{DATE+TIME}'},
62
+ {'find': r'\d{2}m \d{2}s', 'replace': '{TIME}'},
63
63
  ]
64
64
 
65
65
  # SHA values
@@ -85,6 +85,14 @@ RE_AWS = \
85
85
  {'regex': re.compile(r'request id: [0-0a-f]{8}-[0-0a-f]{4}-[0-0a-f]{4}-[0-0a-f]{4}-[0-0a-f]{12}'), 'replace': 'request id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'},
86
86
  ]
87
87
 
88
+ # Data transfer speeds
89
+
90
+ RE_SPEED = \
91
+ [
92
+ {'regex': re.compile(r'[0-9.]+ *MB/s'), 'replace': '{SPEED}'},
93
+ {'regex': re.compile(r'[0-9.]+ *MiB/s'), 'replace': '{SPEED}'},
94
+ ]
95
+
88
96
  ################################################################################
89
97
 
90
98
  def regex_replace(data, regexes):
@@ -150,6 +158,13 @@ def remove_aws_ids(data):
150
158
 
151
159
  ################################################################################
152
160
 
161
+ def remove_speeds(data):
162
+ """ Attempt to remove data transfer speed references from a string """
163
+
164
+ return regex_replace(data, RE_SPEED)
165
+
166
+ ################################################################################
167
+
153
168
  def remove_ansi(text):
154
169
  """ Remove ANSI codes from a string """
155
170
 
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
+ import sys
3
4
  import os
4
5
  import stat
5
6
  import argparse
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: skilleter_thingy
3
- Version: 0.0.48
3
+ Version: 0.0.50
4
4
  Summary: A collection of useful utilities, mainly aimed at making Git more friendly
5
5
  Author-email: John Skilleter <john@skilleter.org.uk>
6
6
  Project-URL: Home, https://skilleter.org.uk