mercurial/subrepo.py
author Martin Geisler <mg@aragost.com>
Mon, 30 Aug 2010 17:11:51 +0200
branchstable
changeset 12133 b046b90c4ae5
parent 11571 636554d58665
child 11572 324bad1dc230
permissions -rw-r--r--
match: mark error messages for translation
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
8812
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     1
# subrepo.py - sub-repository handling for Mercurial
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     2
#
10324
55d134ef8ab7 subrepo: correct copyright
David Soria Parra <dsp@php.net>
parents: 10299
diff changeset
     3
# Copyright 2009-2010 Matt Mackall <mpm@selenic.com>
8812
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     4
#
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 10251
diff changeset
     6
# GNU General Public License version 2 or any later version.
8812
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     7
11109
a2bc2f2d77a9 subrepo: normalize path part of URLs so that pulling subrepos from webdir works
Edouard Gomez <ed.gomez@free.fr>
parents: 11078
diff changeset
     8
import errno, os, re, xml.dom.minidom, shutil, urlparse, posixpath
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
     9
from i18n import _
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
    10
import config, util, node, error
9092
9aebeea7ac00 subrepo: use hg.repository instead of creating localrepo directly
Abderrahim Kitouni <a.kitouni@gmail.com>
parents: 9049
diff changeset
    11
hg = None
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
    12
10177
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
    13
nullstate = ('', '', 'empty')
8812
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    14
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    15
def state(ctx):
11571
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
    16
    """return a state dict, mapping subrepo paths configured in .hgsub
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
    17
    to tuple: (source from .hgsub, revision from .hgsubstate, kind
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
    18
    (key in types dict))
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
    19
    """
8812
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    20
    p = config.config()
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    21
    def read(f, sections=None, remap=None):
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    22
        if f in ctx:
10174
65b6dc44cdbf subrepo: fix includes support in .hgsub
Matt Mackall <mpm@selenic.com>
parents: 10069
diff changeset
    23
            p.parse(f, ctx[f].data(), sections, remap, read)
65b6dc44cdbf subrepo: fix includes support in .hgsub
Matt Mackall <mpm@selenic.com>
parents: 10069
diff changeset
    24
        else:
65b6dc44cdbf subrepo: fix includes support in .hgsub
Matt Mackall <mpm@selenic.com>
parents: 10069
diff changeset
    25
            raise util.Abort(_("subrepo spec file %s not found") % f)
65b6dc44cdbf subrepo: fix includes support in .hgsub
Matt Mackall <mpm@selenic.com>
parents: 10069
diff changeset
    26
65b6dc44cdbf subrepo: fix includes support in .hgsub
Matt Mackall <mpm@selenic.com>
parents: 10069
diff changeset
    27
    if '.hgsub' in ctx:
65b6dc44cdbf subrepo: fix includes support in .hgsub
Matt Mackall <mpm@selenic.com>
parents: 10069
diff changeset
    28
        read('.hgsub')
8812
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    29
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    30
    rev = {}
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    31
    if '.hgsubstate' in ctx:
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    32
        try:
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    33
            for l in ctx['.hgsubstate'].data().splitlines():
9752
a22cdd5e56b7 subrepo: more robust split for .hgsubstate parsing
Matt Mackall <mpm@selenic.com>
parents: 9508
diff changeset
    34
                revision, path = l.split(" ", 1)
8812
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    35
                rev[path] = revision
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    36
        except IOError, err:
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    37
            if err.errno != errno.ENOENT:
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    38
                raise
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    39
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    40
    state = {}
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    41
    for path, src in p[''].items():
10177
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
    42
        kind = 'hg'
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
    43
        if src.startswith('['):
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
    44
            if ']' not in src:
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
    45
                raise util.Abort(_('missing ] in subrepo source'))
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
    46
            kind, src = src.split(']', 1)
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
    47
            kind = kind[1:]
10457
4f38d03d4975 subrepo: make sure that the source path is stripped
David Soria Parra <dsp@php.net>
parents: 10378
diff changeset
    48
        state[path] = (src.strip(), rev.get(path, ''), kind)
8812
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    49
859f841937d0 subrepo: introduce basic state parsing
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    50
    return state
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
    51
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
    52
