diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..33ef847 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# Ignore files generated by nested Zulu install +tests/_support/.config/* +tests/_support/.zulu/* +tests/_support/zulu-install.zsh + +# Ignore output +tests/_output/* +!tests/_output/.gitkeep + +/zulu +*.zwc diff --git a/.guardian.yml b/.guardian.yml new file mode 100644 index 0000000..f4c14e7 --- /dev/null +++ b/.guardian.yml @@ -0,0 +1,5 @@ +files: ./tests/commands/**/* +run: zunit "%file%" +--- +files: ./src/**/*.zsh +run: ./build.zsh diff --git a/build.zsh b/build.zsh new file mode 100755 index 0000000..401191c --- /dev/null +++ b/build.zsh @@ -0,0 +1,23 @@ +#!/usr/bin/env zsh + +# Clear the file to start with +cat /dev/null > zulu + +# Start with the shebang +echo "#!/usr/bin/env zsh\n" >> zulu + +# We need to do some fancy globbing +setopt EXTENDED_GLOB + +# Print each of the source files into the target, removing any comments +# and blank lines from the compiled executable +cat src/**/(^zulu).zsh | grep -v -E '^(\s*#.*[^"]|\s*)$' >> zulu + +# Print the main command last +cat src/zulu.zsh | grep -v -E '^(\s*#.*[^"]|\s*)$' >> zulu + +# Make sure the file is executable +chmod u+x zulu + +# Let the user know we're finished +echo "\033[0;32m✔\033[0;m zulu built successfully" diff --git a/commands/alias b/src/commands/alias.zsh similarity index 89% rename from commands/alias rename to src/commands/alias.zsh index 3168a93..f1c99e9 100644 --- a/commands/alias +++ b/src/commands/alias.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### @@ -16,7 +14,7 @@ function _zulu_alias_usage() { ### # Add an alias ### -_zulu_alias_add() { +function _zulu_alias_add() { local existing alias cmd alias="$1" @@ -31,13 +29,13 @@ _zulu_alias_add() { echo "alias $alias='$cmd'" >> $aliasfile zulu alias load - return + echo "$(_zulu_color green '✔') Alias '$alias' added" } ### # Remove an alias ### -_zulu_alias_rm() { +function _zulu_alias_rm() { local existing alias alias="$1" @@ -50,14 +48,15 @@ _zulu_alias_rm() { echo "$(cat $aliasfile | grep -v "alias $alias=")" >! $aliasfile unalias $alias + zulu alias load - return + echo "$(_zulu_color green '✔') Alias '$alias' removed" } ### # Load aliases ### -_zulu_alias_load() { +function _zulu_alias_load() { source $aliasfile } diff --git a/commands/bundle b/src/commands/bundle.zsh similarity index 99% rename from commands/bundle rename to src/commands/bundle.zsh index 261c350..58f3978 100644 --- a/commands/bundle +++ b/src/commands/bundle.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Print usage information ### diff --git a/commands/cdpath b/src/commands/cdpath.zsh similarity index 92% rename from commands/cdpath rename to src/commands/cdpath.zsh index 54deacc..21f495d 100644 --- a/commands/cdpath +++ b/src/commands/cdpath.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### @@ -108,13 +106,6 @@ function _zulu_cdpath_rm() { function _zulu_cdpath_store() { local separator out - # Check that we have all the parameters we need. This will only happen if - # _zulu_cdpath_store is executed internally. - if [[ "$items" = "" || "$pathfile" = "" ]]; then - echo 'Missing parameters. Was _zulu_cdpath_store called from within the add or remove functions?' - return 1 - fi - # Separate the array by newlines, and print the contents to the pathfile separator=$'\n' local IFS="$separator"; out="${items[*]/#/${separator}}" diff --git a/src/commands/compile.zsh b/src/commands/compile.zsh new file mode 100644 index 0000000..c31648c --- /dev/null +++ b/src/commands/compile.zsh @@ -0,0 +1,90 @@ +#!/usr/bin/env zsh + +### +# Output usage information and exit +### +function _zulu_compile_usage() { + echo '\033[0;32mUsage:\033[0;m' + echo ' zulu_compile [options]' +} + +### +# Resolve symbolic links to a file, a compare it's last-modified date +# with the compiled version, recompiling if needed +### +function _zulu_compile_if_needed() { + local file="$1" follow_symlinks + + zparseopts -D \ + f=follow_symlinks -follow-symlinks=follow_symlinks + + # We can't compile files that do not exist + [[ ! -e $file ]] && return + + # Resolve symlinks if necessary + [[ -n $follow_symlinks && -L $file ]] && file=$(readlink $file) + + # Check if the file is newer than it's compiled version, + # and recompile if necessary + if [[ -s ${file} && ( ! -s ${file}.zwc || ${file} -nt ${file}.zwc) ]]; then + zcompile ${file} + fi +} + +### +# The main zulu_compile process +### +(( $+functions[_zulu_compile] )) || function _zulu_compile() { + local base=${ZULU_DIR:-"${ZDOTDIR:-$HOME}/.zulu"} + local config=${ZULU_CONFIG_DIR:-"${ZDOTDIR:-$HOME}/.config/zulu"} + local help version + + zparseopts -D \ + h=help -help=help + + if [[ -n $help ]]; then + _zulu_compile_usage + exit + fi + + setopt EXTENDED_GLOB + # A list of glob paths pointing to files to be compiled + local -a compile_targets; compile_targets=( + # Zulu's core + ${base}/core/zulu + + # Files linked by packages + ${base}/share/**/*^(*.zwc)(#q@) + ${base}/bin/**/*^(*.zwc)(#q@) + + # Completion dump + ${ZDOTDIR:-${HOME}}/.zcomp^(*.zwc)(.) + + # User env files + ${ZDOTDIR:-${HOME}}/.zshenv + ${ZDOTDIR:-${HOME}}/.zlogin + ${ZDOTDIR:-${HOME}}/.zprofile + ${ZDOTDIR:-${HOME}}/.zshrc + ${ZDOTDIR:-${HOME}}/.zlogout + ) + + # A second list of compile targets. These files have their symlinks resolved + # before they are sourced, so we need to follow the symlink before compiling, + # to ensure the compiled version is picked up + local -a linked_compile_targets; linked_compile_targets=( + # Initialisation scripts for packages + ${base}/init/**/*^(*.zwc)(#q@) + ) + + # Loop through each of the files marked for compilation, and compile + # them if necessary + for file in ${(@f)compile_targets}; do + _zulu_compile_if_needed $file + done + + # Loop through each of the files marked for compilation, follow their + # symlinks, and compile them if necessary + for file in ${(@f)linked_compile_targets}; do + _zulu_compile_if_needed --follow-symlinks $file + done +} diff --git a/commands/fpath b/src/commands/fpath.zsh similarity index 92% rename from commands/fpath rename to src/commands/fpath.zsh index 78f3086..ef2f6f7 100644 --- a/commands/fpath +++ b/src/commands/fpath.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### @@ -108,13 +106,6 @@ function _zulu_fpath_rm() { function _zulu_fpath_store() { local separator out - # Check that we have all the parameters we need. This will only happen if - # _zulu_fpath_store is executed internally. - if [[ "$items" = "" || "$pathfile" = "" ]]; then - echo 'Missing parameters. Was _zulu_fpath_store called from within the add or remove functions?' - return 1 - fi - # Separate the array by newlines, and print the contents to the pathfile separator=$'\n' local IFS="$separator"; out="${items[*]/#/${separator}}" diff --git a/commands/func b/src/commands/func.zsh similarity index 99% rename from commands/func rename to src/commands/func.zsh index b5f21e9..a9a8e78 100644 --- a/commands/func +++ b/src/commands/func.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### diff --git a/commands/info b/src/commands/info.zsh similarity index 98% rename from commands/info rename to src/commands/info.zsh index 34269ca..3114a3c 100644 --- a/commands/info +++ b/src/commands/info.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### diff --git a/commands/init b/src/commands/init.zsh similarity index 97% rename from commands/init rename to src/commands/init.zsh index 2a579df..a9fef21 100644 --- a/commands/init +++ b/src/commands/init.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - function _zulu_init_usage() { echo $(_zulu_color yellow "Usage:") echo " zulu init [options]" @@ -7,6 +5,7 @@ function _zulu_init_usage() { echo $(_zulu_color yellow "Options:") echo " -c, --check-for-update Check for updates on startup" echo " -h, --help Output this help text and exit" + echo " -n, --no-compile Skip compilation of scripts on startup" } function _zulu_init_setup_completion() { @@ -557,21 +556,13 @@ function _zulu_check_for_update() { fi } -### -# Load the zulu commands -### -function _zulu_load_commands() { - for cmd in $(find "$base/core/commands"); do - source $cmd - done -} - ### # Source init scripts for installed packages ### function _zulu_load_packages() { # Source files in the init directory - for f in $(find "$base/init"); do + setopt EXTENDED_GLOB + for f in ${base}/init/**/*^(*.zwc)(#q@N); do if [[ -L $f ]]; then source $(readlink $f) else @@ -586,33 +577,25 @@ function _zulu_load_packages() { function _zulu_init() { local base=${ZULU_DIR:-"${ZDOTDIR:-$HOME}/.zulu"} local config=${ZULU_CONFIG_DIR:-"${ZDOTDIR:-$HOME}/.config/zulu"} - local help check_for_update - - # Ensure path arrays do not contain duplicates. - typeset -gU cdpath fpath mailpath path + local help check_for_update no_compile # Parse CLI options zparseopts -D \ h=help -help=help \ - c=check_for_update -check-for-update=check_for_update + c=check_for_update -check-for-update=check_for_update \ + n=no_compile -no-compile=no_compile if [[ -n $help ]]; then _zulu_init_usage return fi - # Load zulu internal commands - _zulu_load_commands - # Populate paths zulu path reset zulu fpath reset zulu cdpath reset zulu manpath reset - # Source helper functions - source "$base/core/helpers" - # Set up the environment _zulu_init_setup_key_bindings _zulu_init_setup_completion @@ -635,5 +618,11 @@ function _zulu_init() { prompt $theme fi + if [[ -z $no_compile ]]; then + { + zulu compile + } >/dev/null 2>&1 &! + fi + [[ -n $check_for_update ]] && _zulu_check_for_update } diff --git a/commands/install b/src/commands/install.zsh similarity index 99% rename from commands/install rename to src/commands/install.zsh index 117080d..024fbdd 100755 --- a/commands/install +++ b/src/commands/install.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### diff --git a/commands/link b/src/commands/link.zsh similarity index 84% rename from commands/link rename to src/commands/link.zsh index bb6ccc8..510c061 100644 --- a/commands/link +++ b/src/commands/link.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Print usage information ### @@ -81,17 +79,20 @@ function _zulu_link() { # Loop through each of the values in the array, the key is a file within # the package, the value is the name of a symlink to create in the directory - for file link (${(@kv)files}) ln -s $root/${~file} $base/$dir/$link - - # Make sure that commands to be included in bin are executable - if [[ "$dir" = "bin" ]]; then - for file link ("${(@kv)files}") chmod u+x "$root/$file" - fi - - # Source init scripts - if [[ "$dir" = "init" ]]; then - for file link ("${(@kv)files}") source $(readlink "$base/init/$link") - fi + for file link in "${(@kv)files}"; do + # Create a symlink to the file, filtering out .zwc files + ln -s $root/${~file} $base/$dir/$link + + # Make sure that commands to be included in bin are executable + if [[ "$dir" = "bin" ]]; then + chmod u+x "$root/$file" + fi + + # Source init scripts + if [[ "$dir" = "init" ]]; then + source $(readlink "$base/init/$link") + fi + done done package_type=$(jsonval $json 'type') diff --git a/commands/list b/src/commands/list.zsh similarity index 99% rename from commands/list rename to src/commands/list.zsh index 8a7033c..ba80889 100644 --- a/commands/list +++ b/src/commands/list.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Print usage information ### diff --git a/commands/manpath b/src/commands/manpath.zsh similarity index 99% rename from commands/manpath rename to src/commands/manpath.zsh index da9d835..2c813b4 100644 --- a/commands/manpath +++ b/src/commands/manpath.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### diff --git a/commands/path b/src/commands/path.zsh similarity index 92% rename from commands/path rename to src/commands/path.zsh index 2ee5c0a..71c5d9c 100644 --- a/commands/path +++ b/src/commands/path.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### @@ -108,13 +106,6 @@ function _zulu_path_rm() { function _zulu_path_store() { local separator out - # Check that we have all the parameters we need. This will only happen if - # _zulu_path_store is executed internally. - if [[ "$items" = "" || "$pathfile" = "" ]]; then - echo 'Missing parameters. Was _zulu_path_store called from within the add or remove functions?' - return 1 - fi - # Separate the array by newlines, and print the contents to the pathfile separator=$'\n' local IFS="$separator"; out="${items[*]/#/${separator}}" diff --git a/commands/search b/src/commands/search.zsh similarity index 97% rename from commands/search rename to src/commands/search.zsh index 400984a..fa327bf 100644 --- a/commands/search +++ b/src/commands/search.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### diff --git a/commands/self-update b/src/commands/self-update.zsh similarity index 99% rename from commands/self-update rename to src/commands/self-update.zsh index 9f191d6..bf66c4f 100644 --- a/commands/self-update +++ b/src/commands/self-update.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Print usage information ### @@ -20,6 +18,7 @@ function _zulu_self-update_core() { cd $core git fetch origin && git rebase origin + ./build.zsh cd $old } diff --git a/commands/theme b/src/commands/theme.zsh similarity index 97% rename from commands/theme rename to src/commands/theme.zsh index 9f1075a..6db6998 100644 --- a/commands/theme +++ b/src/commands/theme.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### diff --git a/commands/uninstall b/src/commands/uninstall.zsh similarity index 99% rename from commands/uninstall rename to src/commands/uninstall.zsh index ba26806..069e57a 100644 --- a/commands/uninstall +++ b/src/commands/uninstall.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### diff --git a/commands/unlink b/src/commands/unlink.zsh similarity index 98% rename from commands/unlink rename to src/commands/unlink.zsh index 4743885..8e59526 100644 --- a/commands/unlink +++ b/src/commands/unlink.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Print usage information ### diff --git a/commands/update b/src/commands/update.zsh similarity index 99% rename from commands/update rename to src/commands/update.zsh index bced634..fbb35fa 100644 --- a/commands/update +++ b/src/commands/update.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Print usage information ### diff --git a/commands/upgrade b/src/commands/upgrade.zsh similarity index 99% rename from commands/upgrade rename to src/commands/upgrade.zsh index 4d6dddf..3476ebd 100644 --- a/commands/upgrade +++ b/src/commands/upgrade.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### diff --git a/commands/var b/src/commands/var.zsh similarity index 98% rename from commands/var rename to src/commands/var.zsh index e120fd5..b06a5bd 100644 --- a/commands/var +++ b/src/commands/var.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Output usage information ### diff --git a/helpers b/src/helpers.zsh similarity index 99% rename from helpers rename to src/helpers.zsh index 8f18184..3201ad2 100644 --- a/helpers +++ b/src/helpers.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Get the value for a key in a JSON object # diff --git a/zulu b/src/zulu.zsh similarity index 93% rename from zulu rename to src/zulu.zsh index bbd0dcf..42bf362 100755 --- a/zulu +++ b/src/zulu.zsh @@ -1,5 +1,3 @@ -#!/usr/bin/env zsh - ### # Print usage information ### @@ -65,13 +63,6 @@ function _zulu_version() { cmd="$1" - # The init command needs to be loaded itself - if [[ $cmd = 'init' ]]; then - if (( ! $+functions[_zulu_init] )); then - source "$base/core/commands/init" - fi - fi - if [[ -z $cmd ]]; then echo " _____ ___" echo "/__ / __ __/ /_ __"