merge default into stable for 4.0 code freeze stable 4.0-rc
authorKevin Bullock <kbullock+mercurial@ringworld.org>
Tue, 18 Oct 2016 14:15:15 -0500
branchstable
changeset 30215 438173c41587
parent 30214 fc11bb10425f (diff)
parent 30212 260af19891f2 (current diff)
child 30216 a314082946f8
merge default into stable for 4.0 code freeze
hgext/largefiles/overrides.py
tests/test-largefiles-update.t
--- a/hgext/largefiles/overrides.py	Sun Oct 16 13:35:23 2016 -0700
+++ b/hgext/largefiles/overrides.py	Tue Oct 18 14:15:15 2016 -0500
@@ -1385,7 +1385,8 @@
         lfdirstate = lfutil.openlfdirstate(repo.ui, repo)
         unsure, s = lfdirstate.status(matchmod.always(repo.root,
                                                     repo.getcwd()),
-                                      [], False, False, False)
+                                      [], False, True, False)
+        oldclean = set(s.clean)
         pctx = repo['.']
         for lfile in unsure + s.modified:
             lfileabs = repo.wvfs.join(lfile)
@@ -1397,9 +1398,13 @@
                                 lfutil.getexecutable(lfileabs))
             if (standin in pctx and
                 lfhash == lfutil.readstandin(repo, lfile, '.')):
-                lfdirstate.normal(lfile)
+                oldclean.add(lfile)
         for lfile in s.added:
             lfutil.updatestandin(repo, lfutil.standin(lfile))
+        # mark all clean largefiles as dirty, just in case the update gets
+        # interrupted before largefiles and lfdirstate are synchronized
+        for lfile in oldclean:
+            lfdirstate.normallookup(lfile)
         lfdirstate.write()
 
         oldstandins = lfutil.getstandinsstate(repo)
@@ -1408,6 +1413,13 @@
 
         newstandins = lfutil.getstandinsstate(repo)
         filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
+
+        # to avoid leaving all largefiles as dirty and thus rehash them, mark
+        # all the ones that didn't change as clean
+        for lfile in oldclean.difference(filelist):
+            lfdirstate.normal(lfile)
+        lfdirstate.write()
+
         if branchmerge or force or partial:
             filelist.extend(s.deleted + s.removed)
 
--- a/hgext/largefiles/reposetup.py	Sun Oct 16 13:35:23 2016 -0700
+++ b/hgext/largefiles/reposetup.py	Tue Oct 18 14:15:15 2016 -0500
@@ -164,8 +164,8 @@
                     # files from lfdirstate
                     unsure, s = lfdirstate.status(match, [], False, listclean,
                                                   False)
-                    (modified, added, removed, clean) = (s.modified, s.added,
-                                                         s.removed, s.clean)
+                    (modified, added, removed, deleted, clean) = (
+                        s.modified, s.added, s.removed, s.deleted, s.clean)
                     if parentworking:
                         for lfile in unsure:
                             standin = lfutil.standin(lfile)
@@ -206,14 +206,18 @@
                         removed = [lfile for lfile in removed
                                    if lfutil.standin(lfile) in ctx1]
 
-                    # Standins no longer found in lfdirstate has been
-                    # removed
+                    # Standins no longer found in lfdirstate have been deleted
                     for standin in ctx1.walk(lfutil.getstandinmatcher(self)):
                         lfile = lfutil.splitstandin(standin)
                         if not match(lfile):
                             continue
                         if lfile not in lfdirstate:
-                            removed.append(lfile)
+                            deleted.append(lfile)
+                            # Sync "largefile has been removed" back to the
+                            # standin. Removing a file as a side effect of
+                            # running status is gross, but the alternatives (if
+                            # any) are worse.
+                            self.wvfs.unlink(standin)
 
                     # Filter result lists
                     result = list(result)
@@ -237,7 +241,7 @@
                     normals = [[fn for fn in filelist
                                 if not lfutil.isstandin(fn)]
                                for filelist in result]
