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

@@ -7,8 +7,7 @@ import sys
7
7
  import argparse
8
8
  import fnmatch
9
9
  import configparser
10
-
11
- # TODO: Switch to tomlkit
10
+ import shlex
12
11
  from collections import defaultdict
13
12
 
14
13
  import thingy.git2 as git
@@ -27,18 +26,19 @@ import thingy.colour as colour
27
26
 
28
27
  # 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
29
28
  # TODO: [ ] -j option to run in parallel?
30
- # TODO: [ ] init function
29
+ # TODO: [/] init function
31
30
  # TODO: [/] Use the configuration file
32
31
  # TODO: [/] Don't use a fixed list of default branch names
33
32
  # TODO: [/] / Output name of each git repo as it is processed as command sits there seeming to do nothing otherwise.
34
33
  # TODO: [ ] ? Pull/fetch - only output after running command and only if something updated
35
- # TODO: [ ] Don't save the configuration on exit if it hasn't changed
34
+ # TODO: [/] Don't save the configuration on exit if it hasn't changed
36
35
  # TODO: [ ] Consistent colours in output
37
36
  # TODO: [ ] Is it going to be a problem if the same repo is checked out twice or more in the same workspace
38
37
  # TODO: [ ] Better error-handling - e.g. continue/abort option after failure in one repo
39
38
  # TODO: [ ] Dry-run option
40
39
  # TODO: [ ] Verbose option
41
40
  # TODO: [ ] When specifying list of repos, if repo name doesn't contain '/' prefix it with '*'?
41
+ # TODO: [ ] Switch to tomlkit
42
42
 
43
43
  ################################################################################
44
44
 
@@ -103,13 +103,26 @@ def mg_init(args, config, console):
103
103
  By default, it scans the tree for git directories and adds or updates them
104
104
  in the configuration, using the current branch as the default branch. """
105
105
 
106
+ # TODO: [ ] Update should remove or warn about repos that are no longer present
107
+
106
108
  # Search for .git directories
107
109
 
108
110
  for repo in find_git_repos(args.directory, args.repos):
109
111
  if not args.quiet:
110
112
  show_progress(console.columns, repo)
111
113
 
112
- config[repo] = {'default branch': git.branch(path=repo)}
114
+ if not repo in config:
115
+ config[repo] = {
116
+ 'default branch': git.branch(path=repo)
117
+ }
118
+
119
+ remote = git.remotes(path=repo)
120
+
121
+ if 'origin' in remote:
122
+ config[repo]['origin'] = remote['origin']
123
+ config[repo]['name']= os.path.basename(remote['origin']).removesuffix('.git')
124
+ else:
125
+ config[repo]['name'] = os.path.basename(repo)
113
126
 
114
127
  ################################################################################
115
128
 
@@ -259,7 +272,7 @@ def mg_push(args, config, console):
259
272
  result = git.push(path=repo, force_with_lease=args.force)
260
273
 
261
274
  if result:
262
- colour.write(result, indent=4)
275
+ colour.write(result, indent=4)
263
276
 
264
277
  colour.write()
265
278
 
@@ -371,6 +384,48 @@ def mg_clean(args, config, console):
371
384
 
372
385
  ################################################################################
373
386
 
387
+ def mg_dir(args, config, console):
388
+ """Return the location of a working tree, given the name. Returns an
389
+ error unless there is a unique match"""
390
+
391
+ location = []
392
+ search_dir = args.dir[0]
393
+
394
+ for repo in find_git_repos(args.directory, args.repos):
395
+ if fnmatch.fnmatch(config[repo]['name'], search_dir):
396
+ location.append(repo)
397
+
398
+ if len(location) == 0:
399
+ error(f'No matches with {dir}')
400
+ elif len(location) > 1:
401
+ error(f'Multiple matches with {dir}')
402
+
403
+ colour.write(location[0])
404
+
405
+ ################################################################################
406
+
407
+ def mg_run(args, config, console):
408
+ """Run a command in each of the working trees, optionally continuing if
409
+ there's an error"""
410
+
411
+ cmd = shlex.split(args.cmd[0])
412
+
413
+ for repo in find_git_repos(args.directory, args.repos):
414
+ if not args.quiet:
415
+ show_progress(console.columns, repo)
416
+
417
+ output, status = git.git_run_status(cmd, path=repo)
418
+
419
+ if output:
420
+ colour.write(f'[BOLD:{repo}]')
421
+ colour.write()
422
+ colour.write(output, indent=4)
423
+
424
+ if status and not args.cont:
425
+ sys.exit(status)
426
+
427
+ ################################################################################
428
+
374
429
  def main():
