Skip to content

Commit

Permalink
✨ adding new command self add-xxx
Browse files Browse the repository at this point in the history
  • Loading branch information
jcaillon committed Dec 4, 2024
1 parent 7dcef0e commit f2f0287
Show file tree
Hide file tree
Showing 21 changed files with 588 additions and 49 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ valet.tar.gz
# tests
tests.d/1005-lib-io/resources/gitignored/**
tests.d/1004-lib-system/resources/gitignored/**
tests.d/1109-self-add-command/resources/gitignored/**
92 changes: 92 additions & 0 deletions commands.d/self-add-command.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/usr/bin/env bash
set -Eeu -o pipefail
# Title: commands.d/*
# Description: this script is a valet command
# Author: github.com/jcaillon

# import the main script (should always be skipped if the command is run from valet, this is mainly for shellcheck)
if [[ -z "${GLOBAL_CORE_INCLUDED:-}" ]]; then
# shellcheck source=../libraries.d/core
source "$(dirname -- "$(command -v valet)")/libraries.d/core"
fi
# --- END OF COMMAND COMMON PART

# shellcheck source=../libraries.d/lib-string
source string
# shellcheck source=../libraries.d/lib-io
source io
# shellcheck source=../libraries.d/lib-interactive
source interactive

#===============================================================
# >>> command: self add-command
#===============================================================

##<<VALET_COMMAND
# command: self add-command
# function: selfAddCommand
# author: github.com/jcaillon
# shortDescription: Add a new command to the current extension.
# description: |-
# Call this function in an extension directory to add a new command to the extension.
#
# This will create a file from a command template in the ⌜commands.d⌝ directory.
# arguments:
# - name: commandName
# description: |-
# The name of the command to create.
# examples:
# - name: self add-command my-command
# description: |-
# Create a new command named ⌜my-command⌝ in the current extension under the ⌜commands.d⌝ directory.
##VALET_COMMAND
function selfAddCommand() {
local commandName
core::parseArguments "$@" && eval "${RETURNED_VALUE}"
core::checkParseResults "${help:-}" "${parsingErrors:-}"

local templateFlavor="default"

# the command name should only contains letters, digits, spaces and hyphens
if [[ ! ${commandName} =~ ^[-[:alnum:]" "]+$ ]]; then
core::fail "The command name should only contain letters, digits, spaces and hyphens."
return 1
fi

# check if we are working for an extension
core::getUserDirectory
if [[ ${PWD} != "${RETURNED_VALUE}"* && ! -d "commands.d" ]]; then
log::warning "The current directory is not under the valet user directory ⌜${RETURNED_VALUE}⌝."
if ! interactive::promptYesNo "It does not look like the current directory ⌜${PWD}⌝ is a valet extension, do you want to proceed anyway?" true; then
log::info "Aborting the creation of the command."
log::info "You should first create an extension with ⌜valet self extend⌝ and then cd into the created directory."
return 0
fi
fi

local fileName="${commandName// /-}"
string::kebabCaseToCamelCase "${fileName}"
local functionName="${RETURNED_VALUE}"
local newCommandFilePath="${PWD}/commands.d/${fileName}.sh"
local commandTemplateFile="${GLOBAL_VALET_HOME}/extras/template-command-${templateFlavor}.sh"

if [[ -f ${newCommandFilePath} ]]; then
log::warning "The command file ⌜${newCommandFilePath}⌝ already exists."
if ! interactive::promptYesNo "Do you want to override the existing command file?" true; then
log::info "Aborting the creation of the command."
return 0
fi
rm -f "${newCommandFilePath}"
fi

# create the commands directory if it does not exist
io::createDirectoryIfNeeded "${PWD}/commands.d"

io::readFile "${commandTemplateFile}"
local templateContent="${RETURNED_VALUE//_COMMAND_NAME_/"${commandName}"}"
templateContent="${templateContent//_FUNCTION_NAME_/"${functionName}"}"

printf "%s" "${templateContent}" >"${newCommandFilePath}"

log::success "The command ⌜${commandName}⌝ has been created with the file ⌜${newCommandFilePath}⌝."
}
88 changes: 88 additions & 0 deletions commands.d/self-add-library.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env bash
set -Eeu -o pipefail
# Title: commands.d/*
# Description: this script is a valet command
# Author: github.com/jcaillon

# import the main script (should always be skipped if the command is run from valet, this is mainly for shellcheck)
if [[ -z "${GLOBAL_CORE_INCLUDED:-}" ]]; then
# shellcheck source=../libraries.d/core
source "$(dirname -- "$(command -v valet)")/libraries.d/core"
fi
# --- END OF COMMAND COMMON PART

# shellcheck source=../libraries.d/lib-string
source string
# shellcheck source=../libraries.d/lib-io
source io
# shellcheck source=../libraries.d/lib-interactive
source interactive

#===============================================================
# >>> command: self add-library
#===============================================================

##<<VALET_COMMAND
# command: self add-library
# function: selfAddLibrary
# author: github.com/jcaillon
# shortDescription: Add a new library to the current extension.
# description: |-
# Call this function in an extension directory to add a new library to the extension.
#
# This will create a file from a library template in the ⌜libraries.d⌝ directory.
# arguments:
# - name: libraryName
# description: |-
# The name of the library to create.
# examples:
# - name: self add-library my-library
# description: |-
# Create a new library named ⌜my-library⌝ in the current extension under the ⌜libraries.d⌝ directory.
##VALET_COMMAND
function selfAddLibrary() {
local libraryName
core::parseArguments "$@" && eval "${RETURNED_VALUE}"
core::checkParseResults "${help:-}" "${parsingErrors:-}"

local templateFlavor="default"

# the library name should only contains letters, digits, underscores and hyphens
if [[ ! ${libraryName} =~ ^[-[:alnum:]_]+$ ]]; then
core::fail "The library name should only contain letters, digits, spaces and hyphens."
return 1
fi

# check if we are working for an extension
core::getUserDirectory
if [[ ${PWD} != "${RETURNED_VALUE}"* && ! -d "libraries.d" ]]; then
log::warning "The current directory is not under the valet user directory ⌜${RETURNED_VALUE}⌝."
if ! interactive::promptYesNo "It does not look like the current directory ⌜${PWD}⌝ is a valet extension, do you want to proceed anyway?" true; then
log::info "Aborting the creation of the library."
log::info "You should first create an extension with ⌜valet self extend⌝ and then cd into the created directory."
return 0
fi
fi

local newCommandFilePath="${PWD}/libraries.d/lib-${libraryName}"
local commandTemplateFile="${GLOBAL_VALET_HOME}/extras/template-library-${templateFlavor}.sh"

if [[ -f ${newCommandFilePath} ]]; then
log::warning "The library file ⌜${newCommandFilePath}⌝ already exists."
if ! interactive::promptYesNo "Do you want to override the existing library file?" true; then
log::info "Aborting the creation of the library."
return 0
fi
rm -f "${newCommandFilePath}"
fi

# create the commands directory if it does not exist
io::createDirectoryIfNeeded "${PWD}/libraries.d"

io::readFile "${commandTemplateFile}"
local templateContent="${RETURNED_VALUE//_LIBRARY_NAME_/"${libraryName}"}"

printf "%s" "${templateContent}" >"${newCommandFilePath}"

log::success "The library ⌜${libraryName}⌝ has been created with the file ⌜${newCommandFilePath}⌝."
}
9 changes: 8 additions & 1 deletion commands.d/self-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ set -Eeu -o pipefail
# - name: -s, --silent
# description: |-
# Build silently without any info logs.
# examples:
# - name: self build
# description: |-
# Build the valet user commands.
# - name: self build -d ~/my-valet-directory --silent
# description: |-
# Build the valet user commands from the directory ⌜~/my-valet-directory⌝ and with minimal log output.
##VALET_COMMAND
function selfBuild() {
local userDirectory outputFile coreOnly noOutput silent
Expand All @@ -74,7 +81,7 @@ function selfBuild() {
-C | --core-only)
coreOnly=true
;;
-O | --noOutput)
-O | --no-output)
noOutput=true
;;
-s | --silent)
Expand Down
7 changes: 7 additions & 0 deletions commands.d/self-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ options:
- name: --export-current-values
description: |-
When writing the configuration file, export the current values of the variables.
examples:
- name: self config
description: |-
Open the configuration file of Valet with your default editor.
- name: self config --no-edit --override --export-current-values
description: |-
Create (or recreate) the configuration file of Valet reusing the possible current values of the variables.
---"
function selfConfig() {
core::parseArguments "$@" && eval "${RETURNED_VALUE}"
Expand Down
5 changes: 5 additions & 0 deletions commands.d/self-export.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ fi
# - name: -a, --export-all
# description: |-
# Export all the libraries.
# examples:
# - name: !eval "$(valet self export -a)"
# description: |-
# Export all the functions defined in the Valet libraries.
# Then can then be used directly in your bash scripts or from the bash prompt.
##VALET_COMMAND
function selfExport() {
core::parseArguments "$@" && eval "${RETURNED_VALUE}"
Expand Down
15 changes: 13 additions & 2 deletions commands.d/self-extend.sh
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,20 @@ source curl
# description: |-
# Skip the execution of the `extension.setup.sh` script even if it exists.
# examples:
# - name: self extend https://github.com/jcaillon/valet-devops-toolbox.git --version latest
# - name: self extend my-new-extension
# description: |-
# Create a new extension named ⌜my-new-extension⌝ in the user directory.
# - name: self extend .
# description: |-
# Setup the current directory as an extension in the user directory.
# - name: self extend https://github.com/jcaillon/valet-devops-toolbox.git
# description: |-
# Download the latest version of the valet-devops-toolbox application and install it for Valet.
# - name: self extend https://github.com/jcaillon/valet --version extension-1 --name extension-1 --skip-setup
# description: |-
# Download the ⌜extension-1⌝ reference of the valet repository and install it as ⌜extension-1⌝ for Valet.
# Skip the execution of the `extension.setup.sh` script.
# (This is actually a fake extension for testing purposes).
##VALET_COMMAND
function selfExtend() {
local extensionUri version skipSetup name
Expand Down Expand Up @@ -188,7 +199,7 @@ function selfExtend_createExtension() {
rm -Rf "${extensionDirectory}"
fi

local -a subDirectories=(src libraries.d tests.d)
local -a subDirectories=(commands.d libraries.d tests.d)
local subdir
for subdir in "${subDirectories[@]}"; do
io::createDirectoryIfNeeded "${extensionDirectory}/${subdir}"
Expand Down
12 changes: 11 additions & 1 deletion commands.d/self-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ options:
- name: -P, --no-parallel-tests
description: |-
Disable the default behavior of running the tests in parallel. Will run the tests sequentially.
examples:
- name: self test
description: |-
Run all the tests found in the valet user directory.
- name: self test -a
description: |-
Run all the tests found in the valet user directory and automatically approve the results.
- name: self test -i '(my-thing|my-stuff)'
description: |-
Run only the test suites that match the regex pattern ⌜(my-thing|my-stuff)⌝.
---"
function selfTest() {
core::parseArguments "$@" && eval "${RETURNED_VALUE}"
Expand Down Expand Up @@ -195,7 +205,7 @@ function selfTestRunCoreTests() {
log::warning "The valet examples directory ⌜${GLOBAL_VALET_HOME}/examples.d⌝ does not exist, cannot run the tests on the core examples."
else
# we need to rebuild the commands for the examples only
selfTestUtils_rebuildCommands --user-directory "${GLOBAL_VALET_HOME}/examples.d" --noOutput
selfTestUtils_rebuildCommands --user-directory "${GLOBAL_VALET_HOME}/examples.d" --no-output

log::info "Running all test suites in directory ⌜${GLOBAL_VALET_HOME}/examples.d⌝."
selfTestUtils_runTestSuites "${GLOBAL_VALET_HOME}/examples.d/showcase/tests.d"
Expand Down
File renamed without changes.
File renamed without changes.
54 changes: 54 additions & 0 deletions extras/template-command-default.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env bash

#===============================================================
# >>> command: _COMMAND_NAME_
#===============================================================

: "---
command: _COMMAND_NAME_
function: _FUNCTION_NAME_
shortDescription: My new command one line description.
description: |-
My long description.
sudo: false
hideInMenu: false
arguments:
- name: firstArg
description: |-
First argument.
- name: more...
description: |-
Will be an an array of strings.
options:
- name: -o, --option1
description: |-
First option.
noEnvironmentVariable: true
- name: -2, --this-is-option2 <level>
description: |-
An option with a value.
noEnvironmentVariable: false
examples:
- name: _COMMAND_NAME_ -o -2 value1 arg1 more1 more2
description: |-
Call _COMMAND_NAME_ with option1, option2 and some arguments.
---"
function _FUNCTION_NAME_() {
local -a more
local firstArg option1 thisIsOption2
core::parseArguments "$@" && eval "${RETURNED_VALUE}"
core::checkParseResults "${help:-}" "${parsingErrors:-}"

log::info "First argument: ${firstArg:-}."
log::info "Option 1: ${option1:-}."
log::info "Option 2: ${thisIsOption2:-}."
log::info "More: ${more[*]}."

# example use of a library function
# Importing the string library (note that we could also do that at the beginning of the script)
# shellcheck disable=SC1091
source string
string::extractBetween "<b>My bold text</b>" "<b>" "</b>"
local extractedText="${RETURNED_VALUE}"
log::info "Extracted text is: ⌜${extractedText:-}"
}
30 changes: 30 additions & 0 deletions extras/template-library-default.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash

#===============================================================
# >>> library: _LIBRARY_NAME_
#===============================================================

# ## _LIBRARY_NAME_::myFunction
#
# Description of the function goes there.
#
# - $1: **first argument** _as string_:
# description of the first argument
# - $2: force _as bool_:
# (optional) description of the second argument
# (defaults to false)
#
# Returns:
#
# - $?: The exit code of the executable.
# - `RETURNED_VALUE`: The value to return
#
# ```bash
# _LIBRARY_NAME_::myFunction hi true
# echo "${RETURNED_VALUE}"
# ```
#
# > A note about the function.
function _LIBRARY_NAME_::myFunction() {
:;
}
4 changes: 2 additions & 2 deletions libraries.d/lib-profiler
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ function profilerCleanFile() {
awk -F $'\t' -v timePrecision="${timePrecision}" -v clearCoreLine="${clearLine}" '
BEGIN {
printf "%s\n\n", "(D=function depth, I=level of indirection, S=subshell level, timer=elapsed time in seconds, delta=delta between the last command in seconds, caller source:line=the source file and line number of the caller of the function, function=the name of the function in which the command is executed, command=the executed command)";
printf "%s\n", "D I S timer delta source:line function → command";
printf "%s\n", "D I S timer delta source:line function → command";
lastLineWasSkipped = 0;
lastTimer = 0;
baseStackLength = 99999;
Expand Down Expand Up @@ -163,7 +163,7 @@ function profilerBashCleanFile() {
local clearCoreLine="${2}"

printf "%s\n\n" "(D=function depth, I=level of indirection, S=subshell level, timer=elapsed time in seconds, delta=delta between the last command in seconds, caller source:line=the source file and line number of the caller of the function, function=the name of the function in which the command is executed, command=the executed command)"
printf "%s\n" "D I S timer delta source:line function → command"
printf "%s\n" "D I S timer delta source:line function → command"

local lastLineWasSkipped=0
local lastTimer=0
Expand Down
Loading

0 comments on commit f2f0287

Please sign in to comment.