Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb825dc7

Browse files
committed
Implemented multi-line parsing of git-config to the point where a sepcific test-file is working.
This brings us much closer to what git can do, and should at least prevent errors while readingconfiguration files (which would break a lot of features, like handling of remotes since these relyreading configuration files).Fixesgitpython-developers#112
1 parenta0cb95c commitb825dc7

File tree

3 files changed

+271
-39
lines changed

3 files changed

+271
-39
lines changed

‎git/config.py

Lines changed: 67 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
string_types,
2323
FileType,
2424
defenc,
25-
with_metaclass
25+
with_metaclass,
26+
PY3
2627
)
2728

2829
__all__= ('GitConfigParser','SectionConstraint')
@@ -243,7 +244,21 @@ def _read(self, fp, fpname):
243244
cursect=None# None, or a dictionary
244245
optname=None
245246
lineno=0
247+
is_multi_line=False
246248
e=None# None, or an exception
249+
250+
defstring_decode(v):
251+
ifv[-1]=='\\':
252+
v=v[:-1]
253+
# end cut trailing escapes to prevent decode error
254+
255+
ifPY3:
256+
returnv.encode(defenc).decode('unicode_escape')
257+
else:
258+
returnv.decode('string_escape')
259+
# end
260+
# end
261+
247262
whileTrue:
248263
# we assume to read binary !
249264
line=fp.readline().decode(defenc)
@@ -256,46 +271,60 @@ def _read(self, fp, fpname):
256271
ifline.split(None,1)[0].lower()=='rem'andline[0]in"rR":
257272
# no leading whitespace
258273
continue
259-
else:
260-
# is it a section header?
261-
mo=self.SECTCRE.match(line.strip())
274+
275+
# is it a section header?
276+
mo=self.SECTCRE.match(line.strip())
277+
ifnotis_multi_lineandmo:
278+
sectname=mo.group('header').strip()
279+
ifsectnameinself._sections:
280+
cursect=self._sections[sectname]
281+
elifsectname==cp.DEFAULTSECT:
282+
cursect=self._defaults
283+
else:
284+
cursect=self._dict((('__name__',sectname),))
285+
self._sections[sectname]=cursect
286+
self._proxies[sectname]=None
287+
# So sections can't start with a continuation line
288+
optname=None
289+
# no section header in the file?
290+
elifcursectisNone:
291+
raisecp.MissingSectionHeaderError(fpname,lineno,line)
292+
# an option line?
293+
elifnotis_multi_line:
294+
mo=self.OPTCRE.match(line)
262295
ifmo:
263-
sectname=mo.group('header').strip()
264-
ifsectnameinself._sections:
265-
cursect=self._sections[sectname]
266-
elifsectname==cp.DEFAULTSECT:
267-
cursect=self._defaults
268-
else:
269-
cursect=self._dict((('__name__',sectname),))
270-
self._sections[sectname]=cursect
271-
self._proxies[sectname]=None
272-
# So sections can't start with a continuation line
273-
optname=None
274-
# no section header in the file?
275-
elifcursectisNone:
276-
raisecp.MissingSectionHeaderError(fpname,lineno,line)
277-
# an option line?
296+
# We might just have handled the last line, which could contain a quotation we want to remove
297+
optname,vi,optval=mo.group('option','vi','value')
298+
ifviin ('=',':')and';'inoptval:
299+
pos=optval.find(';')
300+
ifpos!=-1andoptval[pos-1].isspace():
301+
optval=optval[:pos]
302+
optval=optval.strip()
303+
ifoptval=='""':
304+
optval=''
305+
# end handle empty string
306+
optname=self.optionxform(optname.rstrip())
307+
iflen(optval)>1andoptval[0]=='"'andoptval[-1]!='"':
308+
is_multi_line=True
309+
optval=string_decode(optval[1:])
310+
# end handle multi-line
311+
cursect[optname]=optval
278312
else:
279-
mo=self.OPTCRE.match(line)
280-
ifmo:
281-
optname,vi,optval=mo.group('option','vi','value')
282-
ifviin ('=',':')and';'inoptval:
283-
pos=optval.find(';')
284-
ifpos!=-1andoptval[pos-1].isspace():
285-
optval=optval[:pos]
286-
optval=optval.strip()
287-
ifoptval=='""':
288-
optval=''
289-
optname=self.optionxform(optname.rstrip())
290-
cursect[optname]=optval
291-
else:
292-
ifnote:
293-
e=cp.ParsingError(fpname)
294-
e.append(lineno,repr(line))
295-
# END
296-
# END ?
297-
# END ?
313+
ifnote:
314+
e=cp.ParsingError(fpname)
315+
e.append(lineno,repr(line))
316+
print(lineno,line)
317+
continue
318+
else:
319+
line=line.rstrip()
320+
ifline.endswith('"'):
321+
is_multi_line=False
322+
line=line[:-1]
323+
# end handle quotations
324+
cursect[optname]+=string_decode(line)
325+
# END parse section or option
298326
# END while reading
327+
299328
# if any parsing errors occurred, raise an exception
300329
ife:
301330
raisee
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
[user]
2+
name = Cody Veal
3+
email = cveal05@gmail.com
4+
5+
[github]
6+
user = cjhveal
7+
8+
[advice]
9+
statusHints = false
10+
11+
[alias]
12+
# add
13+
a = add
14+
aa = add --all
15+
ap = add --patch
16+
17+
aliases = !git config --list | grep 'alias\\.' | sed 's/alias\\.\\([^=]*\\)=\\(.*\\)/\\1\\\t => \\2/' | sort
18+
19+
# branch
20+
br = branch
21+
branches = branch -av
22+
cp = cherry-pick
23+
diverges = !bash -c 'diff -u <(git rev-list --first-parent "${1}") <(git rev-list --first-parent "${2:-HEAD}"g | sed -ne \"s/^ //p\" | head -1' -
24+
track = checkout -t
25+
nb = checkout -b
26+
27+
# commit
28+
amend = commit --amend -C HEAD
29+
c = commit
30+
ca = commit --amend
31+
cm = commit --message
32+
msg = commit --allow-empty -m
33+
34+
co = checkout
35+
36+
# diff
37+
d = diff --color-words # diff by word
38+
ds = diff --staged --color-words
39+
dd = diff --color-words=. # diff by char
40+
dds = diff --staged --color-words=.
41+
dl = diff # diff by line
42+
dls = diff --staged
43+
44+
h = help
45+
46+
# log
47+
authors = "!git log --pretty=format:%aN | sort | uniq -c | sort -rn"
48+
lc = log ORIG_HEAD.. --stat --no-merges
49+
lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset' --abbrev-commit --date=relative
50+
lol = log --graph --decorate --pretty=oneline --abbrev-commit
51+
lola = log --graph --decorate --pretty=oneline --abbrev-commit --all
52+
53+
# merge
54+
m = merge
55+
mm = merge --no-ff
56+
ours = "!f() { git checkout --ours $@ && git add $@; }; f"
57+
theirs = "!f() { git checkout --theirs $@ && git add $@; }; f"
58+
59+
# push/pull
60+
l = pull
61+
p = push
62+
sync = !git pull && git push
63+
64+
# remotes
65+
prune-remotes = "!for remote in `git remote`; do git remote prune $remote; done"
66+
r = remote
67+
68+
# rebase
69+
rb = rebase
70+
rba = rebase --abort
71+
rbc = rebase --continue
72+
rbs = rebase --skip
73+
74+
# reset
75+
rh = reset --hard
76+
rhh = reset HEAD --hard
77+
uncommit = reset --soft HEAD^
78+
unstage = reset HEAD --
79+
unpush = push -f origin HEAD^:master
80+
81+
# stash
82+
ss = stash
83+
sl = stash list
84+
sp = stash pop
85+
sd = stash drop
86+
snapshot = !git stash save "snapshot: $(date)" && git stash apply "stash@{0}"
87+
88+
# status
89+
s = status --short --branch
90+
st = status
91+
92+
# submodule
93+
sm = submodule
94+
sma = submodule add
95+
smu = submodule update --init
96+
pup = !git pull && git submodule init && git submodule update
97+
98+
# file level ignoring
99+
assume = update-index --assume-unchanged
100+
unassume = update-index --no-assume-unchanged
101+
assumed = "!git ls-files -v | grep ^h | cut -c 3-"
102+
103+
104+
[apply]
105+
whitespace = fix
106+
107+
[color]
108+
ui = auto
109+
110+
[color "branch"]
111+
current = yellow reverse
112+
local = yellow
113+
remote = green
114+
115+
[color "diff"]
116+
meta = yellow
117+
frag = magenta
118+
old = red bold
119+
new = green bold
120+
whitespace = red reverse
121+
122+
[color "status"]
123+
added = green
124+
changed = yellow
125+
untracked = cyan
126+
127+
[core]
128+
editor = /usr/bin/vim
129+
excludesfile = ~/.gitignore_global
130+
attributesfile = ~/.gitattributes
131+
132+
[diff]
133+
renames = copies
134+
mnemonicprefix = true
135+
136+
[diff "zip"]
137+
textconv = unzip -c -a
138+
139+
[merge]
140+
log = true
141+
142+
[merge "railsschema"]
143+
name = newer Rails schema version
144+
driver = "ruby -e '\n\
145+
system %(git), %(merge-file), %(--marker-size=%L), %(%A), %(%O), %(%B)\n\
146+
b = File.read(%(%A))\n\
147+
b.sub!(/^<+ .*\\nActiveRecord::Schema\\.define.:version => (\\d+). do\\n=+\\nActiveRecord::Schema\\.define.:version => (\\d+). do\\n>+ .*/) do\n\
148+
%(ActiveRecord::Schema.define(:version => #{[$1, $2].max}) do)\n\
149+
end\n\
150+
File.open(%(%A), %(w)) {|f| f.write(b)}\n\
151+
exit 1 if b.include?(%(<)*%L)'"
152+
153+
[merge "gemfilelock"]
154+
name = relocks the gemfile.lock
155+
driver = bundle lock
156+
157+
[pager]
158+
color = true
159+
160+
[push]
161+
default = upstream
162+
163+
[rerere]
164+
enabled = true
165+
166+
[url "git@github.com:"]
167+
insteadOf = "gh:"
168+
pushInsteadOf = "github:"
169+
pushInsteadOf = "git://github.com/"
170+
171+
[url "git://github.com/"]
172+
insteadOf = "github:"
173+
174+
[url "git@gist.github.com:"]
175+
insteadOf = "gst:"
176+
pushInsteadOf = "gist:"
177+
pushInsteadOf = "git://gist.github.com/"
178+
179+
[url "git://gist.github.com/"]
180+
insteadOf = "gist:"
181+
182+
[url "git@heroku.com:"]
183+
insteadOf = "heroku:"

‎git/test/test_config.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
#
44
# This module is part of GitPython and is released under
55
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
6+
# The test test_multi_line_config requires whitespace (especially tabs) to remain
7+
# flake8: noqa
68

79
fromgit.test.libimport (
810
TestCase,
9-
fixture_path
11+
fixture_path,
12+
assert_equal
1013
)
1114
fromgitimport (
1215
GitConfigParser
@@ -72,6 +75,23 @@ def test_read_write(self):
7275
assertr_config.get(sname,oname)==val
7376
# END for each filename
7477

78+
deftest_multi_line_config(self):
79+
file_obj=self._to_memcache(fixture_path("git_config_with_comments"))
80+
config=GitConfigParser(file_obj,read_only=False)
81+
ev=r"""ruby -e '
82+
system %(git), %(merge-file), %(--marker-size=%L), %(%A), %(%O), %(%B)
83+
b = File.read(%(%A))
84+
b.sub!(/^<+ .*\nActiveRecord::Schema\.define.:version => (\d+). do\n=+\nActiveRecord::Schema\.define.:version => (\d+). do\n>+ .*/) do
85+
%(ActiveRecord::Schema.define(:version => #{[$1, $2].max}) do)
86+
end
87+
File.open(%(%A), %(w)) {|f| f.write(b)}
88+
exit 1 if b.include?(%(<)*%L)'"""
89+
assert_equal(config.get('merge "railsschema"','driver'),ev)
90+
assert_equal(config.get('alias','lg'),
91+
"log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset'"
92+
" --abbrev-commit --date=relative")
93+
assertlen(config.sections())==23
94+
7595
deftest_base(self):
7696
path_repo=fixture_path("git_config")
7797
path_global=fixture_path("git_config_global")

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp