# Create nurfile from common task/command runner config # # Usage: # > cd into/the/project/path # > nurify # Will create nurfile # > nur --help # # The generated nurfile is not meant to replace your current task/commend runner, instead it # will create a nurfile allowing you to use nur instead of the projects task runner. nur # will then still execute the original task runner. # Still this allows you to gradually convert your project to nur by replacing your tasks # bit by bit with new nur variants. When switching to nur this is the recommended method: # Create new nurfile to run old tasks using the old task runner, then convert task for task. def prepare-nurfile [] { "# FILE GENERATED BY nurify COMMAND\n\n" | save -f nurfile } def nurify-from-b5 [] { let global_tasks = ( if (glob ~/.b5/Taskfile | first | path exists) { cat ~/.b5/Taskfile | lines | filter { |it| $it starts-with "task:" } | each { |it| $it | parse --regex "^task:(?P[^(]+).*" | get name | first } } else [] ) prepare-nurfile b5 --quiet help --tasks | lines | filter { |it| $it not-in $global_tasks } | each { |it| $"def --wrapped \"nur ($it | str replace --all ':' ' ')\" [...args] {\n ^b5 --quiet \"($it)\" ...$args\n}\n" } | save -f -a nurfile } def nurify-from-just [] { prepare-nurfile ^just --unsorted --dump --dump-format json | from json | get recipes | transpose k v | each { |it| $"def --wrapped \"nur ($it.k)\" [...args] {\n ^just \"($it.k)\" ...$args\n}\n" } | save -f -a nurfile } def nurify-from-package-json [] { prepare-nurfile open package.json | get scripts | transpose k v | each { |it| $"def --wrapped \"nur ($it.k)\" [...args] {\n ^npm run \"($it.k)\" ...$args\n}\n" } | save -f -a nurfile } def nurify-from-makefile [] { prepare-nurfile open ( glob "[Mm]akefile" | first ) | lines | find --regex '^[\w\.-]+\s*:' | where ($it | str trim -l) == $it | where ($it | str starts-with '.') == false | split column ':' target | get target | str trim | each { |it| $"def --wrapped \"nur ($it)\" [...args] {\n ^make \"($it)\" ...$args\n}\n" } | save -f -a nurfile } def nurify-from-toolkit-nu [] { # Output warning as we cannot support all features and the conversion may not cover all cases # # Example of a case not convertable: # We cannot handle (named) parameters of type "list" as the nur call will not accept a list of # strings. This is only possible with nu builtin or custom commands. But nur is neither of those, as it # is a separate executable using the nu libraries. So we cannot handle this case. Basically nu shell will # tell you that you cannot pass lists to external commands. 😉 print $"(ansi red)Conversion from toolkit.nu may not cover all cases, you might need to extend/fix the generated nurfile(ansi reset)" print $"(ansi red)\(But be aware: Not all features nu shell commands would provide are available as nur is an external command\)(ansi reset)" let toolkit_commands = ( nu -c "use toolkit.nu ; scope modules | where name == 'toolkit' | first | get commands | where name != 'toolkit' | each { |it| print $it.name } ; null" ) | lines def get-toolkit-command-signature [command: string] { let command_signature = ( nu -c $"use toolkit.nu ; scope commands | where type == 'custom' and name == 'toolkit ($command)' | first | get signatures | to nuon" | from nuon ) $command_signature | transpose k v | get v | first } prepare-nurfile "use toolkit.nu\n\n" | save -f -a nurfile $toolkit_commands | each { |it| let signatures = get-toolkit-command-signature $it let arguments = $signatures | each { |param| let param_name = $param.parameter_name mut param_type = if ($param.syntax_shape | is-not-empty) and $param.syntax_shape != 'any' { $': ($param.syntax_shape)' } else '' if $param_type starts-with ': completable<' { $param_type = $": ($param_type | str substring 14..(($param_type | str length) - 2))" } let param_docs = if ($param.description | is-not-empty) { $' # ($param.description)' } match $param { {parameter_type: "positional"} => $" ($param_name)($param_type)($param_docs)", {parameter_type: "named"} => $" --($param_name)($param_type)($param_docs)", {parameter_type: "switch"} => $" --($param_name)($param_docs)", {parameter_type: "rest"} => $" ...($param_name | default 'rest')($param_type)($param_docs)", } } | str join "\n" let call_arguments = $signatures | each { |param| let param_name = $param.parameter_name match $param { {parameter_type: "positional"} => $"$($param_name | str replace --all '-' '_')", {parameter_type: "named"} => $"--($param_name) $($param_name | str replace --all '-' '_')", {parameter_type: "switch"} => $"--($param_name)=$($param_name | str replace --all '-' '_')", } } | str join " " let rest_arguments = $signatures | each { |param| let param_name = $param.parameter_name match $param { {parameter_type: "rest"} => $"...$($param_name | default 'rest' | str replace --all '-' '_')", } } | str join " " let has_rest_arguments = $signatures | any { |param| $param.parameter_type == "rest" } $"def( if $has_rest_arguments { ' --wrapped' }) \"nur ($it)\" [\n($arguments)\n] {\n toolkit ($it) ($call_arguments) (if $has_rest_arguments { $rest_arguments })\n}\n" } | save -f -a nurfile } def nurify-from-lets [] { prepare-nurfile open lets.yaml | get commands | transpose k v | each { |it| $"def --wrapped \"nur ($it.k)\" [...args] {\n ^lets \"($it.k)\" ...$args\n}\n" } | save -f -a nurfile } def nurify-from-task [] { prepare-nurfile open ( glob "[Tt]askfile.{yml,yaml}" | first ) | get tasks | transpose k v | each { |it| $"def --wrapped \"nur ($it.k)\" [...args] {\n ^task \"($it.k)\" ...$args\n}\n" } | save -f -a nurfile } def nurify-from-tusk [] { prepare-nurfile open tusk.yml | get tasks | transpose k v | each { |it| $"def --wrapped \"nur ($it.k)\" [...args] {\n ^tusk \"($it.k)\" ...$args\n}\n" } | save -f -a nurfile } # Create nurfile from different task/command runners. The nurfile will contain tasks to wrap # all tasks and then run original task/command runner. This can be used to gradually migrate to nur. # # Currently supports: # * b5 task runner (when build/Taskfile is found) # * just command runner (when justfile is found) # * npm package.json scripts (when package.json is found) # * make (when [Mm]akefile is found) # * nu toolkit module (when toolkit.nu is found) # * lets (when lets.yaml is found) # * task (when [Tt]askfile.{yml,yaml} is found) # * tusk (when tusk.yml is found) export def main [] { if ("build/Taskfile" | path exists) { print $"(ansi cyan)Found build/Taskfile, converting from b5 task runner(ansi reset)" nurify-from-b5 } else if ("justfile" | path exists) { print $"(ansi cyan)Found justfile, converting from just command runner(ansi reset)" nurify-from-just } else if ("package.json" | path exists) { print $"(ansi cyan)Found package.json, converting from npm script(ansi reset)" nurify-from-package-json } else if (glob "[Mm]akefile" | is-not-empty) { print $"(ansi cyan)Found [Mm]akefile, converting from make(ansi reset)" nurify-from-makefile } else if ("toolkit.nu" | path exists) { print $"(ansi cyan)Found toolkit.nu, converting from toolkit.nu(ansi reset)" nurify-from-toolkit-nu } else if ("lets.yaml" | path exists) { print $"(ansi cyan)Found lets.yaml, converting from lets(ansi reset)" nurify-from-lets } else if (glob "[Tt]askfile.{yml,yaml}" | is-not-empty) { print $"(ansi cyan)Found [Tt]askfile.{yml,yaml}, converting from task(ansi reset)" nurify-from-task } else if ("tusk.yml" | path exists) { print $"(ansi cyan)Found tusk.yml, converting from tusk(ansi reset)" nurify-from-tusk } else { error make {"msg": "Could not find any existing task/command runner, please run nurify in project root"} } }