def writestate(repo, state):
11571
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
    53
    """rewrite .hgsubstate in (outer) repo with these subrepo states"""
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
    54
    repo.wwrite('.hgsubstate',
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
    55
                ''.join(['%s %s\n' % (state[s][1], s)
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
    56
                         for s in sorted(state)]), '')
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
    57
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    58
def submerge(repo, wctx, mctx, actx):
11571
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
    59
    """delegated from merge.applyupdates: merging of .hgsubstate file
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
    60
    in working context, merging context and ancestor context"""
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    61
    if mctx == actx: # backwards?
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    62
        actx = wctx.p1()
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    63
    s1 = wctx.substate
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    64
    s2 = mctx.substate
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    65
    sa = actx.substate
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    66
    sm = {}
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    67
9782
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
    68
    repo.ui.debug("subrepo merge %s %s %s\n" % (wctx, mctx, actx))
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
    69
9779
58a6f3f4d553 subrepo: add some debug output to submerge
Matt Mackall <mpm@selenic.com>
parents: 9752
diff changeset
    70
    def debug(s, msg, r=""):
58a6f3f4d553 subrepo: add some debug output to submerge
Matt Mackall <mpm@selenic.com>
parents: 9752
diff changeset
    71
        if r:
10177
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
    72
            r = "%s:%s:%s" % r
9782
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
    73
        repo.ui.debug("  subrepo %s: %s %s\n" % (s, msg, r))
9779
58a6f3f4d553 subrepo: add some debug output to submerge
Matt Mackall <mpm@selenic.com>
parents: 9752
diff changeset
    74
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    75
    for s, l in s1.items():
11470
34e33d50c26b subrepo: correctly handle update -C with modified subrepos (issue2022)
Matt Mackall <mpm@selenic.com>
parents: 11463
diff changeset
    76
        a = sa.get(s, nullstate)
11463
f0ea93557133 subrepo: fix recording of + in .hgsubstate (issue2217)
Matt Mackall <mpm@selenic.com>
parents: 11455
diff changeset
    77
        ld = l # local state with possible dirty flag for compares
11470
34e33d50c26b subrepo: correctly handle update -C with modified subrepos (issue2022)
Matt Mackall <mpm@selenic.com>
parents: 11463
diff changeset
    78
        if wctx.sub(s).dirty():
11463
f0ea93557133 subrepo: fix recording of + in .hgsubstate (issue2217)
Matt Mackall <mpm@selenic.com>
parents: 11455
diff changeset
    79
            ld = (l[0], l[1] + "+")
11470
34e33d50c26b subrepo: correctly handle update -C with modified subrepos (issue2022)
Matt Mackall <mpm@selenic.com>
parents: 11463
diff changeset
    80
        if wctx == actx: # overwrite
34e33d50c26b subrepo: correctly handle update -C with modified subrepos (issue2022)
Matt Mackall <mpm@selenic.com>
parents: 11463
diff changeset
    81
            a = ld
11463
f0ea93557133 subrepo: fix recording of + in .hgsubstate (issue2217)
Matt Mackall <mpm@selenic.com>
parents: 11455
diff changeset
    82
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    83
        if s in s2:
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    84
            r = s2[s]
11463
f0ea93557133 subrepo: fix recording of + in .hgsubstate (issue2217)
Matt Mackall <mpm@selenic.com>
parents: 11455
diff changeset
    85
            if ld == r or r == a: # no change or local is newer
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    86
                sm[s] = l
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    87
                continue
11463
f0ea93557133 subrepo: fix recording of + in .hgsubstate (issue2217)
Matt Mackall <mpm@selenic.com>
parents: 11455
diff changeset
    88
            elif ld == a: # other side changed
9782
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
    89
                debug(s, "other changed, get", r)
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    90
                wctx.sub(s).get(r)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    91
                sm[s] = r
11463
f0ea93557133 subrepo: fix recording of + in .hgsubstate (issue2217)
Matt Mackall <mpm@selenic.com>
parents: 11455
diff changeset
    92
            elif ld[0] != r[0]: # sources differ
