✨ feat(fish): projectdo plugin
This commit is contained in:
parent
db9d40a5ea
commit
3799ea855f
10 changed files with 431 additions and 4 deletions
4
.config/fish/abbreviations.fish
Normal file
4
.config/fish/abbreviations.fish
Normal file
|
@ -0,0 +1,4 @@
|
|||
abbr -a b --function projectdo_build
|
||||
abbr -a r --function projectdo_run
|
||||
abbr -a t --function projectdo_test
|
||||
abbr -a p --function projectdo_tool
|
23
.config/fish/completions/projectdo.fish
Normal file
23
.config/fish/completions/projectdo.fish
Normal file
|
@ -0,0 +1,23 @@
|
|||
complete -c projectdo --no-files
|
||||
|
||||
set -l commands build run test tool
|
||||
|
||||
# Options
|
||||
complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
|
||||
-s h -l help -d 'Display usage information'
|
||||
complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
|
||||
-s d -l 'dry-run' -d 'Do not execute any commands with side-effects'
|
||||
complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
|
||||
-s q -l quiet -d 'Do not print commands before execution'
|
||||
complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
|
||||
-s v -l version -d 'Dsiplay the version'
|
||||
|
||||
# Actions
|
||||
complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
|
||||
-a build -d 'Build the current project'
|
||||
complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
|
||||
-a run -d 'Run the current project'
|
||||
complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
|
||||
-a test -d 'Test the current project'
|
||||
complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
|
||||
-a tool -d 'Invoke the tool corresponding to the current project'
|
|
@ -1,5 +1,6 @@
|
|||
source ~/.config/fish/variables.fish
|
||||
source ~/.config/fish/keybinds.fish
|
||||
source ~/.config/fish/abbreviations.fish
|
||||
|
||||
if status is-interactive
|
||||
atuin init fish | source
|
||||
|
@ -10,4 +11,4 @@ end
|
|||
starship init fish | source
|
||||
zoxide init fish | source
|
||||
|
||||
alias cd='z' # Couldn't create it as a function because of zoxide init
|
||||
alias cd='z' # Couldn't create it as a function because of zoxide init
|
|
@ -5,3 +5,4 @@ patrickf1/fzf.fish
|
|||
wfxr/forgit
|
||||
danhper/fish-ssh-agent
|
||||
gazorby/fish-abbreviation-tips
|
||||
paldepind/projectdo
|
||||
|
|
|
@ -13,16 +13,17 @@ SETUVAR --export XDG_CACHE_HOME:/home/matt/\x2ecache
|
|||
SETUVAR --export XDG_CONFIG_HOME:/home/matt/\x2econfig
|
||||
SETUVAR --export XDG_DATA_HOME:/home/matt/\x2elocal/share
|
||||
SETUVAR --export XDG_SCRIPT_HOME:/home/matt/\x2elocal/script
|
||||
SETUVAR --export __ABBR_TIPS_KEYS:a__bruh\x1ea__cat\x1ea__cd\x1ea__clock\x1ea__codeinfo\x1ea__disks\x1ea__dots\x1ea__dsize\x1ea__ea\x1ea__ef\x1ea__eg\x1ea__ev\x1ea__f\x1ea__fetch\x1ea__files\x1ea__fsend\x1ea__ga\x1ea__gbd\x1ea__gbl\x1ea__gcb\x1ea__gcf\x1ea__gclean\x1ea__gco\x1ea__gcp\x1ea__gct\x1ea__gd\x1ea__gfetch\x1ea__gfu\x1ea__gi\x1ea__glo\x1ea__gpt\x1ea__grb\x1ea__grc\x1ea__grh\x1ea__gsp\x1ea__gss\x1ea__h\x1ea__info\x1ea__install\x1ea__ip\x1ea__l\x1ea__ld\x1ea__ldh\x1ea__lg\x1ea__lh\x1ea__ls\x1ea__lsh\x1ea__lt\x1ea__lth\x1ea__matrix\x1ea__pages\x1ea__q\x1ea__svn\x1ea__sysproc\x1ea__uninstall\x1ea__update\x1ea__vi\x1ea__vim\x1ea__yP\x1ea__ya\x1ea__yarn\x1ea__yc\x1ea__ym\x1ea__yp\x1ea__yst\x1ea__ysw\x1ea__z\x1ea__zi
|
||||
SETUVAR --export __ABBR_TIPS_VALUES:genact\x20\x2ds\x204\x1ebat\x1ez\x1etty\x2dclock\x20\x2dsbc\x1escc\x20\x2e/\x1eduf\x1eyadm\x20enter\x20lazygit\x1edua\x20i\x1envim\x20\x7e/\x2econfig/fish/aliases\x2efish\x1envim\x20\x7e/\x2econfig/fish/config\x2efish\x1envim\x20\x7e/\x2egitconfig\x1envim\x20\x7e/\x2econfig/fish/variables\x2efish\x1efzf\x1eneofetch\x1explr\x1efloaterm\x1eforgit\x3a\x3aadd\x1eforgit\x3a\x3abranch\x3a\x3adelete\x1eforgit\x3a\x3ablame\x1eforgit\x3a\x3acheckout\x3a\x3abranch\x1eforgit\x3a\x3acheckout\x3a\x3afile\x1eforgit\x3a\x3aclean\x1eforgit\x3a\x3acheckout\x3a\x3acommit\x1eforgit\x3a\x3acherry\x3a\x3apick\x3a\x3afrom\x3a\x3abranch\x1eforgit\x3a\x3acheckout\x3a\x3atag\x1eforgit\x3a\x3adiff\x1eonefetch\x1eforgit\x3a\x3afixup\x1eforgit\x3a\x3aignore\x1eforgit\x3a\x3alog\x1etgpt\x20\x2di\x1eforgit\x3a\x3arebase\x1eforgit\x3a\x3arevert\x3a\x3acommit\x1eforgit\x3a\x3areset\x3a\x3ahead\x1eforgit\x3a\x3astash\x3a\x3apush\x1eforgit\x3a\x3astash\x3a\x3ashow\x1ezi\x1etldr\x1eyay\x20\x2dS\x20\x1eip\x20\x2dc\x20a\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2da\x20\x2d\x2dicons\x20\x2d\x2dgit\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2da\x20\x2d\x2dicons\x20\x2dD\x20\x2d\x2dgit\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2d\x2dicons\x20\x2dD\x20\x2d\x2dgit\x1elazygit\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2d\x2dicons\x20\x2d\x2dgit\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eeza\x20\x2da\x20\x2d\x2dicons\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eeza\x20\x2d\x2dicons\x20\x2d\x2dgit\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2da\x20\x2d\x2dicons\x20\x2d\x2dtree\x20\x2d\x2dgit\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2d\x2dicons\x20\x2d\x2dtree\x20\x2d\x2dgit\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eunimatrix\x20\x2ds\x2095\x1enavi\x1eexit\x1esvn\x5c\x5c\x5c\x20\x2d\x2dconfig\x2ddir\x5c\x5c\x5c\x20\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x22\x5c\x5c\x5c\x24XDG_CONFIG_HOME\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x22/subversion\x1esysz\x1eyay\x20\x2dR\x20\x1eyay\x20\x2dSyu\x1envim\x1envim\x1eyadm\x20push\x1eyadm\x20add\x1eyarn\x20\x2d\x2duse\x2dyarnrc\x20\x22\x24XDG_CONFIG_HOME/yarn/config\x22\x1eyadm\x20commit\x20\x2dS\x20\x2da\x20\x2dm\x1eyadm\x20merge\x1eyadm\x20pull\x1eyadm\x20status\x1eyadm\x20switch\x1e__zoxide_z\x1e__zoxide_zi
|
||||
SETUVAR --export __ABBR_TIPS_KEYS:a__bruh\x1ea__cat\x1ea__cd\x1ea__clock\x1ea__codeinfo\x1ea__disks\x1ea__dots\x1ea__dsize\x1ea__ea\x1ea__ef\x1ea__eg\x1ea__ev\x1ea__f\x1ea__fetch\x1ea__files\x1ea__fsend\x1ea__ga\x1ea__gbd\x1ea__gbl\x1ea__gcb\x1ea__gcf\x1ea__gclean\x1ea__gco\x1ea__gcp\x1ea__gct\x1ea__gd\x1ea__gfetch\x1ea__gfu\x1ea__gi\x1ea__glo\x1ea__gpt\x1ea__grb\x1ea__grc\x1ea__grh\x1ea__gsp\x1ea__gss\x1ea__h\x1ea__info\x1ea__install\x1ea__ip\x1ea__l\x1ea__ld\x1ea__ldh\x1ea__lh\x1ea__ls\x1ea__lsh\x1ea__lt\x1ea__lth\x1ea__matrix\x1ea__q\x1ea__svn\x1ea__sysproc\x1ea__uninstall\x1ea__update\x1ea__vim\x1ea__yP\x1ea__ya\x1ea__yarn\x1ea__yc\x1ea__ym\x1ea__yp\x1ea__yst\x1ea__ysw\x1ea__z\x1ea__zi
|
||||
SETUVAR --export __ABBR_TIPS_VALUES:genact\x20\x2ds\x204\x1ebat\x1ez\x1etty\x2dclock\x20\x2dsbc\x1escc\x20\x2e/\x1eduf\x1eyadm\x20enter\x20lazygit\x1edua\x20i\x1envim\x20\x7e/\x2econfig/fish/aliases\x2efish\x1envim\x20\x7e/\x2econfig/fish/config\x2efish\x1envim\x20\x7e/\x2egitconfig\x1envim\x20\x7e/\x2econfig/fish/variables\x2efish\x1efzf\x1eneofetch\x1explr\x1efloaterm\x1eforgit\x3a\x3aadd\x1eforgit\x3a\x3abranch\x3a\x3adelete\x1eforgit\x3a\x3ablame\x1eforgit\x3a\x3acheckout\x3a\x3abranch\x1eforgit\x3a\x3acheckout\x3a\x3afile\x1eforgit\x3a\x3aclean\x1eforgit\x3a\x3acheckout\x3a\x3acommit\x1eforgit\x3a\x3acherry\x3a\x3apick\x3a\x3afrom\x3a\x3abranch\x1eforgit\x3a\x3acheckout\x3a\x3atag\x1eforgit\x3a\x3adiff\x1eonefetch\x1eforgit\x3a\x3afixup\x1eforgit\x3a\x3aignore\x1eforgit\x3a\x3alog\x1etgpt\x20\x2di\x1eforgit\x3a\x3arebase\x1eforgit\x3a\x3arevert\x3a\x3acommit\x1eforgit\x3a\x3areset\x3a\x3ahead\x1eforgit\x3a\x3astash\x3a\x3apush\x1eforgit\x3a\x3astash\x3a\x3ashow\x1ezi\x1etldr\x1eyay\x20\x2dS\x20\x1eip\x20\x2dc\x20a\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2da\x20\x2d\x2dicons\x20\x2d\x2dgit\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2da\x20\x2d\x2dicons\x20\x2dD\x20\x2d\x2dgit\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2d\x2dicons\x20\x2dD\x20\x2d\x2dgit\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2d\x2dicons\x20\x2d\x2dgit\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eeza\x20\x2da\x20\x2d\x2dicons\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eeza\x20\x2d\x2dicons\x20\x2d\x2dgit\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2da\x20\x2d\x2dicons\x20\x2d\x2dtree\x20\x2d\x2dgit\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eeza\x20\x2d\x2dlong\x20\x2d\x2dheader\x20\x2d\x2dicons\x20\x2d\x2dtree\x20\x2d\x2dgit\x20\x2d\x2dgroup\x2ddirectories\x2dfirst\x1eunimatrix\x20\x2ds\x2095\x1eexit\x1esvn\x5c\x5c\x5c\x20\x2d\x2dconfig\x2ddir\x5c\x5c\x5c\x20\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x22\x5c\x5c\x5c\x24XDG_CONFIG_HOME\x5c\x5c\x5c\x5c\x5c\x5c\x5c\x22/subversion\x1esysz\x1eyay\x20\x2dR\x20\x1eyay\x20\x2dSyu\x1envim\x1eyadm\x20push\x1eyadm\x20add\x1eyarn\x20\x2d\x2duse\x2dyarnrc\x20\x22\x24XDG_CONFIG_HOME/yarn/config\x22\x1eyadm\x20commit\x20\x2dS\x20\x2da\x20\x2dm\x1eyadm\x20merge\x1eyadm\x20pull\x1eyadm\x20status\x1eyadm\x20switch\x1e__zoxide_z\x1e__zoxide_zi
|
||||
SETUVAR __fish_initialized:3400
|
||||
SETUVAR _fisher_acomagu_2F_fish_2D_async_2D_prompt_files:\x7e/\x2econfig/fish/conf\x2ed/__async_prompt\x2efish
|
||||
SETUVAR _fisher_danhper_2F_fish_2D_ssh_2D_agent_files:\x7e/\x2econfig/fish/functions/__ssh_agent_is_started\x2efish\x1e\x7e/\x2econfig/fish/functions/__ssh_agent_start\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/fish\x2dssh\x2dagent\x2efish
|
||||
SETUVAR _fisher_franciscolourenco_2F_done_files:\x7e/\x2econfig/fish/conf\x2ed/done\x2efish
|
||||
SETUVAR _fisher_gazorby_2F_fish_2D_abbreviation_2D_tips_files:\x7e/\x2econfig/fish/functions/__abbr_tips_bind_newline\x2efish\x1e\x7e/\x2econfig/fish/functions/__abbr_tips_bind_space\x2efish\x1e\x7e/\x2econfig/fish/functions/__abbr_tips_clean\x2efish\x1e\x7e/\x2econfig/fish/functions/__abbr_tips_init\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/abbr_tips\x2efish
|
||||
SETUVAR _fisher_joehillen_2F_to_2D_fish_files:\x7e/\x2econfig/fish/functions/to\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/to\x2efish\x1e\x7e/\x2econfig/fish/completions/to\x2efish
|
||||
SETUVAR _fisher_paldepind_2F_projectdo_files:\x7e/\x2econfig/fish/functions/projectdo_build\x2efish\x1e\x7e/\x2econfig/fish/functions/projectdo_run\x2efish\x1e\x7e/\x2econfig/fish/functions/projectdo_test\x2efish\x1e\x7e/\x2econfig/fish/functions/projectdo_tool\x2efish\x1e\x7e/\x2econfig/fish/completions/projectdo\x2efish
|
||||
SETUVAR _fisher_patrickf1_2F_fzf_2E_fish_files:\x7e/\x2econfig/fish/functions/_fzf_configure_bindings_help\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_extract_var_info\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_preview_changed_file\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_preview_file\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_report_diff_type\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_report_file_type\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_directory\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_git_log\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_git_status\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_history\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_processes\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_variables\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_wrapper\x2efish\x1e\x7e/\x2econfig/fish/functions/fzf_configure_bindings\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/fzf\x2efish\x1e\x7e/\x2econfig/fish/completions/fzf_configure_bindings\x2efish
|
||||
SETUVAR _fisher_plugins:franciscolourenco/done\x1eacomagu/fish\x2dasync\x2dprompt\x1ejoehillen/to\x2dfish\x1epatrickf1/fzf\x2efish\x1ewfxr/forgit\x1edanhper/fish\x2dssh\x2dagent\x1egazorby/fish\x2dabbreviation\x2dtips
|
||||
SETUVAR _fisher_plugins:franciscolourenco/done\x1eacomagu/fish\x2dasync\x2dprompt\x1ejoehillen/to\x2dfish\x1epatrickf1/fzf\x2efish\x1ewfxr/forgit\x1edanhper/fish\x2dssh\x2dagent\x1egazorby/fish\x2dabbreviation\x2dtips\x1epaldepind/projectdo
|
||||
SETUVAR _fisher_upgraded_to_4_4:\x1d
|
||||
SETUVAR _fisher_wfxr_2F_forgit_files:\x7e/\x2econfig/fish/conf\x2ed/bin\x1e\x7e/\x2econfig/fish/conf\x2ed/forgit\x2eplugin\x2efish\x1e\x7e/\x2econfig/fish/completions/_git\x2dforgit\x1e\x7e/\x2econfig/fish/completions/git\x2dforgit\x2ebash\x1e\x7e/\x2econfig/fish/completions/git\x2dforgit\x2ezsh
|
||||
SETUVAR fish_color_autosuggestion:6e738d
|
||||
|
|
3
.config/fish/functions/projectdo_build.fish
Normal file
3
.config/fish/functions/projectdo_build.fish
Normal file
|
@ -0,0 +1,3 @@
|
|||
function projectdo_build
|
||||
projectdo -d build
|
||||
end
|
3
.config/fish/functions/projectdo_run.fish
Normal file
3
.config/fish/functions/projectdo_run.fish
Normal file
|
@ -0,0 +1,3 @@
|
|||
function projectdo_run
|
||||
projectdo -d run
|
||||
end
|
3
.config/fish/functions/projectdo_test.fish
Normal file
3
.config/fish/functions/projectdo_test.fish
Normal file
|
@ -0,0 +1,3 @@
|
|||
function projectdo_test
|
||||
projectdo -d test
|
||||
end
|
3
.config/fish/functions/projectdo_tool.fish
Normal file
3
.config/fish/functions/projectdo_tool.fish
Normal file
|
@ -0,0 +1,3 @@
|
|||
function projectdo_tool
|
||||
projectdo -d tool
|
||||
end
|
385
.local/bin/projectdo
Executable file
385
.local/bin/projectdo
Executable file
|
@ -0,0 +1,385 @@
|
|||
#!/bin/sh
|
||||
|
||||
# projectdo – universal project commands.
|
||||
# Copyright (C) 2019-present Simon Friis Vindum
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
VERSION="0.2.0"
|
||||
|
||||
# Global mutable variables.
|
||||
QUIET=false
|
||||
DRY_RUN=false
|
||||
PROJECT_ROOT="${PROJECT_ROOT:-}"
|
||||
ACTION=""
|
||||
TOOL_ARGS="" # Arguments to pass along to the tool
|
||||
IS_TOOL=false # True if ACTION is 'tool' as this action is somewhat special.
|
||||
|
||||
has_command() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# When running the appropriate external tool this function is used which
|
||||
# evaluates the given command while respecting $QUIET and $DRY_RUN.
|
||||
execute() {
|
||||
if [ $QUIET = false ]; then
|
||||
echo "$1" $TOOL_ARGS
|
||||
fi
|
||||
if [ $DRY_RUN = false ]; then
|
||||
if [ $QUIET = false ]; then
|
||||
eval "$1" $TOOL_ARGS
|
||||
else
|
||||
eval "$1" $TOOL_ARGS > /dev/null
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Takes the name of a tool and an action. If the action is `tool` it is
|
||||
# ignored. It handles the common case where the tool is invoked as `tool
|
||||
# action`.
|
||||
execute_command() {
|
||||
if [ "$2" = tool ]; then
|
||||
execute "$1"
|
||||
else
|
||||
execute "$1 $2"
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Every supported tool requires a function `try_tool` where `tool` is a name
|
||||
# indicating what tool the function tries to detect. The function should:
|
||||
#
|
||||
# * Return if it does not detect that the tool is appropriate.
|
||||
# * Read the variables `ACTION` and `IS_TOOL` to determine the correct action
|
||||
# to run.
|
||||
# * When running an action is should use the `execute` function and _exit_ when
|
||||
# it is done.
|
||||
|
||||
# Start list of tools
|
||||
|
||||
# JavaScript + NodeJS
|
||||
|
||||
try_nodejs() {
|
||||
if [ ! -f package.json ]; then
|
||||
return 1
|
||||
fi
|
||||
if [ -f yarn.lock ]; then
|
||||
tool=yarn
|
||||
else
|
||||
tool=npm
|
||||
fi
|
||||
if ! has_command $tool; then
|
||||
echo "Found a package.json file but '$tool' is not installed."
|
||||
exit 1
|
||||
fi
|
||||
local node_action="$ACTION"
|
||||
# Only the "run" action need translation, the others match 1-to-1
|
||||
if [ "$ACTION" = run ]; then
|
||||
node_action=start
|
||||
fi
|
||||
# We check if the package.json file contains an appropriate script. We use
|
||||
# grep for this. The check is not 100% bulletproof, but it's very close. We
|
||||
# could've used `npm run` to get the authorative list of the scripts but
|
||||
# invoking `npm` is two orders of magnitude slower which leads to a
|
||||
# noticeable delay.
|
||||
if ! $IS_TOOL && ! grep -q "^[[:space:]]*\"${node_action}\":" package.json; then
|
||||
return 0
|
||||
fi
|
||||
execute_command "$tool" "$node_action"
|
||||
}
|
||||
|
||||
# Rust + Cargo
|
||||
|
||||
try_cargo() {
|
||||
if [ -f Cargo.toml ]; then
|
||||
execute_command cargo "$ACTION"
|
||||
fi
|
||||
}
|
||||
|
||||
# CMake
|
||||
|
||||
try_cmake() {
|
||||
if [ -f CMakeLists.txt ] && [ "$ACTION" = test ]; then
|
||||
if [ -f build ]; then
|
||||
execute "cmake --build build --target test"
|
||||
else
|
||||
execute "cmake --build . --target test"
|
||||
fi
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
# Haskell + Stack
|
||||
|
||||
try_stack() {
|
||||
if [ -f package.yaml ] && [ -f stack.yaml ]; then
|
||||
execute_command stack "$ACTION"
|
||||
fi
|
||||
}
|
||||
|
||||
# Haskell + Cabal
|
||||
|
||||
try_cabal() {
|
||||
cabal_file="$(find ./ -maxdepth 1 -name "*.cabal" 2> /dev/null | wc -l)"
|
||||
if [ "$cabal_file" -gt 0 ] && [ ! -f stack.yml ]; then
|
||||
execute_command cabal "$ACTION"
|
||||
fi
|
||||
}
|
||||
|
||||
# Maven
|
||||
|
||||
try_maven() {
|
||||
if [ -f pom.xml ]; then
|
||||
case $ACTION in
|
||||
build)
|
||||
execute "mvn compile"
|
||||
exit ;;
|
||||
test)
|
||||
execute "mvn test"
|
||||
exit ;;
|
||||
run)
|
||||
echo "projectdo does not know how to run a project with Maven."
|
||||
exit
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
# Clojure + Leiningen
|
||||
|
||||
try_lein() {
|
||||
if [ -f project.clj ] && [ "$ACTION" = test ]; then
|
||||
execute "lein test"
|
||||
fi
|
||||
}
|
||||
|
||||
# Makefile
|
||||
|
||||
has_make_target() {
|
||||
target="${1?}"
|
||||
output=$(make -n "${target}" 2>&1)
|
||||
exit_code=$?
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
return $exit_code
|
||||
fi
|
||||
|
||||
# If there is a file with the name of the target we're looking for but no
|
||||
# actual target with that name, make will exit successfully with that
|
||||
# message. We need to consider that case as a "target not found". Note that
|
||||
# the way the target is quoted in the output (`test' vs 'test') can differ
|
||||
# across OSes so we only check a prefix up to the problematic quotes.
|
||||
if expr "$output" : "make: Nothing to be done for" 1> /dev/null; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
try_makefile() {
|
||||
if [ -f Makefile ]; then
|
||||
if ! has_command "make"; then
|
||||
echo "Found a Makefile but 'make' is not installed."
|
||||
exit 1
|
||||
fi
|
||||
if $IS_TOOL || [ "$ACTION" = build ]; then
|
||||
# For make "build" is the default action when running `make`
|
||||
execute "make"
|
||||
exit
|
||||
elif [ "$ACTION" = test ]; then
|
||||
# Let's see if the makefile contains a test or check target
|
||||
if has_make_target "test"; then
|
||||
execute "make test"
|
||||
exit
|
||||
elif has_make_target "check"; then
|
||||
execute "make check"
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Python
|
||||
|
||||
try_python() {
|
||||
if [ -f pyproject.toml ]; then
|
||||
if grep -q -m 1 "^\[tool.poetry\]$" pyproject.toml; then
|
||||
case $ACTION in
|
||||
build)
|
||||
execute "poetry build"
|
||||
exit ;;
|
||||
test)
|
||||
# TODO: There are other Python test frameworks, it would be nice to
|
||||
# detect and run the right one.
|
||||
execute "poetry run pytest"
|
||||
exit ;;
|
||||
run)
|
||||
echo "projectdo does not know how to run a project with Poetry."
|
||||
exit
|
||||
esac
|
||||
else
|
||||
echo "Found a pyproject.toml file but projectdo is not sure how to run it."
|
||||
exit
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Go
|
||||
|
||||
try_go() {
|
||||
if [ -f go.mod ] && [ "$ACTION" = test ]; then
|
||||
# We detect Makefiles before we detect Go, so here we know that the Go
|
||||
# project is _not_ tested by a Makefile.
|
||||
|
||||
# Check if the project uses Mage. A magefile could in theory have any name,
|
||||
# but `magefile.go` seems to be the convention.
|
||||
if grep -q -m 1 '^func Check(' magefile.go; then
|
||||
execute "mage check"
|
||||
exit
|
||||
elif grep -q -m 1 '^func Test(' magefile.go; then
|
||||
execute "mage test"
|
||||
exit
|
||||
fi
|
||||
execute "go test"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
# LaTeX
|
||||
|
||||
try_latex() {
|
||||
if [ -f Tectonic.toml ] && [ "$ACTION" = build ]; then
|
||||
execute "tectonic -X build"
|
||||
exit
|
||||
fi
|
||||
}
|
||||
|
||||
# End of list of tools
|
||||
|
||||
detect_and_run() {
|
||||
try_nodejs
|
||||
try_cargo
|
||||
try_stack
|
||||
try_cabal
|
||||
try_cmake
|
||||
try_maven
|
||||
try_lein
|
||||
try_makefile
|
||||
try_python
|
||||
try_go
|
||||
try_latex
|
||||
}
|
||||
|
||||
set_project_root() {
|
||||
if [ -n "$PROJECT_ROOT" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if has_command git; then
|
||||
# Find the root of the git repository if we're inside one. If we're in a
|
||||
# git submodule then the root of the outer git repo is used. If we're not
|
||||
# in a git repo the git command will not output anything and $PROJECT_ROOT
|
||||
# is set to the empty string which is fine.
|
||||
PROJECT_ROOT=$(git rev-parse --show-superproject-working-tree --show-toplevel 2> /dev/null | head -n 1)
|
||||
fi
|
||||
}
|
||||
|
||||
nothing_found() {
|
||||
echo "No way to $ACTION found :'("
|
||||
exit 1
|
||||
}
|
||||
|
||||
display_version() {
|
||||
echo "$(basename "$0") version $VERSION"
|
||||
}
|
||||
|
||||
display_help() {
|
||||
echo "Usage: $(basename "$0") [options] [action] [tool-arguments]
|
||||
Options:
|
||||
-h, --help Display this help.
|
||||
-n, -d, --dry-run Do not execute any commands with side-effects.
|
||||
-q, --quiet Do not print commands as they are about to be executed.
|
||||
-v, --version Display the version of the program (which is $VERSION).
|
||||
|
||||
Actions:
|
||||
build, run, test Build, run, or test the current project.
|
||||
tool Invoke the guessed tool for the current project.
|
||||
|
||||
Tool arguments:
|
||||
Any arguments following [action] are passed along to the invoked tool."
|
||||
}
|
||||
|
||||
# Main execution starts here
|
||||
|
||||
while getopts dhnqv-: c
|
||||
do
|
||||
case $c in
|
||||
d) DRY_RUN=true ;;
|
||||
h) display_help; exit 0 ;;
|
||||
n) DRY_RUN=true ;;
|
||||
q) QUIET=true ;;
|
||||
v) display_version; exit 0 ;;
|
||||
-) case $OPTARG in
|
||||
help) display_help; exit 0 ;;
|
||||
dry-run) DRY_RUN=true ;;
|
||||
quiet) QUIET=true ;;
|
||||
version) display_version; exit 0 ;;
|
||||
'' ) break ;; # "--" should terminate argument processing
|
||||
* ) echo "Illegal option --$OPTARG" >&2; exit 1 ;;
|
||||
esac ;;
|
||||
\?) exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $((OPTIND-1)) # Shift away the parsed option arguments
|
||||
|
||||
if [ "$1" = test ] ||
|
||||
[ "$1" = run ] ||
|
||||
[ "$1" = build ] ||
|
||||
[ "$1" = tool ]; then
|
||||
ACTION=$1
|
||||
if [ "$1" = tool ]; then
|
||||
IS_TOOL=true
|
||||
fi
|
||||
shift 1 # Remove the action from the arguments
|
||||
TOOL_ARGS=$@
|
||||
else
|
||||
if [ -z "$1" ]; then
|
||||
echo "No action specified."
|
||||
else
|
||||
echo "$1 is not a valid action."
|
||||
fi
|
||||
echo ""
|
||||
echo "The valid actions are: build, run, test, tool"
|
||||
echo ""
|
||||
echo "Example: projectdo test"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set_project_root
|
||||
|
||||
while :
|
||||
do
|
||||
# We don't want to do anything if we are in the home or root directory
|
||||
if [ "$PWD" = "$HOME" ] || [ "$PWD" = / ]; then
|
||||
nothing_found
|
||||
fi
|
||||
detect_and_run
|
||||
# If we didn't detect a tool to run in this directory we go up one directory
|
||||
# while ensuring that we don't leave the project root
|
||||
if [ "$PWD" = "$PROJECT_ROOT" ]; then
|
||||
nothing_found
|
||||
fi
|
||||
cd ..
|
||||
done
|
Loading…
Add table
Reference in a new issue