Skip to content

Commit 9059525

Browse files
committed
Made repo.py a package to allow better localization of functions and utilities - the repo module got rather large
1 parent 73959f3 commit 9059525

File tree

5 files changed

+260
-237
lines changed

5 files changed

+260
-237
lines changed

lib/git/index/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Initialize the index module"""
1+
"""Initialize the index package"""
22

33
from base import *
44
from typ import *

lib/git/refs.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,8 @@ def _set_reference(self, ref):
208208
try:
209209
write_value = ref.commit.hexsha
210210
except AttributeError:
211-
sha = str(ref)
212211
try:
213-
obj = Object.new_from_sha(self.repo, hex_to_bin(sha))
212+
obj = self.repo.rev_parse(ref+"^{}") # optionally deref tags
214213
if obj.type != "commit":
215214
raise TypeError("Invalid object type behind sha: %s" % sha)
216215
write_value = obj.hexsha

lib/git/repo/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Initialize the Repo package"""
2+
3+
from base import *

lib/git/repo.py renamed to lib/git/repo/base.py

+31-234
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,39 @@
44
# This module is part of GitPython and is released under
55
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
66

7-
from exc import InvalidGitRepositoryError, NoSuchPathError
8-
from cmd import Git
9-
from objects import Actor
10-
from refs import *
11-
from index import IndexFile
12-
from objects import *
13-
from config import GitConfigParser
14-
from remote import Remote
15-
from string import digits
16-
from db import (
7+
from git.exc import InvalidGitRepositoryError, NoSuchPathError
8+
from git.cmd import Git
9+
from git.objects import Actor
10+
from git.refs import *
11+
from git.index import IndexFile
12+
from git.objects import *
13+
from git.config import GitConfigParser
14+
from git.remote import Remote
15+
from git.db import (
1716
GitCmdObjectDB,
1817
GitDB
1918
)
2019

21-
from gitdb.exc import BadObject
20+
2221
from gitdb.util import (
2322
join,
24-
isdir,
2523
isfile,
26-
join,
2724
hex_to_bin
2825
)
26+
27+
from fun import (
28+
rev_parse,
29+
is_git_dir,
30+
touch
31+
)
32+
2933
import os
3034
import sys
3135
import re
3236

3337

3438
__all__ = ('Repo', )
3539

36-
def touch(filename):
37-
fp = open(filename, "a")
38-
fp.close()
39-
40-
def is_git_dir(d):
41-
""" This is taken from the git setup.c:is_git_directory
42-
function."""
43-
44-
if isdir(d) and \
45-
isdir(join(d, 'objects')) and \
46-
isdir(join(d, 'refs')):
47-
headref = join(d, 'HEAD')
48-
return isfile(headref) or \
49-
(os.path.islink(headref) and
50-
os.readlink(headref).startswith('refs'))
51-
return False
52-
5340

5441
class Repo(object):
5542
"""Represents a git repository and allows you to query references,
@@ -112,7 +99,7 @@ def __init__(self, path=None, odbt = GitDB):
11299
self.git_dir = curpath
113100
self._working_tree_dir = os.path.dirname(curpath)
114101
break
115-
gitpath = os.path.join(curpath, '.git')
102+
gitpath = join(curpath, '.git')
116103
if is_git_dir(gitpath):
117104
self.git_dir = gitpath
118105
self._working_tree_dir = curpath
@@ -142,7 +129,7 @@ def __init__(self, path=None, odbt = GitDB):
142129
self.git = Git(self.working_dir)
143130

144131
# special handling, in special times
145-
args = [os.path.join(self.git_dir, 'objects')]
132+
args = [join(self.git_dir, 'objects')]
146133
if issubclass(odbt, GitCmdObjectDB):
147134
args.append(self.git)
148135
self.odb = odbt(*args)
@@ -163,11 +150,11 @@ def __repr__(self):
163150

164151
# Description property
165152
def _get_description(self):
166-
filename = os.path.join(self.git_dir, 'description')
153+
filename = join(self.git_dir, 'description')
167154
return file(filename).read().rstrip()
168155

169156
def _set_description(self, descr):
170-
filename = os.path.join(self.git_dir, 'description')
157+
filename = join(self.git_dir, 'description')
171158
file(filename, 'w').write(descr+'\n')
172159

173160
description = property(_get_description, _set_description,
@@ -396,11 +383,11 @@ def iter_commits(self, rev=None, paths='', **kwargs):
396383
return Commit.iter_items(self, rev, paths, **kwargs)
397384

398385
def _get_daemon_export(self):
399-
filename = os.path.join(self.git_dir, self.DAEMON_EXPORT_FILE)
386+
filename = join(self.git_dir, self.DAEMON_EXPORT_FILE)
400387
return os.path.exists(filename)
401388

402389
def _set_daemon_export(self, value):
403-
filename = os.path.join(self.git_dir, self.DAEMON_EXPORT_FILE)
390+
filename = join(self.git_dir, self.DAEMON_EXPORT_FILE)
404391
fileexists = os.path.exists(filename)
405392
if value and not fileexists:
406393
touch(filename)
@@ -416,7 +403,7 @@ def _get_alternates(self):
416403
"""The list of alternates for this repo from which objects can be retrieved
417404
418405
:return: list of strings being pathnames of alternates"""
419-
alternates_path = os.path.join(self.git_dir, 'objects', 'info', 'alternates')
406+
alternates_path = join(self.git_dir, 'objects', 'info', 'alternates')
420407

421408
if os.path.exists(alternates_path):
422409
try:
@@ -439,9 +426,9 @@ def _set_alternates(self, alts):
439426
:note:
440427
The method does not check for the existance of the paths in alts
441428
as the caller is responsible."""
442-
alternates_path = os.path.join(self.git_dir, 'objects', 'info', 'alternates')
429+
alternates_path = join(self.git_dir, 'objects', 'info', 'alternates')
443430
if not alts:
444-
if os.path.isfile(alternates_path):
431+
if isfile(alternates_path):
445432
os.remove(alternates_path)
446433
else:
447434
try:
@@ -469,7 +456,7 @@ def is_dirty(self, index=True, working_tree=True, untracked_files=False):
469456
default_args = ('--abbrev=40', '--full-index', '--raw')
470457
if index:
471458
# diff index against HEAD
472-
if os.path.isfile(self.index.path) and self.head.is_valid() and \
459+
if isfile(self.index.path) and self.head.is_valid() and \
473460
len(self.git.diff('HEAD', '--cached', *default_args)):
474461
return True
475462
# END index handling
@@ -677,7 +664,7 @@ def clone(self, path, **kwargs):
677664
# our git command could have a different working dir than our actual
678665
# environment, hence we prepend its working dir if required
679666
if not os.path.isabs(path) and self.git.working_dir:
680-
path = os.path.join(self.git._working_dir, path)
667+
path = join(self.git._working_dir, path)
681668
return Repo(os.path.abspath(path), odbt = odbt)
682669

683670

@@ -696,203 +683,13 @@ def archive(self, ostream, treeish=None, prefix=None, **kwargs):
696683
if treeish is None:
697684
treeish = self.active_branch
698685
if prefix and 'prefix' not in kwargs:
699-
kwargs['prefix'] = prefix
686+
kwargs['prefix'] = prefix
700687
kwargs['output_stream'] = ostream
701688

702689
self.git.archive(treeish, **kwargs)
703690
return self
691+
692+
rev_parse = rev_parse
704693

705-
def rev_parse(self, rev):
706-
"""
707-
:return: Object at the given revision, either Commit, Tag, Tree or Blob
708-
:param rev: git-rev-parse compatible revision specification, please see
709-
http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html
710-
for details
711-
:note: Currently there is no access to the rev-log, rev-specs may only contain
712-
topological tokens such ~ and ^.
713-
:raise BadObject: if the given revision could not be found"""
714-
if '@' in rev:
715-
raise ValueError("There is no rev-log support yet")
716-
717-
718-
# colon search mode ?
719-
if rev.startswith(':/'):
720-
# colon search mode
721-
raise NotImplementedError("commit by message search ( regex )")
722-
# END handle search
723-
724-
# return object specified by the given name
725-
def name_to_object(name):
726-
hexsha = None
727-
728-
# is it a hexsha ? Try the most common ones, which is 7 to 40
729-
if self.re_hexsha_shortened.match(name):
730-
if len(name) != 40:
731-
# find long sha for short sha
732-
raise NotImplementedError("short sha parsing")
733-
else:
734-
hexsha = name
735-
# END handle short shas
736-
else:
737-
for base in ('%s', 'refs/%s', 'refs/tags/%s', 'refs/heads/%s', 'refs/remotes/%s', 'refs/remotes/%s/HEAD'):
738-
try:
739-
hexsha = SymbolicReference.dereference_recursive(self, base % name)
740-
break
741-
except ValueError:
742-
pass
743-
# END for each base
744-
# END handle hexsha
745-
746-
# tried everything ? fail
747-
if hexsha is None:
748-
# it could also be a very short ( less than 7 ) hexsha, which
749-
# wasnt tested in the first run
750-
if len(name) < 7 and self.re_hexsha_domain.match(name):
751-
raise NotImplementedError()
752-
# END try short name
753-
raise BadObject(name)
754-
# END assert hexsha was found
755-
756-
return Object.new_from_sha(self, hex_to_bin(hexsha))
757-
# END object by name
758-
759-
def deref_tag(tag):
760-
while True:
761-
try:
762-
tag = tag.object
763-
except AttributeError:
764-
break
765-
# END dereference tag
766-
return tag
767-
768-
def to_commit(obj):
769-
if obj.type == 'tag':
770-
obj = deref_tag(obj)
771-
772-
if obj.type != "commit":
773-
raise ValueError("Cannot convert object %r to type commit" % obj)
774-
# END verify type
775-
return obj
776-
# END commit converter
777-
778-
obj = None
779-
output_type = "commit"
780-
start = 0
781-
parsed_to = 0
782-
lr = len(rev)
783-
while start < lr:
784-
if rev[start] not in "^~:":
785-
start += 1
786-
continue
787-
# END handle start
788-
789-
if obj is None:
790-
# token is a rev name
791-
obj = name_to_object(rev[:start])
792-
# END initialize obj on first token
793-
794-
token = rev[start]
795-
start += 1
796-
797-
# try to parse {type}
798-
if start < lr and rev[start] == '{':
799-
end = rev.find('}', start)
800-
if end == -1:
801-
raise ValueError("Missing closing brace to define type in %s" % rev)
802-
output_type = rev[start+1:end] # exclude brace
803-
804-
# handle type
805-
if output_type == 'commit':
806-
pass # default
807-
elif output_type == 'tree':
808-
try:
809-
obj = to_commit(obj).tree
810-
except (AttributeError, ValueError):
811-
pass # error raised later
812-
# END exception handling
813-
elif output_type in ('', 'blob'):
814-
if obj.type == 'tag':
815-
obj = deref_tag(obj)
816-
else:
817-
# cannot do anything for non-tags
818-
pass
819-
# END handle tag
820-
else:
821-
raise ValueError("Invalid output type: %s ( in %s )" % (output_type, rev))
822-
# END handle output type
823-
824-
# empty output types don't require any specific type, its just about dereferencing tags
825-
if output_type and obj.type != output_type:
826-
raise ValueError("Could not accomodate requested object type %r, got %s" % (output_type, obj.type))
827-
# END verify ouput type
828-
829-
start = end+1 # skip brace
830-
parsed_to = start
831-
continue
832-
# END parse type
833-
834-
# try to parse a number
835-
num = 0
836-
if token != ":":
837-
found_digit = False
838-
while start < lr:
839-
if rev[start] in digits:
840-
num = num * 10 + int(rev[start])
841-
start += 1
842-
found_digit = True
843-
else:
844-
break
845-
# END handle number
846-
# END number parse loop
847-
848-
# no explicit number given, 1 is the default
849-
# It could be 0 though
850-
if not found_digit:
851-
num = 1
852-
# END set default num
853-
# END number parsing only if non-blob mode
854-
855-
856-
parsed_to = start
857-
# handle hiererarchy walk
858-
try:
859-
if token == "~":
860-
obj = to_commit(obj)
861-
for item in xrange(num):
862-
obj = obj.parents[0]
863-
# END for each history item to walk
864-
elif token == "^":
865-
obj = to_commit(obj)
866-
# must be n'th parent
867-
if num:
868-
obj = obj.parents[num-1]
869-
elif token == ":":
870-
if obj.type != "tree":
871-
obj = obj.tree
872-
# END get tree type
873-
obj = obj[rev[start:]]
874-
parsed_to = lr
875-
else:
876-
raise ValueError("Invalid token: %r" % token)
877-
# END end handle tag
878-
except (IndexError, AttributeError):
879-
raise BadObject("Invalid Revision in %s" % rev)
880-
# END exception handling
881-
# END parse loop
882-
883-
# still no obj ? Its probably a simple name
884-
if obj is None:
885-
obj = name_to_object(rev)
886-
parsed_to = lr
887-
# END handle simple name
888-
889-
if obj is None:
890-
raise ValueError("Revision specifier could not be parsed: %s" % rev)
891-
892-
if parsed_to != lr:
893-
raise ValueError("Didn't consume complete rev spec %s, consumed part: %s" % (rev, rev[:parsed_to]))
894-
895-
return obj
896-
897694
def __repr__(self):
898695
return '<git.Repo "%s">' % self.git_dir

0 commit comments

Comments
 (0)