375
430
  """Main function"""
376
431
 
@@ -384,6 +439,8 @@ def main():
384
439
  'commit': mg_commit,
385
440
  'update': mg_update,
386
441
  'clean': mg_clean,
442
+ 'dir': mg_dir,
443
+ 'run': mg_run,
387
444
  }
388
445
 
389
446
  # Parse args in the form COMMAND OPTIONS SUBCOMMAND SUBCOMMAND_OPTIONS PARAMETERS
@@ -431,6 +488,13 @@ def main():
431
488
  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.')
432
489
  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.')
433
490
 
491
+ parser_dir = subparsers.add_parser('dir', help='Return the location of a working tree, given the repo name')
492
+ parser_dir.add_argument('dir', nargs=1, action='store', help='The name of the working tree')
493
+
494
+ parser_run = subparsers.add_parser('run', help='Run any git command in each of the working trees')
495
+ parser_run.add_argument('--cont', '-c', action='store_true', help='Continue if the command returns an error in any of the working trees')
496
+ parser_run.add_argument('cmd', nargs=1, action='store', help='The command to run (should be quoted)')
497
+
434
498
  # Parse the command line
435
499
 
436
500
  args = parser.parse_args()
@@ -472,14 +536,21 @@ def multigit():
472
536
 
473
537
  try:
474
538
  main()
539
+
540
+ # Catch keyboard aborts
541
+
475
542
  except KeyboardInterrupt:
476
543
  sys.exit(1)
477
544
 
545
+ # Quietly fail if output was being piped and the pipe broke
546
+
478
547
  except BrokenPipeError:
479
548
  sys.exit(2)
480
549
 
550
+ # Catch-all failure for Git errors
551
+
481
552
  except git.GitError as exc:
482
- print(exc)
553
+ sys.stderr.write(exc)
483
554
  sys.exit(3)
484
555
 
485
556
  ################################################################################
@@ -38,6 +38,11 @@ import thingy.gitlab as gitlab
38
38
 
39
39
  (LOCAL, GLOBAL, SYSTEM) = list(range(3))
40
40
 
41
+ # Options always passed to Git (disable autocorrect to stop it running the wrong command
42
+ # if an invalid command name has been specified).
43
+
44
+ STANDARD_GIT_OPTIONS = ['-c', 'help.autoCorrect=never']
45
+
41
46
  ################################################################################
42
47
 
43
48
  class GitError(run.RunError):
@@ -54,7 +59,7 @@ def git(cmd, stdout=None, stderr=None, path=None):
54
59
  to get the exception.
