Skip to content

Instantly share code, notes, and snippets.

@noscript noscript/dpkg-since.py
Last active Jul 27, 2019

Embed
What would you like to do?
Dpkg Time Machine
#!/usr/bin/env python3
# file: dpkg-since.py
# description: lists installed packages since the specified date
# dependencies: 'dateparser', install with 'apt install python3-dateparser'
# changelog:
# * Feb 10 2015 - init release
# * Mar 24 2015 - new: packages sorted by installation time/date
# fix: ignored TIME argument
# * Apr 9 2015 - fix: exclude duplicates
# * Apr 27 2015 - new: recognize dates like '1 hour ago', 'yesterday'
# requires 'dateparser'
# - new: use new line or other splitter character
# * Jul 27 2019 - new: upgraded to python 3
import sys
import getopt
from os.path import basename
from datetime import datetime
from dateparser.date import DateDataParser
from glob import glob
import gzip
def uniquify(seq):
seen = set()
seen_add = seen.add
return [x for x in seq if x not in seen and not seen_add(x)]
def print_usage():
basename_ = basename(sys.argv[0])
print('')
print('Usage:\n\t' + basename_ + ' [OPTIONS] DATE')
print('')
print('Options:')
print('\t-p, --print-date - prints the recognized date as the last line')
print("\t-n, --new-line - use new line as a splitter character")
print("\t-s, --splitter 'char' - set a custom splitter character")
print('\t-h, --help - display this help and exit')
print('')
print('Examples:')
print('\t' + basename_ + ' -v yesterday')
print('\t' + basename_ + ' -n 1 week ago')
print('\t' + basename_ + " -s ', ' 2015-02-14 16:40:35")
def main():
verbose = False
splitter = " "
try:
opts, args = getopt.getopt(sys.argv[1:], "hps:n", ["help", "print-date", "splitter=", "new-line"])
except getopt.GetoptError as err:
print(str(err))
print_usage()
sys.exit(2)
for o, a in opts:
if o in ("-h", "--help"):
print_usage()
sys.exit()
elif o in ("-p", "--print-date"):
verbose = True
elif o in ("-s", "--splitter"):
splitter = a
if splitter == "\\n":
splitter = "\n"
elif o in ("-n", "--new-line"):
splitter = "\n"
else:
assert False, "unhandled option"
if (not args):
print('missing date arguments')
print_usage()
sys.exit(1)
ddp = DateDataParser()
since_date = ddp.get_date_data(' '.join(args))['date_obj']
packages = []
for log in sorted(glob('/var/log/dpkg.log*'), reverse=True):
if log.endswith('.gz'):
f = gzip.open(log, 'r')
else:
f = open(log, 'r')
for line in f:
cols = line.split()
# date + time columns
line_date = datetime.strptime(cols[0] + ' ' + cols[1], "%Y-%m-%d %H:%M:%S")
if line_date >= since_date:
# keep only installed ones
if cols[2] == 'install':
packages.append(cols[3])
print(splitter.join(uniquify(packages)))
if verbose:
print("\n" + since_date.ctime() + "")
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.