Commit Graph

94 Commits

Author SHA1 Message Date
Matt Harbison
312e37cc1e archive: add an experimental config to control the metadata file template
Experimental because given the possible complexity, it may be worth figuring out
how to load this from a file, similar to the style files for the log command,
instead of trying to stuff it on the command line.
2017-07-17 00:49:29 -04:00
Matt Harbison
9f1bd9a3e0 archive: use a templater to build the metadata file
There are no visible changes here.

I'm starting to wonder if adding the '+' to the 'node' line instead of a
separate key line in a4d42f6edc09 was the right thing to do.  The '{node}'
keyword never includes '+' elsewhere, and the way setup.py works, it would
truncate it anyway.  Additionally, the file is missing '{p2node}' when 'wdir()'
merges are archived.  I thought about adding an 'identify' line that would
correspond to `hg id -n`.  But the other nodes are the full 40 characters, and
the output most useful for versioning is the short form.  All of this cries out
for customization via templating.  (Although maybe having the short identify
line by default is still a good idea.)
2017-07-16 17:40:36 -04:00
Jun Wu
e47f7dc2fa codemod: register core configitems using a script
This is done by a script [2] using RedBaron [1], a tool designed for doing
code refactoring. All "default" values are decided by the script and are
strongly consistent with the existing code.

There are 2 changes done manually to fix tests:

  [warn] mercurial/exchange.py: experimental.bundle2-output-capture: default needs manual removal
  [warn] mercurial/localrepo.py: experimental.hook-track-tags: default needs manual removal

Since RedBaron is not confident about how to indent things [2].

[1]: https://github.com/PyCQA/redbaron
[2]: https://github.com/PyCQA/redbaron/issues/100
[3]:

#!/usr/bin/env python
# codemod_configitems.py - codemod tool to fill configitems
#
# Copyright 2017 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import, print_function

import os
import sys

import redbaron

def readpath(path):
    with open(path) as f:
        return f.read()

def writepath(path, content):
    with open(path, 'w') as f:
        f.write(content)

_configmethods = {'config', 'configbool', 'configint', 'configbytes',
                  'configlist', 'configdate'}

def extractstring(rnode):
    """get the string from a RedBaron string or call_argument node"""
    while rnode.type != 'string':
        rnode = rnode.value
    return rnode.value[1:-1]  # unquote, "'str'" -> "str"

def uiconfigitems(red):
    """match *.ui.config* pattern, yield (node, method, args, section, name)"""
    for node in red.find_all('atomtrailers'):
        entry = None
        try:
            obj = node[-3].value
            method = node[-2].value
            args = node[-1]
            section = args[0].value
            name = args[1].value
            if (obj in ('ui', 'self') and method in _configmethods
                and section.type == 'string' and name.type == 'string'):
                entry = (node, method, args, extractstring(section),
                         extractstring(name))
        except Exception:
            pass
        else:
            if entry:
                yield entry

def coreconfigitems(red):
    """match coreconfigitem(...) pattern, yield (node, args, section, name)"""
    for node in red.find_all('atomtrailers'):
        entry = None
        try:
            args = node[1]
            section = args[0].value
            name = args[1].value
            if (node[0].value == 'coreconfigitem' and section.type == 'string'
                and name.type == 'string'):
                entry = (node, args, extractstring(section),
                         extractstring(name))
        except Exception:
            pass
        else:
            if entry:
                yield entry

def registercoreconfig(cfgred, section, name, defaultrepr):
    """insert coreconfigitem to cfgred AST

    section and name are plain string, defaultrepr is a string
    """
    # find a place to insert the "coreconfigitem" item
    entries = list(coreconfigitems(cfgred))
    for node, args, nodesection, nodename in reversed(entries):
        if (nodesection, nodename) < (section, name):
            # insert after this entry
            node.insert_after(
                'coreconfigitem(%r, %r,\n'
                '    default=%s,\n'
                ')' % (section, name, defaultrepr))
            return

