Wikkid Wiki
Wikkid
Home
»
Integrating_with_Breezy
======================= Integrating with Breezy ======================= This page should hopefully become a quick guide to integrating other (Python-based) software with Breezy Manipulating a Working Tree =========================== Most objects in Breezy are found in modules that are named after the class they contain. To manipulate the Working Tree you need to create a ``WorkingTree`` object, which is located in the ``workingtree`` module, e.g.:: from breezy.workingtree import WorkingTree wt = WorkingTree.open('/home/jebw/brztest') This gives us a ``WorkingTree`` object, which has methods provided by itself and by its parent classes:: ``MutableTree`` and ``Tree``. It's worth looking through these three files (workingtree.py, mutabletree.py and tree.py) to see which methods are available. Creating a new Working Tree from a branch ========================================= If you don't have a working tree at all, you can easily start out here:: from breezy.branch import Branch my_branch = Branch.open(branch_url) my_branch.create_checkout(TREEDIR, lightweight=True) my_tree = WorkingTree.open(TREEDIR) Merging changes =============== Once you have a branch, you can start pulling in other people's work easily:: other_branch = Branch.open(other_url) my_tree.merge_from_branch(other_branch) changes = my_tree.changes_from(my_tree.basis_tree()) print "%s files modified, %s added, %s removed" % ( len(changes.modified), len(changes.added), len(changes.removed)) Checking conflicts ================== Of course, it's the case that sometimes merges conflict:: conflicts = my_tree.conflicts() if not conflicts.is_empty(): print "EEE conflicts found:" for conflict in conflicts: print "C " + conflict.path Comparing trees =============== There are two methods for comparing trees: ``changes_from`` and ``iter_changes``. ``iter_changes`` is more regular and precise, but it is somewhat harder to use. See the API documentation for more details. ``changes_from`` creates a Delta object showing changes:: changes = wt.changes_from(wt.basis_tree()) This gives us a Delta object, which has several lists of files for each type of change, e.g. changes.added is a list of added files, changes.removed is list of removed files, changes.modified is a list of modified files. The contents of the lists aren't just filenames, but include other information as well. To grab just the filename, you get the first value, e.g.:: print("list of newly added files") for filename in changes.added: print("%s has been added" % filename[0]) The exception to this is changes.renamed, where the list returned for each renamed file contains both the old and new names -- one or both may interest you, depending on what you're doing. For example:: print("list of renamed files") for filename in changes.renamed: print("%s has been renamed to %s" % (filename[0], filename[1])) Adding Files ============ If you want to add files the same way ``brz add`` does, you can use MutableTree.smart_add. By default, this is recursive. Paths can either be absolute or relative to the workingtree:: wt.smart_add(['dir1/filea.txt', 'fileb.txt', '/home/jebw/testtree/filec.txt']) For more precise control over which files to add, use MutableTree.add:: wt.add(['dir1/filea.txt', 'fileb.txt', '/home/jebw/testtree/filec.txt']) Removing Files ============== You can remove multiple files together. The file paths need to be relative to the workingtree:: wt.remove(['filea.txt', 'fileb.txt', 'dir1']) By default, the files are not deleted, just removed from the inventory. To delete them from the filesystem as well:: wt.remove(['filea.txt', 'fileb.txt', 'dir1'], keep_files=False) Renaming a File =============== You can change the name of a single file using WorkingTree.rename_one. You just provide the old and new names, e.g.:: wt.rename_one('oldfile.txt','newfile.txt') Moving Files ============ You can move multiple files from one directory into another using WorkingTree.move:: wt.move(['olddir/file.txt'], 'newdir') More complicated renames/moves can be done with transform.TreeTransform, which is outside the scope of this document. Committing Changes ================== To commit _all_ the changes to your working tree you can just call the WorkingTree's commit method, giving it a commit message, e.g.:: wt.commit('this is my commit message') To commit only certain files, you need to provide a list of filenames which you want to commit, e.g.:: wt.commit(message='this is my commit message', specific_files=['fileA.txt', 'dir2/fileB.txt', 'fileD.txt']) Generating a Log for a File =========================== Generating a log is, in itself, simple. Grab a branch (see below) and pass it to show_log together with a log formatter, e.g.:: from breezy import log b = Branch.open('/path/to/breezy/branch') lf = log.LongLogFormatter(to_file=sys.stdout) log.show_log(b, lf) Three log formatters are included with breezy: LongLogFormatter, ShortLogFormatter and LineLogFormatter. These provide long, short and single-line log output formats. It's also possible to write your own with very little code. Annotating a File ================= To annotate a file, you want to walk every line of a file, retrieving the revision which last modified/created that line and then retrieving the information for that revision. First get an annotation iterator for the file:: tree, relpath = WorkingTree.open_containing('/path/to/file.txt') fileid = tree.path2id(relpath) annotation = list(tree.annotate_iter(fileid)) To avoid repeatedly retrieving the same revisions, grab all revisions associated with the file together and build up a map of id to revision information. Also build a map of revision numbers, again indexed by the revision id:: revision_ids = set(revision_id for revision_id, text in annotation) revisions = tree.branch.repository.get_revisions(revision_ids) revision_map = dict(izip(revision_ids, revisions)) revno_map = tree.branch.get_revision_id_to_revno_map() Finally, use your annotation iterator to walk the lines of the file, displaying the information from your revision maps as you go:: for revision_id, text in annotation : rev = revision_map[revision_id] revno = revno_map[revision_id] revno_string = '.'.join(str(i) for i in revno) print "%s, %s: %s" % (revno_string, rev.committer, text) Working with branches ===================== To work with a branch you need a branch object associated with your branch:: from breezy.branch import Branch b = Branch.open('/home/jebw/brztest') Branching from an existing branch ================================= To branch you create a branch object representing the original branch, and supply a path/url to the new branch location. The following code clones the trunk branch (the latest copy of the Breezy source code) - be warned there is no feedback while it downloads the 60 mb associated with the branch:: b = Branch.open('http://code.breezy-vcs.org/breezy/trunk') nb = b.controldir.sprout('/tmp/newBranch').open_branch() This provides no feedback, since Breezy automatically uses the 'silent' UI. Pushing and pulling branches ============================ To push a branch, you need to open the source and destination branches, then call push with the other branch as a parameter:: b1 = Branch.open('file:///home/user/mybranch') b2 = Branch.open('http://code.breezy-vcs.org/breezy/trunk') b1.push(b2) Pulling is similar:: b1.pull(b2) If you have a working tree, as well as a branch, you should use WorkingTree.pull, not Branch.pull. This '''won't''' handle conflicts automatically, so any conflicts will be left in the working tree for the user to resolve. Checkout from an existing branch ================================ This performs a Lightweight checkout from an existing Branch:: from breezy.controldir import ControlDir accelerator_tree, source = ControlDir.open_tree_or_branch('http:URL') source.create_checkout('/tmp/newCheckout', None, True, accelerator_tree) To make a heavyweight checkout, change the last line to:: source.create_checkout('/tmp/newCheckout', None, False, accelerator_tree) ================== History Operations ================== Finding the last revision number or id ====================================== To get the last revision number and id of a branch use:: revno, rev_id = branch.last_revision_info() If all you care about is the revision id there is also the method:: rev_id = branch.last_revision() Getting the list of revision ids that make up a branch ====================================================== IMPORTANT: This should be avoided wherever possible, as it scales with the length of history:: rev_ids = branch.revision_history() now ``rev_ids[0]`` is the revision id of the first commit, and ``rev_ids[-1]`` is the revision id of the most recent. Note that if all you want is the last revision id then you should use ``branch.last_revision()`` as described above, as it is much more efficient. Getting a Revision object from a revision id ============================================ The Revision object has attributes like "message" to get the information about the revision:: repo = branch.repository revision = repo.get_revision(rev_id) print revision.message Getting a revision id from a revision number ============================================ To get a revision id for a specific revision number use:: rev_id = branch.get_rev_id(revno) Accessing the files from a revision =================================== To get the file contents and tree shape for a specific revision you need a RevisionTree. These are supplied by the repository for a specific revision id:: revtree = repo.revision_tree(rev_id) RevisionTrees, like all trees, can be compared as described in "Comparing Trees" above. The most common way to list files in a tree is ``Tree.iter_entries()``. The simplest way to get file content is ``Tree.get_file()``. The best way to retrieve file content for large numbers of files `Tree.iter_files_bytes()`` Loading plugins =================================== To allow breezy to work with all plugins enabled you have to force it like this:: from breezy.plugin import load_plugins load_plugins() That code should be close to your "import breezy" to avoid problems. To import a specific plugin you can do:: from breezy.plugins.someplugin import somemodule
Describe the change:
or
Cancel