-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathListUserInstalledPackages.py
171 lines (134 loc) · 5.17 KB
/
ListUserInstalledPackages.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
"""
Description: List all packages manually installed (by users, by admin/root, or both), as determined by the Debian package system.
"""
def main():
"""
Parse any input arguments and process.
"""
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--default', action='store_true', help="list intersecting packages from processing both apt history logs and apt-mark showmanual")
parser.add_argument('--aptMark', action='store_true', help="list packages only from processing apt-mark showmanual")
parser.add_argument('--aptHistory', action='store_true', help="list packages only from processing apt history logs")
args = parser.parse_args()
if args.default:
CombineListsAllInstalledPackages()
elif args.aptMark:
dpkgAllPackageSet = DpkgAllPackageStatus()
aptMarkSet = AptMarkShowManualPackageNames()
finalSet = dpkgAllPackageSet.intersection(aptMarkSet)
jointVerdict = list(finalSet)
jointVerdict.sort()
for item in jointVerdict:
print(item)
elif args.aptHistory:
dpkgAllPackageSet = DpkgAllPackageStatus()
aptHistorySet = AptLogHistoryPackageNames()
finalSet = dpkgAllPackageSet.intersection(aptHistorySet)
jointVerdict = list(finalSet)
jointVerdict.sort()
for item in jointVerdict:
print(item)
else:
CombineListsAllInstalledPackages()
def CombineListsAllInstalledPackages():
"""
Combine and display the results of both querying the Debian package tool
Apt-Mark and manually parsing the logs in /var/log/dpkg.log*. Then display
the combined output.
"""
dpkgAllPackageSet = DpkgAllPackageStatus()
aptHistorySet = AptLogHistoryPackageNames()
aptMarkSet = AptMarkShowManualPackageNames()
finalSet = aptMarkSet.union(aptHistorySet)
finalSet = dpkgAllPackageSet.intersection(finalSet)
jointVerdict = list(finalSet)
jointVerdict.sort()
for item in jointVerdict:
print(item)
def DpkgAllPackageStatus():
"""
Get a Set of strings for ALL installed packages according to the Debian
dpkg system, by reading /var/lib/dpkg/status.
For brevity of development, no sophisticated testing for whether a file does
not conform to the listed expected input. This can be added later if desired.
@assumptions: The extected input file is /var/lib/dpkg/status. We do not
account for any prior log files like status-old.
@return Set-object of strings for all installed packages
"""
from pathlib import Path
import re
INDEX_DPKG_STATUS_PACKAGE_STRING = 1
packageNamesFromLogs = set()
# Get list of all existing DPKG logs in /var/log/dpkg.log*
dpkgStatusPath = "/var/lib/dpkg/status"
openedDpkgStatusPath = Path(dpkgStatusPath)
fileOpened = open(openedDpkgStatusPath, 'r')
contents = fileOpened.readlines()
fileOpened.close()
for line in contents:
if re.search(r'^Package: ', line):
splits = line.strip().split(' ')
packageNamesFromLogs.add(splits[INDEX_DPKG_STATUS_PACKAGE_STRING])
return packageNamesFromLogs
def AptMarkShowManualPackageNames():
"""
Get a Set of strings for all manually installed packages byaccording to the system tool Apt-Mark.
NOTE: Chose to use subprocess.check_output for older Python compatiblity
because this is simple.
@return Set-object of strings for all installed packages
"""
import subprocess
packageNamesAptMarkShowManual = set()
output = subprocess.check_output(['apt-mark', 'showmanual'])
contents = output.decode('utf-8')
for line in contents.splitlines():
packageNamesAptMarkShowManual.add(line)
return packageNamesAptMarkShowManual
def AptLogHistoryPackageNames():
"""
Generate a Set of strings for all manually installed packages by parsing
the Apt history log files for the express 'apt install ' and retrieving
all items listed after that text.
Note this does not account for if they have been removed.
@return Set-object of strings for all installed packages
"""
from pathlib import Path
import gzip
import io
import os
import re
INDEX_APT_HISTORY_LOG_PACKAGE_NAME = 3
packageNamesFromLogs = set()
# Get list of all existing DPKG logs in /var/log/apt/history.log*
aptLogPath = "/var/log/apt"
openedAptLogPath = Path(aptLogPath)
for file in list(openedAptLogPath.glob('**/history.log*')):
# Only read expected text-files and gzip-text files
fileName,ext = os.path.splitext(file)
if ext == '.log' or re.search( r'\d+', ext):
# Process as plain text-file
fileOpened = open(file, 'r')
contents = fileOpened.readlines()
fileOpened.close()
for line in contents:
if re.search(r'apt install ', line):
splits = line.strip().split(' ')
packageNamesFromLogs.add(splits[INDEX_APT_HISTORY_LOG_PACKAGE_NAME])
elif ext == '.gz':
# Process as Gzip file
with gzip.open(file,'r') as gzipFile: # open the gzip file read-only
with io.TextIOWrapper(gzipFile, encoding='utf-8') as decoder: # decode the gzip file contents
contents = decoder.readlines() # Get contents line by line
for line in contents:
if re.search(r'apt install ', line):
splits = line.strip().split(' ')
# Get all items on the install command history line
for item in splits[INDEX_APT_HISTORY_LOG_PACKAGE_NAME:]:
packageNamesFromLogs.add(item)
return packageNamesFromLogs
if __name__ == '__main__':
"""
Invoke the main dispatcher function.
"""
main()