32
32
33
33
class DpkgHistory (dict ):
34
34
""" Parser for the dpkg history logs """
35
- def __init__ (self , var_location = "/var/" , since = None ):
35
+ def __init__ (self , var_location = "/var/" , since = None , do_parse = True ):
36
36
super (DpkgHistory , self ).__init__ ()
37
37
38
38
self ["install" ] = []
39
39
self ["auto-install" ] = []
40
40
self ["upgrade" ] = []
41
41
self ["remove" ] = []
42
42
self ["purge" ] = []
43
-
43
+
44
44
self .var_location = var_location
45
45
self .since = self ._get_date_from_string (since )
46
- self ._get_dpkg_history ()
47
- if len (self ['install' ]) > 0 :
48
- self .auto = self ._find_auto_installs ()
49
- self ._split_installs_by_auto ()
50
- self ._sort_lists ()
46
+ self .auto = []
47
+
48
+ if do_parse :
49
+ self ._get_dpkg_history ()
50
+ if len (self ['install' ]) > 0 :
51
+ self .auto = self ._find_auto_installs ()
52
+ self ._split_installs_by_auto ()
53
+ self ._sort_lists ()
54
+
55
+ def __add__ (self , other ):
56
+ if self .since < other .since :
57
+ order = self , other
58
+ else :
59
+ order = other , self
60
+
61
+ ops_by_package = defaultdict (list )
62
+ versions = defaultdict (list )
63
+ for history in order :
64
+ for op in history .keys ():
65
+ for package , version in history [op ]:
66
+ ops_by_package [package ].append (op )
67
+ if ", " in version :
68
+ version = version .split (", " )
69
+ else :
70
+ version = [version ]
71
+ versions [package ].append (version )
72
+
73
+ combined = DpkgHistory (since = order [0 ].since , do_parse = False )
74
+ combined ._distill_ops (ops_by_package , versions )
75
+ if len (combined ['install' ]) > 0 :
76
+ combined .auto = order [1 ].auto
77
+ combined ._split_installs_by_auto ()
78
+ combined ._sort_lists ()
79
+
80
+ return combined
51
81
52
82
def _get_date_from_string (self , since ):
53
83
if isinstance (since , basestring ):
@@ -61,7 +91,8 @@ def _get_dpkg_history(self):
61
91
""" Read dpkg.log's and return dictionary of ops
62
92
"""
63
93
logfiles = self ._logfiles_to_check ()
64
- self ._parse (logfiles )
94
+ ops_by_package , versions = self ._parse_by_package (logfiles )
95
+ self ._distill_ops (ops_by_package , versions )
65
96
66
97
def _logfiles_to_check (self ):
67
98
""" Return an ordered list of opened logfiles young enough to be
@@ -99,13 +130,13 @@ def _read_files(self, files):
99
130
for line in f :
100
131
yield line .strip ()
101
132
102
- def _parse (self , logfiles ):
133
+ def _parse_by_package (self , logfiles ):
103
134
""" reads in the opened logfiles and makes lists of the ops mentioned.
104
135
Returns a dictionary of lists, each list contains (pkg, version)
105
136
tuples.
106
137
"""
107
138
ops_by_package = defaultdict (list )
108
- version = defaultdict (list )
139
+ versions = defaultdict (list )
109
140
# List ops per package
110
141
for line in self ._read_files (logfiles ):
111
142
if line == "" :
@@ -123,15 +154,18 @@ def _parse(self, logfiles):
123
154
124
155
package = bits [3 ]
125
156
ops_by_package [package ].append (linetype )
126
- version [package ].append (bits [4 :6 ])
127
-
157
+ versions [package ].append (bits [4 :6 ])
158
+
159
+ return ops_by_package , versions
160
+
161
+ def _distill_ops (self , ops_by_package , versions ):
128
162
instup = ("install" , "upgrade" )
129
163
remurge = ("remove" , "purge" )
130
164
# Decide which op to remember for each package
131
165
for package , ops in ops_by_package .iteritems ():
132
166
133
- oldest_version = version [package ][0 ][0 ]
134
- newest_version = version [package ][- 1 ][1 ]
167
+ oldest_version = versions [package ][0 ][0 ]
168
+ newest_version = versions [package ][- 1 ][- 1 ]
135
169
version_change = "%s, %s" % (oldest_version , newest_version )
136
170
137
171
if ops [0 ] == "install" and ops [- 1 ] not in remurge :
0 commit comments