9048
86b4a9b0ddda ui: extract choice from prompt
Simon Heimberg <simohe@besonet.ch>
parents: 8997
diff changeset
    93
                if repo.ui.promptchoice(
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    94
                    _(' subrepository sources for %s differ\n'
8908
105343f9f744 Fix warning: Seen unexpected token "%"
Dongsheng Song <dongsheng.song@gmail.com>
parents: 8815
diff changeset
    95
                      'use (l)ocal source (%s) or (r)emote source (%s)?')
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    96
                      % (s, l[0], r[0]),
9048
86b4a9b0ddda ui: extract choice from prompt
Simon Heimberg <simohe@besonet.ch>
parents: 8997
diff changeset
    97
                      (_('&Local'), _('&Remote')), 0):
9782
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
    98
                    debug(s, "prompt changed, get", r)
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
    99
                    wctx.sub(s).get(r)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   100
                    sm[s] = r
11463
f0ea93557133 subrepo: fix recording of + in .hgsubstate (issue2217)
Matt Mackall <mpm@selenic.com>
parents: 11455
diff changeset
   101
            elif ld[1] == a[1]: # local side is unchanged
9782
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
   102
                debug(s, "other side changed, get", r)
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   103
                wctx.sub(s).get(r)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   104
                sm[s] = r
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   105
            else:
9782
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
   106
                debug(s, "both sides changed, merge with", r)
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   107
                wctx.sub(s).merge(r)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   108
                sm[s] = l
11463
f0ea93557133 subrepo: fix recording of + in .hgsubstate (issue2217)
Matt Mackall <mpm@selenic.com>
parents: 11455
diff changeset
   109
        elif ld == a: # remote removed, local unchanged
9782
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
   110
            debug(s, "remote removed, remove")
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   111
            wctx.sub(s).remove()
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   112
        else:
9048
86b4a9b0ddda ui: extract choice from prompt
Simon Heimberg <simohe@besonet.ch>
parents: 8997
diff changeset
   113
            if repo.ui.promptchoice(
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   114
                _(' local changed subrepository %s which remote removed\n'
8908
105343f9f744 Fix warning: Seen unexpected token "%"
Dongsheng Song <dongsheng.song@gmail.com>
parents: 8815
diff changeset
   115
                  'use (c)hanged version or (d)elete?') % s,
9049
38b5d5e0efab filemerge, subrepo: correct indention
Martin Geisler <mg@lazybytes.net>
parents: 9048
diff changeset
   116
                (_('&Changed'), _('&Delete')), 0):
9782
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
   117
                debug(s, "prompt remove")
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   118
                wctx.sub(s).remove()
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   119
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   120
    for s, r in s2.items():
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   121
        if s in s1:
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   122
            continue
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   123
        elif s not in sa:
9782
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
   124
            debug(s, "remote added, get", r)
10175
fc32b2fc468e subrepo: load from a context where the subrepo exists
Augie Fackler <durin42@gmail.com>
parents: 10174
diff changeset
   125
            mctx.sub(s).get(r)
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   126
            sm[s] = r
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   127
        elif r != sa[s]:
9048
86b4a9b0ddda ui: extract choice from prompt
Simon Heimberg <simohe@besonet.ch>
parents: 8997
diff changeset
   128
            if repo.ui.promptchoice(
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   129
                _(' remote changed subrepository %s which local removed\n'
8908
105343f9f744 Fix warning: Seen unexpected token "%"
Dongsheng Song <dongsheng.song@gmail.com>
parents: 8815
diff changeset
   130
                  'use (c)hanged version or (d)elete?') % s,
9049
38b5d5e0efab filemerge, subrepo: correct indention
Martin Geisler <mg@lazybytes.net>
parents: 9048
diff changeset
   131
                (_('&Changed'), _('&Delete')), 0) == 0:
9782
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
   132
                debug(s, "prompt recreate", r)
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   133
                wctx.sub(s).get(r)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   134
                sm[s] = r
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   135
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   136
    # record merged .hgsubstate
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   137
    writestate(repo, sm)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   138
11112
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   139
def relpath(sub):
11571
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
   140
    """return path to this subrepo as seen from outermost repo"""
