bzr-undelete
Martin Pool
mbp at sourcefrog.net
Fri Feb 20 07:58:04 GMT 2009
2009/2/20 Parth Malwankar <parth.malwankar at gmail.com>:
> Hello,
>
> I have created a bzr-undelete plugin[1] that tries the last:N
> revisions of the branch to undelete the specified file(s)/dir(s).
>
> As I am new to bzrlib API, I would very much appreciate it if
> some of the bzr experts here could review it and let me know
> if something could be improved.
That sounds like a pretty useful thing, probably an answer to a fairly
frequently asked question. You should add it to the plugin list on
bazaar-vcs.org, if you haven't already.
On the grounds of discoverability I'd think about adding it in to the
core, maybe as 'bzr revert --undelete'.
Anyhow, to have a quick look at the code:
> # Author: Parth Malwankar <parth.malwankar at gmail.com>
>
> """Undelete the file(s) deleted using 'bzr rm'"""
> import os
>
> from bzrlib.commands import Command, register_command
> from bzrlib.workingtree import WorkingTree
> from bzrlib import errors
> from bzrlib.revisionspec import RevisionSpec
> from bzrlib.builtins import cmd_revert
> from bzrlib.option import Option
>
> class cmd_undelete(Command):
> """Undelete file(s) deleted using 'bzr rm'
>
> This commands reverts to the last known version of a
> previously deleted file. It steps back in revisions
> starting from previous till the specified '--last'
> (default: 20).
> """
> takes_args = ['file*']
> takes_options = [ 'verbose',
> Option("last", type = int,
> help = "Search for last N revisions. (default: 20)"),
> ]
>
> def run(self, file_list = None, verbose = False, last = 20):
> if not file_list:
> raise errors.BzrCommandError("file(s) not specified")
>
> wt = WorkingTree.open_containing('.')[0]
> for filename in file_list:
> res = self._undelete_file(filename, last, verbose)
> if res == False:
> vprint(filename + " not found in last:"
> + str(last) + " rev.", verbose)
>
> def _undelete_file(self, filename, last, verbose):
> cwd = os.getcwd()
> for i in range(1, last + 1):
> rev = RevisionSpec.from_string("last:" + str(i))
> try:
> filepath = os.path.join(cwd, filename)
> cmd_revert().run(revision = [rev], file_list = [filepath])
> vprint(filename + ". undeleted rev 'last:"
> + str(i) + "'", verbose)
> return True
> except:
> pass
> return False
So this all looks pretty good, except that there is a better way to find
the file. We would probably recommend that you use an extension API
rather than the command line API, but I can understand that directly
addressing the commands is easier to translate from a shell script.
Catching a bare 'except': like this is not so good because if any other
error occurs the program will just keep on running, possibly making things
worse. That's one reason it's good to use the extension API.
The kind of API you should use is: get the branch, then get the revision
by looking up that spec, then get the revision tree. Ask the revision
tree if it has the relevant path. If so, you want to revert to that
version - I'm not sure off hand if there is a simpler way than using the
cmd_revert api.
This would fix one bug in this which is that if you try to undelete a
still-present file it will revert it. And if you do it on '.' it's even
worse.
Hope that helps.
>
> def vprint(s, verbose):
> if verbose == True:
> print s
>
> register_command(cmd_undelete)
--
Martin <http://launchpad.net/~mbp/>
More information about the bazaar
mailing list