55
60
  Optionally redirect stdout and stderr as specified. """
56
61
 
57
- git_cmd = ['git']
62
+ git_cmd = ['git'] + STANDARD_GIT_OPTIONS
58
63
 
59
64
  if path:
60
65
  git_cmd += ['-C', path]
@@ -75,7 +80,7 @@ def git_run_status(cmd, stdout=None, stderr=None, path=None):
75
80
 
76
81
  logging.debug('Running git %s', ' '.join(cmd))
77
82
 
78
- git_cmd = ['git']
83
+ git_cmd = ['git'] + STANDARD_GIT_OPTIONS
79
84
 
80
85
  if path:
81
86
  git_cmd += ['-C', path]
@@ -317,10 +322,10 @@ def merging():
317
322
 
318
323
  ################################################################################
319
324
 
320
- def remotes():
325
+ def remotes(path=None):
321
326
  """ Return the list of git remotes """
322
327
 
323
- repo = pygit2.Repository(os.getcwd())
328
+ repo = pygit2.Repository(path or os.getcwd())
324
329
 
325
330
  git_remotes = {}
326
331
 
@@ -10,11 +10,10 @@
10
10
  of 'a+rw' and applies them to all files and directories in the specified
11
11
  path and must be run with -R/--recursive.
12
12
 
13
- TODO:
14
- Support all file modes as per chmod
15
- Support all command line options of chmod
16
- Implement non-recursive mode
17
- Options for files/directories only
13
+ TODO: [ ] Support all file modes as per chmod
14
+ TODO: [ ] Support all command line options of chmod
15
+ TODO: [ ] Implement non-recursive mode
16
+ TODO: [ ] Options for files/directories only
18
17
 
19
18
  Copyright (C) 2017 John Skilleter
20
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: skilleter_thingy
3
- Version: 0.0.77
3
+ Version: 0.0.79
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
@@ -37,11 +37,11 @@ This README just contains a summary of the functionality of each command.
37
37
 
38
38
  ## ggit
39
39
 
40
- Run a git command in all repos under the current directory
40
+ Run a git command in all working trees under the current directory (note that this is not related to multigit (see below)).
41
41
 
42
42
  ## ggrep
43
43
 
44
- Run 'git grep' in all repos under the current directory
44
+ Run 'git grep' in all repos under the current directory (note that this is not related to multigit (see below)).
45
45
 
46
46
  ## gitprompt
47
47
 
@@ -53,15 +53,11 @@ Improved version of 'git commit --amend'. Updates files that are already in the
53
53
 
54
54
  ## git cleanup
55
55
 
56
- List or delete branches that have already been merged and delete tracking branches that are no longer on ther remote.
56
+ List or delete branches that have already been merged and delete tracking branches that are no longer on the remote.
57
57
 
58
58
  ## git co
59
59
 
60
- Equivalent to 'git checkout' but with intelligent branch matching
61
-
62
- ## git mr
63
-
64
- Push a feature branch to GitLab and create a merge request
60
+ Equivalent to 'git checkout' but with intelligent branch matching, so specifying a partial branch name will work if it uniquely matches an existing branch
65
61
 
66
62
  ## git parent
67
63
 
@@ -83,21 +79,21 @@ Console-based git change review tool.
83
79
 
84
80
  Manage a collection of related git repoitories.
85
81
 
86
- # General Commands
82
+ ## GitLab Commands
87
83
 
88
- ## addpath
84
+ ### git mr
89
85
 
90
- Update a $PATH-type variable by adding or removing entries.
86
+ Push a feature branch to GitLab and create a merge request
91
87
 
92
- ## console-colours
88
+ ### gl
93
89
 
94
- Display all available colours in the console.
90
+ Command line for GitLab
95
91
 
96
- ## diskspacecheck
92
+ # General Commands
97
93
 
98
- Check how much free space is available on all filesystems, ignoring read-only filesystems, /dev and tmpfs.
94
+ ## addpath
99
95
 
100
- Issue a warning if any are above 90% used.
96
+ Update a $PATH-type variable by adding or removing entries.
101
97
 
102
98
  ## docker-purge
103
99
 
@@ -143,7 +139,7 @@ Simple search and replace utility for those times when trying to escape characte
143
139
 
144
140
  ## tfm
145
141
 
146
- Console-based file-manager, similar to Midnight Commander but better.
142
+ Console-based file-manager, similar to Midnight Commander but aiming to be better.
147
143
 
148
144
  ## tfparse
149
145
 
@@ -161,9 +157,7 @@ Create a script to create/update a virtual environment and run a python script i
161
157
 
162
158
  ## xchmod
163
159
 
164
- WIP: Command to run chmod only on files that need it (only modifies files that don't have the required permissions already).
165
-
166
- Currently implements a *very* restricted set of functionality.
160
+ Command to run chmod only on files that need it (only modifies files that don't have the required permissions already).
167
161
 
168
162
  ## yamlcheck
169
163
 
@@ -177,9 +171,15 @@ These will be moved to the skilleter-extras package in due course.
177
171
 
178
172
  Wrapper for the borg backup utility to make it easier to use with a fixed set of options.
179
173
 
180
- ## gl
174
+ ## consolecolours
181
175
 
182
- Command line for GitLab
176
+ Display all available colours in the console.
177
+
178
+ ## diskspacecheck
179
+
180
+ Check how much free space is available on all filesystems, ignoring read-only filesystems, /dev and tmpfs.
181
+
182
+ Issue a warning if any are above 90% used.
183
183
 
184
184
  ## gphotosync
185
185
 
@@ -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=DES_T2XpyR82jR30e26KvrXMgmSepUhSiSffjTru1AU,19026
28
+ skilleter_thingy/multigit.py,sha256=c-EZqU0wFSwb6PxEZmxNIAxdD1vex626ph805RDRcfI,21512
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
@@ -41,7 +41,7 @@ skilleter_thingy/tfparse.py,sha256=u1IZH2J_WH1aORyMozKSI2JKok7_S1MMJhiobzmhlUI,2
41
41
  skilleter_thingy/trimpath.py,sha256=25On5OHTT1rXTzTuRWQeS3FWtTd0XZr5NFDDACR6AGM,2294
42
42
  skilleter_thingy/venv_create.py,sha256=lMcGvWNwP-ZlyPJ1eZU-PHNOnscZHjtjhoT6sLfhIU4,1153
43
43
  skilleter_thingy/window_rename.py,sha256=dCBgZqih_3YKHt35hsOAhARFp3QxOi8w8huC63sqJK8,3128
44
- skilleter_thingy/xchmod.py,sha256=F9_lxKuLqVlHHr3oBI3dkMoFOuwRzYDlpQMTmDcjpBI,4590
44
+ skilleter_thingy/xchmod.py,sha256=NgSNpB7mU28n21xC-PbDF2Y0nKPmvVFOJhtm_r6OT_0,4604
45
45
  skilleter_thingy/yamlcheck.py,sha256=FXylZ5NtHirDlPVhVEUZUZkTugVR-g51BbjaN06akAc,2868
46
46
  skilleter_thingy/thingy/__init__.py,sha256=rVPTxm8L5w52U0YdTd7r_D44SBP7pS3JCJtsf0iIsow,110
47
47
  skilleter_thingy/thingy/colour.py,sha256=-I5HOfWZNVxN85DjNPpzYLIUlzGrzMr3oLRwim7O6us,7103
@@ -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=UEXeSyT5PlYGtdUAQDEZC7Sc7JmYdAlP6osa1tVmpO8,36620
55
+ skilleter_thingy/thingy/git2.py,sha256=_ASpj1uUzxKyIFo4NOblUz99ZAcih-uhGafXczX49jk,36880
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.77.dist-info/LICENSE,sha256=ljOS4DjXvqEo5VzGfdaRwgRZPbNScGBmfwyC8PChvmQ,32422
65
- skilleter_thingy-0.0.77.dist-info/METADATA,sha256=OuTAQKPCHRzc4K-j1oHaFnpO8piPz-pKO5uT-0uPs3s,5938
66
- skilleter_thingy-0.0.77.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
67
- skilleter_thingy-0.0.77.dist-info/entry_points.txt,sha256=uW11ofmIbfPP_5B-pxb8YDkHbeZ_xeCoO6358R9wGVI,2146
68
- skilleter_thingy-0.0.77.dist-info/top_level.txt,sha256=8-JhgToBBiWURunmvfpSxEvNkDHQQ7r25-aBXtZv61g,17
69
- skilleter_thingy-0.0.77.dist-info/RECORD,,
64
+ skilleter_thingy-0.0.79.dist-info/LICENSE,sha256=ljOS4DjXvqEo5VzGfdaRwgRZPbNScGBmfwyC8PChvmQ,32422
65
+ skilleter_thingy-0.0.79.dist-info/METADATA,sha256=6aHbIawlb7OSELGU2QxtkxQiMLTqo-p-Z_WS6Qvwji4,6113
66
+ skilleter_thingy-0.0.79.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
67
+ skilleter_thingy-0.0.79.dist-info/entry_points.txt,sha256=u5ymS-KPljIGTnprV5yJsAjz7qgeT2BZ-Qo_Con_PFM,2145
68
+ skilleter_thingy-0.0.79.dist-info/top_level.txt,sha256=8-JhgToBBiWURunmvfpSxEvNkDHQQ7r25-aBXtZv61g,17
69
+ skilleter_thingy-0.0.79.dist-info/RECORD,,
@@ -1,7 +1,7 @@
1
1
  [console_scripts]
2
2
  addpath = skilleter_thingy:addpath.addpath
3
3
  borger = skilleter_thingy:borger.borger
4
- console_colours = skilleter_thingy:console_colours.console_colours
4
+ consolecolours = skilleter_thingy:console_colours.console_colours
5
5
  diskspacecheck = skilleter_thingy:diskspacecheck.diskspacecheck
6
6
  docker-purge = skilleter_thingy:docker_purge.docker_purge
7
7
  ffind = skilleter_thingy:ffind.ffind