-                    lfstatus = (modified, added, removed, s.deleted, [], [],
+                    lfstatus = (modified, added, removed, deleted, [], [],
                                 clean)
                     result = [sorted(list1 + list2)
                               for (list1, list2) in zip(normals, lfstatus)]
--- a/i18n/pt_BR.po	Sun Oct 16 13:35:23 2016 -0700
+++ b/i18n/pt_BR.po	Tue Oct 18 14:15:15 2016 -0500
@@ -11386,6 +11386,11 @@
 "o bundle em %s está corrompido:\n"
 "%s"
 
+#. i18n: column positioning for "hg summary"
+#, python-format
+msgid "remote: %s\n"
+msgstr "remoto:       %s\n"
+
 msgid "push failed:"
 msgstr "o push falhou:"
 
@@ -15259,32 +15264,26 @@
 msgid "[OPTION]... PATTERN [FILE]..."
 msgstr "[OPÇÃO]... PADRÃO [ARQUIVO]..."
 
-msgid "search for a pattern in specified files and revisions"
-msgstr "procura por um padrão nos arquivos e revisões especificados"
-
-msgid "    Search revisions of files for a regular expression."
-msgstr "    Procura em revisões e arquivos por uma expressão regular."
-
-msgid ""
-"    This command behaves differently than Unix grep. It only accepts\n"
-"    Python/Perl regexps. It searches repository history, not the\n"
-"    working directory. It always prints the revision number in which a\n"
-"    match appears."
-msgstr ""
-"    Este comando se comporta de modo diferente do grep do Unix. Ele\n"
-"    aceita apenas expressões regulares Python/Perl. Ele procura no\n"
-"    histórico do repositório, não no diretório de trabalho. Ele\n"
-"    sempre imprime o número da revisão onde um casamento aparece."
-
-msgid ""
-"    By default, grep only prints output for the first revision of a\n"
+msgid "search revision history for a pattern in specified files"
+msgstr ""
+"procura no histórico de revisões por um padrão nos arquivos especificados"
+
+msgid ""
+"    Search revision history for a regular expression in the specified\n"
+"    files or the entire project."
+msgstr ""
+"    Procura no histórico de revisões por uma expressão regular,\n"
+"    nos arquivos pedidos ou no projeto como um todo."
+
+msgid ""
+"    By default, grep prints the most recent revision number for each\n"
 "    file in which it finds a match. To get it to print every revision\n"
-"    that contains a change in match status (\"-\" for a match that\n"
-"    becomes a non-match, or \"+\" for a non-match that becomes a match),\n"
-"    use the --all flag."
-msgstr ""
-"    Por padrão, grep imprime uma saída apenas para a primeira revisão\n"
-"    de um arquivo no qual ele encontra uma correspondência.\n"
+"    that contains a change in match status (\"-\" for a match that becomes\n"
+"    a non-match, or \"+\" for a non-match that becomes a match), use the\n"
+"    --all flag."
+msgstr ""
+"    Por padrão, grep imprime o número da revisão mais recente\n"
+"    de cada arquivo no qual ele encontre uma correspondência.\n"
 "    Para fazê-lo imprimir todas as revisões que contenham uma\n"
 "    mudança de correspondência (\"-\" para uma correspondência\n"
 "    que se torne uma não correspondência, ou \"+\" para uma não\n"
@@ -15292,6 +15291,23 @@
 "    opção --all ."
 
 msgid ""
+"    PATTERN can be any Python (roughly Perl-compatible) regular\n"
+"    expression."
+msgstr ""
+"    PADRÃO pode ser qualquer expressão regular do Python (são\n"
+"    aproximadamente compatíveis com expressões regulares Perl)."
+
+msgid ""
+"    If no FILEs are specified (and -f/--follow isn't set), all files in\n"
+"    the repository are searched, including those that don't exist in the\n"
+"    current branch or have been deleted in a prior changeset."
+msgstr ""
+"    Se nenhum ARQUIVO for especificado (e se -f/--follow não estiver\n"
+"    definido), a busca será realizada em todos os arquivos do repositório,\n"
+"    incluindo arquivos que não existirem no ramo atual ou que tiverem sido\n"
+"    removidos em uma revisão anterior."
+
+msgid ""
 "    Returns 0 if a match is found, 1 otherwise.\n"
 "    "
 msgstr ""
@@ -17555,11 +17571,6 @@
 msgstr "%d marcadores a serem enviados"
 
 #. i18n: column positioning for "hg summary"
-#, python-format
-msgid "remote: %s\n"
-msgstr "remoto:       %s\n"
-
-#. i18n: column positioning for "hg summary"
 msgid "remote: (synced)\n"
 msgstr "remoto:       (sincronizado)\n"
 
@@ -33836,6 +33847,20 @@
 msgid "number of cpus must be an integer"
 msgstr "o número de cpus deve ser um inteiro"
 
+#~ msgid "    Search revisions of files for a regular expression."
+#~ msgstr "    Procura em revisões e arquivos por uma expressão regular."
+
+#~ msgid ""
+#~ "    This command behaves differently than Unix grep. It only accepts\n"
+#~ "    Python/Perl regexps. It searches repository history, not the\n"
+#~ "    working directory. It always prints the revision number in which a\n"
+#~ "    match appears."
+#~ msgstr ""
+#~ "    Este comando se comporta de modo diferente do grep do Unix. Ele\n"
+#~ "    aceita apenas expressões regulares Python/Perl. Ele procura no\n"
+#~ "    histórico do repositório, não no diretório de trabalho. Ele\n"
+#~ "    sempre imprime o número da revisão onde um casamento aparece."
+
 #~ msgid "use %(path)s to diff repository (or selected files)"
 #~ msgstr "usa %(path)s para exibir diffs do repositório ou arquivos"
 
--- a/tests/test-largefiles-update.t	Sun Oct 16 13:35:23 2016 -0700
+++ b/tests/test-largefiles-update.t	Tue Oct 18 14:15:15 2016 -0500
@@ -144,6 +144,7 @@
   large1 in #1
   $ cat .hglf/large1
   58e24f733a964da346e2407a2bee99d9001184f5
+  $ rm normal1.orig
 
 (merge non-existing largefiles from "other" via conflict prompt -
 make sure the following commit doesn't abort in a confusing way when trying to
@@ -243,6 +244,7 @@
   ? largeY
   $ test -f .hglf/largeY
   [1]
+  $ rm largeY
 
 Test that "hg rollback" restores standins correctly
 
@@ -285,6 +287,7 @@
   58e24f733a964da346e2407a2bee99d9001184f5
   $ cat .hglf/large2
   1deebade43c8c498a3c8daddac0244dc55d1331d
+  $ rm normalX
 
 Test that "hg status" shows status of largefiles correctly just after
 automated commit like rebase/transplant
@@ -598,6 +601,7 @@
   58e24f733a964da346e2407a2bee99d9001184f5
   $ cat large1
   large1 in #1
+  $ rm normal1.orig
 
 Test that rebase updates standins for manually modified largefiles at
 the 1st commit of resuming.
@@ -728,6 +732,42 @@
 
 #endif
 
+Test a fatal error interrupting an update. Verify that status report dirty
+files correctly after an interrupted update. Also verify that checking all
+hashes reveals it isn't clean.
+
+Start with clean dirstates:
+  $ hg up -qcr "8^"
+  $ sleep 1
+  $ hg st
+Update standins without updating largefiles - large1 is modified and largeX is
+added:
+  $ cat << EOF > ../crashupdatelfiles.py
+  > import hgext.largefiles.lfutil
+  > def getlfilestoupdate(oldstandins, newstandins):
+  >      raise SystemExit(7)
+  > hgext.largefiles.lfutil.getlfilestoupdate = getlfilestoupdate
+  > EOF
+  $ hg up -Cr "8" --config extensions.crashupdatelfiles=../crashupdatelfiles.py
+  [7]
+Check large1 content and status ... and that update will undo modifications:
+  $ cat large1
+  large1 in #3
+  $ hg st
+  M large1
+  ! largeX
+  $ hg up -Cr .
+  getting changed largefiles
+  2 largefiles updated, 0 removed
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cat large1
+  manually modified before 'hg transplant --continue'
+  $ hg st
+Force largefiles rehashing and check that all changes have been caught by
+status and update:
+  $ rm .hg/largefiles/dirstate
+  $ hg st
+
   $ cd ..
 
 Test that "hg convert" avoids copying largefiles from the working