Skip to content

Instantly share code, notes, and snippets.

@aslpavel
Created February 16, 2016 23:13
Show Gist options
  • Select an option

  • Save aslpavel/ffb813f68781f55c39cd to your computer and use it in GitHub Desktop.

Select an option

Save aslpavel/ffb813f68781f55c39cd to your computer and use it in GitHub Desktop.

Revisions

  1. aslpavel created this gist Feb 16, 2016.
    78 changes: 78 additions & 0 deletions pkguninstall.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,78 @@
    #! /usr/bin/env python3
    import os
    import re
    import sys
    import subprocess

    def error(msg, code=1):
    sys.stderr.write('[error] {}\n'.format(msg))
    sys.exit(code)

    def confirm(msg):
    sys.stdout.write('{} [y/N]: '.format(msg))
    sys.stdout.flush()
    res = sys.stdin.readline()
    if not res.lower().strip() == 'y':
    sys.stderr.write('[info] canceled by user\n')
    sys.exit(2)

    def pkgutil(*args):
    proc = subprocess.run(('pkgutil',) + args, stdout=subprocess.PIPE)
    if proc.returncode != 0:
    error('pkgutil failed')
    return proc.stdout

    def main():
    if len(sys.argv) != 2:
    sys.stderr.write('Usage: {} <pkg-name>\n'
    .format(os.path.basename(sys.argv[0])))
    sys.exit(1)
    pkg = sys.argv[1]
    info = pkgutil('--info', pkg)
    vol_match, loc_match = (re.search(b'volume: ([^\n]+)', info),
    re.search(b'location: ([^\n]*)', info))
    if not vol_match or not loc_match:
    error('pkgutil info bad output: no location or volume')
    location = (vol_match.group(1) + loc_match.group(1)).decode()
    files = [os.path.join(location, file.decode()) for file in
    pkgutil('--only-files', '--files', pkg).split(b'\n')
    if file != b'']
    dirs = [os.path.join(location, dir.decode()) for dir in
    pkgutil('--only-dirs', '--files', pkg).split(b'\n')
    if dir != b'']
    dirs.sort(key=lambda s: -len(s))
    confirm('[action] delete package {} (loc:{}, files:{}, dirs:{})?'
    .format(pkg, location, len(files), len(dirs)))
    files_ok = 0
    for file in files:
    if not os.path.exists(file):
    files_ok += 1
    continue
    try:
    os.unlink(file)
    files_ok += 1
    except Exception as err:
    sys.stderr.write('{}: \x1b[01;31m{}\x1b[m\n'
    .format(err.strerror, file))
    dirs_ok = 0
    for dir in dirs:
    if not os.path.exists(dir):
    dirs_ok += 1
    continue
    if os.path.isdir(dir) and not os.listdir(dir):
    try:
    os.rmdir(dir)
    dirs_ok += 1
    except Exception as err:
    sys.stderr.write('{}: \x1b[01;31m{}\x1b[m\n'
    .format(err.strerror, dir))
    else:
    sys.stderr.write('\x1b[01;31m{}\x1b[m\n'.format(dir))
    sys.stderr.write('[info] deleted {} (files:{}/{}, dirs:{}/{})\n'
    .format(pkg, files_ok, len(files), dirs_ok, len(dirs)))
    confirm('[action] forget {}?'.format(pkg))
    pkgutil('--forget', pkg)


    if __name__ == '__main__':
    main()