1
=======================
2
Integrating with Bazaar
3
=======================
5
This document provides some general observations on integrating with
6
Bazaar and some recipes for typical tasks. It is intended to be useful to
7
someone developing either a plugin or some other piece of software that
8
integrates with bzr. If you want to know about a topic that's not covered
17
Before doing anything else with bzrlib, you should run `bzrlib.initialize`
18
which sets up some global state.
24
To run command-line commands in-process::
26
from bzrlib.commands import get_command
28
cmd = get_command('version')
31
This will send output through the current UIFactory; you can redirect this
32
elsewhere through the parameters to `bzrlib.initialize`.
35
Manipulating the Working Tree
36
=============================
37
Most objects in Bazaar are in files, named after the class they contain.
38
To manipulate the Working Tree we need a valid WorkingTree object, which
39
is loaded from the workingtree.py file, eg::
41
from bzrlib import workingtree
42
wt = workingtree.WorkingTree.open('/home/jebw/bzrtest')
45
This gives us a WorkingTree object, which has various methods spread over
46
itself, and its parent classes MutableTree and Tree - its worth having a
47
look through these three files (workingtree.py, mutabletree.py and tree.py)
48
to see which methods are available.
53
There are two methods for comparing trees: ``changes_from`` and
54
``iter_changes``. ``iter_changes`` is more regular and precise, but it is
55
somewhat harder to work with. See the API documentation for more details.
57
``changes_from`` creates a Delta object showing changes::
59
from bzrlib import delta
60
changes = wt.changes_from(wt.basis_tree())
62
This gives us a Delta object, which has several lists of files for each type of
63
change, eg changes.added is a list of added files, changes.removed is list
64
of removed files, changes.modified is a list of modified files. The contents
65
of the lists aren't just filenames, but include other information as well.
66
To grab just the filename we want the first value, eg::
68
print("list of newly added files")
69
for filename in changes.added:
70
print("%s has been added" % filename[0])
73
The exception to this is changes.renamed, where the list returned for each
74
renamed files contains both the old and new names -- one or both may interest
75
you, depending on what you're doing.
79
print("list of renamed files")
80
for filename in changes.renamed:
81
print("%s has been renamed to %s" % (filename[0], filename[1]))
87
If you want to add files the same way ``bzr add`` does, you can use
88
MutableTree.smart_add. By default, this is recursive. Paths can either be
89
absolute or relative to the workingtree::
91
wt.smart_add(['dir1/filea.txt', 'fileb.txt',
92
'/home/jebw/bzrtesttree/filec.txt'])
95
For more precise control over which files to add, use MutableTree.add::
97
wt.add(['dir1/filea.txt', 'fileb.txt', '/home/jebw/bzrtesttree/filec.txt'])
103
You can remove multiple files at once. The file paths need to be relative
106
wt.remove(['filea.txt', 'fileb.txt', 'dir1'])
109
By default, the files are not deleted, just removed from the inventory.
110
To delete them from the filesystem as well::
112
wt.remove(['filea.txt', 'fileb.txt', 'dir1'], keep_files=False)
118
You can rename one file to a different name using WorkingTree.rename_one.
119
You just provide the old and new names, eg::
121
wt.rename_one('oldfile.txt','newfile.txt')
127
You can move multiple files from one directory into another using
130
wt.move(['olddir/file.txt'], 'newdir')
133
More complicated renames/moves can be done with transform.TreeTransform,
134
which is outside the scope of this document.
140
To commit _all_ the changes to our working tree we can just call the
141
WorkingTree's commit method, giving it a commit message, eg::
143
wt.commit('this is my commit message')
146
To commit only certain files, we need to provide a list of filenames which we
147
want committing, eg::
149
wt.commit(message='this is my commit message', specific_files=['fileA.txt',
150
'dir2/fileB.txt', 'fileD.txt'])
153
Generating a Log for a File
154
===========================
156
Generating a log is, in itself, simple. Grab a branch (see below) and pass
157
it to show_log together with a log formatter, eg::
159
from bzrlib import log
160
from bzrlib import branch
162
b = branch.Branch.open('/path/to/bazaar/branch')
163
lf = log.LongLogFormatter(to_file=sys.stdout)
167
Three log formatters are included with bzrlib: LongLogFormatter,
168
ShortLogFormatter and LineLogFormatter. These provide long, short and
169
single-line log output formats. It's also possible to write your own in
175
To annotate a file, we want to walk every line of a file, retrieving the
176
revision which last modified/created that line and then retrieving the
177
information for that revision.
179
First we get an annotation iterator for the file we are interested in::
181
tree, relpath = workingtree.WorkingTree.open_containing('/path/to/file.txt')
182
fileid = tree.path2id(relpath)
183
annotation = list(tree.annotate_iter(fileid))
186
To avoid repeatedly retrieving the same revisions we grab all revisions
187
associated with the file at once and build up a map of id to revision
188
information. We also build an map of revision numbers, again indexed
191
revision_ids = set(revision_id for revision_id, text in annotation)
192
revisions = tree.branch.repository.get_revisions(revision_ids)
193
revision_map = dict(izip(revision_ids, revisions))
194
revno_map = tree.branch.get_revision_id_to_revno_map()
197
Finally, we use our annotation iterator to walk the lines of the file,
198
displaying the information from our revision maps as we go::
200
for revision_id, text in annotation :
201
rev = revision_map[revision_id]
202
revno = revno_map[revision_id]
203
revno_string = '.'.join(str(i) for i in revno)
204
print "%s, %s: %s" % (revno_string, rev.committer, text)
207
Working with branches
208
=====================
210
To work with a branch you need a branch object, created from your branch::
212
from bzrlib import branch
214
b = branch.Branch.open('/home/jebw/bzrtest')
217
Branching from an existing branch
218
---------------------------------
220
To branch you create a branch object representing the branch you are
221
branching from, and supply a path/url to the new branch location.
222
The following code clones the bzr.dev branch (the latest copy of the Bazaar
223
source code) - be warned it has to download 60meg so takes a while to run
226
from bzrlib import branch
228
b = branch.Branch.open('http://bazaar.launchpad.net/~bzr-pqm/bzr/bzr.dev')
229
nb = b.bzrdir.sprout('/tmp/newBzrBranch').open_branch()
232
This provides no feedback, since Bazaar automatically uses the 'silent' UI.
235
Pushing and pulling branches
236
----------------------------
238
To push a branch you need to open the source and destination branches, then
239
just call push with the other branch as a parameter::
241
from bzrlib import branch
243
b1 = branch.Branch.open('file:///home/user/mybranch')
244
b2 = branch.Branch.open('http://bazaar.launchpad.net/~bzr-pqm/bzr/bzr.dev')
248
Pulling is much the same::
253
If you have a working tree, as well as a branch, you should use
254
WorkingTree.pull, not Branch.pull.
256
This won't handle conflicts automatically though, so any conflicts will be
257
left in the working tree for the user to resolve.
260
Checkout from an existing branch
261
================================
263
This performs a Lightweight checkout from an existing Branch::
265
from bzrlib import bzrdir
267
accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch('http:URL')
268
source.create_checkout('/tmp/newBzrCheckout', None, True, accelerator_tree)
271
To make a heavyweight checkout, change the last line to::
273
source.create_checkout('/tmp/newBzrCheckout', None, False, accelerator_tree
279
Finding the last revision number or id
280
--------------------------------------
282
To get the last revision number and id of a branch use::
284
revision_number, revision_id = branch.last_revision_info()
287
If all you care about is the revision_id there is also the
290
revision_id = branch.last_revision()
293
Getting the list of revision ids that make up a branch
294
------------------------------------------------------
296
IMPORTANT: This should be avoided wherever possible, as it scales with the
299
revisions = branch.revision_history()
301
now revisions[0] is the revision id of the first commit, and revs[-1] is the
302
revision id of the most recent. Note that if all you want is the last
303
revision then you should use branch.last_revision() as described above, as
304
it is vastly more efficient.
307
Getting a Revision object from a revision id
308
--------------------------------------------
310
The Revision object has attributes like "message" to get the information
313
repo = branch.repository
314
revision = repo.get_revision(rev_id)
317
Accessing the files from a revision
318
-----------------------------------
320
To get the file contents and tree shape for a specific revision you need
321
a RevisionTree. These are supplied by the repository for a specific
324
revtree = repo.revision_tree(rev_id)
326
RevisionTrees, like all trees, can be compared as described in "Comparing
329
The most common way to list files in a tree is ``Tree.iter_entries()``.
330
The simplest way to get file content is ``Tree.get_file()``. The best way
331
to retrieve file content for large numbers of files `Tree.iter_files_bytes()``