653391077f0fb56f2f1a5737c8566789d37d9bb9
[users/seanius/patch-tracker.git] / patchtracker / Patch.py
1 import sys
2 import os
3 import errno
4 from glob import glob
5 import tarfile
6
7 class Diffstat:
8   def __init__(self, patch):
9     self.patch = patch
10     i,o = os.popen2("diffstat -p1")
11     i.write(str(patch))
12     i.close()
13     self.output = o.readlines()
14
15   def stats(self):
16     i,o = os.popen2("diffstat -p1 -t")
17     i.write(str(self.patch))
18     i.close()
19     o.readline()
20     return [map(lambda x: x.strip(), l.split(",")) for l in o.readlines()]
21
22   def summary(self):
23     return self.output[-1]
24
25   def __str__(self):
26     return "".join(self.output)
27
28 class Patch:
29   def __init__(self, fh, level=1):
30     self.p = fh.readlines()
31     self.lvl = level
32
33   def __str__(self):
34     return "".join(self.p)
35
36   def lines(self):
37     return len(self.p)
38
39   def diffstat(self):
40     return Diffstat(self)
41
42 class GenericPatchSeries (list):
43   def blank(self):
44     self.names = []
45     self.style = "unknown"
46     self.patches = {}
47     self.patchargs = {}
48
49   # WTF am i doing this for, again?
50   def iterpatches(self):
51     for p in self.names:
52       yield (p, self.patches[p])
53
54   def __iter__(self):
55     return self.iterpatches()
56
57   def __getitem__(self, y):
58     return self.patches[self.names[y]]
59
60   def __len__(self):
61     return len(self.names)
62
63   def fetch(self, name):
64     return self.patches[name]
65
66   def __str__(self):
67     return "\n".join(self.names)
68
69 # XXX this entire __init__ stuff is way to ugly
70 class PatchSeries (GenericPatchSeries):
71   def __init__(self, dir):
72     fd = None
73     self.blank()
74     self.style = "simple"
75     try:
76       fd = file(os.sep.join([dir, "00list"]))
77       self.style = "dpatch"
78     except IOError, e:
79       if e.errno != errno.ENOENT:
80         #print "ERROR: unable to open dpatch list..."
81         self.blank()
82         return
83     try:
84       fd = file(os.sep.join([dir, "series"]))
85       self.style = "quilt"
86     except IOError, e:
87       if e.errno != errno.ENOENT:
88         #print "ERROR: series file is a directory..."
89         self.blank()
90         return
91
92     if fd:
93       # remove blank lines
94       for line in filter(None, [n.strip() for n in fd.readlines()]):
95         stuff = line.split(' ')
96         # skip comments
97         if stuff[0][0] == "#":
98           continue
99         # here's the name
100         name = stuff[0]
101         #print "\t\t\t%s: %s"%(self.style,name)
102         self.names.append(name)
103         # anything else are either patch args or comments
104         self.patchargs[name] = []
105         for rest in filter(None, stuff[1:]):
106           if rest[0][0] == "#":
107             break
108           else:
109             self.patchargs[name].append(rest)
110
111     else:
112       self.names = os.listdir(dir)
113       self.names.sort()
114       for n in self.names:
115         self.patchargs[n] = []
116
117     # XXX this code is too ugly
118     removelater=[]
119     for p in self.names:
120       try:
121         self.patches[p] = Patch(file(os.sep.join([dir, p])))
122       except IOError, e:
123         if e.errno == errno.ENOENT and self.style == "dpatch":
124           try:
125             self.patches[p] = Patch(file(os.sep.join([dir, p+".dpatch"])))
126           except:
127             #print "ERROR: could not find patch",p
128             self.blank()
129             return
130         elif e.errno == errno.EISDIR:
131           #print "WARNING: directory %s in patch dir, patch list incomplete"%(p)
132           removelater.append(p)
133         else:
134           #print "ERROR: could not find patch",p
135           self.blank()
136           return
137     for p in removelater:
138       self.names.remove(p)
139
140 class Quilt30PatchSeries (GenericPatchSeries):
141   def __init__(self, tarBall):
142     self.blank()
143     self.style = "quilt (3.0)"
144     self.tarfh = tarfile.open(tarBall, 'r:*')
145     try:
146       try:
147         series_fh = self.tarfh.extractfile("debian/patches/debian.series")
148       except KeyError:
149         series_fh = self.tarfh.extractfile("debian/patches/series")
150     except KeyError:
151       series_fh = None
152
153     if series_fh:
154       for line in filter(None, [fn.strip() for fn in series_fh.readlines()]):
155         stuff = line.split(' ')
156         # skip comments
157         if stuff[0][0] == "#":
158           continue
159         # here's the name
160         name = stuff[0]
161         self.names.append(name)
162
163     # XXX to lazy eval this might be better
164     for name in self.names:
165       self.patches[name] = Patch(self.tarfh.extractfile("debian/patches/"+name))
166
167 if __name__ == "__main__":
168   print "Patch.py testing"
169   try:
170     p = Patch(file(sys.argv[1]))
171     print "patch contents:"
172     print p
173   except IndexError:
174     print "usage: %s <patch>"