skilleter-thingy 0.0.75__py3-none-any.whl → 0.0.76__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.

Potentially problematic release.


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

@@ -25,6 +25,7 @@ import thingy.colour as colour
25
25
  default branch = name
26
26
  """
27
27
 
28
+ # TODO: [ ] If the config file isn't in the current directory then search up the directory tree for it but run in the current directory
28
29
  # TODO: [ ] -j option to run in parallel?
29
30
  # TODO: [ ] init function
30
31
  # TODO: [/] Use the configuration file
@@ -37,6 +38,7 @@ import thingy.colour as colour
37
38
  # TODO: [ ] Better error-handling - e.g. continue/abort option after failure in one repo
38
39
  # TODO: [ ] Dry-run option
39
40
  # TODO: [ ] Verbose option
41
+ # TODO: [ ] When specifying list of repos, if repo name doesn't contain '/' prefix it with '*'?
40
42
 
41
43
  ################################################################################
42
44
 
@@ -69,8 +71,13 @@ def show_progress(width, msg):
69
71
  def find_git_repos(directory, wildcard):
70
72
  """Locate and return a list of '.git' directory parent directories in the
71
73
  specified path.
74
+
72
75
  If wildcard is not None then it is treated as a list of wildcards and
73
- only repos matching at least one of the wildcards are returned."""
76
+ only repos matching at least one of the wildcards are returned.
77
+
78
+ If the same repo matches multiple times it will only be returned once. """
79
+
80
+ repos = set()
74
81
 
75
82
  for root, dirs, _ in os.walk(directory):
76
83
  if '.git' in dirs:
@@ -80,10 +87,14 @@ def find_git_repos(directory, wildcard):
80
87
  if wildcard:
81
88
  for card in wildcard:
82
89
  if fnmatch.fnmatch(root, card):
83
- yield root
90
+ if root not in repos:
91
+ yield root
92
+ repos.add(root)
84
93
  break
85
94
  else:
86
- yield root
95
+ if root not in repos:
96
+ yield root
97
+ repos.add(root)
87
98
 
88
99
  ################################################################################
89
100
 
@@ -261,7 +272,10 @@ def mg_checkout(args, config, console):
261
272
  if the branch exists in the repo.
