-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaddToPath
executable file
·214 lines (167 loc) · 6.57 KB
/
addToPath
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/usr/bin/env python3
#
# addToPath: Add a dir to a $PATH-like variable and display it.
# 2020-02-11: Ported from my earlier Perl. Copyright by Steven J. DeRose.
#
import sys
import os
import argparse
import re
__metadata__ = {
"title" : "addToPath",
"description" : "Add a dir to a $PATH-like variable and display it.",
"rightsHolder" : "Steven J. DeRose",
"creator" : "http://viaf.org/viaf/50334488",
"type" : "http://purl.org/dc/dcmitype/Software",
"language" : "Python 3.7",
"created" : "2020-02-11",
"modified" : "2021-11-11",
"publisher" : "http://github.com/sderose",
"license" : "https://creativecommons.org/licenses/by-sa/3.0/"
}
__version__ = __metadata__['modified']
descr = """
=Description=
Add the given path(s) to the end (or start) of the PATH environment variable
(or any other string), and return the resulting string.
Recursive adds are also available.
Will not add a directory if it's already there, or does not exist.
With ''-v'' or ''-p'', prints the full resulting path, one directory per line.
With ''-q'' or ''-p'', does ''not'' print the resulting path as ready to
assign to an environment variable such as $PATH.
Thus, you can use ''-p'' (and give no new directories to add)
just to see the current path, one directory per line.
Or you can use ''-v -q'' to get the same display while also checking for errors.
=Usage=
PATH=`addPath PATH [dir1, dir2, ...]`
==Warning==
To actually get PATH changed you need to do the assignment -- the script can't
do it itself. The easiest way is probably with `` as shown.
This is because a script can't change environment variables for the shell from
which it was invoked -- that's no longer the current environment once it's running.
=Related commands=
My `BashSetup/path_utils` defines several shell functions for manipulating
paths and $PATH-like variables.
=Known bugs and Limitations=
''-v'' reports errors in the prior/original path, but does not fix them.
Duplicate-entry reporting only does simplistic comparison of path strings.
A recursive add that only adds directories if they contain at least one executable
file might be a nice addition.
=History=
2020-02-11: Ported from earlier Perl version by Steven J. DeRose.
The prior version did not have ''--recursive'', ''--normalize'',
''--absolutize'', ''--delim'', ''--prefix'', etc.
2021-11-11: Fix warnings to actually appear.
=Rights=
Copyright 2020-02-11 by Steven J. DeRose. This work is licensed under a
Creative Commons Attribution-Share-alike 3.0 unported license.
See http://creativecommons.org/licenses/by-sa/3.0/ for more information.
For the most recent version, see L<http://www.derose.net/steve/utilities/>
or L<http://github.com/sderose>.
=Options=
"""
def warning(lvl:int, msg:str) -> None:
if (args.verbose >= lvl): sys.stderr.write(msg+"\n")
def checkPath(p):
"""Test a directory for bad conditions.
"""
ok = True
if (not os.path.isdir(p)):
warning(0, "dir does not exist: %s" % (p))
ok = False
if (p in pathIndex):
warning(0, "Duplicate dir: %s" % (p))
ok = False
# Following can be absolutized away
if (re.search(r'\.\./', p)):
warning(0, "dir contains '../': %s" % (p))
ok = False
if (re.search(r'\b\./', p)):
warning(0, "dir contains './': %s" % (p))
ok = False
return ok
###############################################################################
# Main
#
def processOptions():
try:
from BlockFormatter import BlockFormatter
parser = argparse.ArgumentParser(
description=descr, formatter_class=BlockFormatter)
except ImportError:
parser = argparse.ArgumentParser(description=descr)
parser.add_argument(
"--absolutize", action='store_true',
help="""Expand old and new entries to absolute paths. This is more
aggressive than --normalize.""")
parser.add_argument(
"--delim", type=str, default=':',
help='Character to split on. Default: colon (:).')
parser.add_argument(
"--normalize", action='store_true',
help="""Normalize paths to remove redundant or up-level parts (like ../).
On Windows, this also changes slash to backslash.""")
parser.add_argument(
"--pathString", type=str, default=os.environ['PATH'],
help='Use this string instead of the value of $PATH.')
parser.add_argument(
"--printList", "-p", action='store_true',
help='Print the dirs one per line, but not the packed list.')
parser.add_argument(
"--prefix", action='store_true',
help='Add new entries to the beginning instead of the end.')
parser.add_argument(
"--quiet", "-q", action='store_true',
help='Do not print the final result.')
parser.add_argument(
"--recursive", action='store_true',
help='Also add subdirectories of the given dir.')
parser.add_argument(
"--verbose", "-v", action='count', default=0,
help='Add more messages (repeatable).')
parser.add_argument(
"--version", action='version', version=__version__,
help='Display version information, then exit.')
parser.add_argument(
'dirs', type=str, nargs=argparse.REMAINDER,
help='Path(s) to input file(s)')
args0 = parser.parse_args()
return(args0)
###############################################################################
#
args = processOptions()
pathEntries = args.pathString.split(args.delim)
original_count = len(pathEntries)
# Check and index current entries
pathIndex = {}
for p1 in pathEntries:
if (args.absolutize): p2 = os.path.abspath(p1)
if (args.normalize): p2 = os.path.normpath(p1)
else: p2 = p1
checkPath(p2)
pathIndex[p2] = True
if (args.recursive):
subs = []
for dirpath, dirnames, filenames in os.walk(p2):
for dirname in dirnames:
subs.append(os.path.join(dirpath, dirname))
args.dirs.extend(subs)
# Add new entry(s)
for p1 in args.dirs:
p2 = p1
if (args.absolutize): p2 = os.path.abspath(p2)
if (args.normalize): p2 = os.path.normpath(p2)
rc = checkPath(p2)
if (not rc): continue
if (args.prefix): pathEntries.insert(0, p2)
else: pathEntries.append(p2)
pathIndex[p2] = True
final_count = len(pathEntries)
result = ":".join(pathEntries)
if (args.verbose or args.printList):
sys.stderr.write(re.sub(r':', "\n ", result) + "\n")
if (args.verbose):
print("Original had %d entries, final had %d." %
(original_count, final_count))
if (not args.quiet and not args.printList):
print(result)