diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..189c19e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,5 @@ +[*.sh] +charset = utf-8 +trim_trailing_whitespace = true +indent_size = 4 +indent_style = space diff --git a/README.md b/README.md index 9fff05b..fb1f4aa 100644 --- a/README.md +++ b/README.md @@ -45,13 +45,13 @@ In fact, we use it ourselves to develop `phpctl` itself: [devcontainer.json](.de ## Getting started -- [Installation guide](https://phpctl.dev/#installation) -- [How to use](https://phpctl.dev/#usage) -- [Available commands](https://phpctl.dev/commands) -- [The `.phpctlrc` file](https://phpctl.dev/phpctlrc) -- [The `phpctl.ini` file](https://phpctl.dev/phpctlini) -- [Available extensions](https://phpctl.dev/extensions) -- [Why it exists?](https://phpctl.dev/why) +- [Installation guide](./docs/index.md#installation) +- [How to use](./docs/index.md#usage) +- [Available commands](./docs/commands.md) +- [The `.phpctlrc` file](./docs/phpctlrc.md) +- [The `phpctl.ini` file](./docs/phpctlini.md) +- [Available extensions](./docs/extensions.md) +- [Why it exists?](./docs/why.md) ## Contributing Click here to read the [contributing guidelines](CONTRIBUTING.md). diff --git a/docs/_config.yml b/docs/_config.yml index 1245489..245453c 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,7 +1,7 @@ title: phpctl description: Frictionless PHP Development remote_theme: just-the-docs/just-the-docs -url: https://phpctl.dev +url: https://github.com/opencodeco/phpctl repository: https://github.com/opencodeco/phpctl permalink: pretty diff --git a/docs/index.md b/docs/index.md index aa0c9e8..3a4e8a9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,7 +18,7 @@ Take the advantage of goodies commands like `phpctl create` to start a new proje ### Installation ```shell -/bin/bash -c "$(curl -fsSL https://phpctl.dev/install.sh)" +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/opencodeco/phpctl/refs/heads/main/docs/install.sh)" ``` **That is it!** Now you have `phpctl` available in your system. @@ -26,7 +26,7 @@ Take the advantage of goodies commands like `phpctl create` to start a new proje #### Custom installation You can also pass an argument to install at a custom location (e.g. `~/bin`), but you have to make sure that folder is in your `$PATH` variable. ```shell -/bin/bash -c "$(curl -fsSL https://phpctl.dev/install.sh)" ~/bin +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/opencodeco/phpctl/refs/heads/main/docs/install.sh)" -s ~/bin ``` #### Homebrew diff --git a/docs/install.sh b/docs/install.sh index 0a536e3..130f94d 100755 --- a/docs/install.sh +++ b/docs/install.sh @@ -1,46 +1,200 @@ #!/usr/bin/env bash -INSTALL_DIR=~/.phpctl -if [ -z "$1" ]; then - SUDO=sudo - SYMLINK_DIR=/usr/local/bin +set_colors() { + # Initialize colors (if available) + if tput setaf 1 &>/dev/null; then + RED=$(tput setaf 1) + GREEN=$(tput setaf 2) + YELLOW=$(tput setaf 3) + BLUE=$(tput setaf 4) + NC=$(tput sgr0) # Reset attributes + + TPUT_AVAILABLE=true + else + RED='\033[0;31m' + GREEN='\033[0;32m' + YELLOW='\033[0;33m' + BLUE='\033[0;34m' + NC='\033[0m' # No Color + + TPUT_AVAILABLE=false + fi +} + +ensure_dir() { + if [[ -e "${SYMLINK_DIR}" ]]; then + if [[ ! -d "${SYMLINK_DIR}" ]]; then + echo "${RED}Error: ${SYMLINK_DIR} exists but is not a directory. Please remove it or choose a different path.${NC}" + exit 1 + fi + return + fi + + if [[ ! -d ${SYMLINK_DIR} ]]; then + echo "${YELLOW}$SYMLINK_DIR does not exist and will be created.${NC}" + mkdir -p "${SYMLINK_DIR}" 2>/dev/null + local success=$? + + if [[ $success != 0 ]]; then + echo -e -n "${RED}Could not create $SYMLINK_DIR. Exit status: ${success}.${NC} Try again with sudo? (Y/n) " + read -r answer + if [ "$answer" != "${answer#[Nn]}" ]; then + exit 1 + fi + + sudo mkdir -p "${SYMLINK_DIR}" 2>/dev/null + success=$? + if [[ -n $success ]]; then + echo -e -n "${RED}Could not create $SYMLINK_DIR. Exit status: ${success}.${NC}" + exit ${success} + fi + fi + fi +} + +INSTALL_DIR="${HOME}/.phpctl" +SYMLINK_DIR="/usr/local/bin" +LOCAL_SOURCES_DIR="" + +# --- Option Parsing --- +while getopts "hi:s:l:" opt; do + case $opt in + h) + echo "Install phpctl sources and creates symlinks for easy usage." + echo "" + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " -h Display this help message and exit" + echo " -i Set the installation directory (default: $HOME/.phpctl)" + echo " -s Set the symlink directory (default: /usr/local/bin)" + echo " -l Set the local sources directory. If empty, will fetch sources from github. (default: empty string)" + exit 0 + ;; + i) + INSTALL_DIR="$OPTARG" + ;; + s) + SYMLINK_DIR="$OPTARG" + ;; + l) + LOCAL_SOURCES_DIR="$OPTARG" + ;; + \?) + echo "Error: Invalid option: -$OPTARG" >&2 + echo "Try '$0 -h' for more information." >&2 + exit 1 + ;; + :) + echo "Error: Option -$OPTARG requires an argument." >&2 + echo "Try '$0 -h' for more information." >&2 + exit 1 + ;; + esac +done + +set_colors + +# Shift off the options and their arguments, so that any remaining +# positional parameters (if any) are correctly handled. +shift $((OPTIND - 1)) + +# Compatibility with previous script version +if [[ $SYMLINK_DIR = "/usr/local/bin" && -n ${1} ]]; then + SYMLINK_DIR=$1 +fi + +ensure_dir + +if [[ ! -w "${SYMLINK_DIR}" ]]; then + SUDO="sudo" else SUDO="" - SYMLINK_DIR=$1 fi -echo -e "\033[0;33mInstalling phpctl at \033[0m$INSTALL_DIR" -if [ -d "$INSTALL_DIR" ]; then - echo "The install directory is not empty. Attempting to remove it..." - rm -rf $INSTALL_DIR +if [[ -n $SUDO ]]; then + echo "Running in elevated mode. This might require sudo for operations in ${SYMLINK_DIR}." fi -echo -n "" -git clone --quiet https://github.com/opencodeco/phpctl.git $INSTALL_DIR & -PID=$! -while kill -0 $PID 2> /dev/null; do - for CHAR in '-' '/' '|' '\'; do - printf "\b$CHAR" +spinner() { + local i=0 + local sp="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏" + while true; do + printf "\r[%s] Cloning repository..." "${sp:i++%${#sp}:1}" sleep 0.1 done -done -printf "\r" +} +cleanup() { + if [[ -n "$SPINNER_PID" ]]; then + kill "$SPINNER_PID" 2>/dev/null + if $TPUT_AVAILABLE; then + printf "\r%*s\r" "$(tput cols)" "" + else + printf "\r\033[2K" + fi + fi + exit +} -if [ -z "$1" ]; then - echo -n "Sudo will be prompted to symlink the phpctl files." -else - echo -n "Files will be symlinked to ${SYMLINK_DIR}." +install_sources() { + echo -e "${YELLOW}Installing phpctl at ${NC}$INSTALL_DIR" + if [ -d "$INSTALL_DIR" ]; then + echo "The install directory is not empty. Attempting to remove it..." + rm -rf "$INSTALL_DIR" + fi + + if [[ -n "$LOCAL_SOURCES_DIR" ]]; then + echo "Using local sources from: $LOCAL_SOURCES_DIR" + cp -r "$LOCAL_SOURCES_DIR" "$INSTALL_DIR" + else + GITHUB_REPO="https://github.com/opencodeco/phpctl.git" + + trap cleanup EXIT INT TERM + + spinner & + SPINNER_PID=$! + git clone --quiet "$GITHUB_REPO" "$INSTALL_DIR" & + PID=$! + wait "$PID" + _git_status=$? + + kill "$SPINNER_PID" 2>/dev/null + # clear the spinner line one last time + if $TPUT_AVAILABLE; then + printf "\r%*s\r" "$(tput cols)" "" + else + printf "\r\033[2K" + fi + + if [[ $_git_status -eq 0 ]]; then + echo "done." + else + echo "Failed to clone $GITHUB_REPO into $INSTALL_DIR." + echo "Error: git clone failed with status ${_git_status}" + exit 1 + fi + fi + echo "${GREEN}Success: ${NC}Operation completed successfully." +} + +install_sources + +echo -n "Files will be symlinked to ${SYMLINK_DIR}." +if [[ -n $SUDO ]]; then + echo -n " ${RED}Sudo will be prompted to symlink the phpctl files.${NC}" fi -echo -e -n " \033[0;32mDo you want to continue? (Y/n)\033[0m " + +echo -e -n " ${GREEN}Do you want to continue? (Y/n)${NC} " read -r answer if [ "$answer" != "${answer#[Nn]}" ]; then - echo -e "\033[0;31mTo use phpctl globally, link the cloned script to your bin directory, like:\033[0m" - echo "" + echo -e "${RED}To use phpctl globally, link the cloned script to your bin directory, like:${NC}" for file in "${INSTALL_DIR}"/bin/*; do bin=$(basename "$file") echo " ${SUDO} ln -sf ${INSTALL_DIR}/bin/$bin ${SYMLINK_DIR}/$bin" done + echo -e "${YELLOW}Or add ${INSTALL_DIR}/bin to your PATH." else - $SUDO ${INSTALL_DIR}/scripts/symlink-bins.sh ${INSTALL_DIR} + $SUDO "${INSTALL_DIR}/scripts/symlink-bins.sh" "${INSTALL_DIR}" "${SYMLINK_DIR}" fi + +echo "${GREEN}Installation complete!${NC}" diff --git a/docs/uninstall.sh b/docs/uninstall.sh old mode 100644 new mode 100755 index ba40433..4ed1389 --- a/docs/uninstall.sh +++ b/docs/uninstall.sh @@ -1,7 +1,57 @@ #!/usr/bin/env bash -INSTALL_DIR=~/.phpctl -SYMLINK_DIR=/usr/local/bin +INSTALL_DIR="${HOME}/.phpctl" +SYMLINK_DIR="/usr/local/bin" + +while getopts "hi:s:" opt; do + case $opt in + h) + echo "Uninstall phpctl." + echo "" + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " -h Display this help message and exit" + echo " -i Set the installation directory (default: $HOME/.phpctl)" + echo " -s Set the symlink directory (default: /usr/local/bin)" + exit 0 + ;; + i) + INSTALL_DIR="$OPTARG" + ;; + s) + SYMLINK_DIR="$OPTARG" + ;; + \?) # Handle invalid options + echo "Error: Invalid option: -$OPTARG" >&2 + echo "Try '$0 -h' for more information." >&2 + exit 1 + ;; + :) # Handle missing arguments for options that require them + echo "Error: Option -$OPTARG requires an argument." >&2 + echo "Try '$0 -h' for more information." >&2 + exit 1 + ;; + esac +done + +# Shift off the options and their arguments, so that any remaining +# positional parameters (if any) are correctly handled. +shift $((OPTIND - 1)) + +# Compatibility with previous script version +if [[ $SYMLINK_DIR = "/usr/local/bin" && -n ${1} ]]; then + SYMLINK_DIR=$1 +fi + +if [ ! -w "${SYMLINK_DIR}" ]; then + SUDO="sudo" +else + SUDO="" +fi + +if [[ -n $SUDO ]]; then + echo "Running in elevated mode. This might require sudo for operations in ${SYMLINK_DIR}." +fi LINKS=( composer @@ -31,7 +81,7 @@ LINKS=( echo "Removing symbolic links..." for link in "${LINKS[@]}"; do if [ -L "${SYMLINK_DIR}/${link}" ]; then - sudo rm "${SYMLINK_DIR}/${link}" + $SUDO rm "${SYMLINK_DIR}/${link}" echo "Removed ${SYMLINK_DIR}/${link}" else echo "Link ${SYMLINK_DIR}/${link} does not exist, skipping." @@ -48,4 +98,4 @@ else echo "Skipping removal of installation directory." fi -echo "Uninstallation complete." \ No newline at end of file +echo "Uninstallation complete." diff --git a/scripts/symlink-bins.sh b/scripts/symlink-bins.sh index bb01640..8a4ce45 100755 --- a/scripts/symlink-bins.sh +++ b/scripts/symlink-bins.sh @@ -1,4 +1,9 @@ #!/usr/bin/env bash + +local_bin_path="${2:-/usr/local/bin}" +# Add a trailing slash if it's missing +local_bin_path="${local_bin_path%/}/" + for file in "${1:-.}"/bin/*; do - ln -sf "$(realpath "$file")" "/usr/local/bin/$(basename "$file")" + ln -sf "$(realpath "$file")" "${local_bin_path}$(basename "$file")" done diff --git a/tests/install/docker-entrypoint.sh b/tests/install/docker-entrypoint.sh index 87af11d..e62e540 100755 --- a/tests/install/docker-entrypoint.sh +++ b/tests/install/docker-entrypoint.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash neofetch -/bin/bash -c "$(curl -fsSL https://phpctl.dev/install.sh)" +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/opencodeco/phpctl/refs/heads/main/docs/install.sh)" echo "" notty phpctl doctor notty php --version