def main(argv):
    if not argv:
        print('Usage: codemod_configitems.py FILES\n'
              'For example, FILES could be "{hgext,mercurial}/*/**.py"')
    dirname = os.path.dirname
    reporoot = dirname(dirname(dirname(os.path.abspath(__file__))))

    # register configitems to this destination
    cfgpath = os.path.join(reporoot, 'mercurial', 'configitems.py')
    cfgred = redbaron.RedBaron(readpath(cfgpath))

    # state about what to do
    registered = set((s, n) for n, a, s, n in coreconfigitems(cfgred))
    toregister = {} # {(section, name): defaultrepr}
    coreconfigs = set() # {(section, name)}, whether it's used in core

    # first loop: scan all files before taking any action
    for i, path in enumerate(argv):
        print('(%d/%d) scanning %s' % (i + 1, len(argv), path))
        iscore = ('mercurial' in path) and ('hgext' not in path)
        red = redbaron.RedBaron(readpath(path))
        # find all repo.ui.config* and ui.config* calls, and collect their
        # section, name and default value information.
        for node, method, args, section, name in uiconfigitems(red):
            if section == 'web':
                # [web] section has some weirdness, ignore them for now
                continue
            defaultrepr = None
            key = (section, name)
            if len(args) == 2:
                if key in registered:
                    continue
                if method == 'configlist':
                    defaultrepr = 'list'
                elif method == 'configbool':
                    defaultrepr = 'False'
                else:
                    defaultrepr = 'None'
            elif len(args) >= 3 and (args[2].target is None or
                                     args[2].target.value == 'default'):
                # try to understand the "default" value
                dnode = args[2].value
                if dnode.type == 'name':
                    if dnode.value in {'None', 'True', 'False'}:
                        defaultrepr = dnode.value
                elif dnode.type == 'string':
                    defaultrepr = repr(dnode.value[1:-1])
                elif dnode.type in ('int', 'float'):
                    defaultrepr = dnode.value
            # inconsistent default
            if key in toregister and toregister[key] != defaultrepr:
                defaultrepr = None
            # interesting to rewrite
            if key not in registered:
                if defaultrepr is None:
                    print('[note] %s: %s.%s: unsupported default'
                          % (path, section, name))
                    registered.add(key) # skip checking it again
                else:
                    toregister[key] = defaultrepr
                    if iscore:
                        coreconfigs.add(key)

    # second loop: rewrite files given "toregister" result
    for path in argv:
        # reconstruct redbaron - trade CPU for memory
        red = redbaron.RedBaron(readpath(path))
        changed = False
        for node, method, args, section, name in uiconfigitems(red):
            key = (section, name)
            defaultrepr = toregister.get(key)
            if defaultrepr is None or key not in coreconfigs:
                continue
            if len(args) >= 3 and (args[2].target is None or
                                   args[2].target.value == 'default'):
                try:
                    del args[2]
                    changed = True
                except Exception:
                    # redbaron fails to do the rewrite due to indentation
                    # see https://github.com/PyCQA/redbaron/issues/100
                    print('[warn] %s: %s.%s: default needs manual removal'
                          % (path, section, name))
            if key not in registered:
                print('registering %s.%s' % (section, name))
                registercoreconfig(cfgred, section, name, defaultrepr)
                registered.add(key)
        if changed:
            print('updating %s' % path)
            writepath(path, red.dumps())

    if toregister:
        print('updating configitems.py')
        writepath(cfgpath, cfgred.dumps())

if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
2017-07-14 14:22:40 -07:00
Matt Harbison
5a0fd7acbc archival: flag missing files as a dirty wdir() in the metadata file (BC)
Since the identify command adds a '+' for missing files, it's reasonable that
this does too.  Perhaps the node field's hex value should be p1+p2 for merges?
2017-07-09 02:46:03 -04:00
Pierre-Yves David
4ef557608a vfs: use 'vfs' module directly in 'mercurial.archival'
Now that the 'vfs' classes moved in their own module, lets use the new module
directly. We update code iteratively to help with possible bisect needs in the
future.
2017-03-02 13:30:28 +01:00
Pierre-Yves David
e5cb48ac36 vfs: replace 'scmutil.opener' usage with 'scmutil.vfs'
The 'vfs' class is the first class citizen for years. We remove all usages of
the older API. This will let us remove the old API eventually.
2017-03-02 03:52:36 +01:00
Matt Harbison
29208450f3 subrepo: run the repo decoders when archiving
The decoders were already run by default for the main repo, so this seemed like
an oversight.

The extdiff extension has been using 'archive' since a80ec1ea2694 to support -S,
and a colleague noticed that after diffing, making changes, and closing it, the
line endings were wrong for the diff-tool modified files in the subrepository.
(Files in the parent repo were correct, with the same .hgeol settings.)  The
editor (Visual Studio in this case) reloads the file, but doesn't notice the EOL
change.  It still adds new lines with the original EOL setting, and the file
ends up inconsistent.

