hgext/fix.py
author Pulkit Goyal <7895pulkit@gmail.com>
Thu, 08 Feb 2018 17:09:24 +0530
changeset 37190 ecdd8c3044de
parent 37183 ded5ea279a93
child 37207 d3f1d3e4e58d
permissions -rw-r--r--
infinitepush: delete the hack to load the extension after remotenames The remotenames extension which circumvents the default push implementation lives outside the core, so let's delete logic related to loading of extension on the basis of remotenames ext. Differential Revision: https://phab.mercurial-scm.org/D2099
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
37183
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
     1
# fix - rewrite file content in changesets and working copy
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
     2
#
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
     3
# Copyright 2018 Google LLC.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
     4
#
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
     6
# GNU General Public License version 2 or any later version.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
     7
"""rewrite file content in changesets or working copy (EXPERIMENTAL)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
     8
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
     9
Provides a command that runs configured tools on the contents of modified files,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    10
writing back any fixes to the working copy or replacing changesets.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    11
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    12
Here is an example configuration that causes :hg:`fix` to apply automatic
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    13
formatting fixes to modified lines in C++ code::
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    14
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    15
  [fix]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    16
  clang-format:command=clang-format --assume-filename={rootpath}
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    17
  clang-format:linerange=--lines={first}:{last}
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    18
  clang-format:fileset=set:**.cpp or **.hpp
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    19
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    20
The :command suboption forms the first part of the shell command that will be
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    21
used to fix a file. The content of the file is passed on standard input, and the
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    22
fixed file content is expected on standard output. If there is any output on
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    23
standard error, the file will not be affected. Some values may be substituted
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    24
into the command::
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    25
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    26
  {rootpath}  The path of the file being fixed, relative to the repo root
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    27
  {basename}  The name of the file being fixed, without the directory path
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    28
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    29
If the :linerange suboption is set, the tool will only be run if there are
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    30
changed lines in a file. The value of this suboption is appended to the shell
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    31
command once for every range of changed lines in the file. Some values may be
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    32
substituted into the command::
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    33
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    34
  {first}   The 1-based line number of the first line in the modified range
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    35
  {last}    The 1-based line number of the last line in the modified range
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    36
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    37
The :fileset suboption determines which files will be passed through each
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    38
configured tool. See :hg:`help fileset` for possible values. If there are file
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    39
arguments to :hg:`fix`, the intersection of these filesets is used.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    40
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    41
There is also a configurable limit for the maximum size of file that will be
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    42
processed by :hg:`fix`::
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    43
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    44
  [fix]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    45
  maxfilesize=2MB
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    46
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    47
"""
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    48
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    49
from __future__ import absolute_import
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    50
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    51
import collections
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    52
import itertools
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    53
import os
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    54
import re
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    55
import subprocess
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    56
import sys
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    57
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    58
from mercurial.i18n import _
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    59
from mercurial.node import nullrev
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    60
from mercurial.node import wdirrev
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    61
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    62
from mercurial import (
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    63
    cmdutil,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    64
    context,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    65
    copies,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    66
    error,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    67
    match,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    68
    mdiff,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    69
    merge,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    70
    obsolete,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    71
    posix,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    72
    registrar,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    73
    scmutil,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    74
    util,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    75
)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    76
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    77
# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    78
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    79
# be specifying the version(s) of Mercurial they are tested with, or
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    80
# leave the attribute unspecified.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    81
testedwith = 'ships-with-hg-core'
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    82
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    83
cmdtable = {}
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    84
command = registrar.command(cmdtable)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    85
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    86
configtable = {}
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    87
configitem = registrar.configitem(configtable)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    88
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    89
# Register the suboptions allowed for each configured fixer.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    90
FIXER_ATTRS = ('command', 'linerange', 'fileset')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    91
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    92
for key in FIXER_ATTRS:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    93
    configitem('fix', '.*(:%s)?' % key, default=None, generic=True)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    94
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    95
# A good default size allows most source code files to be fixed, but avoids
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    96
# letting fixer tools choke on huge inputs, which could be surprising to the
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    97
# user.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    98
configitem('fix', 'maxfilesize', default='2MB')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
    99
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   100
@command('fix',
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   101
    [('', 'base', [], _('revisions to diff against (overrides automatic '
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   102
                        'selection, and applies to every revision being '
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   103
                        'fixed)'), _('REV')),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   104
     ('r', 'rev', [], _('revisions to fix'), _('REV')),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   105
     ('w', 'working-dir', False, _('fix the working directory')),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   106
     ('', 'whole', False, _('always fix every line of a file'))],
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   107
    _('[OPTION]... [FILE]...'))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   108
