diff options
Diffstat (limited to 'Argcfile.sh')
| -rw-r--r-- | Argcfile.sh | 234 |
1 files changed, 199 insertions, 35 deletions
diff --git a/Argcfile.sh b/Argcfile.sh index 117d719..79c810b 100644 --- a/Argcfile.sh +++ b/Argcfile.sh @@ -3,60 +3,184 @@ set -e # @meta dotenv +BIN_DIR=bin + +LANG_CMDS=( \ + "sh:bash" \ + "js:node" \ + "py:python" \ + "rb:ruby" \ +) + # @cmd Call the function # @arg func![`_choice_func`] The function name # @arg args~[?`_choice_func_args`] The function args call() { - "./bin/$argc_func" "${argc_args[@]}" + basename="${argc_func%.*}" + lang="${argc_func##*.}" + func_path="./$lang/$basename.$lang" + if [[ ! -e "$func_path" ]]; then + _die "error: not found $argc_func" + fi + if [[ "$lang" == "sh" ]]; then + "$func_path" "${argc_args[@]}" + else + "$(_lang_to_cmd "$lang")" "./cmd/cmd.$lang" "$argc_func" + fi } -# @cmd Build all artifacts +# @cmd Build the project +# @option --names-file=functions.txt Path to a file containing function filenames, one per line. +# This file specifies which function files to build. +# Example: +# get_current_weather.sh +# may_execute_js_code.js build() { - if [[ -f functions.txt ]]; then - argc build-declarations-json + argc build-declarations-json --names-file "${argc_names_file}" + argc build-bin --names-file "${argc_names_file}" +} + +# @cmd Build bin dir +# @option --names-file=functions.txt Path to a file containing function filenames, one per line. +build-bin() { + if [[ ! -f "$argc_names_file" ]]; then + _die "no found "$argc_names_file"" fi - if [[ "$OS" = "Windows_NT" ]]; then - argc build-win-shims + mkdir -p "$BIN_DIR" + rm -rf "$BIN_DIR"/* + names=($(cat "$argc_names_file")) + invalid_names=() + for name in "${names[@]}"; do + basename="${name%.*}" + lang="${name##*.}" + func_file="$lang/$name" + if [[ -f "$func_file" ]]; then + if _is_win; then + bin_file="$BIN_DIR/$basename.cmd" + if [[ "$lang" == sh ]]; then + _build_win_sh > "$bin_file" + else + _build_win_lang $lang "$(_lang_to_cmd "$lang")" > "$bin_file" + fi + else + bin_file="$BIN_DIR/$basename" + if [[ "$lang" == sh ]]; then + ln -s "$PWD/$func_file" "$bin_file" + else + ln -s "$PWD/cmd/cmd.$lang" "$bin_file" + fi + fi + else + invalid_names+=("$name") + fi + done + if [[ -n "$invalid_names" ]]; then + _die "error: missing following functions: ${invalid_names[*]}" fi + echo "Build bin" } -# @cmd Build declarations for specific functions -# @option --output=functions.json <FILE> Specify a file path to save the function declarations -# @option --names-file=functions.txt Specify a file containing function names -# @arg funcs*[`_choice_func`] The function names +# @cmd Build declarations.json +# @option --output=functions.json <FILE> Path to a json file to save function declarations +# @option --names-file=functions.txt Path to a file containing function filenames, one per line. +# @arg funcs*[`_choice_func`] The function filenames build-declarations-json() { + set +e if [[ "${#argc_funcs[@]}" -gt 0 ]]; then names=("${argc_funcs[@]}" ) elif [[ -f "$argc_names_file" ]]; then names=($(cat "$argc_names_file")) fi if [[ -z "$names" ]]; then - _die "error: no specific function" + _die "error: no function for building declarations.json" fi - result=() + json_list=() + not_found_funcs=() + build_failed_funcs=() for name in "${names[@]}"; do - result+=("$(build-func-declaration "$name")") + lang="${name##*.}" + func_file="$lang/$name" + if [[ ! -f "$func_file" ]]; then + not_found_funcs+=("$name") + continue; + fi + json_data="$("build-single-declaration" "$name")" + status=$? + if [ $status -eq 0 ]; then + json_list+=("$json_data") + else + build_failed_funcs+=("$name") + fi done - echo "["$(IFS=,; echo "${result[*]}")"]" | jq '.' > "$argc_output" + if [[ -n "$not_found_funcs" ]]; then + _die "error: not found functions: ${not_found_funcs[*]}" + fi + if [[ -n "$build_failed_funcs" ]]; then + _die "error: invalid functions: ${build_failed_funcs[*]}" + fi echo "Build $argc_output" + echo "["$(IFS=,; echo "${json_list[*]}")"]" | jq '.' > "$argc_output" } -# @cmd Build declaration for a single function + +# @cmd Build single declaration # @arg func![`_choice_func`] The function name -build-func-declaration() { - argc --argc-export bin/$1 | _parse_declaration -} - -# @cmd Build shims for the functions -# Because Windows OS can't run bash scripts directly, we need to make a shim for each function -# -# @flag --clear Clear the shims -build-win-shims() { - funcs=($(_choice_func)) - for func in "${funcs[@]}"; do - echo "Shim bin/${func}.cmd" - _win_shim > "bin/${func}.cmd" - done +build-single-declaration() { + func="$1" + lang="${func##*.}" + cmd="$(_lang_to_cmd "$lang")" + if [[ "$lang" == sh ]]; then + argc --argc-export "$lang/$func" | _parse_argc_declaration + else + LLM_FUNCTION_DECLARATE=1 "$cmd" "cmd/cmd.$lang" "$func" + fi +} + +# @cmd List functions that can be put into functions.txt +# Examples: +# argc --list-functions > functions.txt +# argc --list-functions --write +# argc --list-functions search_duckduckgo.sh >> functions.txt +# @flag -w --write Output to functions.txt +# @arg funcs*[`_choice_func`] The function filenames, list all available functions if not provided +list-functions() { + if [[ -n "$argc_write" ]]; then + _choice_func > functions.txt + echo "Write functions.txt" + else + _choice_func + fi +} + +# @cmd Test the project +# @meta require-tools node,python,ruby +test() { + names_file=functions.txt.test + argc list-functions > "$names_file" + argc build --names-file "$names_file" + argc test-call-functions +} + + +# @cmd Test call functions +test-call-functions() { + if _is_win; then + ext=".cmd" + fi + "./bin/may_execute_command$ext" --command 'echo "bash works"' + argc call may_execute_command.sh --command 'echo "bash works"' + + export LLM_FUNCTION_DATA='{"code":"console.log(\"javascript works\")"}' + "./bin/may_execute_js_code$ext" + argc call may_execute_js_code.js + + export LLM_FUNCTION_DATA='{"code":"print(\"python works\")"}' + "./bin/may_execute_py_code$ext" + argc call may_execute_py_code.py + + export LLM_FUNCTION_DATA='{"code":"puts \"ruby works\""}' + "./bin/may_execute_rb_code$ext" + argc call may_execute_rb_code.rb } # @cmd Install this repo to aichat functions_dir @@ -80,7 +204,7 @@ version() { curl --version | head -n 1 } -_parse_declaration() { +_parse_argc_declaration() { jq -r ' def parse_description(flag_option): if flag_option.describe == "" then @@ -123,26 +247,66 @@ _parse_declaration() { }' } -_win_shim() { +_lang_to_cmd() { + match_lang="$1" + for item in "${LANG_CMDS[@]}"; do + lang="${item%:*}" + if [[ "$lang" == "$match_lang" ]]; then + echo "${item#*:}" + fi + done +} + +_build_win_sh() { cat <<-'EOF' @echo off setlocal -set "script_dir=%~dp0" +set "bin_dir=%~dp0" +for %%i in ("%bin_dir:~0,-1%") do set "script_dir=%%~dpi" set "script_name=%~n0" +set "script_name=%script_name%.sh" for /f "delims=" %%a in ('argc --argc-shell-path') do set "_bash_prog=%%a" -"%_bash_prog%" --noprofile --norc "%script_dir%\%script_name%" %* +"%_bash_prog%" --noprofile --norc "%script_dir%sh\%script_name%" %* EOF } +_build_win_lang() { + lang="$1" + cmd="$2" + cat <<-EOF +@echo off +setlocal + +set "bin_dir=%~dp0" +for %%i in ("%bin_dir:~0,-1%") do set "script_dir=%%~dpi" +set "script_name=%~n0" + +$cmd "%script_dir%cmd\cmd.$lang" "%script_name%.$lang" %* +EOF +} + +_is_win() { + if [[ "$OS" == "Windows_NT" ]]; then + return 0 + else + return 1 + fi +} + _choice_func() { - ls -1 bin | grep -v '\.cmd' + for item in "${LANG_CMDS[@]}"; do + lang="${item%:*}" + ls -1 $lang | grep "\.$lang$" + done } _choice_func_args() { args=( "${argc__positionals[@]}" ) - argc --argc-compgen generic "bin/${args[0]}" "${args[@]}" + if [[ "${args[0]}" == *.sh ]]; then + argc --argc-compgen generic "sh/${args[0]}" "${args[@]}" + fi } _die() { |
