Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Create scripts from terminal #8

Merged
merged 14 commits into from
Jun 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 133 additions & 12 deletions scripts/core/output.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,145 @@
#!/usr/bin/env bash

red='\033[0;31m'
green='\033[0;32m'
bold_blue='\033[1m\033[34m'
normal='\033[0m'

_output::parse_code() {
local color="$normal"
case "${1:-}" in
--color)
color="$2"
shift 2
;;
esac

echo "color: $color"

local -r text="${*:-}"

with_code_parsed=$(echo "$text" | awk "{ORS=(NR+1)%2==0?\"${green}\":RS}1" RS="\`" | awk "{ORS=NR%1==0?\"${color}\":RS}1" RS="\`" | tr -d '\n')

echo -e "$with_code_parsed"
}

output::write() {
local -r text="${1:-}"
echo -e "$text"
local with_code_parsed color
color="$normal"
case "${1:-}" in
--color)
color="$2"
shift 2
;;
esac

local -r text="${*:-}"
with_code_parsed="$(_output::parse_code --color "${color}" "$text")"
echo -e "$with_code_parsed"
}
output::answer() {
local color
color="$normal"
case "${1:-}" in
--color)
color="$2"
shift 2
;;
esac
output::write --color "${color}" " > ${*:-}";
}
output::answer() { output::write " > $1"; }
output::error() { output::answer "${red}$1${normal}"; }
output::solution() { output::answer "${green}$1${normal}"; }
output::error() { output::answer --color "${red}" "${red}${*:-}${normal}"; }
output::solution() { output::answer --color "${green}" "${green}${*:-}${normal}"; }
output::question() {
if [ platform::is_macos ]; then
output::answer "🤔 $1: ";
read -r "$2";
local with_code_parsed color
color="$normal"
case "${1:-}" in
--color)
color="$2"
shift 2
;;
esac
with_code_parsed="$(_output::parse_code --color "${color}" "${1:-}")"

if [ "${DOTLY_ENV:-PROD}" == "CI" ] || [ "${DOTLY_INSTALLER:-false}" = true ]; then
answer="y"
else
read -rp "🤔 $with_code_parsed: " "answer"
fi

echo "$answer"
}
output::answer_is_yes() {
if [[ "${1:-Y}" =~ ^[Yy] ]]; then
return 0
fi

return 1
}

output::question_default() {
local with_code_parsed color question default_value var_name
color="$normal"
case "${1:-}" in
--color)
color="$2"
shift 2
;;
esac

