Compare commits

..

1 commit

Author SHA1 Message Date
6693b7cab8 Merge branch 'feat/cli' into 'main'
feat!: add cli with update and list subcommands + gitignore param

See merge request TECHNOFAB/soonix!3
2026-01-05 22:24:28 +01:00
3 changed files with 64 additions and 86 deletions

View file

@ -22,5 +22,4 @@ in rec {
}; };
mkShellHook = userConfig: (make userConfig).config.shellHook; mkShellHook = userConfig: (make userConfig).config.shellHook;
mkCLI = userConfig: (make userConfig).config.packages.soonix;
} }

View file

@ -154,65 +154,57 @@ in {
config = let config = let
hooks = config.hooks; hooks = config.hooks;
# allow excluding gitignore since stuff like renovate can't use/commit it anyways # allow excluding gitignore since stuff like renovate can't use/commit it anyways
runHooks = concatMapStringsSep "\n" (hookName: let getHookNames = {includeGitignored ? true}:
hook = hooks.${hookName}; if includeGitignored
modes = { then (builtins.attrNames hooks)
link = else
# sh map
'' (hook: hook.name)
if [[ ! -L "${hook.output}" ]] || [[ "$(readlink "${hook.output}")" != "${hook.generatedDerivation}" ]]; then (builtins.filter (hook: !hook.hook.gitignore) (builtins.attrValues hooks));
_soonix_log "info" "${hookName}" "Creating symlink: ${hook.output} -> ${hook.generatedDerivation}"
if [[ "$CHECK_MODE" != "true" ]]; then runHooks = args:
concatMapStringsSep "\n" (hookName: let
hook = hooks.${hookName};
modes = {
link =
# sh
''
if [[ ! -L "${hook.output}" ]] || [[ "$(readlink "${hook.output}")" != "${hook.generatedDerivation}" ]]; then
_soonix_log "info" "${hookName}" "Creating symlink: ${hook.output} -> ${hook.generatedDerivation}"
mkdir -p "$(dirname "${hook.output}")" mkdir -p "$(dirname "${hook.output}")"
ln -sf "${hook.generatedDerivation}" "${hook.output}" ln -sf "${hook.generatedDerivation}" "${hook.output}"
_changed=true
else else
_soonix_log "info" "${hookName}" "Would create symlink: ${hook.output} -> ${hook.generatedDerivation}" _soonix_log "info" "${hookName}" "Symlink up to date: ${hook.output}"
fi fi
_changed=true '';
else copy =
_soonix_log "info" "${hookName}" "Symlink up to date: ${hook.output}" # sh
fi ''
''; if [[ ! -f "${hook.output}" ]] || ! cmp -s "${hook.generatedDerivation}" "${hook.output}"; then
copy = _soonix_log "info" "${hookName}" "Copying file: ${hook.generatedDerivation} -> ${hook.output}"
# sh
''
if [[ ! -f "${hook.output}" ]] || ! cmp -s "${hook.generatedDerivation}" "${hook.output}"; then
_soonix_log "info" "${hookName}" "Copying file: ${hook.generatedDerivation} -> ${hook.output}"
if [[ "$CHECK_MODE" != "true" ]]; then
mkdir -p "$(dirname "${hook.output}")" mkdir -p "$(dirname "${hook.output}")"
# required since they're read only # required since they're read only
rm -f "${hook.output}" rm -f "${hook.output}"
cp "${hook.generatedDerivation}" "${hook.output}" cp "${hook.generatedDerivation}" "${hook.output}"
_changed=true
else else
_soonix_log "info" "${hookName}" "Would copy file: ${hook.generatedDerivation} -> ${hook.output}" _soonix_log "info" "${hookName}" "File up to date: ${hook.output}"
fi fi
_changed=true '';
else };
_soonix_log "info" "${hookName}" "File up to date: ${hook.output}"
fi
'';
};
optionalGitignore = optionalGitignore =
if hook.hook.gitignore if hook.hook.gitignore
then '' then ''
_soonix_add_to_gitignore "${hook.output}" _soonix_add_to_gitignore "${hook.output}"
''
else "";
in
builtins.addErrorContext "[soonix] while generating script for ${hookName}"
# sh
'' ''
else ""; # Process hook: ${hookName}
isGitignored =
if hook.hook.gitignore
then "true"
else "false";
in
builtins.addErrorContext "[soonix] while generating script for ${hookName}"
# sh
''
# Process hook: ${hookName}
# Skip if SKIP_GITIGNORE is set and this hook is gitignored
if [[ "$SKIP_GITIGNORE" == "true" && "${isGitignored}" == "true" ]]; then
: # skip
else
while IFS= read -r line; do while IFS= read -r line; do
case "$line" in case "$line" in
UPDATED) _soonix_updated+=("${hookName}") ;; UPDATED) _soonix_updated+=("${hookName}") ;;
@ -225,15 +217,13 @@ in {
${modes.${hook.hook.mode} or (throw "Mode ${hook.hook.mode} doesnt exist")} ${modes.${hook.hook.mode} or (throw "Mode ${hook.hook.mode} doesnt exist")}
if [[ "$CHECK_MODE" != "true" ]]; then # Add to gitignore if requested
# Add to gitignore if requested ${optionalGitignore}
${optionalGitignore}
# Run extra commands if file changed # Run extra commands if file changed
if [[ "$_changed" == "true" && -n "${hook.hook.extra}" ]]; then if [[ "$_changed" == "true" && -n "${hook.hook.extra}" ]]; then
_soonix_log "info" "${hookName}" "Running extra command: ${hook.hook.extra}" _soonix_log "info" "${hookName}" "Running extra command: ${hook.hook.extra}"
eval "${hook.hook.extra}" eval "${hook.hook.extra}"
fi
fi fi
if [[ "$_changed" == "true" ]]; then if [[ "$_changed" == "true" ]]; then
@ -245,17 +235,13 @@ in {
_soonix_log "error" "${hookName}" "Failed to process hook" _soonix_log "error" "${hookName}" "Failed to process hook"
_soonix_failed+=("${hookName}") _soonix_failed+=("${hookName}")
} }
fi '')
'') (getHookNames args);
(builtins.attrNames hooks);
generateShellHook = generateShellHook = args:
builtins.addErrorContext "[soonix] while generating shell hook" builtins.addErrorContext "[soonix] while generating shell hook"
# sh # sh
'' ''
CHECK_MODE=''${CHECK_MODE:-false}
SKIP_GITIGNORE=''${SKIP_GITIGNORE:-false}
_soonix_log() { _soonix_log() {
local level="$1" local level="$1"
local hook="$2" local hook="$2"
@ -289,16 +275,13 @@ in {
_soonix_failed=() _soonix_failed=()
_soonix_uptodate=() _soonix_uptodate=()
${runHooks} ${runHooks args}
local output=$'\E[msoonix:\E[38;5;8m' local output=$'\E[msoonix:\E[38;5;8m'
local status=0 local status=0
if [[ ''${#_soonix_updated[@]} -gt 0 ]]; then if [[ ''${#_soonix_updated[@]} -gt 0 ]]; then
output="$output [updated: ''${_soonix_updated[*]}]" >&2 output="$output [updated: ''${_soonix_updated[*]}]" >&2
if [[ "$CHECK_MODE" == "true" ]]; then
status=2
fi
fi fi
if [[ ''${#_soonix_uptodate[@]} -gt 0 ]]; then if [[ ''${#_soonix_uptodate[@]} -gt 0 ]]; then
output="$output [unchanged: ''${_soonix_uptodate[*]}]" >&2 output="$output [unchanged: ''${_soonix_uptodate[*]}]" >&2
@ -310,8 +293,8 @@ in {
printf "%s\E[m\n" "$output" >&2 printf "%s\E[m\n" "$output" >&2
if [[ $status -ne 0 ]]; then if [[ $status -eq 1 ]]; then
exit $status exit 1
fi fi
''; '';
@ -325,7 +308,7 @@ in {
# nothing to do if no hooks exist # nothing to do if no hooks exist
shellHook = shellHook =
if (builtins.length (builtins.attrNames config.hooks) > 0) if (builtins.length (builtins.attrNames config.hooks) > 0)
then generateShellHook then generateShellHook {}
else ""; else "";
shellHookFile = pkgs.writeShellScript "shellHook" shellHook; shellHookFile = pkgs.writeShellScript "shellHook" shellHook;
devshellModule = { devshellModule = {
@ -342,7 +325,6 @@ in {
set -euo pipefail set -euo pipefail
SKIP_GITIGNORE=false SKIP_GITIGNORE=false
CHECK_MODE=false
COMMAND="" COMMAND=""
show_help() { show_help() {
@ -354,7 +336,6 @@ in {
COMMANDS: COMMANDS:
update Update all managed files update Update all managed files
check Check if all files are up to date (dry-run)
list List all managed file targets list List all managed file targets
help Show this help message help Show this help message
@ -371,7 +352,7 @@ in {
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
case "$1" in case "$1" in
update|check|list|help) update|list|help)
COMMAND="$1" COMMAND="$1"
shift shift
;; ;;
@ -415,18 +396,17 @@ in {
'') (builtins.attrNames hooks)} '') (builtins.attrNames hooks)}
;; ;;
update) update)
function _soonix() { if [[ "$SKIP_GITIGNORE" == "true" ]]; then
${generateShellHook} function _soonix() {
} ${generateShellHook {includeGitignored = false;}}
_soonix }
;; _soonix
check) else
CHECK_MODE=true function _soonix() {
echo "Checking files..." ${generateShellHook {}}
function _soonix() { }
${generateShellHook} _soonix
} fi
_soonix
;; ;;
esac esac
''; '';

View file

@ -87,7 +87,6 @@ in {
assert_file_contains "${soonixBin}" "test.json" assert_file_contains "${soonixBin}" "test.json"
assert_file_contains "${soonixBin}" "SKIP_GITIGNORE" assert_file_contains "${soonixBin}" "SKIP_GITIGNORE"
assert_file_contains "${soonixBin}" "CHECK_MODE"
''; '';
} }
]; ];