def fix(ui, repo, *pats, **opts):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   109
    """rewrite file content in changesets or working directory
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   110
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   111
    Runs any configured tools to fix the content of files. Only affects files
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   112
    with changes, unless file arguments are provided. Only affects changed lines
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   113
    of files, unless the --whole flag is used. Some tools may always affect the
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   114
    whole file regardless of --whole.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   115
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   116
    If revisions are specified with --rev, those revisions will be checked, and
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   117
    they may be replaced with new revisions that have fixed file content.  It is
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   118
    desirable to specify all descendants of each specified revision, so that the
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   119
    fixes propagate to the descendants. If all descendants are fixed at the same
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   120
    time, no merging, rebasing, or evolution will be required.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   121
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   122
    If --working-dir is used, files with uncommitted changes in the working copy
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   123
    will be fixed. If the checked-out revision is also fixed, the working
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   124
    directory will update to the replacement revision.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   125
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   126
    When determining what lines of each file to fix at each revision, the whole
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   127
    set of revisions being fixed is considered, so that fixes to earlier
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   128
    revisions are not forgotten in later ones. The --base flag can be used to
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   129
    override this default behavior, though it is not usually desirable to do so.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   130
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   131
    with repo.wlock(), repo.lock():
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   132
        revstofix = getrevstofix(ui, repo, opts)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   133
        basectxs = getbasectxs(repo, opts, revstofix)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   134
        workqueue, numitems = getworkqueue(ui, repo, pats, opts, revstofix,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   135
                                           basectxs)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   136
        filedata = collections.defaultdict(dict)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   137
        replacements = {}
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   138
        fixers = getfixers(ui)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   139
        # Some day this loop can become a worker pool, but for now it's easier
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   140
        # to fix everything serially in topological order.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   141
        for rev, path in sorted(workqueue):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   142
            ctx = repo[rev]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   143
            olddata = ctx[path].data()
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   144
            newdata = fixfile(ui, opts, fixers, ctx, path, basectxs[rev])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   145
            if newdata != olddata:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   146
                filedata[rev][path] = newdata
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   147
            numitems[rev] -= 1
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   148
            if not numitems[rev]:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   149
                if rev == wdirrev:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   150
                    writeworkingdir(repo, ctx, filedata[rev], replacements)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   151
                else:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   152
                    replacerev(ui, repo, ctx, filedata[rev], replacements)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   153
                del filedata[rev]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   154
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   155
        replacements = {prec: [succ] for prec, succ in replacements.iteritems()}
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   156
        scmutil.cleanupnodes(repo, replacements, 'fix')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   157
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   158
def getworkqueue(ui, repo, pats, opts, revstofix, basectxs):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   159
    """"Constructs the list of files to be fixed at specific revisions
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   160
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   161
    It is up to the caller how to consume the work items, and the only
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   162
    dependence between them is that replacement revisions must be committed in
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   163
    topological order. Each work item represents a file in the working copy or
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   164
    in some revision that should be fixed and written back to the working copy
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   165
    or into a replacement revision.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   166
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   167
    workqueue = []
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   168
    numitems = collections.defaultdict(int)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   169
    maxfilesize = ui.configbytes('fix', 'maxfilesize')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   170
    for rev in revstofix:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   171
        fixctx = repo[rev]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   172
        match = scmutil.match(fixctx, pats, opts)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   173
        for path in pathstofix(ui, repo, pats, opts, match, basectxs[rev],
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   174
                               fixctx):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   175
            if path not in fixctx:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   176
                continue
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   177
            fctx = fixctx[path]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   178
            if fctx.islink():
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   179
                continue
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   180
            if fctx.size() > maxfilesize:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   181
                ui.warn(_('ignoring file larger than %s: %s\n') %
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   182
                        (util.bytecount(maxfilesize), path))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   183
                continue
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   184
            workqueue.append((rev, path))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   185
            numitems[rev] += 1
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   186
    return workqueue, numitems
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   187
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   188
def getrevstofix(ui, repo, opts):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   189
    """Returns the set of revision numbers that should be fixed"""
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   190
    revs = set(scmutil.revrange(repo, opts['rev']))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   191
    for rev in revs:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   192
        checkfixablectx(ui, repo, repo[rev])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   193
    if revs:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   194
        cmdutil.checkunfinished(repo)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   195
        checknodescendants(repo, revs)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   196
    if opts.get('working_dir'):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   197
        revs.add(wdirrev)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   198
        if list(merge.mergestate.read(repo).unresolved()):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   199
            raise error.Abort('unresolved conflicts', hint="use 'hg resolve'")
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   200
    if not revs:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   201
        raise error.Abort(
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   202
            'no changesets specified', hint='use --rev or --working-dir')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   203
    return revs
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   204
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   205
def checknodescendants(repo, revs):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   206
    if (not obsolete.isenabled(repo, obsolete.allowunstableopt) and
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   207
        repo.revs('(%ld::) - (%ld)', revs, revs)):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   208
        raise error.Abort(_('can only fix a changeset together '
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   209
                            'with all its descendants'))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   210
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   211
def checkfixablectx(ui, repo, ctx):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   212
    """Aborts if the revision shouldn't be replaced with a fixed one."""
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   213
    if not ctx.mutable():
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   214
        raise error.Abort('can\'t fix immutable changeset %s' %
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   215
                          (scmutil.formatchangeid(ctx),))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   216
    if ctx.obsolete():
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   217
        # It would be better to actually check if the revision has a successor.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   218
        allowdivergence = ui.configbool('experimental',
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   219
                                        'evolution.allowdivergence')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   220
        if not allowdivergence:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   221
            raise error.Abort('fixing obsolete revision could cause divergence')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   222
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   223
def pathstofix(ui, repo, pats, opts, match, basectxs, fixctx):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   224
    """Returns the set of files that should be fixed in a context
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   225
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   226
    The result depends on the base contexts; we include any file that has
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   227
    changed relative to any of the base contexts. Base contexts should be
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   228
    ancestors of the context being fixed.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   229
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   230
    files = set()
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   231
    for basectx in basectxs:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   232
        stat = repo.status(
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   233
            basectx, fixctx, match=match, clean=bool(pats), unknown=bool(pats))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   234
        files.update(
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   235
            set(itertools.chain(stat.added, stat.modified, stat.clean,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   236
                                stat.unknown)))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   237
    return files
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   238
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   239
def lineranges(opts, path, basectxs, fixctx, content2):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   240
    """Returns the set of line ranges that should be fixed in a file
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   241
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   242
    Of the form [(10, 20), (30, 40)].
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   243
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   244
    This depends on the given base contexts; we must consider lines that have
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   245
    changed versus any of the base contexts, and whether the file has been
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   246
    renamed versus any of them.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   247
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   248
    Another way to understand this is that we exclude line ranges that are
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   249
    common to the file in all base contexts.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   250
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   251
    if opts.get('whole'):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   252
        # Return a range containing all lines. Rely on the diff implementation's
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   253
        # idea of how many lines are in the file, instead of reimplementing it.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   254
        return difflineranges('', content2)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   255
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   256
    rangeslist = []
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   257
    for basectx in basectxs:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   258
        basepath = copies.pathcopies(basectx, fixctx).get(path, path)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   259
        if basepath in basectx:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   260
            content1 = basectx[basepath].data()
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   261
        else:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   262
            content1 = ''
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   263
        rangeslist.extend(difflineranges(content1, content2))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   264
    return unionranges(rangeslist)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   265
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   266
def unionranges(rangeslist):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   267
    """Return the union of some closed intervals
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   268
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   269
    >>> unionranges([])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   270
    []
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   271
    >>> unionranges([(1, 100)])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   272
    [(1, 100)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   273
    >>> unionranges([(1, 100), (1, 100)])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   274
    [(1, 100)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   275
    >>> unionranges([(1, 100), (2, 100)])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   276
    [(1, 100)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   277
    >>> unionranges([(1, 99), (1, 100)])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   278
    [(1, 100)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   279
    >>> unionranges([(1, 100), (40, 60)])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   280
    [(1, 100)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   281
    >>> unionranges([(1, 49), (50, 100)])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   282
    [(1, 100)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   283
    >>> unionranges([(1, 48), (50, 100)])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   284
    [(1, 48), (50, 100)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   285
    >>> unionranges([(1, 2), (3, 4), (5, 6)])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   286
    [(1, 6)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   287
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   288
    rangeslist = sorted(set(rangeslist))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   289
    unioned = []
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   290
    if rangeslist:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   291
        unioned, rangeslist = [rangeslist[0]], rangeslist[1:]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   292
    for a, b in rangeslist:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   293
        c, d = unioned[-1]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   294
        if a > d + 1:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   295
            unioned.append((a, b))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   296
        else:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   297
            unioned[-1] = (c, max(b, d))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   298
    return unioned
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   299
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   300
def difflineranges(content1, content2):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   301
    """Return list of line number ranges in content2 that differ from content1.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   302
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   303
    Line numbers are 1-based. The numbers are the first and last line contained
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   304
    in the range. Single-line ranges have the same line number for the first and
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   305
    last line. Excludes any empty ranges that result from lines that are only
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   306
    present in content1. Relies on mdiff's idea of where the line endings are in
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   307
    the string.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   308
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   309
    >>> lines = lambda s: '\\n'.join([c for c in s])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   310
    >>> difflineranges2 = lambda a, b: difflineranges(lines(a), lines(b))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   311
    >>> difflineranges2('', '')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   312
    []
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   313
    >>> difflineranges2('a', '')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   314
    []
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   315
    >>> difflineranges2('', 'A')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   316
    [(1, 1)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   317
    >>> difflineranges2('a', 'a')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   318
    []
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   319
    >>> difflineranges2('a', 'A')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   320
    [(1, 1)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   321
    >>> difflineranges2('ab', '')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   322
    []
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   323
    >>> difflineranges2('', 'AB')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   324
    [(1, 2)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   325
    >>> difflineranges2('abc', 'ac')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   326
    []
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   327
    >>> difflineranges2('ab', 'aCb')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   328
    [(2, 2)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   329
    >>> difflineranges2('abc', 'aBc')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   330
    [(2, 2)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   331
    >>> difflineranges2('ab', 'AB')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   332
    [(1, 2)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   333
    >>> difflineranges2('abcde', 'aBcDe')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   334
    [(2, 2), (4, 4)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   335
    >>> difflineranges2('abcde', 'aBCDe')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   336
    [(2, 4)]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   337
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   338
    ranges = []
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   339
    for lines, kind in mdiff.allblocks(content1, content2):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   340
        firstline, lastline = lines[2:4]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   341
        if kind == '!' and firstline != lastline:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   342
            ranges.append((firstline + 1, lastline))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   343
    return ranges
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   344
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   345
def getbasectxs(repo, opts, revstofix):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   346
    """Returns a map of the base contexts for each revision
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   347
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   348
    The base contexts determine which lines are considered modified when we
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   349
    attempt to fix just the modified lines in a file.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   350
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   351
    # The --base flag overrides the usual logic, and we give every revision
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   352
    # exactly the set of baserevs that the user specified.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   353
    if opts.get('base'):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   354
        baserevs = set(scmutil.revrange(repo, opts.get('base')))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   355
        if not baserevs:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   356
            baserevs = {nullrev}
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   357
        basectxs = {repo[rev] for rev in baserevs}
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   358
        return {rev: basectxs for rev in revstofix}
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   359
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   360
    # Proceed in topological order so that we can easily determine each
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   361
    # revision's baserevs by looking at its parents and their baserevs.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   362
    basectxs = collections.defaultdict(set)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   363
    for rev in sorted(revstofix):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   364
        ctx = repo[rev]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   365
        for pctx in ctx.parents():
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   366
            if pctx.rev() in basectxs:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   367
                basectxs[rev].update(basectxs[pctx.rev()])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   368
            else:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   369
                basectxs[rev].add(pctx)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   370
    return basectxs
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   371
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   372
def fixfile(ui, opts, fixers, fixctx, path, basectxs):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   373
    """Run any configured fixers that should affect the file in this context
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   374
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   375
    Returns the file content that results from applying the fixers in some order
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   376
    starting with the file's content in the fixctx. Fixers that support line
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   377
    ranges will affect lines that have changed relative to any of the basectxs
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   378
    (i.e. they will only avoid lines that are common to all basectxs).
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   379
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   380
    newdata = fixctx[path].data()
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   381
    for fixername, fixer in fixers.iteritems():
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   382
        if fixer.affects(opts, fixctx, path):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   383
            ranges = lineranges(opts, path, basectxs, fixctx, newdata)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   384
            command = fixer.command(path, ranges)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   385
            if command is None:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   386
                continue
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   387
            ui.debug('subprocess: %s\n' % (command,))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   388
            proc = subprocess.Popen(
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   389
                command,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   390
                shell=True,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   391
                cwd='/',
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   392
                stdin=subprocess.PIPE,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   393
                stdout=subprocess.PIPE,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   394
                stderr=subprocess.PIPE)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   395
            newerdata, stderr = proc.communicate(newdata)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   396
            if stderr:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   397
                showstderr(ui, fixctx.rev(), fixername, stderr)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   398
            else:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   399
                newdata = newerdata
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   400
    return newdata
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   401
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   402
def showstderr(ui, rev, fixername, stderr):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   403
    """Writes the lines of the stderr string as warnings on the ui
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   404
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   405
    Uses the revision number and fixername to give more context to each line of
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   406
    the error message. Doesn't include file names, since those take up a lot of
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   407
    space and would tend to be included in the error message if they were
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   408
    relevant.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   409
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   410
    for line in re.split('[\r\n]+', stderr):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   411
        if line:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   412
            ui.warn(('['))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   413
            if rev is None:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   414
                ui.warn(_('wdir'), label='evolve.rev')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   415
            else:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   416
                ui.warn((str(rev)), label='evolve.rev')
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   417
            ui.warn(('] %s: %s\n') % (fixername, line))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   418
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   419
def writeworkingdir(repo, ctx, filedata, replacements):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   420
    """Write new content to the working copy and check out the new p1 if any
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   421
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   422
    We check out a new revision if and only if we fixed something in both the
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   423
    working directory and its parent revision. This avoids the need for a full
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   424
    update/merge, and means that the working directory simply isn't affected
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   425
    unless the --working-dir flag is given.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   426
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   427
    Directly updates the dirstate for the affected files.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   428
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   429
    for path, data in filedata.iteritems():
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   430
        fctx = ctx[path]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   431
        fctx.write(data, fctx.flags())
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   432
        if repo.dirstate[path] == 'n':
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   433
            repo.dirstate.normallookup(path)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   434
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   435
    oldparentnodes = repo.dirstate.parents()
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   436
    newparentnodes = [replacements.get(n, n) for n in oldparentnodes]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   437
    if newparentnodes != oldparentnodes:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   438
        repo.setparents(*newparentnodes)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   439
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   440
def replacerev(ui, repo, ctx, filedata, replacements):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   441
    """Commit a new revision like the given one, but with file content changes
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   442
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   443
    "ctx" is the original revision to be replaced by a modified one.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   444
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   445
    "filedata" is a dict that maps paths to their new file content. All other
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   446
    paths will be recreated from the original revision without changes.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   447
    "filedata" may contain paths that didn't exist in the original revision;
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   448
    they will be added.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   449
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   450
    "replacements" is a dict that maps a single node to a single node, and it is
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   451
    updated to indicate the original revision is replaced by the newly created
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   452
    one. No entry is added if the replacement's node already exists.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   453
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   454
    The new revision has the same parents as the old one, unless those parents
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   455
    have already been replaced, in which case those replacements are the parents
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   456
    of this new revision. Thus, if revisions are replaced in topological order,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   457
    there is no need to rebase them into the original topology later.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   458
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   459
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   460
    p1rev, p2rev = repo.changelog.parentrevs(ctx.rev())
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   461
    p1ctx, p2ctx = repo[p1rev], repo[p2rev]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   462
    newp1node = replacements.get(p1ctx.node(), p1ctx.node())
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   463
    newp2node = replacements.get(p2ctx.node(), p2ctx.node())
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   464
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   465
    def filectxfn(repo, memctx, path):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   466
        if path not in ctx:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   467
            return None
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   468
        fctx = ctx[path]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   469
        copied = fctx.renamed()
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   470
        if copied:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   471
            copied = copied[0]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   472
        return context.memfilectx(
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   473
            repo,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   474
            memctx,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   475
            path=fctx.path(),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   476
            data=filedata.get(path, fctx.data()),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   477
            islink=fctx.islink(),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   478
            isexec=fctx.isexec(),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   479
            copied=copied)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   480
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   481
    overrides = {('phases', 'new-commit'): ctx.phase()}
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   482
    with ui.configoverride(overrides, source='fix'):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   483
        memctx = context.memctx(
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   484
            repo,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   485
            parents=(newp1node, newp2node),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   486
            text=ctx.description(),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   487
            files=set(ctx.files()) | set(filedata.keys()),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   488
            filectxfn=filectxfn,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   489
            user=ctx.user(),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   490
            date=ctx.date(),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   491
            extra=ctx.extra(),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   492
            branch=ctx.branch(),
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   493
            editor=None)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   494
        sucnode = memctx.commit()
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   495
        prenode = ctx.node()
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   496
        if prenode == sucnode:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   497
            ui.debug('node %s already existed\n' % (ctx.hex()))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   498
        else:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   499
            replacements[ctx.node()] = sucnode
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   500
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   501
def getfixers(ui):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   502
    """Returns a map of configured fixer tools indexed by their names
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   503
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   504
    Each value is a Fixer object with methods that implement the behavior of the
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   505
    fixer's config suboptions. Does not validate the config values.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   506
    """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   507
    result = {}
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   508
    for name in fixernames(ui):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   509
        result[name] = Fixer()
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   510
        attrs = ui.configsuboptions('fix', name)[1]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   511
        for key in FIXER_ATTRS:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   512
            setattr(result[name], '_' + key, attrs.get(key, ''))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   513
    return result
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   514
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   515
def fixernames(ui):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   516
    """Returns the names of [fix] config options that have suboptions"""
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   517
    names = set()
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   518
    for k, v in ui.configitems('fix'):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   519
        if ':' in k:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   520
            names.add(k.split(':', 1)[0])
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   521
    return names
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   522
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   523
class Fixer(object):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   524
    """Wraps the raw config values for a fixer with methods"""
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   525
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   526
    def affects(self, opts, fixctx, path):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   527
        """Should this fixer run on the file at the given path and context?"""
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   528
        return scmutil.match(fixctx, [self._fileset], opts)(path)
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   529
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   530
    def command(self, path, ranges):
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   531
        """A shell command to use to invoke this fixer on the given file/lines
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   532
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   533
        May return None if there is no appropriate command to run for the given
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   534
        parameters.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   535
        """
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   536
        parts = [self._command.format(rootpath=path,
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   537
                                      basename=os.path.basename(path))]
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   538
        if self._linerange:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   539
            if not ranges:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   540
                # No line ranges to fix, so don't run the fixer.
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   541
                return None
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   542
            for first, last in ranges:
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   543
                parts.append(self._linerange.format(first=first, last=last))
ded5ea279a93 fix: new extension for automatically modifying file contents
Danny Hooper <hooper@google.com>
parents:
diff changeset
   544
        return ' '.join(parts)