| 1 | """Utilities for CVS administration."""
|
|---|
| 2 |
|
|---|
| 3 | import string
|
|---|
| 4 | import os
|
|---|
| 5 | import time
|
|---|
| 6 | import md5
|
|---|
| 7 | import fnmatch
|
|---|
| 8 |
|
|---|
| 9 | if not hasattr(time, 'timezone'):
|
|---|
| 10 | time.timezone = 0
|
|---|
| 11 |
|
|---|
| 12 | class File:
|
|---|
| 13 |
|
|---|
| 14 | """Represent a file's status.
|
|---|
| 15 |
|
|---|
| 16 | Instance variables:
|
|---|
| 17 |
|
|---|
| 18 | file -- the filename (no slashes), None if uninitialized
|
|---|
| 19 | lseen -- true if the data for the local file is up to date
|
|---|
| 20 | eseen -- true if the data from the CVS/Entries entry is up to date
|
|---|
| 21 | (this implies that the entry must be written back)
|
|---|
| 22 | rseen -- true if the data for the remote file is up to date
|
|---|
| 23 | proxy -- RCSProxy instance used to contact the server, or None
|
|---|
| 24 |
|
|---|
| 25 | Note that lseen and rseen don't necessary mean that a local
|
|---|
| 26 | or remote file *exists* -- they indicate that we've checked it.
|
|---|
| 27 | However, eseen means that this instance corresponds to an
|
|---|
| 28 | entry in the CVS/Entries file.
|
|---|
| 29 |
|
|---|
| 30 | If lseen is true:
|
|---|
| 31 |
|
|---|
| 32 | lsum -- checksum of the local file, None if no local file
|
|---|
| 33 | lctime -- ctime of the local file, None if no local file
|
|---|
| 34 | lmtime -- mtime of the local file, None if no local file
|
|---|
| 35 |
|
|---|
| 36 | If eseen is true:
|
|---|
| 37 |
|
|---|
| 38 | erev -- revision, None if this is a no revision (not '0')
|
|---|
| 39 | enew -- true if this is an uncommitted added file
|
|---|
| 40 | edeleted -- true if this is an uncommitted removed file
|
|---|
| 41 | ectime -- ctime of last local file corresponding to erev
|
|---|
| 42 | emtime -- mtime of last local file corresponding to erev
|
|---|
| 43 | extra -- 5th string from CVS/Entries file
|
|---|
| 44 |
|
|---|
| 45 | If rseen is true:
|
|---|
| 46 |
|
|---|
| 47 | rrev -- revision of head, None if non-existent
|
|---|
| 48 | rsum -- checksum of that revision, Non if non-existent
|
|---|
| 49 |
|
|---|
| 50 | If eseen and rseen are both true:
|
|---|
| 51 |
|
|---|
| 52 | esum -- checksum of revision erev, None if no revision
|
|---|
| 53 |
|
|---|
| 54 | Note
|
|---|
| 55 | """
|
|---|
| 56 |
|
|---|
| 57 | def __init__(self, file = None):
|
|---|
| 58 | if file and '/' in file:
|
|---|
| 59 | raise ValueError, "no slash allowed in file"
|
|---|
| 60 | self.file = file
|
|---|
| 61 | self.lseen = self.eseen = self.rseen = 0
|
|---|
| 62 | self.proxy = None
|
|---|
| 63 |
|
|---|
| 64 | def __cmp__(self, other):
|
|---|
| 65 | return cmp(self.file, other.file)
|
|---|
| 66 |
|
|---|
| 67 | def getlocal(self):
|
|---|
| 68 | try:
|
|---|
| 69 | self.lmtime, self.lctime = os.stat(self.file)[-2:]
|
|---|
| 70 | except os.error:
|
|---|
| 71 | self.lmtime = self.lctime = self.lsum = None
|
|---|
| 72 | else:
|
|---|
| 73 | self.lsum = md5.new(open(self.file).read()).digest()
|
|---|
| 74 | self.lseen = 1
|
|---|
| 75 |
|
|---|
| 76 | def getentry(self, line):
|
|---|
| 77 | words = string.splitfields(line, '/')
|
|---|
| 78 | if self.file and words[1] != self.file:
|
|---|
| 79 | raise ValueError, "file name mismatch"
|
|---|
| 80 | self.file = words[1]
|
|---|
| 81 | self.erev = words[2]
|
|---|
| 82 | self.edeleted = 0
|
|---|
| 83 | self.enew = 0
|
|---|
| 84 | self.ectime = self.emtime = None
|
|---|
| 85 | if self.erev[:1] == '-':
|
|---|
| 86 | self.edeleted = 1
|
|---|
| 87 | self.erev = self.erev[1:]
|
|---|
| 88 | if self.erev == '0':
|
|---|
| 89 | self.erev = None
|
|---|
| 90 | self.enew = 1
|
|---|
| 91 | else:
|
|---|
| 92 | dates = words[3]
|
|---|
| 93 | self.ectime = unctime(dates[:24])
|
|---|
| 94 | self.emtime = unctime(dates[25:])
|
|---|
| 95 | self.extra = words[4]
|
|---|
|
|---|