Without this change, the first file `cat`d in the test prints '\r (esc)' EOL,
but the second doesn't on Windows or Linux.
2017-02-25 21:13:59 -05:00
Augie Fackler
a83eebb5b7 archival: simplify code and drop message about Python 2.5 2016-11-21 18:17:02 -05:00
Pulkit Goyal
8b4f697218 py3: remove use of *L syntax
The int in Python 3 behaves as long so no need of L's in py3.
Moreover we dont need long here.
2016-09-01 02:29:46 +05:30
timeless
f77cdcd3b1 pycompat: switch to util.stringio for py3 compat 2016-04-10 20:55:37 +00:00
Martin von Zweigbergk
c84bb33a89 match: rename "narrowmatcher" to "subdirmatcher" (API)
I keep mistaking "narrowmatcher" for narrowhg's
narrowmatcher. "subdirmatcher" seems more to the point anyway.
2016-02-05 21:09:32 -08:00
Pierre-Yves David
30913031d4 error: get Abort from 'error' instead of 'util'
The home of 'Abort' is 'error' not 'util' however, a lot of code seems to be
confused about that and gives all the credit to 'util' instead of the
hardworking 'error'. In a spirit of equity, we break the cycle of injustice and
give back to 'error' the respect it deserves. And screw that 'util' poser.

For great justice.
2015-10-08 12:55:45 -07:00
timeless@mozdev.org
521ee1e86c archival: drop self.filename - deprecated in py2.6 2015-09-04 05:54:35 -04:00
Gregory Szorc
d30eb7e23d archival: use absolute_import 2015-08-07 19:47:49 -07:00
Matt Harbison
0d9eba99eb archive: use {changessincelatesttag} to build the metadata file
This isolates the current magic when dealing with wdir() and only().
2015-06-30 23:56:49 -04:00
Matt Mackall
b050378961 merge with stable 2015-07-01 16:33:31 -05:00
Matt Mackall
174e090e10 archive: fix changesincelatesttag with wdir() 2015-07-01 15:12:45 -05:00
Matt Mackall
2173cc3777 merge with stable 2015-06-29 16:38:22 -05:00
Matt Harbison
d4e8d4f13c archive: don't assume '.' is being archived for changessincelatesttag
Hardcoding '.' is wrong, and yielded strange results when archiving old
revisions.  For example, when archiving the cset that adds the signature to 3.4
(a4f6d198e7df), the resulting value was previously 51 (the number of commits on
stable between 3.4 and today), even though it was a direct descendant of a tag,
with a {latesttagdistance} of 2.  This still includes all other _ancestor_ paths
not included in {latesttag}.

Note that archiving wdir() currently blows up several lines above this when
building the 'base' variable.  Since wdir() isn't documented, ignore that it
needs work to handle wdir() here for now.
2015-06-25 21:16:47 -04:00
Gregory Szorc
3aa1c73868 global: mass rewrite to use modern octal syntax
Python 2.6 introduced a new octal syntax: "0oXXX", replacing "0XXX". The
old syntax is not recognized in Python 3 and will result in a parse
error.

Mass rewrite all instances of the old octal syntax to the new syntax.

This patch was generated by `2to3 -f numliterals -w -n .` and the diff
was selectively recorded to exclude changes to "<N>l" syntax conversion,
which will be handled separately.
2015-06-23 22:30:33 -07:00
Yuya Nishihara
7de01412a9 archive: look for first visible revision to build repo identity (issue4591)
No test for the case where all revisions are hidden because "archive" command
aborts if the target revision is null.
2015-04-08 23:30:02 +09:00
Yuya Nishihara
d2b9482bcd archive: extract metadata() closure to module-level function
This function will be reused in largefiles.
2015-04-08 22:37:03 +09:00
Yuya Nishihara
553dc1006c archive: use ctx object consistently to build meta data 2015-04-08 22:31:04 +09:00
Matt Harbison
abed66c145 archive: report the node as "{p1node}+" when archiving a dirty wdir()
This is more useful than reporting all 'f's, allowing the archive to be diffed
against a specific revision to see what changed.
2015-06-16 23:14:45 -04:00
Matt Harbison
0dc20be5d4 archive: support 'wdir()'
This is a step toward replacing the extdiff internals with archive, in order to
support 'extdiff -S'.  Only Mercurial subrepos are supported for now.

If a file is missing from the filesystem, it is silently skipped.  Perhaps it
should warn, but it cannot abort when working with extdiff because deleting a
file is a legitimate diff.
2015-06-16 23:06:57 -04:00
Matt Harbison
d3aeafb647 archive: change the default prefix to '' from None
All current callers supply some sort of prefix, so the issue was hidden.  But if
no parameter was specified, a crash occurred in the write() closure when
concatenating 'prefix' and 'name'.
2015-02-15 17:21:48 -05:00
Siddharth Agarwal
94be18d96c archive: store number of changes since latest tag as well
This is different from latesttagdistance in that while latesttagdistance is
defined to be the length of the longest path to the latest tag,
changessincelatesttag is the number of changes contained in @ that aren't
contained in the latest tag. So, if 't' is the latest tag in the repository
below:

      t
      |
      v
 --o--o----o
    \       \
     ..o..o..@