11112
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   141
    if not hasattr(sub, '_repo'):
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   142
        return sub._path
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   143
    parent = sub._repo
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   144
    while hasattr(parent, '_subparent'):
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   145
        parent = parent._subparent
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   146
    return sub._repo.root[len(parent.root)+1:]
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   147
8815
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   148
def _abssource(repo, push=False):
11571
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
   149
    """return pull/push path of repo - either based on parent repo
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
   150
    .hgsub info or on the subrepos own config"""
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   151
    if hasattr(repo, '_subparent'):
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   152
        source = repo._subsource
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   153
        if source.startswith('/') or '://' in source:
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   154
            return source
10665
664bb0ce95ed subrepo: forward the push to argument into _abssource
Edouard Gomez <ed.gomez@free.fr>
parents: 10510
diff changeset
   155
        parent = _abssource(repo._subparent, push)
9186
f783bb979fb3 subrepo: use '/' for joining non-local paths
Matt Mackall <mpm@selenic.com>
parents: 8997
diff changeset
   156
        if '://' in parent:
f783bb979fb3 subrepo: use '/' for joining non-local paths
Matt Mackall <mpm@selenic.com>
parents: 8997
diff changeset
   157
            if parent[-1] == '/':
f783bb979fb3 subrepo: use '/' for joining non-local paths
Matt Mackall <mpm@selenic.com>
parents: 8997
diff changeset
   158
                parent = parent[:-1]
11109
a2bc2f2d77a9 subrepo: normalize path part of URLs so that pulling subrepos from webdir works
Edouard Gomez <ed.gomez@free.fr>
parents: 11078
diff changeset
   159
            r = urlparse.urlparse(parent + '/' + source)
a2bc2f2d77a9 subrepo: normalize path part of URLs so that pulling subrepos from webdir works
Edouard Gomez <ed.gomez@free.fr>
parents: 11078
diff changeset
   160
            r = urlparse.urlunparse((r[0], r[1],
11117
dd543e8da87e subrepo: fix 2.5ism in url parsing
Matt Mackall <mpm@selenic.com>
parents: 11112
diff changeset
   161
                                     posixpath.normpath(r[2]),
11109
a2bc2f2d77a9 subrepo: normalize path part of URLs so that pulling subrepos from webdir works
Edouard Gomez <ed.gomez@free.fr>
parents: 11078
diff changeset
   162
                                     r[3], r[4], r[5]))
a2bc2f2d77a9 subrepo: normalize path part of URLs so that pulling subrepos from webdir works
Edouard Gomez <ed.gomez@free.fr>
parents: 11078
diff changeset
   163
            return r
a2bc2f2d77a9 subrepo: normalize path part of URLs so that pulling subrepos from webdir works
Edouard Gomez <ed.gomez@free.fr>
parents: 11078
diff changeset
   164
        return posixpath.normpath(os.path.join(parent, repo._subsource))
8815
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   165
    if push and repo.ui.config('paths', 'default-push'):
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   166
        return repo.ui.config('paths', 'default-push', repo.root)
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   167
    return repo.ui.config('paths', 'default', repo.root)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   168
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   169
def subrepo(ctx, path):
11571
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
   170
    """return instance of the right subrepo class for subrepo in path"""
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   171
    # subrepo inherently violates our import layering rules
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   172
    # because it wants to make repo objects from deep inside the stack
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   173
    # so we manually delay the circular imports to not break
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   174
    # scripts that don't use our demand-loading
9092
9aebeea7ac00 subrepo: use hg.repository instead of creating localrepo directly
Abderrahim Kitouni <a.kitouni@gmail.com>
parents: 9049
diff changeset
   175
    global hg
9aebeea7ac00 subrepo: use hg.repository instead of creating localrepo directly
Abderrahim Kitouni <a.kitouni@gmail.com>
parents: 9049
diff changeset
   176
    import hg as h
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   177
    hg = h
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   178
8997
70f5d3be5917 subrepo: audit subrepo paths
Matt Mackall <mpm@selenic.com>
parents: 8908
diff changeset
   179
    util.path_auditor(ctx._repo.root)(path)
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   180
    state = ctx.substate.get(path, nullstate)
10177
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
   181
    if state[2] not in types:
10299
e768941f14c1 subrepo: fix errors reported by pylint
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10273
diff changeset
   182
        raise util.Abort(_('unknown subrepo type %s') % state[2])
