infinitepush: add summary of not-backed-up files to smartlog

Summary:
Allow summarisation of commits that have not been backed up
by infinitepush.

1. Add a template keyword (backupstatus) which evaluates to
   one of "Public", "Backed up", "Backup pending", or
   "Not backed up" depending on the backup state of the
   commit.  Commits are pending for 10 minutes, after which
   they are declared not backed up.

2. Add a summary to the end of smartlog that shows the
   number of commits that are not backed up.

   Configuration options allow the addition of an education
   message to inform users what to do about their failing
   backups, and the message can also be suppressed.

Test Plan:
   New unit test for both the keyword and the summary.

Reviewers: #fbhgext, stash

Subscribers: mitrandir, quark, akushner

Differential Revision: https://phab.mercurial-scm.org/D184
This commit is contained in:
Mark Thomas 2017-08-01 03:12:04 -07:00
parent 72f38ebdf0
commit c8581c4465
3 changed files with 172 additions and 2 deletions

View File

@ -139,6 +139,7 @@ configscratchpush = 'infinitepush-scratchpush'
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 @@ def clientextsetup(ui):
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)

View File

@ -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 mercurial import (
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 @@ def isbackedup(ui, repo, **opts):
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 @@ def _readlocalbackupstate(ui, repo):
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:

View File

@ -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.