[[ $# -lt 3 ]] && return 1

question="$1"
default_value="$2"
var_name="$3"

with_code_parsed="$(_output::parse_code --color "${color}" "$question")"

read -rp "🤔 $with_code_parsed ? [$default_value]: " PROMPT_REPLY
eval "$var_name=\"${PROMPT_REPLY:-$default_value}\""
}

output::yesno() {
local with_code_parsed color question default PROMPT_REPLY values
color="$normal"
case "${1:-}" in
--color)
color="$2"
shift 2
;;
esac

[[ $# -eq 0 ]] && return 1

question="$1"
default="${2:-Y}"
with_code_parsed="$(_output::parse_code --color "${color}" "$question")"

if [[ "$default" =~ ^[Yy] ]]; then
values="Y/n"
else
read -rp " $1: " "$2"
values="y/N"
fi

output::question_default "$with_code_parsed" "$values" "PROMPT_REPLY"
[[ "$PROMPT_REPLY" == "$values" ]] && PROMPT_REPLY=""
[[ "${PROMPT_REPLY:-$default}" =~ ^[Yy] ]]
}

output::empty_line() { echo ''; }
output::header() { output::empty_line; output::write "${bold_blue}---- $1 ----${normal}"; }

output::header() {
output::empty_line
output::write --color "${bold_blue}" "${bold_blue}---- ${*:-} ----${normal}"
}
output::h1_without_margin() { output::write --color "${bold_blue}" "${bold_blue}# ${*:-}${normal}"; }
output::h1() {
output::empty_line
output::h1_without_margin "${*:-}"
}
output::h2() {
output::empty_line
output::write --color "${bold_blue}" "${bold_blue}## ${*:-}${normal}"
}
output::h3() {
output::empty_line
output::write --color "${bold_blue}" "${bold_blue}### ${*:-}${normal}"
}
152 changes: 152 additions & 0 deletions scripts/script/create
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#!/usr/bin/env bash

set -euo pipefail

[[ -z "$DOTLY_PATH" ]] && exit 1

#shellcheck source=/dev/null
. "$DOTLY_PATH/scripts/core/_main.sh"
dot::load_library "templating.sh"

##? Dotly script creator
##?
##?
##? Usage:
##? create [-h | --help]
##? create [-v | --version]
##? create bin <name>
##? create [-c | --core] [-s | --sample] [--author <author>] [--email <email>] <context> <script_name> [<script_description>...]
##?
##? Options:
##? bin Create a command in $DOTFILES_PATH/bin
##? -h --help Show this help
##? -v --version Show the program version
##? -s --sample Create a script using more complete example with some comments.
##? useful if it is your first script. Anyway you can see more help
##? in the docopt website: http://docopt.org
##? -c --core Create the context and script in "$DOTLY_PATH/scripts" instead of
##? your "$DOTFILES_PATH/scripts" folder
##? --author <author> Provide who is the author, if none the default git author will
##? be used
##? --email <email> Provide author email, if none the default git author email will
##? be used
##?
##? Author:
##? Gabriel Trabanco <gtrabanco@users.noreply.github.com>
##?
docs::parse "$@"

SCRIPT_NAME="lazy script create"
SCRIPT_VERSION="1.1.0"

# Print name and version
if ${version:-}; then
output::write "$SCRIPT_NAME v$SCRIPT_VERSION"
exit
fi

case "${1:-}" in
"bin")
new_script_path="$DOTFILES_PATH/bin/${name:-}"
if [[ -z "${name:-}" ]]; then
output::error "🚨 No name for the script provided"
exit 1
fi

if [[ ! -d "$DOTFILES_PATH" ]]; then
output::error "❌ Your dotfiles could not be found"
exit 1
fi
mkdir -p "$DOTFILES_PATH/bin"

if [[ -f "$new_script_path" ]] &&\
! output::yesno " ⚠️ Script \`${name:-}\` exists in \`\$DOTFILES_PATH/bin\`! Do you want to overwrite it (this will delete current file)"
then
output::error "User aborted"
exit 1
fi

rm -f "$new_script_path"
touch "$new_script_path"
printf "#!/usr/bin/env bash\n\n" >> "$new_script_path"
printf "set -euo pipefail\n" >> "$new_script_path"
#shellcheck disable=SC2016
printf '. "$DOTLY_PATH/scripts/core/_main.sh"\n' >> "$new_script_path"

chmod u+x "$new_script_path"

output::empty_line
output::solution "The script \`$name\` where successfully created."
output::write ""
output::write "You can access the scipt with your favorite editor by executing:"
output::write "\$EDITOR \"\$DOTFILES_PATH/bin/${name:-}\""
output::empty_line

;;
*)
if [[ -z "${context:-}" ]] || [[ -z "${script_name:-}" ]]; then
output::error "You should provide a context and script name"
output::write "Use: $0 -h"
exit 1
fi

SCRIPT_TEMPLATE_PATH="$(dot::get_script_path)/src/templates/script"

# Path variables
if ${core:-}; then
output::empty_line
output::write "\033[0;31m\033[1m ALERT!!!!!"
output::write "Create this script in your DOTLY scripts folder could be very dangerous."
output::write "This is an option thinked only for DOTLY devs.\033[0m"
output::empty_line
output::yesno "Are you sure you still want to coninue" "N" || { output::answer "User aborted" && exit 1; }

script_path="$DOTLY_PATH/scripts/$context"
else
script_path="$DOTFILES_PATH/scripts/$context"
fi

script_filepath="$script_path/$script_name"

