/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to doc/developers/integration.txt

  • Committer: Robert Collins
  • Date: 2005-10-19 10:11:57 UTC
  • mfrom: (1185.16.78)
  • mto: This revision was merged to the branch mainline in revision 1470.
  • Revision ID: robertc@robertcollins.net-20051019101157-17438d311e746b4f
mergeĀ fromĀ upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
=======================
2
 
Integrating with Breezy
3
 
=======================
4
 
 
5
 
This document provides some general observations on integrating with
6
 
Breezy 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 brz.  If you want to know about a topic that's not covered
9
 
here, just ask us.
10
 
 
11
 
 
12
 
 
13
 
 
14
 
Starting with breezy
15
 
====================
16
 
 
17
 
Within brz
18
 
----------
19
 
 
20
 
When using breezy within the ``brz`` program (for instance as a brz
21
 
plugin), breezy's global state is already available for use.
22
 
 
23
 
From outside brz
24
 
----------------
25
 
 
26
 
To use breezy outside of ``brz`` some global state needs to be setup.
27
 
breezy needs ways to handle user input, passwords, a place to emit
28
 
progress bars, logging setup appropriately for your program. The easiest
29
 
way to set all this up in the same fashion ``brz`` does is to call
30
 
``breezy.initialize``.
31
 
 
32
 
This returns a context manager within which breezy functions will work
33
 
correctly. See the pydoc for ``breezy.initialize`` for more information.
34
 
(You can get away without entering the context manager, because the setup
35
 
work happens directly from ``initialize``.)
36
 
 
37
 
 
38
 
Running brz commands
39
 
====================
40
 
 
41
 
To run command-line commands in-process::
42
 
 
43
 
  from breezy.commands import get_command
44
 
 
45
 
  cmd = get_command('version')
46
 
  cmd.run([])
47
 
 
48
 
This will send output through the current UIFactory; you can redirect this
49
 
elsewhere through the parameters to `breezy.initialize`.
50
 
 
51
 
 
52
 
Manipulating the Working Tree
53
 
=============================
54
 
Most objects in Breezy are in files, named after the class they contain.
55
 
To manipulate the Working Tree we need a valid WorkingTree object, which
56
 
is loaded from the workingtree.py file, eg::
57
 
 
58
 
  from breezy import workingtree
59
 
  wt = workingtree.WorkingTree.open('/home/jebw/brztest')
60
 
 
61
 
 
62
 
This gives us a WorkingTree object, which has various methods spread over
63
 
itself, and its parent classes MutableTree and Tree - it's worth having a
64
 
look through these three files (workingtree.py, mutabletree.py and tree.py)
65
 
to see which methods are available.
66
 
 
67
 
Compare trees
68
 
-------------
69
 
 
70
 
There are two methods for comparing trees: ``changes_from`` and
71
 
``iter_changes``.  ``iter_changes`` is more regular and precise, but it is
72
 
somewhat harder to work with.  See the API documentation for more details.
73
 
 
74
 
``changes_from`` creates a Delta object showing changes::
75
 
 
76
 
  from breezy import delta
77
 
  changes = wt.changes_from(wt.basis_tree())
78
 
 
79
 
This gives us a Delta object, which has several lists of files for each type of
80
 
change, eg changes.added is a list of added files, changes.removed is list
81
 
of removed files, changes.modified is a list of modified files. The contents
82
 
of the lists aren't just filenames, but include other information as well.
83
 
To grab just the filename we want the first value, eg::
84
 
 
85
 
  print("list of newly added files")
86
 
  for filename in changes.added:
87
 
    print("%s has been added" % filename[0])
88
 
 
89
 
 
90
 
The exception to this is changes.renamed, where the list returned for each
91
 
renamed files contains both the old and new names -- one or both may interest
92
 
you, depending on what you're doing.
93
 
 
94
 
For example::
95
 
 
96
 
  print("list of renamed files")
97
 
  for filename in changes.renamed:
98
 
    print("%s has been renamed to %s" % (filename[0], filename[1]))
99
 
 
100
 
 
101
 
Adding Files
102
 
------------
103
 
 
104
 
If you want to add files the same way ``brz add`` does, you can use
105
 
MutableTree.smart_add.  By default, this is recursive. Paths can either be
106
 
absolute or relative to the workingtree::
107
 
 
108
 
  wt.smart_add(['dir1/filea.txt', 'fileb.txt',
109
 
                '/home/jebw/brztesttree/filec.txt'])
110
 
 
111
 
 
112
 
