frace / git-passport Goto Github PK
View Code? Open in Web Editor NEWA Git command and hook written in Python to manage multiple Git accounts / user identities.
Home Page: https://github.com/frace/git-passport
License: Other
A Git command and hook written in Python to manage multiple Git accounts / user identities.
Home Page: https://github.com/frace/git-passport
License: Other
Placing the script in a $PATH, e.g. /usr/local/bin/git-passport
would extend the possibilities of usage. Executing git passport
manually would call the script as ususal. Optionally users could link to the path and use it as a hook.
I have to test that...
I tried git 1.9.* (several subversions) and 2.2.2, and none triggered the pre-commit
hook during git init
. The hooks were successfully copied from the templates folder, and triggered successfully when I tried to commit, but the README gives the impression a simple git init
should trigger pre-commit
. Is this a change in more recent git versions? If so, is there a hook that runs during git init
, or is some other hook or method necessary?
Performance-wise there's always the option to not call a separate program and use something like a libgit binding, e.g. pygit2 instead.
Reference: http://codereview.stackexchange.com/a/77176
@Ferada
I considered to use a Git module in first place but then decided to use subprocess because I didn't want to force users to install external dependencies for a hook.
I want to use the same passport credentials across multiple service domains.
There are several ways I could think to accomplish this with git-passport. The easiest is to make the service
field a delimited list of services. (I suggest comma-delimited since that is most common.) Alternatively, regex could be introduced. The latter could be useful for domains with multiple similar variations, though I haven't seen that much in the wild.
get_user_input should reset sys.stdin to its previous value I think. Again, think of reusing this; same with the sys.exit.
Reference: http://codereview.stackexchange.com/a/77176
add_global_id does nothing if either global_email or global_name doesn't exist. Shouldn't it rather mention that problem to the user?
Reference: http://codereview.stackexchange.com/a/77176
Examples:
-f / --force
: Force to re-passport the current git repository even if there is a passport setup already
-c / --clean
: Delete the active passport of the current git repository
I personally don't use origin as a remote very often. It would be great if that could be configurable.
Reference: http://codereview.stackexchange.com/a/77176
sys.exit(time.sleep(..)) implies that the return value of time.sleep is somehow significant. time.sleep(); sys.exit() is clearer. I'd also consider waiting for a keypress (or newline) from the user before exiting instead of using a timeout.
Reference: http://codereview.stackexchange.com/a/77176
In quite a few cases with my own repositories git-passport doesn't recognize the url correctly. This has to do with the use of urlparse. Some examples:
>>> from urllib.parse import urlparse
>>> urlparse('[email protected]:tverlaan/git-passport')
ParseResult(scheme='', netloc='', path='[email protected]:tverlaan/git-passport', params='', query='', fragment='')
>>> urlparse('github.com:tverlaan/git-passport')
ParseResult(scheme='github.com', netloc='', path='tverlaan/git-passport', params='', query='', fragment='')
>>> urlparse('https://github.com/tverlaan/git-passport.git')
ParseResult(scheme='https', netloc='github.com', path='/tverlaan/git-passport.git', params='', query='', fragment='')
I can think of two alternatives for fixing this issue:
The first solution would also allow for automatic matching different usernames for different projects with the same base url (say github.com). I'm happy to issue a PR, but I wanted to discuss first.
sys.exit already exits the process, no raise necessary, unless I'm completely missing the idiom here. And then maybe don't catch the exception in the first place, just let it propagate. The result will be the same if you already print the exception.
Reference: http://codereview.stackexchange.com/a/77176
This is a style choice, but the creation of the preset dictionary can be shorter if you'd just use the literal dictionary syntax, i.e. preset = {"General": {...}, "Passport 0": {...}, ...} instead of repeating the keys all the time.
Reference: http://codereview.stackexchange.com/a/77176
I'd structure the loop more like while True: read selection; if in pool: return selection. That's way less confusing than if not in pool: continue; (else) break; return.
Reference: http://codereview.stackexchange.com/a/77176
The docstrings say Returns: error (str): Exception, but the functions don't return exceptions, they raise them, so the docstring should say Throws or Raises instead and mention what kind of exception it uses. If you can't know that, e.g. in most of the git_* functions, leave it out, or refer to the specific function which might cause problems, i.e. subprocess.Popen.
Reference: http://codereview.stackexchange.com/a/77176
I'd wrap getting values from git in a separate function, maybe git_config_get, which would (for now) still use the same subprocess.Popen method with passed in arguments and then does the communicate/decode handling. And reraising the exception isn't necessary. Whether you create a separate git_config_set (instead of using the same mechanism as git config) is kind of a trade-off.
Reference: http://codereview.stackexchange.com/a/77176
Membership testing with sets and dictionaries is much faster, O(1), than searching sequences, O(n). When testing "a in b", b should be a set or dictionary instead of a list or tuple.
Reference: https://wiki.python.org/moin/PythonSpeed
Test:
In [4]: timeit.timeit('whitelist = [["General", "Passport"], ["email", "enable_hook", "name", "service", "sleep_duration"]]', number = 10000)
Out[4]: 0.010425090789794922
In [5]: timeit.timeit('whitelist = [{"General", "Passport"}, {"email", "enable_hook", "name", "service", "sleep_duration"}]', number = 10000)
Out[5]: 0.00904703140258789
Also, I would use less sys.exits in general. It is helpful if you can just import the script for testing purposes and it's jarring if using e.g. config_create suddenly kills the interpreter. Same for proper testing later.
Reference: http://codereview.stackexchange.com/a/77176
@Ferada
I understand the concerns in regards to testing and importing the script in the interpreter. However I just checked where I do call them. The point is that I really need them in situations where the script is used as a Git hook in order to quit a possible commit if something goes wrong with a Git ID/passport.
Unfortunately I don't see a way to reduce the number of calls of sys.exit()
right now. The only thing I could think of is to introduce a enable_debug
or enable_testing
variable which lets us disable the sys.exit()
calls conditionally.
Example:
if config["enable_hook"] and git_infected():
...
For performance, you can always use iteritems on dictionaries if you don't need the intermediate list.
Reference: http://codereview.stackexchange.com/a/77176
@Ferada
As far as I know iteritems()
is gone in Python3 instead items()
returns an iterator now. See:
I kind of find the output with lots of irregular characters unexpected, but of course that's your choice.
Reference: http://codereview.stackexchange.com/a/77176
@Ferada
I wanted the messages to stand out from the usual Git output, so I decided to use some characters (~, leading period
) for highlighting. I guess that worked out well. :) However the characters might change in the future.
Is it necessary that the passport sections be consecutively numbered? If so, this could cause some tedium when removing an early entry in a long list of passports and having to -1 most of the sections.
generate_matches could very well be a regular function and accept the two arguments pattern and raw_config instead.
Reference: http://codereview.stackexchange.com/a/77176
There's no indicator of the index anymore if you merge in the multidomain support. There should be an indicator to the user which option to select.
Just as example, in config_create you can remove one level of indentation if you return early, i.e. if not os.path.exists(filename): return;.
Reference: http://codereview.stackexchange.com/a/77176
textwrap.dedent(foo).strip() is nice, I'm copying that; since you use it very often I think that separate functions, like dedented or so, are in order; something short and simple. Same for lstrip.
Reference: http://codereview.stackexchange.com/a/77176
@Ferada
Do you mean to create a separate function like:
def dedented(message, strip_type):
if strip_type == "strip":
return textwrap.dedent(message).strip()
elif strip_type == "lstrip":
return textwrap.dedent(message).lstrip()
elif strip_type == "rstrip":
return textwrap.dedent(message).rstrip()
else:
return
For some reason using python 3.5.2 and git 2.7.4 on Max OX i get this error:
error: could not lock config file .git/config: File exists
And the file .git/config is not updated with the selection.
If would be wonderful to add the signingkey
property to have different PGP keys per passport.
I'd get rid of the config_validate function and do that in config_read instead, using a separate config_read_passport or so, which then uses ConfigParser.getboolean and the other get... functions with a very strict schema, so you make sure that everything coming out of the config object is properly parsed. That way you have to write less verification code (as the ConfigParser object takes care of that for you) and you can spend that on making sure that the individual passports have the correct format before handing them off to the rest of the application.
Reference: http://codereview.stackexchange.com/a/77176
@Ferada
Do you talk about to define config_validate()
as an inner function of config_read()
?
Possibly would it make sense to transform config_validate()
into a decorator function which then is used to decorate config_read()
?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.