10177
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
   183
    return types[state[2]](ctx, path, state[:2])
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   184
10027
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   185
# subrepo classes need to implement the following methods:
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   186
# __init__(self, ctx, path, state)
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   187
# dirty(self): returns true if the dirstate of the subrepo
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   188
#   does not match current stored state
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   189
# commit(self, text, user, date): commit the current changes
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   190
#   to the subrepo with the given log message. Use given
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   191
#   user and date if possible. Return the new state of the subrepo.
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   192
# remove(self): remove the subrepo (should verify the dirstate
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   193
#   is not dirty first)
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   194
# get(self, state): run whatever commands are needed to put the
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   195
#   subrepo into this state
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   196
# merge(self, state): merge currently-saved state with the new state.
11571
636554d58665 subrepo: docstrings
Mads Kiilerich <mads@kiilerich.com>
parents: 11470
diff changeset
   197
# push(self, force): perform whatever action is analogous to 'hg push'
10027
30d51a0df46c subrepo: document necessary methods for a subrepo class
Augie Fackler <durin42@gmail.com>
parents: 9783
diff changeset
   198
#   This may be a no-op on some systems.
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   199
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   200
class hgsubrepo(object):
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   201
    def __init__(self, ctx, path, state):
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   202
        self._path = path
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   203
        self._state = state
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   204
        r = ctx._repo
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   205
        root = r.wjoin(path)
10666
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   206
        create = False
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   207
        if not os.path.exists(os.path.join(root, '.hg')):
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   208
            create = True
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   209
            util.makedirs(root)
10666
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   210
        self._repo = hg.repository(r.ui, root, create=create)
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   211
        self._repo._subparent = r
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   212
        self._repo._subsource = state[0]
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   213
10666
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   214
        if create:
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   215
            fp = self._repo.opener("hgrc", "w", text=True)
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   216
            fp.write('[paths]\n')
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   217
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   218
            def addpathconfig(key, value):
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   219
                fp.write('%s = %s\n' % (key, value))
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   220
                self._repo.ui.setconfig('paths', key, value)
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   221
10697
c90d923fff64 subrepo: fix hgrc paths section during subrepo pulling
Edouard Gomez <ed.gomez@free.fr>
parents: 10666
diff changeset
   222
            defpath = _abssource(self._repo)
c90d923fff64 subrepo: fix hgrc paths section during subrepo pulling
Edouard Gomez <ed.gomez@free.fr>
parents: 10666
diff changeset
   223
            defpushpath = _abssource(self._repo, True)
10666
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   224
            addpathconfig('default', defpath)
10697
c90d923fff64 subrepo: fix hgrc paths section during subrepo pulling
Edouard Gomez <ed.gomez@free.fr>
parents: 10666
diff changeset
   225
            if defpath != defpushpath:
c90d923fff64 subrepo: fix hgrc paths section during subrepo pulling
Edouard Gomez <ed.gomez@free.fr>
parents: 10666
diff changeset
   226
                addpathconfig('default-push', defpushpath)
10666
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   227
            fp.close()
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   228
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   229
    def dirty(self):
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   230
        r = self._state[1]
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   231
        if r == '':
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   232
            return True
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   233
        w = self._repo[None]
10666
4c50a90b90fc subrepo: keep ui and hgrc in sync when creating new repo
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10665
diff changeset
   234
        if w.p1() != self._repo[r]: # version checked out change
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   235
            return True
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   236
        return w.dirty() # working directory changed
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   237
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   238
    def commit(self, text, user, date):
11112
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   239
        self._repo.ui.debug("committing subrepo %s\n" % relpath(self))
8813
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   240
        n = self._repo.commit(text, user, date)
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   241
        if not n:
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   242
            return self._repo['.'].hex() # different version checked out
db3c1ab0e632 commit: recurse into subrepositories
Matt Mackall <mpm@selenic.com>
parents: 8812
diff changeset
   243
        return node.hex(n)
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   244
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   245
    def remove(self):
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   246
        # we can't fully delete the repository as it may contain
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   247
        # local-only history
11112
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   248
        self._repo.ui.note(_('removing subrepo %s\n') % relpath(self))
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   249
        hg.clean(self._repo, node.nullid, False)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   250
