cmdpackage 0.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cmdpackage-0.1.3.dist-info/METADATA +211 -0
- cmdpackage-0.1.3.dist-info/RECORD +17 -0
- cmdpackage-0.1.3.dist-info/WHEEL +5 -0
- cmdpackage-0.1.3.dist-info/entry_points.txt +2 -0
- cmdpackage-0.1.3.dist-info/licenses/LICENSE +21 -0
- cmdpackage-0.1.3.dist-info/top_level.txt +1 -0
- src/__init__.py +73 -0
- src/defs/__init__.py +0 -0
- src/defs/createzVirtualEnv.py +27 -0
- src/defs/runSubProc.py +10 -0
- src/defs/writeCLIPackage.py +98 -0
- src/defs/writePyProject.py +140 -0
- src/defs/writeSetup.py +124 -0
- src/templates/__init__.py +0 -0
- src/templates/cmdTemplate.py +772 -0
- src/templates/pyprojectTemplate.py +114 -0
- src/templates/setupTemplates.py +113 -0
@@ -0,0 +1,772 @@
|
|
1
|
+
#!/usr/bin/python
|
2
|
+
from string import Template
|
3
|
+
from textwrap import dedent
|
4
|
+
|
5
|
+
initFile = dedent("""import sys, os
|
6
|
+
from .classes.argParse import ArgParse
|
7
|
+
from .commands.cmdSwitchbord import cmdSwitchbord
|
8
|
+
|
9
|
+
def main():
|
10
|
+
#packName = os.path.basename(sys.argv[0])
|
11
|
+
argParse = ArgParse()
|
12
|
+
cmdSwitchbord(argParse)
|
13
|
+
|
14
|
+
if __name__ == '__main__':
|
15
|
+
main()
|
16
|
+
""")
|
17
|
+
cmdSwitchbordFileStr = dedent("""import sys, traceback
|
18
|
+
from argparse import Namespace
|
19
|
+
from ..defs.logIt import printIt, lable
|
20
|
+
from .commands import Commands
|
21
|
+
from .cmdOptSwitchbord import cmdOptSwitchbord
|
22
|
+
from ..classes.argParse import ArgParse
|
23
|
+
|
24
|
+
cmdObj = Commands()
|
25
|
+
commands = cmdObj.commands
|
26
|
+
switchFlags = cmdObj.switchFlags["switcheFlags"]
|
27
|
+
|
28
|
+
def cmdSwitchbord(argParse: ArgParse):
|
29
|
+
global commands
|
30
|
+
theCmd = 'notSet'
|
31
|
+
try:
|
32
|
+
if len(sys.argv) > 1:
|
33
|
+
if len(sys.argv) > 2:
|
34
|
+
switchFlagChk = sys.argv[2]
|
35
|
+
if len(sys.argv) == 3 and switchFlagChk[0] in '-+?':
|
36
|
+
if switchFlagChk[1:] in switchFlags.keys():
|
37
|
+
print(f'00001: {switchFlagChk}')
|
38
|
+
cmdOptSwitchbord(switchFlagChk, switchFlags)
|
39
|
+
else:
|
40
|
+
if switchFlagChk not in ["-h", "--help"]:
|
41
|
+
printIt(f'{switchFlagChk} not defined',lable.WARN)
|
42
|
+
else:
|
43
|
+
argParse.parser.print_help()
|
44
|
+
exit()
|
45
|
+
args: Namespace = argParse.args
|
46
|
+
theCmd = args.commands[0]
|
47
|
+
if theCmd in commands.keys():
|
48
|
+
exec(f'from ..commands.{theCmd} import {theCmd}')
|
49
|
+
exec(f'{theCmd}(argParse)')
|
50
|
+
else:
|
51
|
+
print(args)
|
52
|
+
printIt(f'Command "{theCmd}" not present.\\n',lable.ERROR)
|
53
|
+
argParse.parser.print_help()
|
54
|
+
else:
|
55
|
+
argParse.parser.print_help()
|
56
|
+
except Exception as e:
|
57
|
+
tb_str = ''.join(traceback.format_exception(None, e, e.__traceback__))
|
58
|
+
printIt(f'{theCmd}\\n{tb_str}', lable.ERROR)
|
59
|
+
exit()
|
60
|
+
""")
|
61
|
+
cmdOptSwitchbordFileStr = dedent("""from ..classes.optSwitches import OptSwitches
|
62
|
+
|
63
|
+
def cmdOptSwitchbord(switchFlag: str, switchFlags: str):
|
64
|
+
optSwitches = OptSwitches(switchFlags)
|
65
|
+
optSwitches.toggleSwitchFlag(switchFlag)
|
66
|
+
""")
|
67
|
+
newCmdTemplateStr = """from ..defs.logIt import printIt, lable, cStr, color
|
68
|
+
from .commands import Commands
|
69
|
+
|
70
|
+
cmdObj = Commands()
|
71
|
+
commands = cmdObj.commands
|
72
|
+
|
73
|
+
def ${defName}(argParse):
|
74
|
+
global commands
|
75
|
+
args = argParse.args
|
76
|
+
theCmd = args.commands[0]
|
77
|
+
theArgNames = list(commands[theCmd].keys())
|
78
|
+
theArgs = args.arguments
|
79
|
+
argIndex = 0
|
80
|
+
intOnly = True
|
81
|
+
printIt("Modify default behavour in ${packName}/commands/${defName}.py", lable.DEBUG)
|
82
|
+
# delete place holder code bellow that loops though arguments provided
|
83
|
+
# when this command is called when not needed.
|
84
|
+
# Note: that function having a name that is entered as an argument part
|
85
|
+
# of this code and is called using the built in exec function. while argIndex < len(theArgs):
|
86
|
+
while argIndex < len(theArgs):
|
87
|
+
anArg = theArgs[argIndex]
|
88
|
+
if anArg in commands[theCmd]:
|
89
|
+
intOnly = False
|
90
|
+
exec(f"{anArg}(argParse)")
|
91
|
+
elif intOnly: # starts out with intergr
|
92
|
+
printIt(f"{theArgNames[argIndex+1]}: {anArg}",lable.INFO)
|
93
|
+
argIndex += 1
|
94
|
+
if len(theArgs) == 0:
|
95
|
+
printIt("no argument(s) entered", lable.INFO)
|
96
|
+
|
97
|
+
"""
|
98
|
+
argDefTemplateStr = dedent("""def ${argName}(argParse):
|
99
|
+
args = argParse.args
|
100
|
+
printIt(args, lable.INFO)
|
101
|
+
|
102
|
+
""")
|
103
|
+
newCmdStr = dedent("""import os, sys, copy
|
104
|
+
from ..defs.logIt import printIt, lable
|
105
|
+
from ..classes.argParse import ArgParse
|
106
|
+
from .commands import Commands, cmdDescriptionTagStr
|
107
|
+
from .templates.newCmd import cmdDefTemplate, argDefTemplate
|
108
|
+
import readline
|
109
|
+
readline.parse_and_bind('tab: compleat')
|
110
|
+
readline.parse_and_bind('set editing-mode vi')
|
111
|
+
|
112
|
+
def newCmd(argParse: ArgParse):
|
113
|
+
args = argParse.args
|
114
|
+
#cmd = args.commands
|
115
|
+
cmdObj = Commands()
|
116
|
+
argsDict = args.arguments
|
117
|
+
newCmdName = args.arguments[0]
|
118
|
+
if newCmdName not in cmdObj.commands.keys():
|
119
|
+
theArgs = verifyArgsWithDiscriptions(cmdObj, argsDict)
|
120
|
+
updateCMDJson(cmdObj, theArgs)
|
121
|
+
writeCodeFile(theArgs)
|
122
|
+
printIt(f'"{newCmdName}" added.',lable.NewCmd)
|
123
|
+
else:
|
124
|
+
printIt(f'"{newCmdName}" exists. use modCmd or rmCmd to modiify or remove this command.',lable.INFO)
|
125
|
+
|
126
|
+
def verifyArgsWithDiscriptions(cmdObj: Commands, theArgs) -> dict:
|
127
|
+
rtnDict = {}
|
128
|
+
argIndex = 0
|
129
|
+
cmdName = theArgs[argIndex]
|
130
|
+
while argIndex < len(theArgs):
|
131
|
+
argName = theArgs[argIndex]
|
132
|
+
if argName[0] == '-':
|
133
|
+
if len(argName) >= 2:
|
134
|
+
if argName[2] == '-':
|
135
|
+
printIt("Only single hyphen options allowed.",lable.WARN)
|
136
|
+
exit(0)
|
137
|
+
else:
|
138
|
+
theDisc = input(f'Enter help description for {argName}:\\n')
|
139
|
+
if theDisc == '': theDisc = f'no help for {argName}'
|
140
|
+
else:
|
141
|
+
printIt("Missing ascii letters after hyphen.",lable.WARN)
|
142
|
+
exit(0)
|
143
|
+
else:
|
144
|
+
theDisc = input(f'Enter help description for {argName}:\\n')
|
145
|
+
if theDisc == '': theDisc = f'no help for {argName}'
|
146
|
+
rtnDict[argName] = theDisc
|
147
|
+
argIndex += 1
|
148
|
+
return rtnDict
|
149
|
+
|
150
|
+
def writeCodeFile(theArgs: dict) -> str:
|
151
|
+
fileDir = os.path.dirname(__file__)
|
152
|
+
fileName = os.path.join(fileDir, f'{list(theArgs.keys())[0]}.py')
|
153
|
+
if os.path.isfile(fileName):
|
154
|
+
rtnStr = lable.EXISTS
|
155
|
+
else:
|
156
|
+
ourStr = cmdCodeBlock(theArgs)
|
157
|
+
with open(fileName, 'w') as fw:
|
158
|
+
fw.write(ourStr)
|
159
|
+
rtnStr = lable.SAVED
|
160
|
+
return rtnStr
|
161
|
+
|
162
|
+
def cmdCodeBlock(theArgs: dict) -> str:
|
163
|
+
packName = os.path.basename(sys.argv[0])
|
164
|
+
argNames = list(theArgs.keys())
|
165
|
+
cmdName = argNames[0]
|
166
|
+
defTemp = cmdDefTemplate
|
167
|
+
argTemp = argDefTemplate
|
168
|
+
rtnStr = defTemp.substitute(
|
169
|
+
packName=packName, defName=cmdName,
|
170
|
+
)
|
171
|
+
argIndex = 1
|
172
|
+
while argIndex < len(argNames): # add subarg functions
|
173
|
+
argName = argNames[argIndex]
|
174
|
+
rtnStr += argTemp.substitute(argName=argName)
|
175
|
+
argIndex += 1
|
176
|
+
return rtnStr
|
177
|
+
|
178
|
+
def updateCMDJson(cmdObj: Commands, theArgs: dict) -> None:
|
179
|
+
commands = copy.deepcopy(cmdObj.commands)
|
180
|
+
argNames = list(theArgs.keys())
|
181
|
+
defName = argNames[0]
|
182
|
+
defDiscription = theArgs[argNames[0]]
|
183
|
+
commands[defName] = {}
|
184
|
+
commands[defName][f'{defName}{cmdDescriptionTagStr}'] = defDiscription
|
185
|
+
argIndex = 1
|
186
|
+
while argIndex < len(theArgs): # add subarg functions
|
187
|
+
argName = argNames[argIndex]
|
188
|
+
commands[defName][argName] = theArgs[argName]
|
189
|
+
argIndex += 1
|
190
|
+
cmdObj.commands = commands
|
191
|
+
""")
|
192
|
+
modCmdStr = dedent("""import os, copy
|
193
|
+
from ..defs.logIt import printIt, lable
|
194
|
+
from ..classes.argParse import ArgParse
|
195
|
+
from .commands import Commands, cmdDescriptionTagStr
|
196
|
+
from .templates.newCmd import cmdDefTemplate, argDefTemplate
|
197
|
+
import readline
|
198
|
+
readline.parse_and_bind('tab: compleat')
|
199
|
+
readline.parse_and_bind('set editing-mode vi')
|
200
|
+
|
201
|
+
cmdObj = Commands()
|
202
|
+
commands = cmdObj.commands
|
203
|
+
|
204
|
+
def modCmd(argParse: ArgParse):
|
205
|
+
args = argParse.args
|
206
|
+
#cmd = args.commands
|
207
|
+
cmdObj = Commands()
|
208
|
+
modCmdName = args.arguments[0]
|
209
|
+
if modCmdName in cmdObj.commands.keys():
|
210
|
+
theArgs = verifyArgsWithDiscriptions(cmdObj, args.arguments)
|
211
|
+
if len(theArgs.keys()) > 0:
|
212
|
+
updateCMDJson(cmdObj, modCmdName, theArgs)
|
213
|
+
printIt(f'"{modCmdName}" modified.',lable.ModCmd)
|
214
|
+
else:
|
215
|
+
printIt(f'"{modCmdName}" unchanged.',lable.INFO)
|
216
|
+
else:
|
217
|
+
printIt(f'"{modCmdName}" does not exists. use newCmd or add it.',lable.INFO)
|
218
|
+
|
219
|
+
def verifyArgsWithDiscriptions(cmdObj: Commands, theArgs) -> dict:
|
220
|
+
rtnDict = {}
|
221
|
+
argIndex = 0
|
222
|
+
cmdName = theArgs[argIndex]
|
223
|
+
while argIndex < len(theArgs):
|
224
|
+
argName = theArgs[argIndex]
|
225
|
+
if argName[0] == '-':
|
226
|
+
if len(argName) >= 2:
|
227
|
+
if argName[2] == '-':
|
228
|
+
printIt("Only single hyphen options allowed.",lable.WARN)
|
229
|
+
exit(0)
|
230
|
+
else:
|
231
|
+
theDisc = input(f'Enter help description for {argName}:\\n')
|
232
|
+
if theDisc == '': theDisc = f'no help for {argName}'
|
233
|
+
else:
|
234
|
+
printIt("Missing ascii letters after hyphen.",lable.WARN)
|
235
|
+
exit(0)
|
236
|
+
else:
|
237
|
+
theDisc = ''
|
238
|
+
saveDisc = False
|
239
|
+
if argIndex == 0 and len(theArgs) == 1:
|
240
|
+
chgDisc = input(f'Replace description for {argName} (y/N): ')
|
241
|
+
if chgDisc.lower() == 'y':
|
242
|
+
saveDisc = True
|
243
|
+
elif argIndex > 0:
|
244
|
+
if argName in cmdObj.commands[cmdName].keys():
|
245
|
+
chgDisc = input(f'Replace description for {argName} (y/N): ')
|
246
|
+
if chgDisc.lower() == 'y':
|
247
|
+
saveDisc = True
|
248
|
+
else: # add new arg
|
249
|
+
saveDisc = True
|
250
|
+
newArg = True
|
251
|
+
if saveDisc:
|
252
|
+
theDisc = input(f'Enter help description for {argName}:\\n')
|
253
|
+
if theDisc == '': theDisc = f'no help for {argName}'
|
254
|
+
if saveDisc:
|
255
|
+
# only poulate rtnDict with modified discriptions
|
256
|
+
rtnDict[argName] = theDisc
|
257
|
+
argIndex += 1
|
258
|
+
return rtnDict
|
259
|
+
|
260
|
+
def writeCodeFile(theArgs: dict) -> str:
|
261
|
+
fileDir = os.path.dirname(__file__)
|
262
|
+
fileName = os.path.join(fileDir, f'{list(theArgs.keys())[0]}.py')
|
263
|
+
if os.path.isfile(fileName):
|
264
|
+
rtnStr = lable.EXISTS
|
265
|
+
else:
|
266
|
+
ourStr = cmdCodeBlock(theArgs)
|
267
|
+
with open(fileName, 'w') as fw:
|
268
|
+
fw.write(ourStr)
|
269
|
+
rtnStr = lable.SAVED
|
270
|
+
return rtnStr
|
271
|
+
|
272
|
+
def cmdCodeBlock(theArgs: dict) -> str:
|
273
|
+
argNames = list(theArgs.keys())
|
274
|
+
defName = argNames[0]
|
275
|
+
defTemp = cmdDefTemplate
|
276
|
+
argTemp = argDefTemplate
|
277
|
+
rtnStr = defTemp.substitute(
|
278
|
+
defName=defName
|
279
|
+
)
|
280
|
+
argIndex = 1
|
281
|
+
while argIndex < len(argNames): # add subarg functions
|
282
|
+
argName = argNames[argIndex]
|
283
|
+
rtnStr += argTemp.substitute(argName=theArgs[argName])
|
284
|
+
argIndex += 1
|
285
|
+
return rtnStr
|
286
|
+
|
287
|
+
def updateCMDJson(cmdObj: Commands, modCmdName: str, theArgs: dict) -> None:
|
288
|
+
commands = copy.deepcopy(cmdObj.commands)
|
289
|
+
argNames = list(theArgs.keys())
|
290
|
+
if modCmdName in argNames:
|
291
|
+
commands[modCmdName][f'{modCmdName}{cmdDescriptionTagStr}'] = theArgs[modCmdName]
|
292
|
+
argIndex = 1
|
293
|
+
else: argIndex = 0
|
294
|
+
while argIndex < len(theArgs): # add subarg functions
|
295
|
+
argName = argNames[argIndex]
|
296
|
+
commands[modCmdName][argName] = theArgs[argName]
|
297
|
+
argIndex += 1
|
298
|
+
cmdObj.commands = commands
|
299
|
+
""")
|
300
|
+
rmCmdStr = dedent("""import os, json
|
301
|
+
from ..defs.logIt import printIt, lable, cStr, color
|
302
|
+
from .commands import Commands
|
303
|
+
|
304
|
+
cmdObj = Commands()
|
305
|
+
commands = cmdObj.commands
|
306
|
+
theDir = os.path.dirname(os.path.realpath(__file__))
|
307
|
+
jsonFileName = os.path.join(theDir,'commands.json')
|
308
|
+
|
309
|
+
def rmCmd(argParse):
|
310
|
+
global commands
|
311
|
+
args = argParse.args
|
312
|
+
theArgs = args.arguments
|
313
|
+
argIndex = 0
|
314
|
+
cmdName = theArgs[argIndex]
|
315
|
+
while argIndex < len(theArgs):
|
316
|
+
anArg = theArgs[argIndex]
|
317
|
+
if anArg in commands and len(theArgs) == 1:
|
318
|
+
if anArg == cmdName:
|
319
|
+
if anArg in ["newCmd", "modCmd", "rmCmd"]:
|
320
|
+
printIt(f'Permission denied for "{anArg}".',lable.WARN)
|
321
|
+
exit(0)
|
322
|
+
chkRm: str = input(f"Perminantly delete {anArg} (y/N): ")
|
323
|
+
if chkRm == '': chkRm = 'N'
|
324
|
+
if chkRm.lower() == 'y':
|
325
|
+
removeCmd(anArg)
|
326
|
+
else:
|
327
|
+
printIt(f'Command "{anArg}" must be removed seperataly from "{cmdName}".',lable.WARN)
|
328
|
+
elif cmdName in commands:
|
329
|
+
if anArg in commands[cmdName]:
|
330
|
+
chkRm: str = input(f"Perminantly delete {anArg} (y/N): ")
|
331
|
+
if chkRm == '': chkRm = 'N'
|
332
|
+
if chkRm.lower() == 'y':
|
333
|
+
removeCmdArg(cmdName, anArg)
|
334
|
+
else:
|
335
|
+
printIt(f'"{cmdName}" is not currently a Command.',lable.WARN)
|
336
|
+
argIndex = len(theArgs)
|
337
|
+
argIndex += 1
|
338
|
+
|
339
|
+
def removeCmdArg(cmdName, argName):
|
340
|
+
global jsonFileName
|
341
|
+
with open(jsonFileName, 'r') as rf:
|
342
|
+
theJson = json.load(rf)
|
343
|
+
del theJson[cmdName][argName]
|
344
|
+
with open(jsonFileName, 'w') as wf:
|
345
|
+
json.dump(theJson, wf, indent=2)
|
346
|
+
printIt(argName,lable.RmArg)
|
347
|
+
|
348
|
+
def removeCmd(cmdName):
|
349
|
+
global jsonFileName
|
350
|
+
with open(jsonFileName, 'r') as rf:
|
351
|
+
theJson = json.load(rf)
|
352
|
+
del theJson[cmdName]
|
353
|
+
with open(jsonFileName, 'w') as wf:
|
354
|
+
json.dump(theJson, wf, indent=2)
|
355
|
+
pyFileName = f'{cmdName}.py'
|
356
|
+
pyFileName = os.path.join(theDir, pyFileName)
|
357
|
+
if os.path.isfile(pyFileName):
|
358
|
+
os.remove(pyFileName)
|
359
|
+
printIt(cmdName,lable.RmCmd)
|
360
|
+
""")
|
361
|
+
commandsJsonDict = {
|
362
|
+
"switcheFlags": {},
|
363
|
+
"newCmd": {
|
364
|
+
"newCmd_description": "Add new command <cmdName> with [argNames...]. Also creates a file cmdName.py.",
|
365
|
+
"cmdName": "Name of new command",
|
366
|
+
"argName": "(argName...), Optional names of argument to associate with the new command."
|
367
|
+
},
|
368
|
+
"modCmd": {
|
369
|
+
"modCmd_description": "Modify a command or argument discriptions, or add another argument for command. The cmdName.py file will not be modified.",
|
370
|
+
"cmdName": "Name of command being modified",
|
371
|
+
"argName": "(argName...) Optional names of argument(s) to modify."
|
372
|
+
},
|
373
|
+
"rmCmd": {
|
374
|
+
"rmCmd_description": "Remove <cmdName> and delete file cmdName.py, or remove an argument for a command.",
|
375
|
+
"cmdName": "Name of command to remove, cmdName.py and other commands listed as argument(s) will be delated.",
|
376
|
+
"argName": "Optional names of argument to remove.v It is and I am both pi."
|
377
|
+
}
|
378
|
+
}
|
379
|
+
commandsFileStr = dedent("""import json, os
|
380
|
+
from copy import copy
|
381
|
+
import inspect
|
382
|
+
|
383
|
+
cmdDescriptionTagStr = "_description"
|
384
|
+
|
385
|
+
class Commands(object):
|
386
|
+
def __init__(self) -> None:
|
387
|
+
self.cmdFileDir = os.path.dirname(inspect.getfile(self.__class__))
|
388
|
+
self.cmdFileName = os.path.join(self.cmdFileDir, "commands.json" )
|
389
|
+
with open(self.cmdFileName, "r") as fr:
|
390
|
+
rawJson = json.load(fr)
|
391
|
+
self._switchFlags = {}
|
392
|
+
try:
|
393
|
+
self._switchFlags["switcheFlags"] = copy(rawJson["switcheFlags"])
|
394
|
+
del rawJson["switcheFlags"]
|
395
|
+
except: self._switchFlags["switcheFlags"] = {}
|
396
|
+
self._commands = rawJson
|
397
|
+
self.checkForUpdates()
|
398
|
+
|
399
|
+
@property
|
400
|
+
def commands(self):
|
401
|
+
return self._commands
|
402
|
+
|
403
|
+
@commands.setter
|
404
|
+
def commands(self, aDict: dict):
|
405
|
+
self._commands = aDict
|
406
|
+
self._writeCmdJsonFile()
|
407
|
+
|
408
|
+
@property
|
409
|
+
def switchFlags(self):
|
410
|
+
return self._switchFlags
|
411
|
+
|
412
|
+
@switchFlags.setter
|
413
|
+
def switchFlags(self, aDict: dict):
|
414
|
+
self._switchFlags = aDict
|
415
|
+
self._writeCmdJsonFile()
|
416
|
+
|
417
|
+
def _writeCmdJsonFile(self):
|
418
|
+
# outJson = copy(self._switchFlags)
|
419
|
+
# outJson.update(self._commands)
|
420
|
+
outJson = self._switchFlags | self._commands
|
421
|
+
with open(self.cmdFileName, "w") as fw:
|
422
|
+
json.dump(outJson, fw, indent=2)
|
423
|
+
|
424
|
+
def checkForUpdates(self):
|
425
|
+
dirList = os.listdir(self.cmdFileDir)
|
426
|
+
for aFile in dirList:
|
427
|
+
if aFile[:-2] == "py":
|
428
|
+
chkName = aFile[:-3]
|
429
|
+
if chkName not in self.commands and chkName != "commands":
|
430
|
+
self.commands[chkName] = [" - No argument"]
|
431
|
+
""")
|
432
|
+
optSwitchesTemplate = Template(dedent("""import json
|
433
|
+
from pathlib import Path
|
434
|
+
from ..defs.logIt import printIt, lable
|
435
|
+
|
436
|
+
|
437
|
+
rcFileDir = Path(__file__).resolve().parents[2]
|
438
|
+
rcFileName = rcFileDir.joinpath(f'.${name}rc')
|
439
|
+
|
440
|
+
class OptSwitches():
|
441
|
+
def __init__(self, switchFlags: dict) -> None:
|
442
|
+
self.switchFlags = switchFlags
|
443
|
+
self.optSwitches = readOptSwitches()
|
444
|
+
|
445
|
+
def toggleSwitchFlag(self, switchFlag: str):
|
446
|
+
optSwitches = {}
|
447
|
+
optSwitches["switcheFlags"] = {}
|
448
|
+
currSwitchFlag = switchFlag[1:]
|
449
|
+
if switchFlag[0] in '+':
|
450
|
+
currSwitchValue = True # not (self.optSwitches["switcheFlags"][currSwitchFlag] == True)
|
451
|
+
else:
|
452
|
+
currSwitchValue = False
|
453
|
+
try:
|
454
|
+
self.optSwitches["switcheFlags"][currSwitchFlag] = currSwitchValue
|
455
|
+
except:
|
456
|
+
print('here')
|
457
|
+
self.optSwitches["switcheFlags"][currSwitchFlag] = True
|
458
|
+
writeOptJson(self.optSwitches, self.switchFlags)
|
459
|
+
|
460
|
+
def readOptSwitches() -> dict:
|
461
|
+
global rcFileName
|
462
|
+
optSwitches = {}
|
463
|
+
if rcFileName.is_file():
|
464
|
+
with open(rcFileName, 'r') as rf:
|
465
|
+
rawRcJson = json.load(rf)
|
466
|
+
optSwitches["switcheFlags"] = rawRcJson["switcheFlags"]
|
467
|
+
else:
|
468
|
+
optSwitches["switcheFlags"] = {}
|
469
|
+
return optSwitches
|
470
|
+
|
471
|
+
def writeOptJson(optSwitches: dict, switchFlags: dict) -> dict:
|
472
|
+
global rcFileName
|
473
|
+
rawRC = {}
|
474
|
+
if rcFileName.is_file():
|
475
|
+
with open(rcFileName, 'r') as rf:
|
476
|
+
rawRC = json.load(rf)
|
477
|
+
rawRC = rawRC | optSwitches
|
478
|
+
for switchFlag in switchFlags.keys(): # fill in missing items'
|
479
|
+
try: _ = rawRC["switcheFlags"][switchFlag]
|
480
|
+
except: rawRC["switcheFlags"][switchFlag] = False
|
481
|
+
printIt(formatOptStr(rawRC["switcheFlags"]), lable.INFO)
|
482
|
+
with open(rcFileName, 'w') as wf:
|
483
|
+
json.dump(rawRC, wf, indent=2)
|
484
|
+
|
485
|
+
def formatOptStr(optSwitches: dict) -> str:
|
486
|
+
rtnStr = "Current option values: "
|
487
|
+
for cmdOpt in optSwitches:
|
488
|
+
rtnStr += f'-{cmdOpt}={optSwitches[cmdOpt]}, '
|
489
|
+
rtnStr = rtnStr[:-2]
|
490
|
+
return rtnStr
|
491
|
+
"""))
|
492
|
+
argParseTemplate = Template(dedent("""import os, sys, argparse, shlex
|
493
|
+
from ..defs.logIt import color, cStr
|
494
|
+
from ..commands.commands import Commands, cmdDescriptionTagStr
|
495
|
+
|
496
|
+
class PiHelpFormatter(argparse.RawTextHelpFormatter):
|
497
|
+
# Corrected _max_action_length for the indenting of subactions
|
498
|
+
def add_argument(self, action):
|
499
|
+
if action.help is not argparse.SUPPRESS:
|
500
|
+
# find all invocations
|
501
|
+
get_invocation = self._format_action_invocation
|
502
|
+
invocations = [get_invocation(action)]
|
503
|
+
current_indent = self._current_indent
|
504
|
+
for subaction in self._iter_indented_subactions(action):
|
505
|
+
# compensate for the indent that will be added
|
506
|
+
indent_chg = self._current_indent - current_indent
|
507
|
+
added_indent = 'x'*indent_chg
|
508
|
+
print('added_indent', added_indent)
|
509
|
+
invocations.append(added_indent+get_invocation(subaction))
|
510
|
+
#print('inv', invocations)
|
511
|
+
|
512
|
+
# update the maximum item length
|
513
|
+
invocation_length = max([len(s) for s in invocations])
|
514
|
+
action_length = invocation_length + self._current_indent
|
515
|
+
self._action_max_length = max(self._action_max_length,
|
516
|
+
action_length)
|
517
|
+
|
518
|
+
# add the item to the list
|
519
|
+
self._add_item(self._format_action, [action])
|
520
|
+
|
521
|
+
def str_or_int(arg):
|
522
|
+
try:
|
523
|
+
return int(arg) # try convert to int
|
524
|
+
except ValueError:
|
525
|
+
pass
|
526
|
+
if type(arg) == str:
|
527
|
+
return arg
|
528
|
+
raise argparse.ArgumentTypeError("arguments must be an integer or string")
|
529
|
+
|
530
|
+
class ArgParse():
|
531
|
+
|
532
|
+
def __init__(self):
|
533
|
+
if not sys.stdin.isatty():
|
534
|
+
self.parser = argparse.ArgumentParser(add_help=False)
|
535
|
+
self.parser.add_argument('commands', nargs=1)
|
536
|
+
self.parser.add_argument('arguments', nargs='*')
|
537
|
+
self.args = self.parser.parse_args(sys.argv[1:])
|
538
|
+
else:
|
539
|
+
_, tCols = os.popen('stty size', 'r').read().split()
|
540
|
+
tCols = int(tCols)
|
541
|
+
indentPad = 8
|
542
|
+
formatter_class=lambda prog: PiHelpFormatter(prog, max_help_position=8,width=tCols)
|
543
|
+
commandsHelp = ""
|
544
|
+
argumentsHelp = ""
|
545
|
+
theCmds = Commands()
|
546
|
+
commands = theCmds.commands
|
547
|
+
switchFlag = theCmds.switchFlags["switcheFlags"]
|
548
|
+
for cmdName in commands:
|
549
|
+
needCmdDescription = True
|
550
|
+
needArgDescription = True
|
551
|
+
arguments = commands[cmdName]
|
552
|
+
argumentsHelp += cStr(cmdName, color.YELLOW) + ': \\n'
|
553
|
+
for argName in arguments:
|
554
|
+
if argName[-len(cmdDescriptionTagStr):] == cmdDescriptionTagStr:
|
555
|
+
cmdHelp = cStr(cmdName, color.YELLOW) + ': ' + f'{arguments[argName]}'
|
556
|
+
if len(cmdHelp) > tCols:
|
557
|
+
indentPad = len(cmdName) + 2
|
558
|
+
cmdHelp = formatHelpWidth(cmdHelp, tCols, indentPad)
|
559
|
+
else:
|
560
|
+
cmdHelp += '\\n'
|
561
|
+
commandsHelp += cmdHelp
|
562
|
+
needCmdDescription = False
|
563
|
+
else:
|
564
|
+
argHelp = cStr(f' <{argName}> ', color.CYAN) + f'{arguments[argName]}'
|
565
|
+
if len(argHelp) > tCols:
|
566
|
+
indentPad = len(argName) + 5
|
567
|
+
argHelp = ' ' + formatHelpWidth(argHelp, tCols, indentPad)
|
568
|
+
else:
|
569
|
+
argHelp += '\\n'
|
570
|
+
argumentsHelp += argHelp
|
571
|
+
needArgDescription = False
|
572
|
+
if needArgDescription:
|
573
|
+
argumentsHelp = argumentsHelp[:-1]
|
574
|
+
argumentsHelp += "no arguments\\n"
|
575
|
+
if needCmdDescription:
|
576
|
+
commandsHelp += cStr(cmdName, color.WHITE) + '\\n'
|
577
|
+
# commandsHelp = commandsHelp[:-1]
|
578
|
+
|
579
|
+
self.parser = argparse.ArgumentParser(
|
580
|
+
description = "pi pip package pip package pip package",
|
581
|
+
epilog="Have Fun!", formatter_class=formatter_class)
|
582
|
+
|
583
|
+
self.parser.add_argument("commands",
|
584
|
+
type=str,
|
585
|
+
nargs=1,
|
586
|
+
metavar= f'{cStr(cStr("Commands", color.YELLOW), color.UNDERLINE)}:',
|
587
|
+
help=commandsHelp)
|
588
|
+
|
589
|
+
self.parser.add_argument("arguments",
|
590
|
+
type=str_or_int,
|
591
|
+
nargs="*",
|
592
|
+
metavar= f'{cStr(cStr("Arguments", color.CYAN), color.UNDERLINE)}:',
|
593
|
+
#metavar="arguments:",
|
594
|
+
help=argumentsHelp)
|
595
|
+
|
596
|
+
for optFlag in switchFlag:
|
597
|
+
flagHelp = switchFlag[optFlag]
|
598
|
+
self.parser.add_argument(f'-{optFlag}', action='store_true', help=flagHelp)
|
599
|
+
self.args = self.parser.parse_args()
|
600
|
+
|
601
|
+
def formatHelpWidth(theText, tCols, indentPad=1) -> str:
|
602
|
+
# this uses the screen with to estabhish tCols
|
603
|
+
|
604
|
+
#tCols = int(tCols) - 20
|
605
|
+
#print(tCols)
|
606
|
+
# tCols = 60
|
607
|
+
spPaddingStr = ' '*indentPad
|
608
|
+
rtnStr = ''
|
609
|
+
outLine = ''
|
610
|
+
tokens = shlex.split(theText)
|
611
|
+
# print(tokens)
|
612
|
+
# exit()
|
613
|
+
for token in tokens: # loop though tokens
|
614
|
+
chkStr = outLine + token + ' '
|
615
|
+
if len(chkStr) <= tCols: # check line length after concatinating each word
|
616
|
+
outLine = chkStr # less the the colums of copy over to outline
|
617
|
+
else:
|
618
|
+
if len(token) > tCols:
|
619
|
+
# when the match word is longer then the terminal character width (tCols),
|
620
|
+
# DEBUG how it should be handeled here.
|
621
|
+
print(f'here with long match.group():\\n{token}')
|
622
|
+
exit()
|
623
|
+
chkStr = token
|
624
|
+
while len(chkStr) > tCols: # a single word may be larger the tCols
|
625
|
+
outLine += chkStr[:tCols]
|
626
|
+
chkStr = f'\\n{chkStr[tCols:]}'
|
627
|
+
outLine += chkStr
|
628
|
+
else:
|
629
|
+
rtnStr += outLine
|
630
|
+
outLine = f'\\n{spPaddingStr}{token} '
|
631
|
+
rtnStr += f'{outLine}\\n'
|
632
|
+
#rtnStr = rtnStr[:-1]
|
633
|
+
return rtnStr
|
634
|
+
"""))
|
635
|
+
logPrintTemplate = Template(dedent("""import os, time
|
636
|
+
from inspect import currentframe, getframeinfo
|
637
|
+
|
638
|
+
# Class of different termianl styles
|
639
|
+
class color():
|
640
|
+
|
641
|
+
BLACK = "\\033[30m"
|
642
|
+
RED = "\\033[31m"
|
643
|
+
GREEN = "\\033[32m"
|
644
|
+
YELLOW = "\\033[33m"
|
645
|
+
BLUE = "\\033[34m"
|
646
|
+
MAGENTA = "\\033[35m"
|
647
|
+
CYAN = "\\033[36m"
|
648
|
+
WHITE = "\\033[37m"
|
649
|
+
UNDERLINE = "\\033[4m"
|
650
|
+
RESET = "\\033[0m"
|
651
|
+
|
652
|
+
# message: color
|
653
|
+
l2cDict: dict = {
|
654
|
+
"BK": RESET,
|
655
|
+
"ERROR: ": RED,
|
656
|
+
"PASS: ": GREEN,
|
657
|
+
"WARN: ": YELLOW,
|
658
|
+
"SAVED: ": BLUE,
|
659
|
+
"DEBUG: ": MAGENTA,
|
660
|
+
"REPLACED: ": CYAN,
|
661
|
+
"INFO: ": WHITE,
|
662
|
+
"IMPORT: ": UNDERLINE,
|
663
|
+
"RESET": RESET,
|
664
|
+
"File Not Found: ": YELLOW,
|
665
|
+
"FAIL: ": RED,
|
666
|
+
"Useage: ": WHITE,
|
667
|
+
"DELETE: ": YELLOW,
|
668
|
+
"EXISTS: ": GREEN,
|
669
|
+
"READ: ": GREEN,
|
670
|
+
"TOUCHED: ": GREEN,
|
671
|
+
"MKDIR: ": GREEN,
|
672
|
+
"NEW CMD ADDED: ": GREEN,
|
673
|
+
"CMD MODIFIED: ": GREEN,
|
674
|
+
"CMD REMOVED: ": GREEN,
|
675
|
+
"ARG REMOVED: ": GREEN,
|
676
|
+
"IndexError: ": RED,
|
677
|
+
"Testing: ": CYAN,
|
678
|
+
"Update: ": CYAN
|
679
|
+
}
|
680
|
+
|
681
|
+
|
682
|
+
class lable():
|
683
|
+
SAVED = "SAVED: "
|
684
|
+
REPLACED = "REPLACED: "
|
685
|
+
BLANK = "BK"
|
686
|
+
ERROR = "ERROR: "
|
687
|
+
PASS = "PASS: "
|
688
|
+
WARN = "WARN: "
|
689
|
+
DEBUG = "DEBUG: "
|
690
|
+
INFO = "INFO: "
|
691
|
+
IMPORT = "IMPORT: "
|
692
|
+
RESET = "RESET"
|
693
|
+
FileNotFound = "File Not Found: "
|
694
|
+
FAIL = "FAIL: "
|
695
|
+
Useage = "Useage: "
|
696
|
+
MKDIR = "MKDIR: "
|
697
|
+
DELETE = "DELETE: "
|
698
|
+
EXISTS = "EXISTS: "
|
699
|
+
READ = "READ: "
|
700
|
+
TOUCHED = "TOUCHED: "
|
701
|
+
NewCmd = "NEW CMD ADDED: "
|
702
|
+
ModCmd = "CMD MODIFIED: "
|
703
|
+
RmCmd = "CMD REMOVED: "
|
704
|
+
RmArg = "ARG REMOVED: "
|
705
|
+
IndexError = "IndexError: "
|
706
|
+
TESTING = "Testing: "
|
707
|
+
UPDATE = "Update: "
|
708
|
+
|
709
|
+
|
710
|
+
# log function
|
711
|
+
def logIt(*message, logFileName="${name}.log"):
|
712
|
+
# write log
|
713
|
+
now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
|
714
|
+
|
715
|
+
prtStr = ""
|
716
|
+
needClip = False
|
717
|
+
if len(message) > 0:
|
718
|
+
for mess in message:
|
719
|
+
if mess == lable.BLANK:
|
720
|
+
pass
|
721
|
+
elif mess in color.l2cDict:
|
722
|
+
prtStr = mess + prtStr
|
723
|
+
else:
|
724
|
+
needClip = True
|
725
|
+
prtStr += str(mess) + " "
|
726
|
+
if needClip:
|
727
|
+
prtStr = prtStr[:-1]
|
728
|
+
|
729
|
+
prtStr = "["+now+"] "+prtStr+"\\n"
|
730
|
+
|
731
|
+
with open(logFileName, "a") as f:
|
732
|
+
f.write(prtStr)
|
733
|
+
|
734
|
+
def printIt(*message):
|
735
|
+
prtStr = ""
|
736
|
+
rtnStr = ""
|
737
|
+
needClip = False
|
738
|
+
if len(message) > 0:
|
739
|
+
for mess in message:
|
740
|
+
if mess == lable.BLANK:
|
741
|
+
prtStr += message
|
742
|
+
rtnStr += message
|
743
|
+
elif mess in color.l2cDict:
|
744
|
+
prtStr = color.l2cDict[mess] + mess + color.RESET + prtStr
|
745
|
+
rtnStr = mess + rtnStr
|
746
|
+
else:
|
747
|
+
needClip = True
|
748
|
+
prtStr += str(mess) + " "
|
749
|
+
rtnStr += str(mess) + " "
|
750
|
+
if needClip:
|
751
|
+
prtStr = prtStr[:-1]
|
752
|
+
rtnStr = rtnStr[:-1]
|
753
|
+
print(prtStr)
|
754
|
+
return rtnStr
|
755
|
+
|
756
|
+
def cStr(inStr:str, cVal:str):
|
757
|
+
return cVal + inStr + color.RESET
|
758
|
+
|
759
|
+
def deleteLog(logFileName="${name}.log"):
|
760
|
+
if os.path.isfile(logFileName): os.remove(logFileName)
|
761
|
+
|
762
|
+
def getCodeFile():
|
763
|
+
cf = currentframe()
|
764
|
+
codeObj =cf.f_back.f_code
|
765
|
+
codeObjStr = str(codeObj).split(",")[1].split(\'"\')[1]
|
766
|
+
codeObjStr = os.path.basename(codeObjStr)
|
767
|
+
return codeObjStr
|
768
|
+
|
769
|
+
def getCodeLine():
|
770
|
+
cf = currentframe()
|
771
|
+
return cf.f_back.f_lineno
|
772
|
+
"""))
|