# Which template to use
if ${sample:-}; then
SCRIPT_TEMPLATE_PATH="${SCRIPT_TEMPLATE_PATH}-more"
fi

# Create the script context (folder)
mkdir -p "$script_path"

if [[ -d "$DOTFILES_PATH/scripts/$context" ]]; then
output::solution "$script_path were created or exists previously"
fi

# If script exits ask user to overwrite
if [[ -f $script_filepath ]]; then
output::yesno "The script exists, do you want to delete it and create a empty script" "N" ||\
{
output::error "The script name \"$script_name\" exists in context \"$context\" and user refuse to recreate the script" &&\
output::write "Provide a different name for the script or context." &&\
exit 1
}
fi

# Variables for the script
author="${author:-$(git config --global --get user.name)}"
email="${email:-$(git config --global --get user.email)}"
description="${script_description[*]:-}"

# Description can not be empty
[[ -z "$description" ]] && output::question "Description can not be empty, describe your script" "description"

cp "${SCRIPT_TEMPLATE_PATH}" "$script_filepath"
templating::replace "$script_filepath" --script-name="$script_name" --script-context="$context" --script-author="$author" --script-author-email="$email" --script-description="$description" > /dev/null
chmod u+x "$script_filepath"

output::empty_line
output::solution "The script '$script_name' where successfully created."
output::write ""
output::write "You can access the scipt with your favorite editor by executing:"
output::write "\$EDITOR \"\$DOTFILES_PATH/scripts/$context/$script_name\""
output::empty_line
;;
esac
78 changes: 78 additions & 0 deletions scripts/script/install-remote
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env bash

set -euo pipefail

[[ -z "$DOTLY_PATH" ]] && exit 1

#shellcheck source=/dev/null
. "$DOTLY_PATH/scripts/core/_main.sh"

##? Install remote context or script in your $DOTFILES_PATH from url. It
##? must be the url to the raw file.
##? If you fill the last param <script_name>, the remote file name will be
##? omited and renamed in your $DOTFILES_PATH/scripts/<context> folder
##?
##? Usage:
##? install-remote [ -h | --help ]
##? install-remote [ -v | --version ]
##? install-remote <context> <script_raw_url> [<script_name>]
##?
##? Options:
##? -h --help Show this help
##? -v --version Show the program version
##?
##?
##? Author:
##? Gabriel Trabanco Llano <gtrabanco@users.noreply.github.com>
docs::parse "$@"

SCRIPT_NAME="lazy dotly install-remote"
SCRIPT_VERSION="1.0.0"

# Print name and version
if ${version:-}; then
output::write "$SCRIPT_NAME v$SCRIPT_VERSION"
exit
fi

# Save current working directory to return user there
STARTING_DIRECTORY="$(pwd)"
CURL_BIN="$(which curl)"

# Script name if provided if not with downloaded name
[[ -n $script_name ]] && script_name_args="-o $script_name" || script_name_args=${script_name:-"-O"}

# Download command
download_command="$CURL_BIN -k -L -f -q $script_name_args"

# Scripts context directory
{ [[ -z "${context:-}" ]] || [[ -z "${script_raw_url:-}" ]]; } && output::error "Error no context or script name." && exit 1
dotfiles_context="$DOTFILES_PATH/scripts/${context:-}"

# Create context directory and move to it
mkdir -p "$dotfiles_context"
cd "$dotfiles_context" || exit 1

# Download the script
output::write "Downloading the script ⚡️"
eval "$download_command $script_raw_url"
if [ ! $? ] ; then
if [ -z "$(ls -A "$dotfiles_context" 2>/dev/null)" ]; then
output::error "The context '$dotfiles_context' is empty. File could not be downloaded."
exit 1
fi
fi

# Getting the name
script_name="$(ls -Art | tail -n 1)"

# Applying execution rights
chmod u+x "$dotfiles_context/$script_name"

# How to use it :)
echo
output::solution "The script was successfully added 😀"
output::write "You can execute the script now with:"
output::write "dot $context $script_name"

cd "$STARTING_DIRECTORY" || exit 1
Loading