File: uninstall-mac-pkg

package info (click to toggle)
awscli 2.31.35-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 156,692 kB
  • sloc: python: 213,816; xml: 14,082; makefile: 189; sh: 178; javascript: 8
file content (180 lines) | stat: -rwxr-xr-x 5,355 bytes parent folder | download
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
172
173
174
175
176
177
178
179
180
#!/usr/bin/env python
"""Script to uninstall AWS CLI V2 Mac PKG"""

import argparse
import os
import re
import sys
from datetime import datetime
from subprocess import PIPE, CalledProcessError, check_output

SCRIPTS_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(SCRIPTS_DIR)

from utils import BadRCError, run

_PKG_ID = 'com.amazon.aws.cli2'
_PKGUTIL_PATTERN = re.compile(
    (
        r'version:\s*(?P<version>.*?)\n'
        r'volume:\s*(?P<volume>.*?)\n'
        r'location:\s*(?P<location>.*?)\n'
        r'install-time:\s*(?P<install_time>.*?)\n'
    ),
    re.X,
)


def uninstall():
    assert _is_installed(), 'Could not find AWS CLI installation.'
    assert os.geteuid() == 0, 'Script must be run as root (with sudo).'

    # First we remove all the files listed in the pkg's receipt file,
    # and our own custom metadata file.
    root_dir = _get_root_dir()
    list_files = _get_file_list(root_dir)
    _erase_files(list_files)

    # Once these are all removed the directories should all be empty and can
    # be deleted.
    list_dirs = _get_dir_list(root_dir)
    _erase_dirs(list_dirs)

    # Finally we forget the package receipt.
    _forget()

    print('Successfully uninstalled AWS CLI from %s' % root_dir)
    return 0


def _get_root_dir():
    lines = run('pkgutil --pkg-info %s /' % _PKG_ID, echo=False)
    output = _PKGUTIL_PATTERN.search(lines)
    path = os.path.join(output.group('volume'), output.group('location'))
    return path


def _get_file_list(root):
    lines = run(
        'pkgutil --only-files --files %s /' % _PKG_ID, echo=False
    ).split('\n')
    pkg_file_list = [os.path.join(root, line) for line in lines if line]
    extra_files = _read_install_metadata(root)
    return pkg_file_list + extra_files


def _read_install_metadata(root):
    # Install metadata is a list of files that were installed by helper scripts
    # executed by the PKG. In the AWS CLI V2's case, we use a postinstall
    # script to add binaries symlinks to /usr/bin. These are untracked by the
    # pkg receipt. To track them we add them to a special .install-metdata file
    # in the installer directory.
    metadata_path = os.path.join(root, 'aws-cli', '.install-metadata')
    if not os.path.isfile(metadata_path):
        return []
    extra_files = open(metadata_path).read()
    return extra_files.split('\n')[:-1]


def _get_dir_list(root):
    lines = run(
        'pkgutil --only-dirs --files %s /' % _PKG_ID, echo=False
    ).split('\n')
    # Longer directory names are listed first to force them to come before
    # their parent directories. This ensures that child directories are
    # deleted before their parents.
    return sorted(
        [os.path.join(root, line) for line in lines if line],
        key=lambda x: -len(x),
    )


def _erase_files(file_list):
    for path in file_list:
        if os.path.isfile(path) or os.path.islink(path):
            os.remove(path)


def _erase_dirs(dir_list):
    for path in dir_list:
        if os.path.isdir(path):
            os.rmdir(path)


def _forget():
    # Forget is the pkgutil command to delete the pkg installer receipt.
    # Once the files have been deleted, the pkgutil command will continue to
    # report that they are installed until the pkg id has been forgotten.
    run('pkgutil --forget %s' % _PKG_ID, echo=False)


def check():
    assert _is_installed(), 'Could not find AWS CLI installation.'

    lines = run('pkgutil --pkg-info %s /' % _PKG_ID, echo=False)
    output = _PKGUTIL_PATTERN.search(lines)
    root = os.path.join(output.group('volume'), output.group('location'))
    print(
        'Found AWS CLI version %s installed at %s'
        % (output.group('version'), root)
    )
    print(
        'Installed on %s'
        % datetime.fromtimestamp(int(output.group('install_time')))
    )
    command = 'sudo %s uninstall' % os.path.abspath(__file__)
    print('To uninstall run the command:')
    print(command)
    return 0


def _is_installed():
    try:
        result = run('pkgutil --pkg-info %s /' % _PKG_ID, echo=False)
    except BadRCError:
        return False
    return True


def _warn_missing_arg(print_help):
    # wrap `parser.print_help()` to return 1 so any callers don't receive
    # a potentially misleading 0 exit code from a failed call.
    def missing_arg_warning():
        print(
            'Missing input: script requires at least one positional argument\n'
        )
        print_help()
        return 1

    return missing_arg_warning


def main():
    parser = argparse.ArgumentParser(usage=__doc__)
    subparsers = parser.add_subparsers()
    check_parser = subparsers.add_parser(
        'check',
        help=(
            'Check if the AWS CLI is currently installed from a PKG '
            'installer.'
        ),
    )
    check_parser.set_defaults(func=check)
    uninstall_parser = subparsers.add_parser(
        'uninstall', help='Uninstall the AWS CLI installed from the Mac PKG'
    )
    uninstall_parser.set_defaults(func=uninstall)

    # default to help string if no args are passed
    parser.set_defaults(func=_warn_missing_arg(parser.print_help))

    args = parser.parse_args()
    return args.func()


if __name__ == '__main__':
    try:
        sys.exit(main())
    except AssertionError as e:
        print(e)
        sys.exit(1)