]> arthur.barton.de Git - bup.git/blob - lib/bup/repo.py
0bfccc37745fe11ae35e3b54b1e9ae721f342ea4
[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 is_remote(self):
47         return False
48
49     def cat(self, ref):
50         """If ref does not exist, yield (None, None, None).  Otherwise yield
51         (oidx, type, size), and then all of the data associated with
52         ref.
53
54         """
55         it = self._cp.get(ref)
56         oidx, typ, size = info = next(it)
57         yield info
58         if oidx:
59             for data in it:
60                 yield data
61         assert not next(it, None)
62
63     def join(self, ref):
64         return self._cp.join(ref)
65
66     def refs(self, patterns=None, limit_to_heads=False, limit_to_tags=False):
67         for ref in git.list_refs(patterns=patterns,
68                                  limit_to_heads=limit_to_heads,
69                                  limit_to_tags=limit_to_tags,
70                                  repo_dir=self.repo_dir):
71             yield ref
72
73 class RemoteRepo:
74     def __init__(self, address):
75         self.address = address
76         self.client = client.Client(address)
77         self.rev_list = self.client.rev_list
78         self._id = _repo_id(self.address)
79
80     def close(self):
81         if self.client:
82             self.client.close()
83             self.client = None
84
85     def __del__(self):
86         self.close()
87
88     def __enter__(self):
89         return self
90
91     def __exit__(self, type, value, traceback):
92         self.close()
93
94     def id(self):
95         """Return an identifier that differs from any other repository that
96         doesn't share the same repository-specific information
97         (e.g. refs, tags, etc.)."""
98         return self._id
99
100     def is_remote(self):
101         return True
102
103     def cat(self, ref):
104         """If ref does not exist, yield (None, None, None).  Otherwise yield
105         (oidx, type, size), and then all of the data associated with
106         ref.
107
108         """
109         # Yield all the data here so that we don't finish the
110         # cat_batch iterator (triggering its cleanup) until all of the
111         # data has been read.  Otherwise we'd be out of sync with the
112         # server.
113         items = self.client.cat_batch((ref,))
114         oidx, typ, size, it = info = next(items)
115         yield info[:-1]
116         if oidx:
117             for data in it:
118                 yield data
119         assert not next(items, None)
120
121     def join(self, ref):
122         return self.client.join(ref)
123
124     def refs(self, patterns=None, limit_to_heads=False, limit_to_tags=False):
125         for ref in self.client.refs(patterns=patterns,
126                                     limit_to_heads=limit_to_heads,
127                                     limit_to_tags=limit_to_tags):
128             yield ref