File: setting_util.py

package info (click to toggle)
i3pystatus 3.35%2Bgit20190107.1c972b8-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 1,124 kB
  • sloc: python: 12,177; makefile: 146; sh: 14
file content (136 lines) | stat: -rwxr-xr-x 4,382 bytes parent folder | download | duplicates (4)
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
#!/usr/bin/env python
import glob
import inspect
import os
import getpass
import sys
import signal
import pkgutil
from collections import defaultdict, OrderedDict

import keyring

import i3pystatus
from i3pystatus import Module, SettingsBase
from i3pystatus.core import ClassFinder
from i3pystatus.core.exceptions import ConfigInvalidModuleError


def signal_handler(signal, frame):
    sys.exit(0)


def get_int_in_range(prompt, _range):
    while True:
        try:
            answer = input(prompt)
        except EOFError:
            print()
            sys.exit(0)
        try:
            n = int(answer.strip())
            if n in _range:
                return n
            else:
                print("Value out of range!")
        except ValueError:
            print("Invalid input!")


def enumerate_choices(choices):
    lines = []
    for index, choice in enumerate(choices, start=1):
        lines.append(" %d - %s\n" % (index, choice))
    return "".join(lines)


def get_modules():
    for importer, modname, ispkg in pkgutil.iter_modules(i3pystatus.__path__):
        if modname not in ["core", "tools"]:
            yield modname


def get_credential_modules():
    verbose = "-v" in sys.argv

    protected_settings = SettingsBase._SettingsBase__PROTECTED_SETTINGS
    class_finder = ClassFinder(Module)
    credential_modules = defaultdict(dict)
    for module_name in get_modules():
        try:
            module = class_finder.get_module(module_name)
            clazz = class_finder.get_class(module)
        except (ImportError, ConfigInvalidModuleError):
            if verbose:
                print("ImportError while importing", module_name)
            continue

        members = [m[0] for m in inspect.getmembers(clazz) if not m[0].startswith('_')]
        if any([hasattr(clazz, setting) for setting in protected_settings]):
            credential_modules[clazz.__name__]['credentials'] = list(set(protected_settings) & set(members))
            credential_modules[clazz.__name__]['key'] = "%s.%s" % (clazz.__module__, clazz.__name__)
        elif hasattr(clazz, 'required'):
            protected = []
            required = getattr(clazz, 'required')
            for setting in protected_settings:
                if setting in required:
                    protected.append(setting)
            if protected:
                credential_modules[clazz.__name__]['credentials'] = protected
                credential_modules[clazz.__name__]['key'] = "%s.%s" % (clazz.__module__, clazz.__name__)
    return credential_modules


def main():
    signal.signal(signal.SIGINT, signal_handler)

    print("""%s - part of i3pystatus
This allows you to edit keyring-protected settings of
i3pystatus modules, which are stored globally (independent
of your i3pystatus configuration) in your keyring.

Options:
    -l: list all stored settings (no values are printed)
    -v: print informational messages
""" % os.path.basename(sys.argv[0]))

    credential_modules = get_credential_modules()

    if "-l" in sys.argv:
        for name, module in credential_modules.items():
            print(name)
            for credential in module['credentials']:
                if keyring.get_password("%s.%s" % (module['key'], credential), getpass.getuser()):
                    print(" - %s: set" % credential)
                else:
                    print(" - %s: unset" % credential)
        return

    choices = list(credential_modules.keys())
    prompt = "Choose a module to edit:\n"
    prompt += enumerate_choices(choices)
    prompt += "> "

    index = get_int_in_range(prompt, range(1, len(choices) + 1))
    module_name = choices[index - 1]
    module = credential_modules[module_name]

    prompt = "Choose setting of %s to edit:\n" % module_name
    prompt += enumerate_choices(module["credentials"])
    prompt += "> "

    choices = module['credentials']
    index = get_int_in_range(prompt, range(1, len(choices) + 1))
    setting = choices[index - 1]

    answer = getpass.getpass("Enter value for %s:\n> " % setting)
    answer2 = getpass.getpass("Re-enter value\n> ")
    if answer == answer2:
        key = "%s.%s" % (module['key'], setting)
        keyring.set_password(key, getpass.getuser(), answer)
        print("%s set!" % setting)
    else:
        print("Values don't match - nothing set.")

if __name__ == "__main__":
    main()