9507
5987183d6e59 subrepo: add auto-pull for merge
Matt Mackall <mpm@selenic.com>
parents: 9186
diff changeset
   251
    def _get(self, state):
10177
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
   252
        source, revision, kind = state
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   253
        try:
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   254
            self._repo.lookup(revision)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   255
        except error.RepoError:
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   256
            self._repo._subsource = source
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   257
            srcurl = _abssource(self._repo)
10671
001ffc2b3d22 subrepo: wrap long line
Martin Geisler <mg@lazybytes.net>
parents: 10670
diff changeset
   258
            self._repo.ui.status(_('pulling subrepo %s from %s\n')
11112
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   259
                                 % (relpath(self), srcurl))
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   260
            other = hg.repository(self._repo.ui, srcurl)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   261
            self._repo.pull(other)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   262
9507
5987183d6e59 subrepo: add auto-pull for merge
Matt Mackall <mpm@selenic.com>
parents: 9186
diff changeset
   263
    def get(self, state):
5987183d6e59 subrepo: add auto-pull for merge
Matt Mackall <mpm@selenic.com>
parents: 9186
diff changeset
   264
        self._get(state)
10177
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
   265
        source, revision, kind = state
9782
c1c40511c276 subrepo: add more debugging output, lose _ markers
Matt Mackall <mpm@selenic.com>
parents: 9781
diff changeset
   266
        self._repo.ui.debug("getting subrepo %s\n" % self._path)
8814
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   267
        hg.clean(self._repo, revision, False)
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   268
ab668c92a036 subrepo: add update/merge logic
Matt Mackall <mpm@selenic.com>
parents: 8813
diff changeset
   269
    def merge(self, state):
9507
5987183d6e59 subrepo: add auto-pull for merge
Matt Mackall <mpm@selenic.com>
parents: 9186
diff changeset
   270
        self._get(state)
9781
eccc8aacd6f9 subrepo: do a linear update when appropriate
Matt Mackall <mpm@selenic.com>
parents: 9780
diff changeset
   271
        cur = self._repo['.']
eccc8aacd6f9 subrepo: do a linear update when appropriate
Matt Mackall <mpm@selenic.com>
parents: 9780
diff changeset
   272
        dst = self._repo[state[1]]
10251
a19d2993385d subrepo: fix merging of already merged subrepos (issue1986)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10068
diff changeset
   273
        anc = dst.ancestor(cur)
a19d2993385d subrepo: fix merging of already merged subrepos (issue1986)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10068
diff changeset
   274
        if anc == cur:
11112
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   275
            self._repo.ui.debug("updating subrepo %s\n" % relpath(self))
9781
eccc8aacd6f9 subrepo: do a linear update when appropriate
Matt Mackall <mpm@selenic.com>
parents: 9780
diff changeset
   276
            hg.update(self._repo, state[1])
10251
a19d2993385d subrepo: fix merging of already merged subrepos (issue1986)
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10068
diff changeset
   277
        elif anc == dst:
11112
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   278
            self._repo.ui.debug("skipping subrepo %s\n" % relpath(self))
9781
eccc8aacd6f9 subrepo: do a linear update when appropriate
Matt Mackall <mpm@selenic.com>
parents: 9780
diff changeset
   279
        else:
11112
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   280
            self._repo.ui.debug("merging subrepo %s\n" % relpath(self))
9781
eccc8aacd6f9 subrepo: do a linear update when appropriate
Matt Mackall <mpm@selenic.com>
parents: 9780
diff changeset
   281
            hg.merge(self._repo, state[1], remind=False)
8815
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   282
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   283
    def push(self, force):
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   284
        # push subrepos depth-first for coherent ordering
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   285
        c = self._repo['']
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   286
        subs = c.substate # only repos that are committed
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   287
        for s in sorted(subs):
11067
49e14ec67144 subrepo: propagate and catch push failures
Matt Mackall <mpm@selenic.com>
parents: 10954
diff changeset
   288
            if not c.sub(s).push(force):
49e14ec67144 subrepo: propagate and catch push failures
Matt Mackall <mpm@selenic.com>
parents: 10954
diff changeset
   289
                return False
8815
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   290
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   291
        dsturl = _abssource(self._repo, True)
