Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 1 | """RCS interface module. |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 2 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 3 | Defines the class RCS, which represents a directory with rcs version |
| 4 | files and (possibly) corresponding work files. |
| 5 | |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 6 | """ |
| 7 | |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 8 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 9 | import fnmatch |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 10 | import os |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 11 | import re |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 12 | import string |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 13 | import tempfile |
| 14 | |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 15 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 16 | class RCS: |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 17 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 18 | """RCS interface class (local filesystem version). |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 19 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 20 | An instance of this class represents a directory with rcs version |
| 21 | files and (possible) corresponding work files. |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 22 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 23 | Methods provide access to most rcs operations such as |
| 24 | checkin/checkout, access to the rcs metadata (revisions, logs, |
| 25 | branches etc.) as well as some filesystem operations such as |
| 26 | listing all rcs version files. |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 27 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 28 | XXX BUGS / PROBLEMS |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 29 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 30 | - The instance always represents the current directory so it's not |
| 31 | very useful to have more than one instance around simultaneously |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 32 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 33 | """ |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 34 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 35 | # Characters allowed in work file names |
Fred Drake | 79e75e1 | 2001-07-20 19:05:50 +0000 | [diff] [blame] | 36 | okchars = string.ascii_letters + string.digits + '-_=+' |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 37 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 38 | def __init__(self): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 39 | """Constructor.""" |
| 40 | pass |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 41 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 42 | def __del__(self): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 43 | """Destructor.""" |
| 44 | pass |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 45 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 46 | # --- Informational methods about a single file/revision --- |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 47 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 48 | def log(self, name_rev, otherflags = ''): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 49 | """Return the full log text for NAME_REV as a string. |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 50 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 51 | Optional OTHERFLAGS are passed to rlog. |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 52 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 53 | """ |
| 54 | f = self._open(name_rev, 'rlog ' + otherflags) |
| 55 | data = f.read() |
| 56 | status = self._closepipe(f) |
| 57 | if status: |
| 58 | data = data + "%s: %s" % status |
| 59 | elif data[-1] == '\n': |
| 60 | data = data[:-1] |
| 61 | return data |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 62 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 63 | def head(self, name_rev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 64 | """Return the head revision for NAME_REV""" |
| 65 | dict = self.info(name_rev) |
| 66 | return dict['head'] |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 67 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 68 | def info(self, name_rev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 69 | """Return a dictionary of info (from rlog -h) for NAME_REV |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 70 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 71 | The dictionary's keys are the keywords that rlog prints |
| 72 | (e.g. 'head' and its values are the corresponding data |
| 73 | (e.g. '1.3'). |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 74 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 75 | XXX symbolic names and locks are not returned |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 76 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 77 | """ |
| 78 | f = self._open(name_rev, 'rlog -h') |
| 79 | dict = {} |
| 80 | while 1: |
| 81 | line = f.readline() |
| 82 | if not line: break |
| 83 | if line[0] == '\t': |
| 84 | # XXX could be a lock or symbolic name |
| 85 | # Anything else? |
Tim Peters | e6ddc8b | 2004-07-18 05:56:09 +0000 | [diff] [blame] | 86 | continue |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 87 | i = string.find(line, ':') |
| 88 | if i > 0: |
| 89 | key, value = line[:i], string.strip(line[i+1:]) |
| 90 | dict[key] = value |
| 91 | status = self._closepipe(f) |
| 92 | if status: |
Collin Winter | 6f2df4d | 2007-07-17 20:59:35 +0000 | [diff] [blame^] | 93 | raise IOError(status) |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 94 | return dict |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 95 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 96 | # --- Methods that change files --- |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 97 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 98 | def lock(self, name_rev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 99 | """Set an rcs lock on NAME_REV.""" |
| 100 | name, rev = self.checkfile(name_rev) |
| 101 | cmd = "rcs -l%s %s" % (rev, name) |
| 102 | return self._system(cmd) |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 103 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 104 | def unlock(self, name_rev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 105 | """Clear an rcs lock on NAME_REV.""" |
| 106 | name, rev = self.checkfile(name_rev) |
| 107 | cmd = "rcs -u%s %s" % (rev, name) |
| 108 | return self._system(cmd) |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 109 | |
| 110 | def checkout(self, name_rev, withlock=0, otherflags=""): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 111 | """Check out NAME_REV to its work file. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 112 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 113 | If optional WITHLOCK is set, check out locked, else unlocked. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 114 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 115 | The optional OTHERFLAGS is passed to co without |
| 116 | interpretation. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 117 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 118 | Any output from co goes to directly to stdout. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 119 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 120 | """ |
| 121 | name, rev = self.checkfile(name_rev) |
| 122 | if withlock: lockflag = "-l" |
| 123 | else: lockflag = "-u" |
| 124 | cmd = 'co %s%s %s %s' % (lockflag, rev, otherflags, name) |
| 125 | return self._system(cmd) |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 126 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 127 | def checkin(self, name_rev, message=None, otherflags=""): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 128 | """Check in NAME_REV from its work file. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 129 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 130 | The optional MESSAGE argument becomes the checkin message |
| 131 | (default "<none>" if None); or the file description if this is |
| 132 | a new file. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 133 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 134 | The optional OTHERFLAGS argument is passed to ci without |
| 135 | interpretation. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 136 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 137 | Any output from ci goes to directly to stdout. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 138 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 139 | """ |
| 140 | name, rev = self._unmangle(name_rev) |
| 141 | new = not self.isvalid(name) |
| 142 | if not message: message = "<none>" |
| 143 | if message and message[-1] != '\n': |
| 144 | message = message + '\n' |
| 145 | lockflag = "-u" |
Guido van Rossum | 3b0a329 | 2002-08-09 16:38:32 +0000 | [diff] [blame] | 146 | if new: |
| 147 | f = tempfile.NamedTemporaryFile() |
| 148 | f.write(message) |
| 149 | f.flush() |
| 150 | cmd = 'ci %s%s -t%s %s %s' % \ |
| 151 | (lockflag, rev, f.name, otherflags, name) |
| 152 | else: |
Thomas Wouters | 49fd7fa | 2006-04-21 10:40:58 +0000 | [diff] [blame] | 153 | message = re.sub(r'([\"$`])', r'\\\1', message) |
Guido van Rossum | 3b0a329 | 2002-08-09 16:38:32 +0000 | [diff] [blame] | 154 | cmd = 'ci %s%s -m"%s" %s %s' % \ |
| 155 | (lockflag, rev, message, otherflags, name) |
| 156 | return self._system(cmd) |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 157 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 158 | # --- Exported support methods --- |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 159 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 160 | def listfiles(self, pat = None): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 161 | """Return a list of all version files matching optional PATTERN.""" |
| 162 | files = os.listdir(os.curdir) |
Collin Winter | 6f2df4d | 2007-07-17 20:59:35 +0000 | [diff] [blame^] | 163 | files = list(filter(self._isrcs, files)) |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 164 | if os.path.isdir('RCS'): |
| 165 | files2 = os.listdir('RCS') |
Collin Winter | 6f2df4d | 2007-07-17 20:59:35 +0000 | [diff] [blame^] | 166 | files2 = list(filter(self._isrcs, files2)) |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 167 | files = files + files2 |
Collin Winter | 6f2df4d | 2007-07-17 20:59:35 +0000 | [diff] [blame^] | 168 | files = list(map(self.realname, files)) |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 169 | return self._filter(files, pat) |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 170 | |
| 171 | def isvalid(self, name): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 172 | """Test whether NAME has a version file associated.""" |
| 173 | namev = self.rcsname(name) |
| 174 | return (os.path.isfile(namev) or |
| 175 | os.path.isfile(os.path.join('RCS', namev))) |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 176 | |
| 177 | def rcsname(self, name): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 178 | """Return the pathname of the version file for NAME. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 179 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 180 | The argument can be a work file name or a version file name. |
| 181 | If the version file does not exist, the name of the version |
| 182 | file that would be created by "ci" is returned. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 183 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 184 | """ |
| 185 | if self._isrcs(name): namev = name |
| 186 | else: namev = name + ',v' |
| 187 | if os.path.isfile(namev): return namev |
| 188 | namev = os.path.join('RCS', os.path.basename(namev)) |
| 189 | if os.path.isfile(namev): return namev |
| 190 | if os.path.isdir('RCS'): |
| 191 | return os.path.join('RCS', namev) |
| 192 | else: |
| 193 | return namev |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 194 | |
| 195 | def realname(self, namev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 196 | """Return the pathname of the work file for NAME. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 197 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 198 | The argument can be a work file name or a version file name. |
| 199 | If the work file does not exist, the name of the work file |
| 200 | that would be created by "co" is returned. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 201 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 202 | """ |
| 203 | if self._isrcs(namev): name = namev[:-2] |
| 204 | else: name = namev |
| 205 | if os.path.isfile(name): return name |
| 206 | name = os.path.basename(name) |
| 207 | return name |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 208 | |
| 209 | def islocked(self, name_rev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 210 | """Test whether FILE (which must have a version file) is locked. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 211 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 212 | XXX This does not tell you which revision number is locked and |
| 213 | ignores any revision you may pass in (by virtue of using rlog |
| 214 | -L -R). |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 215 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 216 | """ |
| 217 | f = self._open(name_rev, 'rlog -L -R') |
| 218 | line = f.readline() |
| 219 | status = self._closepipe(f) |
| 220 | if status: |
Collin Winter | 6f2df4d | 2007-07-17 20:59:35 +0000 | [diff] [blame^] | 221 | raise IOError(status) |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 222 | if not line: return None |
| 223 | if line[-1] == '\n': |
| 224 | line = line[:-1] |
| 225 | return self.realname(name_rev) == self.realname(line) |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 226 | |
| 227 | def checkfile(self, name_rev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 228 | """Normalize NAME_REV into a (NAME, REV) tuple. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 229 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 230 | Raise an exception if there is no corresponding version file. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 231 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 232 | """ |
| 233 | name, rev = self._unmangle(name_rev) |
| 234 | if not self.isvalid(name): |
Collin Winter | 6f2df4d | 2007-07-17 20:59:35 +0000 | [diff] [blame^] | 235 | raise os.error('not an rcs file %r' % (name,)) |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 236 | return name, rev |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 237 | |
| 238 | # --- Internal methods --- |
| 239 | |
| 240 | def _open(self, name_rev, cmd = 'co -p', rflag = '-r'): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 241 | """INTERNAL: open a read pipe to NAME_REV using optional COMMAND. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 242 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 243 | Optional FLAG is used to indicate the revision (default -r). |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 244 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 245 | Default COMMAND is "co -p". |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 246 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 247 | Return a file object connected by a pipe to the command's |
| 248 | output. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 249 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 250 | """ |
| 251 | name, rev = self.checkfile(name_rev) |
| 252 | namev = self.rcsname(name) |
| 253 | if rev: |
| 254 | cmd = cmd + ' ' + rflag + rev |
Walter Dörwald | 70a6b49 | 2004-02-12 17:35:32 +0000 | [diff] [blame] | 255 | return os.popen("%s %r" % (cmd, namev)) |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 256 | |
| 257 | def _unmangle(self, name_rev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 258 | """INTERNAL: Normalize NAME_REV argument to (NAME, REV) tuple. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 259 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 260 | Raise an exception if NAME contains invalid characters. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 261 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 262 | A NAME_REV argument is either NAME string (implying REV='') or |
| 263 | a tuple of the form (NAME, REV). |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 264 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 265 | """ |
| 266 | if type(name_rev) == type(''): |
| 267 | name_rev = name, rev = name_rev, '' |
| 268 | else: |
| 269 | name, rev = name_rev |
| 270 | for c in rev: |
| 271 | if c not in self.okchars: |
Collin Winter | 6f2df4d | 2007-07-17 20:59:35 +0000 | [diff] [blame^] | 272 | raise ValueError("bad char in rev") |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 273 | return name_rev |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 274 | |
| 275 | def _closepipe(self, f): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 276 | """INTERNAL: Close PIPE and print its exit status if nonzero.""" |
| 277 | sts = f.close() |
| 278 | if not sts: return None |
| 279 | detail, reason = divmod(sts, 256) |
| 280 | if reason == 0: return 'exit', detail # Exit status |
| 281 | signal = reason&0x7F |
| 282 | if signal == 0x7F: |
| 283 | code = 'stopped' |
| 284 | signal = detail |
| 285 | else: |
| 286 | code = 'killed' |
| 287 | if reason&0x80: |
| 288 | code = code + '(coredump)' |
| 289 | return code, signal |
Tim Peters | e6ddc8b | 2004-07-18 05:56:09 +0000 | [diff] [blame] | 290 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 291 | def _system(self, cmd): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 292 | """INTERNAL: run COMMAND in a subshell. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 293 | |
Jeremy Hylton | a05e293 | 2000-06-28 14:48:01 +0000 | [diff] [blame] | 294 | Standard input for the command is taken from /dev/null. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 295 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 296 | Raise IOError when the exit status is not zero. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 297 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 298 | Return whatever the calling method should return; normally |
| 299 | None. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 300 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 301 | A derived class may override this method and redefine it to |
| 302 | capture stdout/stderr of the command and return it. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 303 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 304 | """ |
| 305 | cmd = cmd + " </dev/null" |
| 306 | sts = os.system(cmd) |
Collin Winter | 6f2df4d | 2007-07-17 20:59:35 +0000 | [diff] [blame^] | 307 | if sts: raise IOError("command exit status %d" % sts) |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 308 | |
| 309 | def _filter(self, files, pat = None): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 310 | """INTERNAL: Return a sorted copy of the given list of FILES. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 311 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 312 | If a second PATTERN argument is given, only files matching it |
| 313 | are kept. No check for valid filenames is made. |
Tim Peters | e6ddc8b | 2004-07-18 05:56:09 +0000 | [diff] [blame] | 314 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 315 | """ |
| 316 | if pat: |
| 317 | def keep(name, pat = pat): |
| 318 | return fnmatch.fnmatch(name, pat) |
Collin Winter | 6f2df4d | 2007-07-17 20:59:35 +0000 | [diff] [blame^] | 319 | files = list(filter(keep, files)) |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 320 | else: |
| 321 | files = files[:] |
| 322 | files.sort() |
| 323 | return files |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 324 | |
| 325 | def _remove(self, fn): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 326 | """INTERNAL: remove FILE without complaints.""" |
| 327 | try: |
| 328 | os.unlink(fn) |
| 329 | except os.error: |
| 330 | pass |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 331 | |
| 332 | def _isrcs(self, name): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 333 | """INTERNAL: Test whether NAME ends in ',v'.""" |
| 334 | return name[-2:] == ',v' |