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 |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 11 | import regsub |
| 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 |
| 36 | okchars = string.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? |
| 86 | continue |
| 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: |
| 93 | raise IOError, status |
| 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" |
| 146 | textfile = None |
| 147 | try: |
| 148 | if new: |
| 149 | textfile = tempfile.mktemp() |
| 150 | f = open(textfile, 'w') |
| 151 | f.write(message) |
| 152 | f.close() |
| 153 | cmd = 'ci %s%s -t%s %s %s' % \ |
| 154 | (lockflag, rev, textfile, otherflags, name) |
| 155 | else: |
| 156 | message = regsub.gsub('\([\\"$`]\)', '\\\\\\1', message) |
| 157 | cmd = 'ci %s%s -m"%s" %s %s' % \ |
| 158 | (lockflag, rev, message, otherflags, name) |
| 159 | return self._system(cmd) |
| 160 | finally: |
| 161 | if textfile: self._remove(textfile) |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 162 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 163 | # --- Exported support methods --- |
Guido van Rossum | 79ed32d | 1995-06-23 14:40:06 +0000 | [diff] [blame] | 164 | |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 165 | def listfiles(self, pat = None): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 166 | """Return a list of all version files matching optional PATTERN.""" |
| 167 | files = os.listdir(os.curdir) |
| 168 | files = filter(self._isrcs, files) |
| 169 | if os.path.isdir('RCS'): |
| 170 | files2 = os.listdir('RCS') |
| 171 | files2 = filter(self._isrcs, files2) |
| 172 | files = files + files2 |
| 173 | files = map(self.realname, files) |
| 174 | return self._filter(files, pat) |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 175 | |
| 176 | def isvalid(self, name): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 177 | """Test whether NAME has a version file associated.""" |
| 178 | namev = self.rcsname(name) |
| 179 | return (os.path.isfile(namev) or |
| 180 | os.path.isfile(os.path.join('RCS', namev))) |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 181 | |
| 182 | def rcsname(self, name): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 183 | """Return the pathname of the version file for NAME. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 184 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 185 | The argument can be a work file name or a version file name. |
| 186 | If the version file does not exist, the name of the version |
| 187 | file that would be created by "ci" is returned. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 188 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 189 | """ |
| 190 | if self._isrcs(name): namev = name |
| 191 | else: namev = name + ',v' |
| 192 | if os.path.isfile(namev): return namev |
| 193 | namev = os.path.join('RCS', os.path.basename(namev)) |
| 194 | if os.path.isfile(namev): return namev |
| 195 | if os.path.isdir('RCS'): |
| 196 | return os.path.join('RCS', namev) |
| 197 | else: |
| 198 | return namev |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 199 | |
| 200 | def realname(self, namev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 201 | """Return the pathname of the work file for NAME. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 202 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 203 | The argument can be a work file name or a version file name. |
| 204 | If the work file does not exist, the name of the work file |
| 205 | that would be created by "co" is returned. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 206 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 207 | """ |
| 208 | if self._isrcs(namev): name = namev[:-2] |
| 209 | else: name = namev |
| 210 | if os.path.isfile(name): return name |
| 211 | name = os.path.basename(name) |
| 212 | return name |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 213 | |
| 214 | def islocked(self, name_rev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 215 | """Test whether FILE (which must have a version file) is locked. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 216 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 217 | XXX This does not tell you which revision number is locked and |
| 218 | ignores any revision you may pass in (by virtue of using rlog |
| 219 | -L -R). |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 220 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 221 | """ |
| 222 | f = self._open(name_rev, 'rlog -L -R') |
| 223 | line = f.readline() |
| 224 | status = self._closepipe(f) |
| 225 | if status: |
| 226 | raise IOError, status |
| 227 | if not line: return None |
| 228 | if line[-1] == '\n': |
| 229 | line = line[:-1] |
| 230 | return self.realname(name_rev) == self.realname(line) |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 231 | |
| 232 | def checkfile(self, name_rev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 233 | """Normalize NAME_REV into a (NAME, REV) tuple. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 234 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 235 | Raise an exception if there is no corresponding version file. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 236 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 237 | """ |
| 238 | name, rev = self._unmangle(name_rev) |
| 239 | if not self.isvalid(name): |
| 240 | raise os.error, 'not an rcs file %s' % `name` |
| 241 | return name, rev |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 242 | |
| 243 | # --- Internal methods --- |
| 244 | |
| 245 | def _open(self, name_rev, cmd = 'co -p', rflag = '-r'): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 246 | """INTERNAL: open a read pipe to NAME_REV using optional COMMAND. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 247 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 248 | Optional FLAG is used to indicate the revision (default -r). |
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 | Default COMMAND is "co -p". |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 251 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 252 | Return a file object connected by a pipe to the command's |
| 253 | output. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 254 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 255 | """ |
| 256 | name, rev = self.checkfile(name_rev) |
| 257 | namev = self.rcsname(name) |
| 258 | if rev: |
| 259 | cmd = cmd + ' ' + rflag + rev |
| 260 | return os.popen("%s %s" % (cmd, `namev`)) |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 261 | |
| 262 | def _unmangle(self, name_rev): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 263 | """INTERNAL: Normalize NAME_REV argument to (NAME, REV) tuple. |
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 | Raise an exception if NAME contains invalid characters. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 266 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 267 | A NAME_REV argument is either NAME string (implying REV='') or |
| 268 | a tuple of the form (NAME, REV). |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 269 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 270 | """ |
| 271 | if type(name_rev) == type(''): |
| 272 | name_rev = name, rev = name_rev, '' |
| 273 | else: |
| 274 | name, rev = name_rev |
| 275 | for c in rev: |
| 276 | if c not in self.okchars: |
| 277 | raise ValueError, "bad char in rev" |
| 278 | return name_rev |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 279 | |
| 280 | def _closepipe(self, f): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 281 | """INTERNAL: Close PIPE and print its exit status if nonzero.""" |
| 282 | sts = f.close() |
| 283 | if not sts: return None |
| 284 | detail, reason = divmod(sts, 256) |
| 285 | if reason == 0: return 'exit', detail # Exit status |
| 286 | signal = reason&0x7F |
| 287 | if signal == 0x7F: |
| 288 | code = 'stopped' |
| 289 | signal = detail |
| 290 | else: |
| 291 | code = 'killed' |
| 292 | if reason&0x80: |
| 293 | code = code + '(coredump)' |
| 294 | return code, signal |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 295 | |
| 296 | def _system(self, cmd): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 297 | """INTERNAL: run COMMAND in a subshell. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 298 | |
Jeremy Hylton | a05e293 | 2000-06-28 14:48:01 +0000 | [diff] [blame] | 299 | Standard input for the command is taken from /dev/null. |
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 | Raise IOError when the exit status is not zero. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 302 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 303 | Return whatever the calling method should return; normally |
| 304 | None. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 305 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 306 | A derived class may override this method and redefine it to |
| 307 | capture stdout/stderr of the command and return it. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 308 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 309 | """ |
| 310 | cmd = cmd + " </dev/null" |
| 311 | sts = os.system(cmd) |
| 312 | if sts: raise IOError, "command exit status %d" % sts |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 313 | |
| 314 | def _filter(self, files, pat = None): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 315 | """INTERNAL: Return a sorted copy of the given list of FILES. |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 316 | |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 317 | If a second PATTERN argument is given, only files matching it |
| 318 | are kept. No check for valid filenames is made. |
| 319 | |
| 320 | """ |
| 321 | if pat: |
| 322 | def keep(name, pat = pat): |
| 323 | return fnmatch.fnmatch(name, pat) |
| 324 | files = filter(keep, files) |
| 325 | else: |
| 326 | files = files[:] |
| 327 | files.sort() |
| 328 | return files |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 329 | |
| 330 | def _remove(self, fn): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 331 | """INTERNAL: remove FILE without complaints.""" |
| 332 | try: |
| 333 | os.unlink(fn) |
| 334 | except os.error: |
| 335 | pass |
Guido van Rossum | 802c437 | 1995-06-23 21:58:18 +0000 | [diff] [blame] | 336 | |
| 337 | def _isrcs(self, name): |
Guido van Rossum | 4117e54 | 1998-09-14 16:44:15 +0000 | [diff] [blame] | 338 | """INTERNAL: Test whether NAME ends in ',v'.""" |
| 339 | return name[-2:] == ',v' |