11111
d2da9e6dd13e subrepo: print pushing url
Edouard Gomez <ed.gomez@free.fr>
parents: 11109
diff changeset
   292
        self._repo.ui.status(_('pushing subrepo %s to %s\n') %
11112
4a9bee613737 subrepo: print paths relative to upper repo root for push/pull/commit
Edouard Gomez <ed.gomez@free.fr>
parents: 11111
diff changeset
   293
            (relpath(self), dsturl))
8815
e87b0fc4750b subrepo: basic push support
Matt Mackall <mpm@selenic.com>
parents: 8814
diff changeset
   294
        other = hg.repository(self._repo.ui, dsturl)
11067
49e14ec67144 subrepo: propagate and catch push failures
Matt Mackall <mpm@selenic.com>
parents: 10954
diff changeset
   295
        return self._repo.push(other, force)
10177
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
   296
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   297
class svnsubrepo(object):
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   298
    def __init__(self, ctx, path, state):
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   299
        self._path = path
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   300
        self._state = state
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   301
        self._ctx = ctx
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   302
        self._ui = ctx._repo.ui
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   303
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   304
    def _svncommand(self, commands):
10954
33119d0252c1 subrepo: fix repo root path handling in svn subrepo
Brett Cannon <brett@python.org>
parents: 10697
diff changeset
   305
        path = os.path.join(self._ctx._repo.origroot, self._path)
33119d0252c1 subrepo: fix repo root path handling in svn subrepo
Brett Cannon <brett@python.org>
parents: 10697
diff changeset
   306
        cmd = ['svn'] + commands + [path]
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   307
        cmd = [util.shellquote(arg) for arg in cmd]
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   308
        cmd = util.quotecommand(' '.join(cmd))
10199
c2e2a5e6c36b subrepo: force en_US.UTF-8 locale when calling svn
Patrick Mezard <pmezard@gmail.com>
parents: 10197
diff changeset
   309
        env = dict(os.environ)
10271
9b38bec5dc29 subrepo: make svn use C locale for portability
Patrick Mezard <pmezard@gmail.com>
parents: 10264
diff changeset
   310
        # Avoid localized output, preserve current locale for everything else.
9b38bec5dc29 subrepo: make svn use C locale for portability
Patrick Mezard <pmezard@gmail.com>
parents: 10264
diff changeset
   311
        env['LC_MESSAGES'] = 'C'
10199
c2e2a5e6c36b subrepo: force en_US.UTF-8 locale when calling svn
Patrick Mezard <pmezard@gmail.com>
parents: 10197
diff changeset
   312
        write, read, err = util.popen3(cmd, env=env, newlines=True)
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   313
        retdata = read.read()
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   314
        err = err.read().strip()
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   315
        if err:
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   316
            raise util.Abort(err)
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   317
        return retdata
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   318
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   319
    def _wcrev(self):
10272
886858b834da subrepo: svn xml output is much easier to parse
Patrick Mezard <pmezard@gmail.com>
parents: 10271
diff changeset
   320
        output = self._svncommand(['info', '--xml'])
886858b834da subrepo: svn xml output is much easier to parse
Patrick Mezard <pmezard@gmail.com>
parents: 10271
diff changeset
   321
        doc = xml.dom.minidom.parseString(output)
886858b834da subrepo: svn xml output is much easier to parse
Patrick Mezard <pmezard@gmail.com>
parents: 10271
diff changeset
   322
        entries = doc.getElementsByTagName('entry')
886858b834da subrepo: svn xml output is much easier to parse
Patrick Mezard <pmezard@gmail.com>
parents: 10271
diff changeset
   323
        if not entries:
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   324
            return 0
10272
886858b834da subrepo: svn xml output is much easier to parse
Patrick Mezard <pmezard@gmail.com>
parents: 10271
diff changeset
   325
        return int(entries[0].getAttribute('revision') or 0)
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   326
10273
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   327
    def _wcchanged(self):
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   328
        """Return (changes, extchanges) where changes is True
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   329
        if the working directory was changed, and extchanges is
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   330
        True if any of these changes concern an external entry.
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   331
        """
10272
886858b834da subrepo: svn xml output is much easier to parse
Patrick Mezard <pmezard@gmail.com>
parents: 10271
diff changeset
   332
        output = self._svncommand(['status', '--xml'])
