46
43
ref_locs = ['', 'refs', 'refs/tags', 'refs/heads', 'refs/remotes']
48
45
def __init__(self, root):
49
if os.path.isdir(os.path.join(root, ".git", "objects")):
46
controldir = os.path.join(root, ".git")
47
if os.path.exists(os.path.join(controldir, "objects")):
51
self._controldir = os.path.join(root, ".git")
52
elif os.path.isdir(os.path.join(root, "objects")):
49
self._basedir = controldir
54
self._controldir = root
56
raise NotGitRepository(root)
53
self.path = controldir
58
54
self.tags = [Tag(name, ref) for name, ref in self.get_tags().items()]
59
self._object_store = None
62
return self._controldir
64
def fetch_objects(self, determine_wants, graph_walker, progress):
65
wants = determine_wants(self.heads())
67
ref = graph_walker.next()
69
commits_to_send.append(ref)
70
if ref in self.object_store:
72
ref = graph_walker.next()
74
for sha in commits_to_send:
81
def parse_tree(tree, sha_done):
82
for mode, name, x in tree.entries():
87
parse_tree(t, sha_done)
92
if treesha not in sha_done:
93
t = self.tree(treesha)
95
parse_tree(t, sha_done)
97
progress("counting objects: %d\r" % len(sha_done))
100
yield self.get_object(sha)
102
59
def object_dir(self):
103
return os.path.join(self.controldir(), OBJECTDIR)
106
def object_store(self):
107
if self._object_store is None:
108
self._object_store = ObjectStore(self.object_dir())
109
return self._object_store
112
return os.path.join(self.object_dir(), PACKDIR)
60
return os.path.join(self.basedir(), objectdir)
114
62
def _get_ref(self, file):
115
63
f = open(file, 'rb')
117
65
contents = f.read()
118
if contents.startswith(SYMREF):
119
ref = contents[len(SYMREF):]
66
if contents.startswith(symref):
67
ref = contents[len(symref):]
120
68
if ref[-1] == '\n':
122
70
return self.ref(ref)
123
assert len(contents) == 41, 'Invalid ref in %s' % file
71
assert len(contents) == 41, 'Invalid ref'
124
72
return contents[:-1]
128
76
def ref(self, name):
129
77
for dir in self.ref_locs:
130
file = os.path.join(self.controldir(), dir, name)
78
file = os.path.join(self.basedir(), dir, name)
131
79
if os.path.exists(file):
132
80
return self._get_ref(file)
135
ret = {"HEAD": self.head()}
136
for dir in ["refs/heads", "refs/tags"]:
137
for name in os.listdir(os.path.join(self.controldir(), dir)):
138
path = os.path.join(self.controldir(), dir, name)
139
if os.path.isfile(path):
140
ret["/".join([dir, name])] = self._get_ref(path)
143
def set_ref(self, name, value):
144
file = os.path.join(self.controldir(), name)
145
open(file, 'w').write(value+"\n")
147
def remove_ref(self, name):
148
file = os.path.join(self.controldir(), name)
149
if os.path.exists(file):
153
82
def get_tags(self):
155
for root, dirs, files in os.walk(os.path.join(self.controldir(), 'refs', 'tags')):
157
ret[name] = self._get_ref(os.path.join(root, name))
84
for name in os.listdir(os.path.join(self.basedir(), 'refs', 'tags')):
85
ret[name] = self._get_ref(os.path.join(self.basedir(), 'refs', 'tags', name))
162
for root, dirs, files in os.walk(os.path.join(self.controldir(), 'refs', 'heads')):
164
ret[name] = self._get_ref(os.path.join(root, name))
90
for name in os.listdir(os.path.join(self.basedir(), 'refs', 'heads')):
91
ret[name] = self._get_ref(os.path.join(self.basedir(), 'refs', 'heads', name))
168
95
return self.ref('HEAD')
170
97
def _get_object(self, sha, cls):
171
assert len(sha) in (20, 40)
172
ret = self.get_object(sha)
173
if ret._type != cls._type:
175
raise NotCommitError(ret)
177
raise NotBlobError(ret)
179
raise NotTreeError(ret)
181
raise Exception("Type invalid: %r != %r" % (ret._type, cls._type))
98
assert len(sha) == 40, "Incorrect length sha: %s" % str(sha)
101
path = os.path.join(self.object_dir(), dir, file)
102
if not os.path.exists(path):
103
# Should this raise instead?
105
return cls.from_file(path)
184
107
def get_object(self, sha):
185
return self.object_store[sha]
187
def get_parents(self, sha):
188
return self.commit(sha).parents
108
return self._get_object(sha, ShaFile)
190
110
def commit(self, sha):
191
111
return self._get_object(sha, Commit)
113
def get_tree(self, sha):
194
114
return self._get_object(sha, Tree)
196
116
def get_blob(self, sha):
252
168
create = init_bare
255
class ObjectStore(object):
257
def __init__(self, path):
262
return os.path.join(self.path, PACKDIR)
264
def __contains__(self, sha):
265
# TODO: This can be more efficient
274
"""List with pack objects."""
275
if self._packs is None:
276
self._packs = list(load_packs(self.pack_dir()))
279
def _get_shafile(self, sha):
282
# Check from object dir
283
path = os.path.join(self.path, dir, file)
284
if os.path.exists(path):
285
return ShaFile.from_file(path)
288
def get_raw(self, sha):
289
"""Obtain the raw text for an object.
291
:param sha: Sha for the object.
292
:return: tuple with object type and object contents.
294
for pack in self.packs:
296
return pack.get_raw(sha, self.get_raw)
297
# FIXME: Are pack deltas ever against on-disk shafiles ?
298
ret = self._get_shafile(sha)
300
return ret.as_raw_string()
303
def __getitem__(self, sha):
304
assert len(sha) == 40, "Incorrect length sha: %s" % str(sha)
305
ret = self._get_shafile(sha)
309
type, uncomp = self.get_raw(sha)
310
return ShaFile.from_raw_string(type, uncomp)
312
def move_in_pack(self, path):
313
"""Move a specific file containing a pack into the pack directory.
315
:note: The file should be on the same file system as the
318
:param path: Path to the pack file.
321
entries = p.sorted_entries(self.get_raw)
322
basename = os.path.join(self.pack_dir(),
323
"pack-%s" % iter_sha1(entry[0] for entry in entries))
324
write_pack_index_v2(basename+".idx", entries, p.calculate_checksum())
325
os.rename(path, basename + ".pack")
328
"""Add a new pack to this object store.
330
:return: Fileobject to write to and a commit function to
331
call when the pack is finished.
333
fd, path = tempfile.mkstemp(dir=self.pack_dir(), suffix=".pack")
334
f = os.fdopen(fd, 'w')
336
if os.path.getsize(path) > 0:
337
self.move_in_pack(path)