1
# Copyright 2014 Canonical Ltd. This software is licensed under the
2
# GNU General Public License version 3 (see the file LICENSE).
12
from bzrlib.branch import Branch
13
from bzrlib.bzrdir import BzrDir
14
from bzrlib.plugin import load_plugins
15
from bzrlib.workingtree import WorkingTree
20
class NotABranchError(Exception):
24
class NoSuchFileError(Exception):
28
class DivergedBranchError(Exception):
32
class PermissionDeniedError(Exception):
36
class NoWorkingTreeError(Exception):
40
class AlreadyControlDirError(Exception):
44
class BzrBranch(object):
45
"Simplified bazaar branch API"
46
def __init__(self, location):
47
if location.startswith("file://"):
48
location = location[7:]
49
if urlutils.is_url(location):
52
if not os.path.isabs(location):
53
location = os.path.normpath(os.path.join(os.getcwd(),
56
self.location = location
64
self._branch = Branch.open(self.location)
65
except errors.NotBranchError:
75
self._tree = WorkingTree.open(self.location)
77
except errors.NoWorkingTree:
84
return not self.is_local
89
return self.is_local_branch()
91
return self.is_remote_branch()
93
def is_local_branch(self):
94
if self.bzr_branch is None:
98
# only cache remote is_branch() calls
99
@CacheDisk.cache(unique_attrs=('location',))
100
def is_remote_branch(self):
101
if self.bzr_branch is None:
107
if self.bzr_tree is None:
112
@CacheDisk.cache(unique_attrs=('location',))
115
return self.bzr_branch.revno()
118
def revno_tree(self):
119
if self.is_remote or not self.bzr_tree:
121
return self.bzr_branch.revision_id_to_revno(
122
self.bzr_tree.last_revision())
126
if self.is_remote or self.bzr_branch is None:
128
return self.bzr_branch.get_parent()
130
def has_changes(self, unknowns=False, detritus=False):
131
"Check whether changes or stray files are present in the branch"
134
if not self.bzr_tree:
136
if self.bzr_tree.has_changes():
138
if unknowns and list(self.bzr_tree.unknowns()):
140
if detritus and list(self.bzr_tree.ignored_files()):
145
if self.is_remote or not self.bzr_tree:
146
raise NoWorkingTreeError
147
self.bzr_tree.revert()
149
def cleantree(self, unknowns=True, detritus=True):
150
if self.is_remote or not self.bzr_tree:
151
raise NoWorkingTreeError
154
targets.extend(list(self.bzr_tree.unknowns()))
156
self.bzr_tree.lock_read()
157
targets.extend([f[0] for f in self.bzr_tree.ignored_files()])
158
for target in [os.path.join(self.location, t) for t in targets]:
159
if os.path.isdir(target):
160
shutil.rmtree(target)
164
def clone(self, dest_dir, revno=None):
165
if not self.bzr_branch:
167
if revno is not None:
168
revision_id = self.bzr_branch.get_rev_id(revno)
172
self.bzr_branch.bzrdir.sprout(dest_dir, revision_id=revision_id)
173
except errors.PermissionDenied:
174
raise PermissionDeniedError("Could not create bzr repo in {}"
176
except errors.NoSuchFile:
177
raise NoSuchFileError("No such file or directory: {}"
179
cloned = BzrBranch(dest_dir)
180
CacheDisk.delete_cache_dir(cloned, unique_attrs=('location',))
183
@CacheDisk.delete(unique_attrs=('location',))
188
BzrDir.create_branch_convenience(self.location)
189
except errors.AlreadyControlDirError:
190
raise AlreadyControlDirError
192
def pull(self, src_location=None, overwrite=False, revno=None):
193
if not self.is_branch:
194
raise NotABranchError("{} is not a branch".format(self.location))
195
if src_location is None and self.is_local:
196
src_location = self.parent
197
other = BzrBranch(src_location)
198
if not other.is_branch:
199
raise NotABranchError("{} is not a branch".format(other.location))
202
self.bzr_tree.pull(other.bzr_branch,
205
self.bzr_tree.update(revision=revno)
207
self.bzr_branch.pull(other.bzr_branch,
210
except errors.DivergedBranches:
211
message = "Branches have diverged: {} and {}".format(
212
self.location, other.location)
213
raise DivergedBranchError(message)
216
def push(self, dest_location, update=True, update_revno=None,
218
dest_branch = BzrBranch(dest_location)
219
if not dest_branch.is_branch:
222
self.bzr_branch.push(dest_branch.bzr_branch, overwrite=overwrite)
223
except errors.DivergedBranches:
224
raise DivergedBranchError
226
dest_branch.update(update_revno)
229
def update(self, revno=None):
231
if revno is not None:
232
rev_id = self.bzr_branch.get_rev_id(revno)
233
self.bzr_tree.update(revision=rev_id)