10273
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   333
        externals, changes = [], []
10272
886858b834da subrepo: svn xml output is much easier to parse
Patrick Mezard <pmezard@gmail.com>
parents: 10271
diff changeset
   334
        doc = xml.dom.minidom.parseString(output)
10273
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   335
        for e in doc.getElementsByTagName('entry'):
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   336
            s = e.getElementsByTagName('wc-status')
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   337
            if not s:
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   338
                continue
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   339
            item = s[0].getAttribute('item')
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   340
            props = s[0].getAttribute('props')
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   341
            path = e.getAttribute('path')
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   342
            if item == 'external':
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   343
                externals.append(path)
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   344
            if (item not in ('', 'normal', 'unversioned', 'external')
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   345
                or props not in ('', 'none')):
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   346
                changes.append(path)
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   347
        for path in changes:
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   348
            for ext in externals:
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   349
                if path == ext or path.startswith(ext + os.sep):
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   350
                    return True, True
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   351
        return bool(changes), False
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   352
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   353
    def dirty(self):
10273
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   354
        if self._wcrev() == self._state[1] and not self._wcchanged()[0]:
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   355
            return False
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   356
        return True
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   357
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   358
    def commit(self, text, user, date):
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   359
        # user and date are out of our hands since svn is centralized
10273
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   360
        changed, extchanged = self._wcchanged()
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   361
        if not changed:
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   362
            return self._wcrev()
10273
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   363
        if extchanged:
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   364
            # Do not try to commit externals
e898bc7810ad subrepo: handle svn externals and meta changes (issue1982)
Patrick Mezard <pmezard@gmail.com>
parents: 10272
diff changeset
   365
            raise util.Abort(_('cannot commit svn externals'))
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   366
        commitinfo = self._svncommand(['commit', '-m', text])
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   367
        self._ui.status(commitinfo)
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   368
        newrev = re.search('Committed revision ([\d]+).', commitinfo)
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   369
        if not newrev:
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   370
            raise util.Abort(commitinfo.splitlines()[-1])
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   371
        newrev = newrev.groups()[0]
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   372
        self._ui.status(self._svncommand(['update', '-r', newrev]))
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   373
        return newrev
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   374
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   375
    def remove(self):
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   376
        if self.dirty():
10299
e768941f14c1 subrepo: fix errors reported by pylint
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10273
diff changeset
   377
            self._ui.warn(_('not removing repo %s because '
e768941f14c1 subrepo: fix errors reported by pylint
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10273
diff changeset
   378
                            'it has changes.\n' % self._path))
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   379
            return
10510
f77f3383c666 i18n: mark more strings for translation
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 10457
diff changeset
   380
        self._ui.note(_('removing subrepo %s\n') % self._path)
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   381
        shutil.rmtree(self._ctx.repo.join(self._path))
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   382
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   383
    def get(self, state):
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   384
        status = self._svncommand(['checkout', state[0], '--revision', state[1]])
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   385
        if not re.search('Checked out revision [\d]+.', status):
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   386
            raise util.Abort(status.splitlines()[-1])
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   387
        self._ui.status(status)
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   388
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   389
    def merge(self, state):
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   390
        old = int(self._state[1])
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   391
        new = int(state[1])
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   392
        if new > old:
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   393
            self.get(state)
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   394
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   395
    def push(self, force):
11455
3827728b54e2 subrepo: fix silent push failure for SVN (issue2241)
Matt Mackall <mpm@selenic.com>
parents: 11117
diff changeset
   396
        # push is a no-op for SVN
3827728b54e2 subrepo: fix silent push failure for SVN (issue2241)
Matt Mackall <mpm@selenic.com>
parents: 11117
diff changeset
   397
        return True
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   398
10177
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
   399
types = {
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
   400
    'hg': hgsubrepo,
10178
cd477be6f2fc subrepo: Subversion support
Augie Fackler <durin42@gmail.com>
parents: 10177
diff changeset
   401
    'svn': svnsubrepo,
10177
5ca0d220ae21 subrepo: add table-based dispatch for subrepo types
Augie Fackler <durin42@gmail.com>
parents: 10175
diff changeset
   402
    }