then latesttagdistance is 2, but changessincelatesttag is 4.

Note that changessincelatesttag is always greater than or equal to the
latesttagdistance -- that's because changessincelatesttag counts all the
changes in the longest path since the latest tag, and possibly others. This is
an important fact that we'll take advantage of in upcoming patches.
2014-12-12 15:27:13 -08:00
Matt Harbison
7624013ead subrepo: drop the 'ui' parameter to archive()
The current state of subrepo methods is to pass a 'ui' object to some methods,
which has the effect of overriding the subrepo configuration since it is the
root repo's 'ui' that is passed along as deep as there are subrepos.  Other
subrepo method are *not* passed the root 'ui', and instead delegate to their
repo object's 'ui'.  Even in the former case where the root 'ui' is available,
some methods are inconsistent in their use of both the root 'ui' and the local
repo's 'ui'.  (Consider hg._incoming() uses the root 'ui' for path expansion
and some status messages, but also calls bundlerepo.getremotechanges(), which
eventually calls discovery.findcommonincoming(), which calls
setdiscovery.findcommonheads(), which calls status() on the local repo 'ui'.)

This inconsistency with respect to the configured output level is probably
always hidden, because --verbose, --debug and --quiet, along with their 'ui.xxx'
equivalents in the global and user level hgrc files are propagated from the
parent repo to the subrepo via 'baseui'.  The 'ui.xxx' settings in the parent
repo hgrc file are not propagated, but that seems like an unusual thing to set
on a per repo config file.  Any 'ui.xxx' options changed by --config are also
not propagated, because they are set on repo.ui by dispatch.py, not repo.baseui.

The goal here is to cleanup the subrepo methods by dropping the 'ui' parameter,
which in turn prevents mixing subtly different 'ui' instances on a given subrepo
level.  Some methods use more than just the output level settings in 'ui' (add
for example ends up calling scmutil.checkportabilityalert() with both the root
and local repo's 'ui' at different points).  This series just goes for the low
hanging fruit and switches methods that only use the output level.

If we really care about not letting a subrepo config override the root repo's
output level, we can propagate the verbose, debug and quiet settings to the
subrepo in the same way 'ui.commitsubrepos' is in hgsubrepo.__init__.

Archive only uses the 'ui' object to call its progress() method, and gitsubrepo
calls status().
2014-12-13 14:53:46 -05:00
Augie Fackler
a5b17bd9d1 cleanup: use __builtins__.any instead of util.any
any() is available in all Python versions we support now.
2015-05-16 14:30:07 -04:00
Matt Harbison
9fe8bb732e archive: drop the leading '.' path component from the prefix (issue4634)
Unix utilities like tar will happily prefix the files it packs with './', but
annoyingly, Windows Explorer will not show these packed files when it opens the
archive.  Since there doesn't seem to be a point in including './' in the path
names, just drop it.  The default 'hg archive' prefix is the basename of the
archive, so specifying '.' allows for that default to be disabled completely.
2015-05-05 20:52:38 -04:00
Angel Ezquerra
9b84fa41a7 archive: raise error.Abort if the file pattern matches no files
Note that we could raise this exception even if no pattern were specified, but
the revision contained no files. However this should not happen in practice
since in that case commands.py/archive would exit earlier with an "no working
directory: please specify a revision" error message instead.
2013-03-21 22:09:15 +01:00
Mads Kiilerich
2d6545f8b6 subrepos: process subrepos in sorted order
Add sorted() in places found by testing with PYTHONHASHSEED=random and code
inspection.

An alternative to sprinkling sorted() all over would be to change substate to a
custom dict with sorted iterators...
2012-12-12 02:38:14 +01:00
Mads Kiilerich
b66ec06f79 archival: tarit should never close the dest passed to it
Some archive types closed the open file passed to it, some didn't.

This could cause either missing or duplicate close and cause problems in hgweb.

The fix in 4f98880c1b4e should only have closed the compressors and archivers -
not the underlying file itself if no compressor is used.
2013-01-15 01:05:12 +01:00
Mads Kiilerich
bd884d9410 archival: avoid touching deprecated gzip name attribute
The existing workaround didn't work when no filename was specified.

If running in a context with warnings enabled and subsecond mtime it gave a
warning:
  DeprecationWarning: use the name attribute
2013-01-03 21:07:04 +01:00
Mads Kiilerich
959c978f9d archival: pass integer to struct.pack int field instead of float
If running in a context with warnings enabled and subsecond mtime it gave a
warning:
  DeprecationWarning: integer argument expected, got float
2013-01-03 21:07:04 +01:00
Bryan O'Sullivan
7a018d3dd7 Merge with crew-stable 2012-09-19 09:38:51 -07:00
FUJIWARA Katsunori
e08cbc5b19 archival: add "extended-timestamp" extra block for zip archives (issue3600)
Before this patch, zip archives created by "hg archive" are extracted
with unexpected timestamp, if TZ is not configured as GMT.

This patch adds "extended-timestamp" extra block to zip archives, and
unzip will extract such archives with timestamp specified in added
extra block, even though TZ is not configured as GMT.

Please see documents below for detail about specification of zip file
format and "extended-timestamp" extra block:

  http://www.pkware.com/documents/casestudies/APPNOTE.TXT
  http://www.opensource.apple.com/source/zip/zip-6/unzip/unzip/proginfo/extra.fld

Original implementation of this patch was suggested by "Jun Omae
<jun66j5@gmail.com>".
2012-09-18 19:46:15 +09:00
Mads Kiilerich
48016eb3fc declare local constants instead of using magic values and comments 2012-08-27 23:16:22 +02:00
Matt Harbison
63a46b018b subrepo: propagate matcher to subrepos when archiving
Add a match object to subrepo.archive(). This will allow the -X and -I
options to be honored inside subrepos when archiving. They formerly
only affect the top level repo.
2012-06-16 22:34:06 -04:00
Thomas Arendsen Hein
0c30f8dca5 archive: make progress only show files that are actually archived
Before this, files that are excluded (or not included) were shown when
using progress bar or --debug.

Reported by Andrew Shadura.
2012-06-12 12:05:52 +02:00
Greg Ward
bc1dfb1ac9 atomictempfile: make close() consistent with other file-like objects.
The usual contract is that close() makes your writes permanent, so
atomictempfile's use of close() to *discard* writes (and rename() to
keep them) is rather unexpected. Thus, change it so close() makes
things permanent and add a new discard() method to throw them away.
discard() is only used internally, in __del__(), to ensure that writes
are discarded when an atomictempfile object goes out of scope.

