forked from nedbat/odds
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathset_env.py
More file actions
executable file
·150 lines (134 loc) · 4.12 KB
/
set_env.py
File metadata and controls
executable file
·150 lines (134 loc) · 4.12 KB
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
#!/usr/bin/env python3
#
# Run this like:
#
# $ $(set_env.py FILE-GLOB ...)
#
# It looks through the specificed files for lines like this:
#
# # $set_env.py: ENVVAR_NAME - Description of the environment variable.
#
# and prompts for values. You can review, change, or delete values.
#
# Because it changes environment variables, you must run it inside $() as
# shown. This is handy in your shell startup file:
#
# alias set_env='$(set_env.py $(git ls-files))'
import contextlib
import glob
import os
import re
import sys
SETTINGS = []
def find_settings(args):
args = args or ["*.py", "**/*.py"]
line_pattern = r"\$set_env.py: (\w+) - (.*)"
settings = set()
filenames = [fname for glb in args for fname in glob.glob(glb, recursive=True)]
for filename in filenames:
with open(filename) as f:
try:
for line in f:
m = re.search(line_pattern, line)
if m:
settings.add(m.groups())
except UnicodeDecodeError:
# Probably wasn't a text file, ignore it.
pass
print(f"Read {len(filenames)} files")
global SETTINGS
SETTINGS = sorted(settings)
def read_them():
values = {}
for name, _ in SETTINGS:
values[name] = os.environ.get(name)
return values
def show_them(values):
for i, (name, description) in enumerate(SETTINGS, start=1):
value = values[name]
if value is None:
eq = ' '
value = ''
else:
eq = '='
value = repr(value)
print("{:2d}: {:>30s} {} {:12s} {}".format(i, name, eq, value, description))
def get_by_num(values, n):
setting_name = SETTINGS[int(n)-1][0]
return values[setting_name]
def set_by_num(values, n, value):
setting_name = SETTINGS[int(n)-1][0]
values[setting_name] = value
PROMPT = "## [value] | w fname | ? | q > "
HELP = """\
Commands:
"##" means a number of an environment variable, from 1 to {maxnum}.
## value - Give a value to a variable
## - Toggle a variable between empty and '1'
w fname - Write the values to a source-able file
? - Show this help
q - Quit
"""
def get_new_values(values):
show = True
while True:
if show:
show_them(values)
show = False
print("")
print(PROMPT, end='')
sys.stderr.flush()
try:
cmd = input("").strip().split()
except EOFError:
print("\n")
break
if not cmd:
continue
elif cmd[0] == 'w':
fname = cmd[1]
with open(fname, "w") as out:
for line in as_exports(values):
print(line, file=out)
elif cmd[0] == 'q':
break
elif cmd[0] == '?':
print(HELP.format(maxnum=len(SETTINGS)))
else:
try:
num = int(cmd[0])
except ValueError:
print("Don't understand option {!r}".format(cmd[0]))
continue
else:
if len(cmd) >= 2:
set_by_num(values, num, " ".join(cmd[1:]))
else:
if get_by_num(values, num):
value = None
else:
value = '1'
set_by_num(values, num, value)
show = True
return values
def as_exports(values):
exports = []
for name, value in values.items():
if value is None:
exports.append("typeset +x {}".format(name))
else:
exports.append("export {}={!r}".format(name, value))
return exports
def main(args):
# All output has to go to stderr. Stdout will be executed.
with contextlib.redirect_stdout(sys.stderr):
find_settings(args)
values = read_them()
if values:
values = get_new_values(values)
else:
print("No settings found!")
if values:
print("eval " + "; ".join(as_exports(values)))
if __name__ == '__main__':
main(sys.argv[1:])