all repos — pls @ 66e16b031122b996dfcb569b404197fcca8dd3f2

A polite but determined task runner.

Updates.
h3rald h3rald@h3rald.com
Sun, 03 Oct 2021 11:00:25 +0200
commit

66e16b031122b996dfcb569b404197fcca8dd3f2

parent

71cdd6181da9601a3d2f511ee9e4e64a7d522822

6 files changed, 113 insertions(+), 78 deletions(-)

jump to
M .gitignore.gitignore

@@ -3,3 +3,4 @@ nimblecache/

htmldocs/ pls.exe pls +pkgs
M pls.nimblepls.nimble

@@ -32,8 +32,8 @@ const program = "pls"

const program_file = "src/pls.nim" const zip = "zip -X" -proc shell(command, args: string, dest = "") = - exec command & " " & args & " " & dest +proc shell(task, args: string, dest = "") = + exec task & " " & args & " " & dest proc filename_for(os: string, arch: string): string = return "pls" & "_v" & version & "_" & os & "_" & arch & ".zip"
M src/pls.nimsrc/pls.nim

@@ -22,14 +22,14 @@ let usage* = """ $1 v$2 - $3

(c) 2021 $4 Usage: - pls <command> [<target>] Executes <command> (on <target>). + pls <task> [<target>] Executes <task> (on <target>). - => For more information on available commands, run: pls help + => For more information on available tasks, run: pls help Options: --help, -h Displays this message. - --force, -f Do not ask for confirmation when executing the specified command. - --global, -g Execute command within the global project instead of the local one. + --force, -f Do not ask for confirmation when executing the specified task. + --global, -g Execute task within the global project instead of the local one. --log, -l Specifies the log level (debug|info|notice|warn|error|fatal). Default: info --version, -h Displays the version of the application.

@@ -73,24 +73,61 @@ let prop = addProperty(obj)

obj[prop.key] = prop.value done = not confirm("Do you want to add/remove more properties?") -proc addCommandDefinition(parentObj: JsonNode, name = ""): tuple[key: string, value: JsonNode] = - # TODO: validate name of command definition! (not _syntax or _description, etc.) +proc addTaskDefinition(parentObj: JsonNode, name = ""): tuple[key: string, value: JsonNode] = + # TODO: validate name of task definition! (not _syntax or _description, etc.) if name == "": - result.key = editValue("Command Definition Matcher") + result.key = editValue("Task Definition Matcher") else: - printValue(" Command Definition Matcher", name) + printValue(" Task Definition Matcher", name) result.key = name result.value = newJObject() result.value["cmd"] = addProperty(parentObj[name], "cmd").value result.value["pwd"] = addProperty(parentObj[name], "pwd").value - # TODO: delete command definition matcher if all properties are null. + # TODO: delete task definition matcher if all properties are null. -proc addCommandDefinitions(obj: var JsonNode) = +proc addTaskDefinitions(obj: var JsonNode) = var done = false while (not done): - let prop = addCommandDefinition(obj) + let prop = addTaskDefinition(obj) obj[prop.key] = prop.value - done = not confirm("Do you want to add/remove more command definitions?") + done = not confirm("Do you want to add/remove more task definitions?") + +proc changeValue(oldv: tuple[label: string, value: JsonNode], newv: tuple[label: string, value: JsonNode]): bool = + if oldv.value != newJNull(): + printDeleted(oldv.label, $oldv.value) + if newv.value != newJNull(): + printAdded(newv.label, $newv.value) + return confirm("Confirm change?") + +proc updateDefinitions(prj: var PlsProject): bool = + result = false + let sysTasks = plsTpl.parseJson["tasks"] + for k, v in sysTasks.pairs: + if prj.tasks.hasKey(k): + let sysTask = sysTasks[k] + var prjTask = prj.tasks[k] + for prop, val in sysTask.pairs: + let sysProp = sysTask[prop] + var prjProp = newJNull() + if prjTask.hasKey(prop): + prjProp = prjTask[prop] + if prjProp != newJNull(): + if prjProp != sysProp: + let sysVal = (label: k & "." & prop, value: sysProp) + let prjVal = (label: k & "." & prop, value: prjProp) + if changeValue(prjVal, sysVal): + prjTask[prop] = sysProp + result = true + else: + result = true + # Adding new property + printAdded("$1.$2" % [k, prop], $sysProp) + prjTask[prop] = sysProp + else: + result = true + # Adding new task + printAdded(k, $sysTasks[k]) + prj.tasks[k] = sysTasks[k] ### MAIN ###

@@ -156,7 +193,7 @@ quit(3)

let kind = args[1] let alias = args[2] var props = newJObject() - if not ["target", "command"].contains(kind): + if not ["target", "task"].contains(kind): fatal "Unknown definition type $1" % kind quit(6) prj.load

@@ -177,32 +214,32 @@ notice "Definining new target: " & alias

warn "Specify properties for target '$1':" % alias addProperties(props) prj.defTarget(alias, props) - else: # command - if prj.commands.hasKey(alias): - notice "Redefining existing command: " & alias - warn "Specify properties for command '$1':" % alias - props = prj.commands[alias] + else: # task + if prj.tasks.hasKey(alias): + notice "Redefining existing task: " & alias + warn "Specify properties for task '$1':" % alias + props = prj.tasks[alias] for k, v in props.mpairs: if ["_syntax", "_description"].contains(k): let prop = addProperty(props, k) props[prop.key] = prop.value else: - let prop = addCommandDefinition(props, k) + let prop = addTaskDefinition(props, k) props[prop.key] = prop.value - if confirm "Do you want to add/remove more command definitions?": - addCommandDefinitions(props) + if confirm "Do you want to add/remove more task definitions?": + addTaskDefinitions(props) else: props["_syntax"] = addProperty(props, "_syntax").value props["_description"] = addProperty(props, "_description").value - addCommandDefinitions(props) - prj.defCommand(alias, props) + addTaskDefinitions(props) + prj.defTask(alias, props) of "undef": if args.len < 3: fatal "No alias specified." quit(3) let kind = args[1] let alias = args[2] - if not ["target", "command"].contains(kind): + if not ["target", "task"].contains(kind): fatal "Unknown definition type $1" % kind quit(6) prj.load

@@ -212,12 +249,12 @@ fatal "Target '$1' not defined." % [alias]

quit(4) if force or confirm("Remove definition for target '$1'?" % alias): prj.undefTarget(alias) - else: # command - if not prj.commands.hasKey(alias): - fatal "Command '$1' not defined." % [alias] + else: # task + if not prj.tasks.hasKey(alias): + fatal "Task '$1' not defined." % [alias] quit(4) - if force or confirm("Remove definition for command '$1'?" % alias): - prj.undefCommand(alias) + if force or confirm("Remove definition for task '$1'?" % alias): + prj.undefTask(alias) of "info": prj.load if args.len < 2:

@@ -233,6 +270,10 @@ quit(4)

let data = prj.targets[alias] for k, v in data.pairs: echo "$1:\t$2" % [k, $v] + of "update": + prj.load + if updateDefinitions(prj): + prj.save of "help": echo "" if args.len < 2:

@@ -245,7 +286,7 @@ else:

let cmd = args[1] let help = prj.help[cmd] if not prj.help.hasKey(cmd): - fatal "Command '$1' is not defined." % cmd + fatal "Task '$1' is not defined." % cmd quit(5) printGreen " pls " & help["_syntax"].getStr echo "\n $1\n" % help["_description"].getStr
M src/plspkg/help.jsonsrc/plspkg/help.json

@@ -1,22 +1,22 @@

{ "help": { - "_syntax": "help [<command>]", - "_description": "Display help on the specified command (or all commands)." + "_syntax": "help [<task>]", + "_description": "Display help on the specified task (or all tasks)." }, "info": { "_syntax": "info [<target>]", "_description": "Displays information on <target> (or all targets)." }, "init": { - "_syntax": "init [<storage-dir>]", - "_description": "Initializes a project in the current directory (using <storage-dir> as storage directory)." + "_syntax": "init", + "_description": "Initializes a project in the current directory." }, "def": { - "_syntax": "def (command|target) <alias>", - "_description": "Configures a new or existing command or target <alias>." + "_syntax": "def (task|target) <alias>", + "_description": "Configures a new or existing task or target <alias>." }, "undef": { - "_syntax": "undef (command|target) <alias>", - "_description": "Unmaps the previously-mapped command or target <alias>." + "_syntax": "undef (task|target) <alias>", + "_description": "Unmaps the previously-mapped task or target <alias>." } }
M src/plspkg/pls.jsonsrc/plspkg/pls.json

@@ -1,4 +1,4 @@

{ - "commands": {}, + "tasks": {}, "targets": {} }
M src/plspkg/project.nimsrc/plspkg/project.nim

@@ -9,7 +9,7 @@

type PlsProject* = object dir*: string - commands*: JsonNode + tasks*: JsonNode targets*: JsonNode tasklists*: JsonNode

@@ -39,25 +39,18 @@ if not prj.configFile.fileExists:

fatal "Project not initialized - configuration file not found." quit(10) let cfg = prj.configFile.parseFile - prj.commands = cfg["commands"] + prj.tasks = cfg["tasks"] prj.targets = cfg["targets"] if cfg.hasKey("dir"): prj.dir = cfg["dir"].getStr proc help*(prj: var PlsProject): JsonNode = - result = systemHelp.parseJson + result = newJObject() if prj.configured: prj.load - for k, v in prj.tasklists.pairs: - let syntax = "$$$1" % k - let description = "Executes: $1" % v.elems.mapIt(it.getStr).join(", ") - result["$"&k] = (""" - { - "_syntax": "$1", - "_description": "$2" - } - """ % [syntax, description]).parseJson - for k, v in prj.commands.pairs: + for k, v in systemHelp.parseJson.pairs: + result[k] = v + for k, v in prj.tasks.pairs: if v.hasKey("_syntax") and v.hasKey("_description"): result[k] = (""" {

@@ -68,7 +61,7 @@ """ % [v["_syntax"].getStr, v["_description"].getStr]).parseJson

proc save*(prj: PlsProject) = var o = newJObject() - o["commands"] = %prj.commands + o["tasks"] = %prj.tasks o["targets"] = %prj.targets prj.configFile.writeFile(o.pretty)

@@ -96,7 +89,7 @@ prj.targets.delete(alias)

prj.save notice "Target '$1' removed." % alias -proc defCommand*(prj: var PlsProject, alias: string, props: var JsonNode) = +proc defTask*(prj: var PlsProject, alias: string, props: var JsonNode) = for k, v in props.mpairs: if v == newJNull(): props.delete(k):

@@ -105,31 +98,31 @@ for kk, vv in v.pairs:

if vv == newJNull(): v.delete(kk) prj.load - if not prj.commands.hasKey alias: - notice "Adding command '$1'..." % alias - prj.commands[alias] = newJObject() + if not prj.tasks.hasKey alias: + notice "Adding task '$1'..." % alias + prj.tasks[alias] = newJObject() else: - notice "Updating command '$1'..." % alias - prj.commands[alias] = newJObject() + notice "Updating task '$1'..." % alias + prj.tasks[alias] = newJObject() for key, val in props.pairs: - prj.commands[alias][key] = val + prj.tasks[alias][key] = val notice " $1: $2" % [key, $val] prj.save - notice "Command '$1' saved." % alias + notice "Task '$1' saved." % alias -proc undefCommand*(prj: var PlsProject, alias: string) = +proc undefTask*(prj: var PlsProject, alias: string) = prj.load - prj.commands.delete(alias) + prj.tasks.delete(alias) prj.save - notice "Command '$1' removed." % alias + notice "Task '$1' removed." % alias -proc lookupCommand(prj: PlsProject, command: string, props: seq[string], cmd: var JsonNode): bool = - if not prj.commands.hasKey command: - warn "Command '$1' not found" % command +proc lookupTask(prj: PlsProject, task: string, props: seq[string], cmd: var JsonNode): bool = + if not prj.tasks.hasKey task: + warn "Task '$1' not found" % task return - var cmds = prj.commands[command] + var cmds = prj.tasks[task] var score = 0 - # Cycle through command definitions + # Cycle through task definitions for key, val in cmds: if key == "_syntax" or key == "_description": continue

@@ -142,11 +135,11 @@ score = params.len

cmd = val return score > 0 -proc execute*(prj: var PlsProject, command, alias: string): int {.discardable.} = +proc execute*(prj: var PlsProject, task, alias: string): int {.discardable.} = prj.load if not prj.targets.hasKey alias: raise PlsError(msg: "Target definition '$1' not found. Nothing to do." % [alias]) - notice "$1: $2" % [command, alias] + notice "$1: $2" % [task, alias] let target = prj.targets[alias] var keys = newSeq[string](0) for key, val in target.pairs:

@@ -156,7 +149,7 @@ var cmd: string

var pwd = prj.dir if target.hasKey("dir"): pwd = target["dir"].getStr - if prj.lookupCommand(command, keys, res): + if prj.lookupTask(task, keys, res): cmd = res["cmd"].getStr.replace(placeholder) do (m: int, n: int, c: openArray[string]) -> string: return target[c[0]].getStr if res.hasKey("pwd"):

@@ -168,14 +161,14 @@ pwd.createDir()

pwd.setCurrentDir() result = execShellCmd cmd else: - debug "Command '$1' not available for target '$2'" % [command, alias] + debug "Task '$1' not available for target '$2'" % [task, alias] setCurrentDir(prj.dir) -proc executeRec*(prj: var PlsProject, command, alias: string) = +proc executeRec*(prj: var PlsProject, task, alias: string) = prj.load let pwd = getCurrentDir() var dir = alias - if (execute(prj, command, alias) != 0): + if (execute(prj, task, alias) != 0): return if prj.targets[alias].hasKey("dir"): dir = prj.targets[alias]["dir"].getStr

@@ -184,5 +177,5 @@ if childProj.configured:

childProj.load() setCurrentDir(childProj.dir) for key, val in childProj.targets.pairs: - childProj.executeRec(command, key) + childProj.executeRec(task, key) setCurrentDir(pwd)