Mercurial > hg
diff hgext/chainsaw.py @ 51433:d36a81d70f25
chainsaw-update: taking care of initial cloning
Perhaps we should go just a bit lower level than this `instance()`,
since the main added value in our use-case is full path resolution,
that we need to do anyway for the rmtree cleanup.
author | Georges Racinet <georges.racinet@octobus.net> |
---|---|
date | Fri, 23 Feb 2024 11:41:55 +0100 |
parents | fe68a2dc0bf2 |
children | dd519ea71416 |
line wrap: on
line diff
--- a/hgext/chainsaw.py Fri Feb 23 11:30:58 2024 +0100 +++ b/hgext/chainsaw.py Fri Feb 23 11:41:55 2024 +0100 @@ -26,8 +26,12 @@ cmdutil, commands, error, + localrepo, registrar, ) +from mercurial.utils import ( + urlutil, +) cmdtable = {} command = registrar.command(cmdtable) @@ -73,23 +77,49 @@ b'', _(b'repository to clone from'), ), + ( + b'', + b'dest', + b'', + _(b'repository to update to REV (possibly cloning)'), + ), + ( + b'', + b'initial-clone-minimal', + False, + _( + b'Pull only the prescribed revision upon initial cloning. ' + b'This has the side effect of ignoring clone-bundles, ' + b'which if often slower on the client side and stressful ' + b'to the server than applying available clone bundles.' + ), + ), ], - _(b'hg admin::chainsaw-update [OPTION] --rev REV --source SOURCE...'), + _( + b'hg admin::chainsaw-update [OPTION] --rev REV --source SOURCE --dest DEST' + ), helpbasic=True, + norepo=True, ) -def update(ui, repo, **opts): +def update(ui, **opts): """pull and update to a given revision, no matter what, (EXPERIMENTAL) Context of application: *some* Continuous Integration (CI) systems, packaging or deployment tools. - Wanted end result: clean working directory updated at the given revision. + Wanted end result: local repository at the given REPO_PATH, having the + latest changes to the given revision and with a clean working directory + updated at the given revision. chainsaw-update pulls from one source, then updates the working directory to the given revision, overcoming anything that would stand in the way. By default, it will: + - clone if the local repo does not exist yet, **removing any directory + at the given path** that would not be a Mercurial repository. + The initial clone is full by default, so that clonebundles can be + applied. Use the --initial-clone-minimal flag to avoid this. - break locks if needed, leading to possible corruption if there is a concurrent write access. - perform recovery actions if needed @@ -116,10 +146,36 @@ """ rev = opts['rev'] source = opts['source'] + repo_path = opts['dest'] if not rev: raise error.InputError(_(b'specify a target revision with --rev')) if not source: raise error.InputError(_(b'specify a pull path with --source')) + if not repo_path: + raise error.InputError(_(b'specify a repo path with --dest')) + repo_path = urlutil.urllocalpath(repo_path) + + try: + repo = localrepo.instance(ui, repo_path, create=False) + repo_created = False + ui.status(_(b'loaded repository at "%s"\n' % repo_path)) + except error.RepoError: + try: + shutil.rmtree(repo_path) + except FileNotFoundError: + ui.status(_(b'no such directory: "%s"\n' % repo_path)) + else: + ui.status( + _( + b'removed non-repository file or directory ' + b'at "%s"' % repo_path + ) + ) + + ui.status(_(b'creating repository at "%s"\n' % repo_path)) + repo = localrepo.instance(ui, repo_path, create=True) + repo_created = True + if repo.svfs.tryunlink(b'lock'): ui.status(_(b'had to break store lock\n')) if repo.vfs.tryunlink(b'wlock'): @@ -129,10 +185,14 @@ repo.recover() ui.status(_(b'pulling from %s\n') % source) + if repo_created and not opts.get('initial_clone_minimal'): + pull_revs = [] + else: + pull_revs = [rev] overrides = {(b'ui', b'quiet'): True} - with ui.configoverride(overrides, b'chainsaw-update'): + with repo.ui.configoverride(overrides, b'chainsaw-update'): pull = cmdutil.findcmd(b'pull', commands.table)[1][0] - pull(ui, repo, source, rev=[rev], remote_hidden=False) + pull(repo.ui, repo, source, rev=pull_revs, remote_hidden=False) purge = cmdutil.findcmd(b'purge', commands.table)[1][0] purge(