fastgit 0.1.2__tar.gz → 0.1.3__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.
- {fastgit-0.1.2/fastgit.egg-info → fastgit-0.1.3}/PKG-INFO +1 -1
- {fastgit-0.1.2 → fastgit-0.1.3}/fastgit/__init__.py +1 -1
- {fastgit-0.1.2 → fastgit-0.1.3}/fastgit/_modidx.py +4 -0
- {fastgit-0.1.2 → fastgit-0.1.3}/fastgit/core.py +60 -25
- {fastgit-0.1.2 → fastgit-0.1.3/fastgit.egg-info}/PKG-INFO +1 -1
- {fastgit-0.1.2 → fastgit-0.1.3}/LICENSE +0 -0
- {fastgit-0.1.2 → fastgit-0.1.3}/MANIFEST.in +0 -0
- {fastgit-0.1.2 → fastgit-0.1.3}/README.md +0 -0
- {fastgit-0.1.2 → fastgit-0.1.3}/fastgit.egg-info/SOURCES.txt +0 -0
- {fastgit-0.1.2 → fastgit-0.1.3}/fastgit.egg-info/dependency_links.txt +0 -0
- {fastgit-0.1.2 → fastgit-0.1.3}/fastgit.egg-info/entry_points.txt +0 -0
- {fastgit-0.1.2 → fastgit-0.1.3}/fastgit.egg-info/requires.txt +0 -0
- {fastgit-0.1.2 → fastgit-0.1.3}/fastgit.egg-info/top_level.txt +0 -0
- {fastgit-0.1.2 → fastgit-0.1.3}/pyproject.toml +0 -0
- {fastgit-0.1.2 → fastgit-0.1.3}/setup.cfg +0 -0
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
It is designed for interactive use and automation alike: errors print tersely by default (like git itself) or raise on request, exit codes that mean "no" rather than "failed" are returned normally, and passing `sync=False` gives an async client for servers and concurrent code."""
|
|
6
6
|
|
|
7
|
-
__version__ = "0.1.
|
|
7
|
+
__version__ = "0.1.3"
|
|
8
8
|
|
|
9
9
|
from .core import *
|
|
@@ -20,8 +20,12 @@ d = { 'settings': { 'branch': 'main',
|
|
|
20
20
|
'fastgit.core.Git.top': ('core.html#git.top', 'fastgit/core.py'),
|
|
21
21
|
'fastgit.core.GitRes': ('core.html#gitres', 'fastgit/core.py'),
|
|
22
22
|
'fastgit.core.GitRes.__new__': ('core.html#gitres.__new__', 'fastgit/core.py'),
|
|
23
|
+
'fastgit.core._arunlocal': ('core.html#_arunlocal', 'fastgit/core.py'),
|
|
24
|
+
'fastgit.core._depr_uname': ('core.html#_depr_uname', 'fastgit/core.py'),
|
|
23
25
|
'fastgit.core._gitcmd': ('core.html#_gitcmd', 'fastgit/core.py'),
|
|
24
26
|
'fastgit.core._gitres': ('core.html#_gitres', 'fastgit/core.py'),
|
|
27
|
+
'fastgit.core._longopts': ('core.html#_longopts', 'fastgit/core.py'),
|
|
28
|
+
'fastgit.core._runlocal': ('core.html#_runlocal', 'fastgit/core.py'),
|
|
25
29
|
'fastgit.core.acallgit': ('core.html#acallgit', 'fastgit/core.py'),
|
|
26
30
|
'fastgit.core.callgit': ('core.html#callgit', 'fastgit/core.py'),
|
|
27
31
|
'fastgit.core.get_top': ('core.html#get_top', 'fastgit/core.py')}}}
|
|
@@ -12,6 +12,7 @@ from fastcore.utils import *
|
|
|
12
12
|
from fastcore.aio import then
|
|
13
13
|
import subprocess,asyncio
|
|
14
14
|
from subprocess import CalledProcessError
|
|
15
|
+
from functools import cache
|
|
15
16
|
|
|
16
17
|
# %% ../nbs/00_core.ipynb #880c6a46
|
|
17
18
|
_ok1 = {'merge-tree','merge-base','grep','check-ignore','diff','diff-index','diff-files','diff-tree','show-ref','config','rev-parse'}
|
|
@@ -24,53 +25,75 @@ class GitRes(str):
|
|
|
24
25
|
return self
|
|
25
26
|
|
|
26
27
|
# %% ../nbs/00_core.ipynb #e4c0a290
|
|
27
|
-
def _gitcmd(path, *args,
|
|
28
|
-
assert not (uname and pre), "Pass `uname` or `pre`, not both"
|
|
29
|
-
if uname:
|
|
30
|
-
warn("`uname` is deprecated; pass e.g `pre=['/usr/bin/sudo','-u',uname]` instead", DeprecationWarning, stacklevel=3)
|
|
31
|
-
pre = ['/usr/bin/sudo', '-u', uname]
|
|
28
|
+
def _gitcmd(path, *args, pre=None):
|
|
32
29
|
cmd = ['git', '-C', str(Path(path).expanduser().resolve())] + list(args)
|
|
33
30
|
return [*pre, *cmd] if pre else cmd
|
|
34
31
|
|
|
35
|
-
def
|
|
32
|
+
def _depr_uname(uname, pre):
|
|
33
|
+
assert not (uname and pre), "Pass `uname` or `pre`, not both"
|
|
34
|
+
if not uname: return pre
|
|
35
|
+
warn("`uname` is deprecated; pass e.g `pre=['/usr/bin/sudo','-u',uname]` instead", DeprecationWarning, stacklevel=4)
|
|
36
|
+
return ['/usr/bin/sudo', '-u', uname]
|
|
37
|
+
|
|
38
|
+
def _gitres(args, out, err, returncode, ok_exit):
|
|
36
39
|
if ok_exit is None: ok_exit = 1 if args and args[0] in _ok1 else 0
|
|
37
|
-
if returncode not in (0, *listify(ok_exit)): raise CalledProcessError(returncode,
|
|
40
|
+
if returncode not in (0, *listify(ok_exit)): raise CalledProcessError(returncode, ['git', *args], out, err)
|
|
38
41
|
return GitRes((out + err).strip(), returncode)
|
|
39
42
|
|
|
40
|
-
def
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
r
|
|
44
|
-
|
|
43
|
+
def _runlocal(path, args, pre=None):
|
|
44
|
+
"Default runner: compose the local argv and run it in a subprocess"
|
|
45
|
+
r = subprocess.run(_gitcmd(path, *args, pre=pre), capture_output=True, text=True)
|
|
46
|
+
return r.stdout, r.stderr, r.returncode
|
|
47
|
+
|
|
48
|
+
def callgit(
|
|
49
|
+
path, # Directory to run git in
|
|
50
|
+
*args, # git subcommand and arguments
|
|
51
|
+
uname=None, # Deprecated; use `pre`
|
|
52
|
+
pre=None, # argv prefix, e.g. a sudo wrapper
|
|
53
|
+
ok_exit=None, # Extra accepted exit codes (default: 1 for `_ok1` commands)
|
|
54
|
+
runner=None, # Replaces the local subprocess: `(path, args, pre) -> (stdout, stderr, returncode)`
|
|
55
|
+
):
|
|
56
|
+
"Run git in `path`, returning stripped stdout+stderr as a `GitRes`"
|
|
57
|
+
out,err,rc = (runner or _runlocal)(path, list(args), pre=_depr_uname(uname, pre))
|
|
58
|
+
return _gitres(args, out, err, rc, ok_exit)
|
|
45
59
|
|
|
46
60
|
# %% ../nbs/00_core.ipynb #4c0df6c6
|
|
47
|
-
def get_top(folder):
|
|
48
|
-
try: return callgit(folder, 'rev-parse', '--show-toplevel')
|
|
61
|
+
def get_top(folder, runner=None):
|
|
62
|
+
try: return callgit(folder, 'rev-parse', '--show-toplevel', runner=runner)
|
|
49
63
|
except CalledProcessError: return None
|
|
50
64
|
|
|
65
|
+
# %% ../nbs/00_core.ipynb #2c57b813
|
|
66
|
+
@cache
|
|
67
|
+
def _longopts(cmd):
|
|
68
|
+
"Long options `git <cmd>` lists for completion; empty if unavailable"
|
|
69
|
+
try: r = subprocess.run(['git', cmd, '--git-completion-helper'], capture_output=True, text=True)
|
|
70
|
+
except OSError: return set()
|
|
71
|
+
return {o.rstrip('=') for o in r.stdout.split()} if r.returncode==0 else set()
|
|
72
|
+
|
|
51
73
|
# %% ../nbs/00_core.ipynb #97f78839
|
|
52
74
|
class Git:
|
|
53
75
|
"Run git commands in dir `d`; `sync=False` makes every command return an awaitable"
|
|
54
|
-
def __init__(self, d, pre=None, raise_exc=False, sync=True): self.d,self.pre,self.raise_exc,self._sync = Path(d).expanduser(),pre,raise_exc,sync
|
|
76
|
+
def __init__(self, d, pre=None, raise_exc=False, sync=True, runner=None): self.d,self.pre,self.raise_exc,self._sync,self.runner = Path(d).expanduser(),pre,raise_exc,sync,runner
|
|
55
77
|
|
|
56
78
|
def __call__(self, cmd, *args, mute_errors=False, raise_exc=None, ok_exit=None, **kwargs):
|
|
57
79
|
paths = [str(p) for p in listify(kwargs.pop('__', None) or [])]
|
|
58
80
|
args = listify(args)
|
|
59
81
|
kwargs = {k:v for k,v in kwargs.items() if v is not False}
|
|
60
|
-
|
|
61
|
-
args +=
|
|
62
|
-
args += [f'
|
|
63
|
-
args += [f'--{k.replace("_","-")}' for k,v in kwargs.items() if
|
|
82
|
+
def _short(k): return len(k)==1 or (len(k)<=3 and k.isalnum() and (o:=_longopts(cmd)) and f'--{k}' not in o)
|
|
83
|
+
args += concat((f'-{k}',str(v)) for k,v in kwargs.items() if _short(k) and v is not True)
|
|
84
|
+
args += [f'-{k}' for k,v in kwargs.items() if _short(k) and v is True]
|
|
85
|
+
args += [f'--{k.replace("_","-")}={v}' for k,v in kwargs.items() if not _short(k) and v is not True]
|
|
86
|
+
args += [f'--{k.replace("_","-")}' for k,v in kwargs.items() if not _short(k) and v is True]
|
|
64
87
|
if paths: args += ['--'] + paths
|
|
65
88
|
f = self._run if self._sync else self._arun
|
|
66
89
|
return f(cmd, args, mute_errors, ifnone(raise_exc, self.raise_exc), ok_exit)
|
|
67
90
|
|
|
68
91
|
def _run(self, cmd, args, mute_errors, raise_exc, ok_exit):
|
|
69
|
-
try: return callgit(self.d, cmd, *args, pre=self.pre, ok_exit=ok_exit)
|
|
92
|
+
try: return callgit(self.d, cmd, *args, pre=self.pre, ok_exit=ok_exit, runner=self.runner)
|
|
70
93
|
except CalledProcessError as e: self._err(e, cmd, args, mute_errors, raise_exc)
|
|
71
94
|
|
|
72
95
|
async def _arun(self, cmd, args, mute_errors, raise_exc, ok_exit):
|
|
73
|
-
try: return await acallgit(self.d, cmd, *args, pre=self.pre, ok_exit=ok_exit)
|
|
96
|
+
try: return await acallgit(self.d, cmd, *args, pre=self.pre, ok_exit=ok_exit, runner=self.runner)
|
|
74
97
|
except CalledProcessError as e: self._err(e, cmd, args, mute_errors, raise_exc)
|
|
75
98
|
|
|
76
99
|
def _err(self, e, cmd, args, mute_errors, raise_exc):
|
|
@@ -101,9 +124,21 @@ def commits(self:Git): return then(self.log('--oneline', mute_errors=True, raise
|
|
|
101
124
|
def current_branch(self:Git): return self.branch('--show-current')
|
|
102
125
|
|
|
103
126
|
# %% ../nbs/00_core.ipynb #b69ecf1c
|
|
104
|
-
async def
|
|
105
|
-
"Async `
|
|
106
|
-
cmd = _gitcmd(path, *args,
|
|
127
|
+
async def _arunlocal(path, args, pre=None):
|
|
128
|
+
"Async `_runlocal`"
|
|
129
|
+
cmd = _gitcmd(path, *args, pre=pre)
|
|
107
130
|
p = await asyncio.create_subprocess_exec(*cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
108
131
|
out,err = await p.communicate()
|
|
109
|
-
return
|
|
132
|
+
return out.decode(), err.decode(), p.returncode
|
|
133
|
+
|
|
134
|
+
async def acallgit(
|
|
135
|
+
path, # Directory to run git in
|
|
136
|
+
*args, # git subcommand and arguments
|
|
137
|
+
uname=None, # Deprecated; use `pre`
|
|
138
|
+
pre=None, # argv prefix, e.g. a sudo wrapper
|
|
139
|
+
ok_exit=None, # Extra accepted exit codes (default: 1 for `_ok1` commands)
|
|
140
|
+
runner=None, # Async runner replacing the local subprocess: `async (path, args, pre) -> (stdout, stderr, returncode)`
|
|
141
|
+
):
|
|
142
|
+
"Async `callgit`: identical contract, run in an `asyncio` subprocess"
|
|
143
|
+
out,err,rc = await (runner or _arunlocal)(path, list(args), pre=_depr_uname(uname, pre))
|
|
144
|
+
return _gitres(args, out, err, rc, ok_exit)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|