]> arthur.barton.de Git - bup.git/blob - lib/bup/repo.py
cc8a3fd2e7161043b2bb158b0c2d25b55081a28a
[bup.git] / lib / bup / repo.py
1
2 from __future__ import absolute_import
3 from os.path import realpath
4 from functools import partial
5
6 from bup import client, git
7
8
9 _next_repo_id = 0
10 _repo_ids = {}
11
12 def _repo_id(key):
13     global _next_repo_id, _repo_ids
14     repo_id = _repo_ids.get(key)
15     if repo_id:
16         return repo_id
17     next_id = _next_repo_id = _next_repo_id + 1
18     _repo_ids[key] = next_id
19     return next_id
20
21 class LocalRepo:
22     def __init__(self, repo_dir=None):
23         self.repo_dir = realpath(repo_dir or git.repo())
24         self._cp = git.cp(self.repo_dir)
25         self.rev_list = partial(git.rev_list, repo_dir=self.repo_dir)
26         self._id = _repo_id(self.repo_dir)
27
28     def close(self):
29         pass
30
31     def __del__(self):
32         self.close()
33
34     def __enter__(self):
35         return self
36
37     def __exit__(self, type, value, traceback):
38         self.close()
39
40     def id(self):
41         """Return an identifier that differs from any other repository that
42         doesn't share the same repository-specific information
43         (e.g. refs, tags, etc.)."""
44         return self._id
45
46     def cat(self, ref):
47         """If ref does not exist, yield (None, None, None).  Otherwise yield
48         (oidx, type, size), and then all of the data associated with
49         ref.
50
51         """
52         it = self._cp.get(ref)
53         oidx, typ, size = info = next(it)
54         yield info
55         if oidx:
56             for data in it:
57                 yield data
58         assert not next(it, None)
59
60     def join(self, ref):
61         return self._cp.join(ref)
62
63     def refs(self, patterns=None, limit_to_heads=False, limit_to_tags=False):
64         for ref in git.list_refs(patterns=patterns,
65                                  limit_to_heads=limit_to_heads,
66                                  limit_to_tags=limit_to_tags,
67                                  repo_dir=self.repo_dir):
68             yield ref
69
70 class RemoteRepo:
71     def __init__(self, address):
72         self.address = address
73         self.client = client.Client(address)
74         self.rev_list = self.client.rev_list
75         self._id = _repo_id(self.address)
76
77     def close(self):
78         if self.client:
79             self.client.close()
80             self.client = None
81
82     def __del__(self):
83         self.close()
84
85     def __enter__(self):
86         return self
87
88     def __exit__(self, type, value, traceback):
89         self.close()
90
91     def id(self):
92         """Return an identifier that differs from any other repository that
93         doesn't share the same repository-specific information
94         (e.g. refs, tags, etc.)."""
95         return self._id
96
97     def cat(self, ref):
98         """If ref does not exist, yield (None, None, None).  Otherwise yield
99         (oidx, type, size), and then all of the data associated with
100         ref.
101
102         """
103         # Yield all the data here so that we don't finish the
104         # cat_batch iterator (triggering its cleanup) until all of the
105         # data has been read.  Otherwise we'd be out of sync with the
106         # server.
107         items = self.client.cat_batch((ref,))
108         oidx, typ, size, it = info = next(items)
109         yield info[:-1]
110         if oidx:
111             for data in it:
112                 yield data
113         assert not next(items, None)
114
115     def join(self, ref):
116         return self.client.join(ref)
117
118     def refs(self, patterns=None, limit_to_heads=False, limit_to_tags=False):
119         for ref in self.client.refs(patterns=patterns,
120                                     limit_to_heads=limit_to_heads,
121                                     limit_to_tags=limit_to_tags):
122             yield ref