For more precise control over which files to add, use MutableTree.add::
113
 
 
114
 
  wt.add(['dir1/filea.txt', 'fileb.txt', '/home/jebw/brztesttree/filec.txt'])
115
 
 
116
 
 
117
 
Removing Files
118
 
--------------
119
 
 
120
 
You can remove multiple files at once.  The file paths need to be relative
121
 
to the workingtree::
122
 
 
123
 
  wt.remove(['filea.txt', 'fileb.txt', 'dir1'])
124
 
 
125
 
 
126
 
By default, the files are not deleted, just removed from the inventory.
127
 
To delete them from the filesystem as well::
128
 
 
129
 
  wt.remove(['filea.txt', 'fileb.txt', 'dir1'], keep_files=False)
130
 
 
131
 
 
132
 
Renaming a File
133
 
---------------
134
 
 
135
 
You can rename one file to a different name using WorkingTree.rename_one.
136
 
You just provide the old and new names, eg::
137
 
 
138
 
  wt.rename_one('oldfile.txt','newfile.txt')
139
 
 
140
 
 
141
 
Moving Files
142
 
------------
143
 
 
144
 
You can move multiple files from one directory into another using
145
 
WorkingTree.move::
146
 
 
147
 
  wt.move(['olddir/file.txt'], 'newdir')
148
 
 
149
 
 
150
 
More complicated renames/moves can be done with transform.TreeTransform,
151
 
which is outside the scope of this document.
152
 
 
153
 
 
154
 
Committing Changes
155
 
------------------
156
 
 
157
 
To commit _all_ the changes to our working tree we can just call the
158
 
WorkingTree's commit method, giving it a commit message, eg::
159
 
 
160
 
  wt.commit('this is my commit message')
161
 
 
162
 
 
163
 
To commit only certain files, we need to provide a list of filenames which we
164
 
want committing, eg::
165
 
 
166
 
  wt.commit(message='this is my commit message', specific_files=['fileA.txt',
167
 
            'dir2/fileB.txt', 'fileD.txt'])
168
 
 
169
 
 
170
 
Generating a Log for a File
171
 
===========================
172
 
 
173
 
Generating a log is, in itself, simple.  Grab a branch (see below) and pass
174
 
it to show_log together with a log formatter, eg::
175
 
 
176
 
  from breezy import log
177
 
  from breezy import branch
178
 
 
179
 
  b = branch.Branch.open('/path/to/bazaar/branch')
180
 
  lf = log.LongLogFormatter(to_file=sys.stdout)
181
 
  log.show_log(b, lf)
182
 
 
183
 
 
184
 
Three log formatters are included with breezy: LongLogFormatter,
185
 
ShortLogFormatter and LineLogFormatter.  These provide long, short and
186
 
single-line log output formats. It's also possible to write your own in
187
 
very little code.
188
 
 
189
 
Annotating a File
190
 
=================
191
 
 
192
 
To annotate a file, we want to walk every line of a file, retrieving the
193
 
revision which last modified/created that line and then retrieving the
194
 
information for that revision.
195
 
 
196
 
First we get an annotation iterator for the file we are interested in::
197
 
 
198
 
  tree, relpath = workingtree.WorkingTree.open_containing('/path/to/file.txt')
199
 
  fileid = tree.path2id(relpath)
200
 
  annotation = list(tree.annotate_iter(fileid))
201
 
 
202
 
 
203
 
To avoid repeatedly retrieving the same revisions we grab all revisions
204
 
associated with the file at once and build up a map of id to revision
205
 
information. We also build an map of revision numbers, again indexed
206
 
by the revision id::
207
 
 
208
 
  revision_ids = set(revision_id for revision_id, text in annotation)
209
 
  revisions = tree.branch.repository.get_revisions(revision_ids)
210
 
  revision_map = dict(izip(revision_ids, revisions))
211
 
  revno_map = tree.branch.get_revision_id_to_revno_map()
212
 
 
213
 
 
214
 
Finally, we use our annotation iterator to walk the lines of the file,
215
 
displaying the information from our revision maps as we go::
216
 
 
217
 
  for revision_id, text in annotation :
218
 
      rev = revision_map[revision_id]
219
 
      revno = revno_map[revision_id]
220
 
      revno_string = '.'.join(str(i) for i in revno)
221
 
      print "%s, %s: %s" % (revno_string, rev.committer, text)
222
 
 
223
 
 
224
 
Working with branches
225
 
=====================
226
 
 
227
 