262
273
  If the 'create' option is specified then branch is created"""
263
274
 
264
- # TODO: Add --create handling
275
+ # TODO: [ ] Add --create handling
276
+ # TODO: [ ] Checkout remote branches
277
+ # TODO: [ ] only try checkout if branch exists
278
+ # TODO: [ ] option to fetch before checking out
265
279
 
266
280
  for repo in find_git_repos(args.directory, args.repos):
267
281
  if not args.quiet:
@@ -270,9 +284,9 @@ def mg_checkout(args, config, console):
270
284
  branch = args.branch or config[repo]['default branch']
271
285
 
272
286
  if git.branch(path=repo) != branch:
273
- console.write(f'Checking out [BLUE:{branch}] in [BLUE:{repo}]')
287
+ colour.write(f'Checking out [BLUE:{branch}] in [BOLD:{repo}]')
274
288
 
275
- git.checkout(branch, path=repo)
289
+ git.checkout(branch, create=args.create, path=repo)
276
290
 
277
291
  ################################################################################
278
292
 
@@ -327,6 +341,36 @@ def mg_update(args, config, console):
327
341
 
328
342
  ################################################################################
329
343
 
344
+ def mg_clean(args, config, console):
345
+ """Clean the repos"""
346
+
347
+ for repo in find_git_repos(args.directory, args.repos):
348
+ if not args.quiet:
349
+ show_progress(console.columns, repo)
350
+
351
+ result = git.clean(recurse=args.recurse, force=args.force, dry_run=args.dry_run,
352
+ quiet=args.quiet, exclude=args.exclude, ignore_rules=args.x,
353
+ remove_only_ignored=args.X, path=repo)
354
+
355
+ first_skip = True
356
+
357
+ if result:
358
+ colour.write(f'[BOLD:{repo}]')
359
+
360
+ for item in result:
361
+ skipping = item.startswith('Skipping repository ')
362
+
363
+ if skipping and not args.verbose:
364
+ if first_skip:
365
+ colour.write(f' Skipping sub-repositories')
366
+ first_skip = False
367
+ else:
368
+ colour.write(f' {item.strip()}')
369
+
370
+ colour.write()
371
+
372
+ ################################################################################
373
+
330
374
  def main():
331
375
  """Main function"""
332
376
 
@@ -339,6 +383,7 @@ def main():
339
383
  'checkout': mg_checkout,
340
384
  'commit': mg_commit,
341
385
  'update': mg_update,
386
+ 'clean': mg_clean,
342
387
  }
343
388
 
344
389
  # Parse args in the form COMMAND OPTIONS SUBCOMMAND SUBCOMMAND_OPTIONS PARAMETERS
@@ -351,7 +396,7 @@ def main():
351
396
  parser.add_argument('--quiet', '-q', action='store_true', help='Minimal console output')
352
397
  parser.add_argument('--config', '-c', action='store', default=DEFAULT_CONFIG_FILE, help=f'The configuration file (defaults to {DEFAULT_CONFIG_FILE})')
353
398
  parser.add_argument('--directory', '--dir', action='store', default='.', help='The top-level directory of the multigit tree (defaults to the current directory)')
354
- parser.add_argument('--repos', '-r', action='append', default=None, help='The list of repo names to work on (defaults to all repos and can contain shell wildcards)')
399
+ parser.add_argument('--repos', '-r', action='append', default=None, help='The repo names to work on (defaults to all repos and can contain shell wildcards and can be issued multiple times on the command line)')
355
400
 
356
401
  subparsers = parser.add_subparsers(dest='command')
357
402
 
@@ -365,7 +410,7 @@ def main():
365
410
  parser_push = subparsers.add_parser('push', help='Run git push in every repo where the current branch isn\'t the default and the most recent commit was by the current user')
366
411
 
367
412
  parser_checkout = subparsers.add_parser('checkout', help='Checkout the specified branch')
368
- parser_checkout.add_argument('--create', action='store_true', help='Create the specified branch and check it out')
413
+ parser_checkout.add_argument('--create', '-b', action='store_true', help='Create the specified branch and check it out')
369
414
  parser_checkout.add_argument('branch', nargs='?', default=None, action='store', help='The branch name to check out (defaults to the default branch)')
370
415
 
371
416
  parser_commit = subparsers.add_parser('commit', help='Commit changes')
@@ -373,6 +418,17 @@ def main():
373
418
 
374
419
  parser_update = subparsers.add_parser('update', help='Pull the default branch and if the current branch isn\'t the default branch, rebase it onto the default branch')
375
420
 
421
+ parser_clean = subparsers.add_parser('clean', help='Remove untracked files from the working tree')
422
+
423
+ parser_clean.add_argument('--recurse', '-d', action='store_true', help='Recurse into subdirectories')
424
+ parser_clean.add_argument('--force', '-f', action='store_true', help='If the Git configuration variable clean.requireForce is not set to false, git clean will refuse to delete files or directories unless given -f or -i')
425
+ #parser_clean.add_argument('--interactive', '-i', action='store_true', help='Show what would be done and clean files interactively.')
426
+ parser_clean.add_argument('--dry-run', '-n', action='store_true', help='Don’t actually remove anything, just show what would be done.')
427
+ #parser_clean.add_argument('--quiet', '-q', , action='store_true', help='Be quiet, only report errors, but not the files that are successfully removed.')
428
+ parser_clean.add_argument('--exclude', '-e', action='store', help='Use the given exclude pattern in addition to the standard ignore rules.')
429
+ parser_clean.add_argument('-x', action='store_true', help='Don’t use the standard ignore rules, but still use the ignore rules given with -e options from the command line.')
430
+ parser_clean.add_argument('-X', action='store_true', help='Remove only files ignored by Git. This may be useful to rebuild everything from scratch, but keep manually created files.')
431
+
376
432
  # Parse the command line
377
433
 
378
434
  args = parser.parse_args()
@@ -382,8 +438,6 @@ def main():
382
438
  if not args.command:
383
439
  error('No command specified')
384
440
 
385
- # TODO: If the config file isn't in the current directory then search up the directory tree for it but run in the current directory
386
-
387
441
  # If the configuration file exists, read it
388
442
 
389
443
  config = configparser.ConfigParser()
@@ -418,9 +472,14 @@ def multigit():
418
472
  main()
419
473
  except KeyboardInterrupt:
420
474
  sys.exit(1)
475
+
421
476
  except BrokenPipeError:
422
477
  sys.exit(2)
423
478
 
479
+ except git.GitError as exc:
480
+ print(exc)
481
+ sys.exit(3)
482
+
424
483
  ################################################################################
425
484
 
426
485
  if __name__ == '__main__':
@@ -1239,6 +1239,38 @@ def log(branch1, branch2=None):
1239
1239
 
1240
1240
  return git(cmd)
1241
1241
 
1242
+ ################################################################################
1243
+
1244
+ def clean(recurse=False, force=False, dry_run=False, quiet=False,
1245
+ exclude=None, ignore_rules=False, remove_only_ignored=False, path=None):
1246
+
1247
+ """ Run git clean """
1248
+
1249
+ cmd = ['clean']
1250
+
1251
+ if recurse:
1252
+ cmd.append('-d')
1253
+
1254
+ if force:
1255
+ cmd.append('--force')
1256
+
1257
+ if dry_run:
1258
+ cmd.append('--dry-run')
1259
+
1260
+ if quiet:
1261
+ cmd.append('--quiet')
1262
+
1263
+ if exclude:
1264
+ cmd += ['--exclude', exclude]
1265
+
1266
+ if ignore_rules:
1267
+ cmd.append('-x')
1268
+
1269
+ if remove_only_ignored:
1270
+ cmd.append('-X')
1271
+
1272
+ return git(cmd, path=path)
1273
+
1242
1274
  ################################################################################
1243
1275
  # Entry point
1244
1276
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: skilleter_thingy
3
- Version: 0.0.75
3
+ Version: 0.0.76
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
@@ -25,7 +25,7 @@ skilleter_thingy/gl.py,sha256=9zbGpKxw6lX9RghLkdy-Q5sZlqtbB3uGFO04qTu1dH8,5954
25
25
  skilleter_thingy/gphotosync.py,sha256=Vb2zYTEFp26BYdkG810SRg9afyfDqvq4CLHTk-MFf60,22388
26
26
  skilleter_thingy/linecount.py,sha256=5voQtjJjDCVx4zjPwVRy620NpuLiwwFitzxjIsRGtxQ,4310
27
27
  skilleter_thingy/moviemover.py,sha256=j_Xb9_jFdgpFBAXcF4tEqbnKH_FonlnUU39LiCK980k,4470
28
- skilleter_thingy/multigit.py,sha256=QKn2DLf5Fr6WJr99PEM1YV5mmTlfoX7Qt5SbaXA4S8w,15695
28
+ skilleter_thingy/multigit.py,sha256=TiPpPKO-xB0MUrV1Obv4UEZMi209vrcidFolDdFH8hM,18788
29
29
  skilleter_thingy/photodupe.py,sha256=l0hbzSLb2Vk2ceteg-x9fHXCEE1uUuFo84hz5rsZUPA,4184
30
30
  skilleter_thingy/phototidier.py,sha256=5gSjlINUxf3ZQl3NG0o7CsWwODvTbokIMIafLFvn8Hc,7818
31
31
  skilleter_thingy/py_audit.py,sha256=xJm5k5qyeA6ii8mODa4dOkmP8L1drv94UHuxR54RsIM,4384
@@ -52,7 +52,7 @@ skilleter_thingy/thingy/dircolors.py,sha256=5NbXMsGWdABLvvZfB70VPmN6N5HyyihfpgoQ
52
52
  skilleter_thingy/thingy/docker.py,sha256=9EFatudoVPfB1UbDEtzdJDB3o6ToHiNHv8-oLsUeqiQ,2449
53
53
  skilleter_thingy/thingy/files.py,sha256=oW6E6WWwVFSUPdrZnKMx7P_w_hh3etjoN7RrqvYHCHc,4705
54
54
  skilleter_thingy/thingy/git.py,sha256=qXWIduF4jbP5pKFYt_hW9Ex5iL9mSBBrcNKBkULhRTg,38834
55
- skilleter_thingy/thingy/git2.py,sha256=ylEuwO-URTLxFQI--y5ed0Dg0v88reupCRBQnnkohf0,35971
55
+ skilleter_thingy/thingy/git2.py,sha256=UEXeSyT5PlYGtdUAQDEZC7Sc7JmYdAlP6osa1tVmpO8,36620
56
56
  skilleter_thingy/thingy/gitlab.py,sha256=uXAF918xnPk6qQyiwPQDbMZfqtJzhiRqDS7yEtJEIAg,6079
57
57
  skilleter_thingy/thingy/path.py,sha256=8uM2Q9zFRWv_SaVOX49PeecQXttl7J6lsmBuRXWsXKY,4732
58
58
  skilleter_thingy/thingy/popup.py,sha256=jW-nbpdeswqEMTli7OmBv1J8XQsvFoMI0J33O6dOeu8,2529
@@ -61,9 +61,9 @@ skilleter_thingy/thingy/run.py,sha256=6SNKWF01fSxzB10GMU9ajraXYZqAL1w0PXkqjJdr1U
61
61
  skilleter_thingy/thingy/tfm_pane.py,sha256=oqy5zBzKwfbjbGqetbbhpKi4x5He7sl4qkmhUeqtdZc,19789
62
62
  skilleter_thingy/thingy/tidy.py,sha256=71DCyj0VJrj52RmjQyj1eOiQJIfy5EIPHuThOrS6ZTA,5876
63
63
  skilleter_thingy/thingy/venv_template.py,sha256=SsVNvSwojd8NnFeQaZPCRQYTNdwJRplpZpygbUEXRnY,1015
64
- skilleter_thingy-0.0.75.dist-info/LICENSE,sha256=ljOS4DjXvqEo5VzGfdaRwgRZPbNScGBmfwyC8PChvmQ,32422
65
- skilleter_thingy-0.0.75.dist-info/METADATA,sha256=QbQfpZry6Uc_yjViSwKltz6mj4IE8hiT5ED0sBJqBIc,5313
66
- skilleter_thingy-0.0.75.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
67
- skilleter_thingy-0.0.75.dist-info/entry_points.txt,sha256=uW11ofmIbfPP_5B-pxb8YDkHbeZ_xeCoO6358R9wGVI,2146
68
- skilleter_thingy-0.0.75.dist-info/top_level.txt,sha256=8-JhgToBBiWURunmvfpSxEvNkDHQQ7r25-aBXtZv61g,17
69
- skilleter_thingy-0.0.75.dist-info/RECORD,,
64
+ skilleter_thingy-0.0.76.dist-info/LICENSE,sha256=ljOS4DjXvqEo5VzGfdaRwgRZPbNScGBmfwyC8PChvmQ,32422
65
+ skilleter_thingy-0.0.76.dist-info/METADATA,sha256=88wOrTIgIDHyAdQssoVO1z_DCE0rWxNey0c8XnJEjq0,5313
66
+ skilleter_thingy-0.0.76.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
67
+ skilleter_thingy-0.0.76.dist-info/entry_points.txt,sha256=uW11ofmIbfPP_5B-pxb8YDkHbeZ_xeCoO6358R9wGVI,2146
68
+ skilleter_thingy-0.0.76.dist-info/top_level.txt,sha256=8-JhgToBBiWURunmvfpSxEvNkDHQQ7r25-aBXtZv61g,17
69
+ skilleter_thingy-0.0.76.dist-info/RECORD,,