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