]> arthur.barton.de Git - bup.git/blob - lib/bup/repo.py
main: treat BUP_FORCE_TTY as bitmap
[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, vfs
7 from bup.compat import pending_raise
8
9
10 _next_repo_id = 0
11 _repo_ids = {}
12
13 def _repo_id(key):
14     global _next_repo_id, _repo_ids
15     repo_id = _repo_ids.get(key)
16     if repo_id:
17         return repo_id
18     next_id = _next_repo_id = _next_repo_id + 1
19     _repo_ids[key] = next_id
20     return next_id
21
22 class LocalRepo:
23     def __init__(self, repo_dir=None):
24         self.closed = False
25         self.repo_dir = realpath(repo_dir or git.repo())
26         self._cp = git.cp(self.repo_dir)
27         self.update_ref = partial(git.update_ref, repo_dir=self.repo_dir)
28         self.rev_list = partial(git.rev_list, repo_dir=self.repo_dir)
29         self._id = _repo_id(self.repo_dir)
30
31     def close(self):
32         self.closed = True
33
34     def __del__(self):
35         assert self.closed
36
37     def __enter__(self):
38         return self
39
40     def __exit__(self, type, value, traceback):
41         with pending_raise(value, rethrow=False):
42             self.close()
43
44     def id(self):
45         """Return an identifier that differs from any other repository that
46         doesn't share the same repository-specific information
47         (e.g. refs, tags, etc.)."""
48         return self._id
49
50     def is_remote(self):
51         return False
52
53     def new_packwriter(self, compression_level=1,
54                        max_pack_size=None, max_pack_objects=None):
55         return git.PackWriter(repo_dir=self.repo_dir,
56                               compression_level=compression_level,
57                               max_pack_size=max_pack_size,
58                               max_pack_objects=max_pack_objects)
59
60     def cat(self, ref):
61         """If ref does not exist, yield (None, None, None).  Otherwise yield
62         (oidx, type, size), and then all of the data associated with
63         ref.
64
65         """
66         it = self._cp.get(ref)
67         oidx, typ, size = info = next(it)
68         yield info
69         if oidx:
70             for data in it:
71                 yield data
72         assert not next(it, None)
73
74     def join(self, ref):
75         return self._cp.join(ref)
76
77     def refs(self, patterns=None, limit_to_heads=False, limit_to_tags=False):
78         for ref in git.list_refs(patterns=patterns,
79                                  limit_to_heads=limit_to_heads,
80                                  limit_to_tags=limit_to_tags,
81                                  repo_dir=self.repo_dir):
82             yield ref
83
84     ## Of course, the vfs better not call this...
85     def resolve(self, path, parent=None, want_meta=True, follow=True):
86         ## FIXME: mode_only=?
87         return vfs.resolve(self, path,
88                            parent=parent, want_meta=want_meta, follow=follow)
89
90
91 class RemoteRepo:
92     def __init__(self, address):
93         self.closed = False
94         self.address = address
95         self.client = client.Client(address)
96         self.new_packwriter = self.client.new_packwriter
97         self.update_ref = self.client.update_ref
98         self.rev_list = self.client.rev_list
99         self._id = _repo_id(self.address)
100
101     def close(self):
102         if not self.closed:
103             self.closed = True
104             self.client.close()
105             self.client = None
106
107     def __del__(self):
108         assert self.closed
109
110     def __enter__(self):
111         return self
112
113     def __exit__(self, type, value, traceback):
114         with pending_raise(value, rethrow=False):
115             self.close()
116
117     def id(self):
118         """Return an identifier that differs from any other repository that
119         doesn't share the same repository-specific information
120         (e.g. refs, tags, etc.)."""
121         return self._id
122
123     def is_remote(self):
124         return True
125
126     def cat(self, ref):
127         """If ref does not exist, yield (None, None, None).  Otherwise yield
128         (oidx, type, size), and then all of the data associated with
129         ref.
130
131         """
132         # Yield all the data here so that we don't finish the
133         # cat_batch iterator (triggering its cleanup) until all of the
134         # data has been read.  Otherwise we'd be out of sync with the
135         # server.
136         items = self.client.cat_batch((ref,))
137         oidx, typ, size, it = info = next(items)
138         yield info[:-1]
139         if oidx:
140             for data in it:
141                 yield data
142         assert not next(items, None)
143
144     def join(self, ref):
145         return self.client.join(ref)
146
147     def refs(self, patterns=None, limit_to_heads=False, limit_to_tags=False):
148         for ref in self.client.refs(patterns=patterns,
149                                     limit_to_heads=limit_to_heads,
150                                     limit_to_tags=limit_to_tags):
151             yield ref
152
153     def resolve(self, path, parent=None, want_meta=True, follow=True):
154         ## FIXME: mode_only=?
155         return self.client.resolve(path, parent=parent, want_meta=want_meta,
156                                    follow=follow)