aboutsummaryrefslogtreecommitdiffstats
path: root/setuptools/svn_utils.py
blob: 657393e2e54b3be1e817613eaafaf942a1493221 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import os
import re
import sys
import codecs
from distutils import log
from xml.sax.saxutils import unescape
import xml.dom.pulldom

#requires python >= 2.4
from subprocess import Popen as _Popen, PIPE as _PIPE

#NOTE: Use of the command line options
#      require SVN 1.3 or newer (December 2005)
#      and SVN 1.3 hsan't been supported by the
#      developers since mid 2008.

#subprocess is called several times with shell=(sys.platform=='win32')
#see the follow for more information:
#       http://bugs.python.org/issue8557
#       http://stackoverflow.com/questions/5658622/
#              python-subprocess-popen-environment-path
def _run_command(args, stdout=_PIPE, stderr=_PIPE):
        #regarding the shell argument, see: http://bugs.python.org/issue8557
        proc = _Popen(args, stdout=stdout, stderr=stderr,
                      shell=(sys.platform=='win32'))

        data = proc.communicate()[0]
        #TODO: this is probably NOT always utf-8
        try:
            data = unicode(data, encoding='utf-8')
        except NameError:
            data = str(data, encoding='utf-8')

        return proc.returncode, data

#svnversion return values (previous implementations return max revision)
#   4123:4168     mixed revision working copy
#   4168M         modified working copy
#   4123S         switched working copy
#   4123:4168MS   mixed revision, modified, switched working copy
_SVN_VER_RE = re.compile(r'(?:(\d+):)?(\d+)([a-z]*)\s*$', re.I)

def parse_revision(path):
    code, data = _run_command(['svnversion', path])

    if code:
        log.warn("svnversion failed")
        return []

    parsed = _SVN_VER_RE.match(data)
    if parsed:
        try:
            #No max needed this command summarizes working copy since 1.0
            return int(parsed.group(2))
        except ValueError:
            #This should only happen if the revision is WAY too big.
            pass
    return 0


def parse_dir_entries(path):
    code, data = _run_command(['svn', 'info',
                            '--depth', 'immediates', '--xml', path])

    if code:
        log.warn("svn info failed")
        return []

    doc = xml.dom.pulldom.parseString(data)
    entries = list()
    for event, node in doc:
        if event=='START_ELEMENT' and node.nodeName=='entry':
            doc.expandNode(node)
            entries.append(node)

    if entries:
        return [
            _get_entry_name(element)
            for element in entries[1:]
            if _get_entry_schedule(element).lower() != 'deleted'
            ]
    else:
        return []

def _get_entry_name(entry):
    return entry.getAttribute('path')

def _get_entry_schedule(entry):
    schedule = entry.getElementsByTagName('schedule')[0]
    return "".join([t.nodeValue for t in schedule.childNodes
                                if t.nodeType == t.TEXT_NODE])

#--xml wasn't supported until 1.5.x
#-R without --xml parses a bit funny
def parse_externals(path):
    try:
        code, lines = _run_command(['svn',
                                 'propget', 'svn:externals', path])

        if code:
            log.warn("svn propget failed")
            return []

        lines = [line for line in lines.splitlines() if line]
    except ValueError:
        lines = []

    externals = []
    for line in lines:
        line = line.split()
        if not line:
            continue

        #TODO: urlparse?
        if "://" in line[-1] or ":\\\\" in line[-1]:
            externals.append(line[0])
        else:
            externals.append(line[-1])

    return externals

def get_svn_tool_version():
    _, data = _run_command(['svn', '--version', '--quiet'])
    if data:
        return data.strip()
    else:
        return ''