I audited mercurial.*, hgext.*, and ~80 third-party extensions, and
found no one using the existing semantics of close() to discard
writes, so this should be safe.
2011-08-25 20:21:04 -04:00
Adrian Buehlmann
cf126bb7dd move opener from util to scmutil 2011-04-20 19:54:57 +02:00
Markus F.X.J. Oberhumer
c2ca636151 archive: use hardcoded constants when creating .zip archives
Do not rely on local stat constants, which may differ.
2011-03-16 23:54:55 +01:00
Dan Villiom Podlaski Christiansen
ec590d5cd4 explicitly close files
Add missing calls to close() to many places where files are
opened. Relying on reference counting to catch them soon-ish is not
portable and fails in environments with a proper GC, such as PyPy.
2010-12-24 15:23:01 +01:00
Martin Geisler
290569c6d1 subrepo: add progress bar support to archive 2010-11-29 16:34:10 +01:00
Martin Geisler
70d929229e archive: add support for progress extension 2010-11-29 16:17:05 +01:00
Matt Mackall
6bcc439bb1 merge with stable 2010-12-08 13:12:12 -06:00
Brodie Rao
08a14dad90 archival: don't set gzip filename header when there's no filename
This mainly affects hgweb, which can generate tar.gz archives without
filenames. Without this change, the header would be set to ".gz",
which can confuse Safari into extracting the file and renaming it to
"gz" when "Open 'safe' files after downloading" is enabled.

file(1) before:

hg-crew-439421eab08d.tar.gz: gzip compressed data, was ".gz", last modified: Thu Dec  2 11:46:20 2010, max compression

after:

hg-crew-439421eab08d.tar.gz: gzip compressed data, last modified: Thu Dec  2 11:46:20 2010, max compression
2010-12-07 19:47:53 +11:00
Matt Mackall
8b31da4540 branch: operate on branch names in local string space where possible
Previously, branch names were ideally manipulated as UTF-8 strings,
because they were stored as UTF-8 in the dirstate and the changelog
and could not be safely converted to the local encoding and back.

However, only about 80% of branch name code was actually using the
right encoding conventions. This patch uses the localstr addition to
allow working on branch names as local strings, which simplifies
handling so that the previously incorrect code becomes correct.
2010-11-24 15:56:32 -06:00
Martin Geisler
34af0cf109 subrepo: add support for 'hg archive' 2010-09-20 15:46:17 +02:00