diff --git a/infinitepush/__init__.py b/infinitepush/__init__.py --- a/infinitepush/__init__.py +++ b/infinitepush/__init__.py @@ -139,6 +139,7 @@ confignonforwardmove = 'non-forward-move' cmdtable = infinitepushcommands.cmdtable +revsetpredicate = backupcommands.revsetpredicate _scratchbranchmatcher = lambda x: False _maybehash = re.compile(r'^[a-f0-9]+$').search @@ -316,6 +317,18 @@ partorder.insert( index, partorder.pop(partorder.index(scratchbranchparttype))) + def wrapsmartlog(loaded): + if not loaded: + return + smartlogmod = extensions.find('smartlog') + wrapcommand(smartlogmod.cmdtable, 'smartlog', _smartlog) + extensions.afterloaded('smartlog', wrapsmartlog) + +def _smartlog(orig, ui, repo, **opts): + res = orig(ui, repo, **opts) + backupcommands.smartlogsummary(ui, repo) + return res + def _showbookmarks(ui, bookmarks, **opts): # Copy-paste from commands.py fm = ui.formatter('bookmarks', opts) diff --git a/infinitepush/backupcommands.py b/infinitepush/backupcommands.py --- a/infinitepush/backupcommands.py +++ b/infinitepush/backupcommands.py @@ -23,6 +23,10 @@ # Hostname value to use. If not specified then socket.gethostname() will # be used hostname = '' + + # Enable reporting of infinitepush backup status as a summary at the end + # of smartlog. + enablestatus = False """ from __future__ import absolute_import @@ -57,13 +61,14 @@ from collections import defaultdict, namedtuple from mercurial import policy from mercurial.extensions import wrapfunction, unwrapfunction -from mercurial.node import bin, hex, nullrev +from mercurial.node import bin, hex, nullrev, short from mercurial.i18n import _ osutil = policy.importmod(r'osutil') cmdtable = {} command = registrar.command(cmdtable) +revsetpredicate = registrar.revsetpredicate() backupbookmarktuple = namedtuple('backupbookmarktuple', ['hostname', 'reporoot', 'localbookmark']) @@ -301,6 +306,39 @@ ui.write(_('backed up' if r in backeduprevs else 'not backed up')) ui.write(_('\n')) +@revsetpredicate('backedup') +def backedup(repo, subset, x): + """Draft changesets that have been backed up by infinitepush""" + bkpstate = _readlocalbackupstate(repo.ui, repo) + visiblebkpheads = [head for head in bkpstate.heads if head in repo] + return subset & repo.revs('draft() and ::%ls', visiblebkpheads) + +def smartlogsummary(ui, repo): + if not ui.configbool('infinitepushbackup', 'enablestatus'): + return + + bkpstate = _readlocalbackupstate(ui, repo) + visiblebkpheads = [head for head in bkpstate.heads if head in repo] + unbackeduprevs = repo.revs('draft() and not ::%ls', visiblebkpheads) + + # Count the number of changesets that haven't been backed up for 10 minutes. + # If there is only one, also print out its hash. + backuptime = time.time() - 10 * 60 # 10 minutes ago + count = 0 + singleunbackeduprev = None + for rev in unbackeduprevs: + if repo[rev].date()[0] <= backuptime: + singleunbackeduprev = rev + count += 1 + if count > 0: + if count > 1: + ui.warn(_('note: %d changesets are not backed up.\n') % count) + else: + ui.warn(_('note: changeset %s is not backed up.\n') % + short(repo[singleunbackeduprev].node())) + ui.warn(_('Run `hg pushbackup` to perform a backup. If this fails,\n' + 'please report to the Source Control @ FB group.\n')) + def _dobackup(ui, repo, dest, **opts): ui.status(_('starting backup %s\n') % time.strftime('%H:%M:%S %d %b %Y %Z')) start = time.time() @@ -657,7 +695,7 @@ raise ValueError('bad types of bookmarks or heads') result = backupstate() - result.heads = set(state['heads']) + result.heads = set(map(str, state['heads'])) result.localbookmarks = state['bookmarks'] return result except (ValueError, KeyError, TypeError) as e: diff --git a/tests/test-infinitepush-backup-status.t b/tests/test-infinitepush-backup-status.t new file mode 100644 --- /dev/null +++ b/tests/test-infinitepush-backup-status.t @@ -0,0 +1,119 @@ + + $ setup() { + > cat << EOF >> .hg/hgrc + > [extensions] + > fbamend=$TESTDIR/../hgext3rd/fbamend + > smartlog=$TESTDIR/../hgext3rd/smartlog.py + > [infinitepushbackup] + > enablestatus = True + > [experimental] + > evolution=createmarkers + > EOF + > } + $ . "$TESTDIR/library.sh" + $ . "$TESTDIR/library-infinitepush.sh" + $ setupcommon + +Setup server + $ hg init repo + $ cd repo + $ setupserver + $ cd .. + +Setup client + $ hg clone ssh://user@dummy/repo client -q + $ cd client + $ setup + $ now=`date +%s` + $ touch file1 + $ hg add file1 + $ commit_time=`expr $now - 15 \* 60` + $ hg commit -d "$commit_time 0" -m "Public changeset" + $ hg push + pushing to ssh://user@dummy/repo + searching for changes + remote: adding changesets + remote: adding manifests + remote: adding file changes + remote: added 1 changesets with 1 changes to 1 files + $ echo a > file1 + $ changeset_time=`expr $now - 13 \* 60` + $ hg commit -d "$commit_time 0" -m "Backed up changeset" + $ hg pushbackup + starting backup .* (re) + searching for changes + remote: pushing 1 commit: + remote: * Backed up changeset (glob) + finished in \d+\.(\d+)? seconds (re) + $ echo b > file1 + $ commit_time=`expr $now - 11 \* 60` + $ hg commit -d "$commit_time 0" -m "Not backed up changeset" + $ echo c > file1 + $ commit_time=`expr $now - 9 \* 60` + $ hg commit -d "$commit_time 0" -m "Backup pending changeset" + +Check backup status of commits + $ hg log -T '{rev} {desc}\n' -r 'backedup()' + 1 Backed up changeset + $ hg log -T '{rev} {desc}\n' -r 'draft() - backedup()' + 2 Not backed up changeset + 3 Backup pending changeset + +Check smartlog output + $ hg smartlog + @ changeset: 3:* (glob) + | tag: tip + | user: test + | date: * (glob) + | summary: Backup pending changeset + | + o changeset: 2:* (glob) + | user: test + | date: * (glob) + | summary: Not backed up changeset + | + o changeset: 1:* (glob) + | user: test + | date: * (glob) + | summary: Backed up changeset + | + o changeset: 0:* (glob) + user: test + date: * (glob) + summary: Public changeset + + note: changeset * is not backed up. (glob) + Run `hg pushbackup` to perform a backup. If this fails, + please report to the Source Control @ FB group. + +Check smartlog summary can be suppressed + $ hg smartlog -T '{rev}: {desc}\n' --config infinitepushbackup.enablestatus=no + @ 3: Backup pending changeset + | + o 2: Not backed up changeset + | + o 1: Backed up changeset + | + o 0: Public changeset + +Check smartlog summary with multiple unbacked up changesets + $ hg up 2 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo b2 > file1 + $ commit_time=`expr $now - 11 \* 60` + $ hg commit -d "$commit_time 0" -m "Not backed up changeset 2" + created new head + $ hg smartlog -T '{rev}: {desc}\n' + @ 4: Not backed up changeset 2 + | + | o 3: Backup pending changeset + |/ + o 2: Not backed up changeset + | + o 1: Backed up changeset + | + o 0: Public changeset + + note: 2 changesets are not backed up. + Run `hg pushbackup` to perform a backup. If this fails, + please report to the Source Control @ FB group.