To work with a branch you need a branch object, created from your branch::
228
 
 
229
 
  from breezy import branch
230
 
 
231
 
  b = branch.Branch.open('/home/jebw/brztest')
232
 
 
233
 
 
234
 
Branching from an existing branch
235
 
---------------------------------
236
 
 
237
 
To branch you create a branch object representing the branch you are
238
 
branching from, and supply a path/url to the new branch location.
239
 
The following code clones the brz trunk branch (the latest copy of the Breezy
240
 
source code) - be warned it has to download 60meg so takes a while to run
241
 
with no feedback::
242
 
 
243
 
  from breezy import branch
244
 
 
245
 
  b = branch.Branch.open('bzr+ssh://bazaar.launchpad.net/+branch/brz/')
246
 
  nb = b.controldir.sprout('/tmp/newBrzBzranch').open_branch()
247
 
 
248
 
 
249
 
This provides no feedback, since Breezy automatically uses the 'silent' UI.
250
 
 
251
 
 
252
 
Pushing and pulling branches
253
 
----------------------------
254
 
 
255
 
To push a branch you need to open the source and destination branches, then
256
 
just call push with the other branch as a parameter::
257
 
 
258
 
  from breezy import branch
259
 
 
260
 
  b1 = branch.Branch.open('file:///home/user/mybranch')
261
 
  b2 = branch.Branch.open('bzr+ssh://bazaar.launchpad.net/+branch/brz/')
262
 
  b1.push(b2)
263
 
 
264
 
 
265
 
Pulling is much the same::
266
 
 
267
 
  b1.pull(b2)
268
 
 
269
 
 
270
 
If you have a working tree, as well as a branch, you should use
271
 
WorkingTree.pull, not Branch.pull.
272
 
 
273
 
This won't handle conflicts automatically though, so any conflicts will be
274
 
left in the working tree for the user to resolve.
275
 
 
276
 
 
277
 
Checkout from an existing branch
278
 
================================
279
 
 
280
 
This performs a Lightweight checkout from an existing Branch::
281
 
 
282
 
  from breezy import bzrdir
283
 
 
284
 
  accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch('http:URL')
285
 
  source.create_checkout('/tmp/newBrzCheckout', None, True, accelerator_tree)
286
 
 
287
 
 
288
 
To make a heavyweight checkout, change the last line to::
289
 
 
290
 
  source.create_checkout('/tmp/newBrzCheckout', None, False, accelerator_tree
291
 
 
292
 
 
293
 
History Operations
294
 
==================
295
 
 
296
 
Finding the last revision number or id
297
 
--------------------------------------
298
 
 
299
 
To get the last revision number and id of a branch use::
300
 
 
301
 
  revision_number, revision_id = branch.last_revision_info()
302
 
 
303
 
 
304
 
If all you care about is the revision_id there is also the
305
 
method::
306
 
 
307
 
  revision_id = branch.last_revision()
308
 
 
309
 
 
310
 
Getting the list of revision ids that make up a branch
311
 
------------------------------------------------------
312
 
 
313
 
IMPORTANT: This should be avoided wherever possible, as it scales with the
314
 
length of history::
315
 
 
316
 
  revisions = branch.revision_history()
317
 
 
318
 
now revisions[0] is the revision id of the first commit, and revs[-1] is the
319
 
revision id of the most recent. Note that if all you want is the last
320
 
revision then you should use branch.last_revision() as described above, as
321
 
it is vastly more efficient.
322
 
 
323
 
 
324
 
Getting a Revision object from a revision id
325
 
--------------------------------------------
326
 
 
327
 
The Revision object has attributes like "message" to get the information
328
 
about the revision::
329
 
 
330
 
  repo = branch.repository
331
 
  revision = repo.get_revision(rev_id)
332
 
 
333
 
 
334
 
Accessing the files from a revision
335
 
-----------------------------------
336
 
 
337
 
To get the file contents and tree shape for a specific revision you need
338
 
a RevisionTree. These are supplied by the repository for a specific
339
 
revision id::
340
 
 
341
 
  revtree = repo.revision_tree(rev_id)
342
 
 
343
 
RevisionTrees, like all trees, can be compared as described in "Comparing
344
 
Trees" above.
345
 
 
346
 
The most common way to list files in a tree is ``Tree.iter_entries()``.
347
 
The simplest way to get file content is ``Tree.get_file()``.  The best way
348
 
to retrieve file content for large numbers of files `Tree.iter_files_bytes()``
349