# Copyright (c) 2017 Eric Wendelin # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies # of the Software, and to permit persons to whom the Software is furnished to do # so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # Bash breaks words on : by default. Subproject tasks have ':' # Avoid inaccurate completions for subproject tasks COMP_WORDBREAKS=$(echo "$COMP_WORDBREAKS" | sed -e 's/://g') __gradle-set-project-root-dir() { local dir=`pwd` project_root_dir=`pwd` while [[ $dir != '/' ]]; do if [[ -f "$dir/settings.gradle" || -f "$dir/gradlew" ]]; then project_root_dir=$dir return 0 fi dir="$(dirname "$dir")" done return 1 } __gradle-init-cache-dir() { cache_dir="$HOME/.gradle/completion" mkdir -p $cache_dir } __gradle-set-build-file() { # Look for default build script in the settings file (settings.gradle by default) # Otherwise, default is the file 'build.gradle' in the current directory. gradle_build_file="$project_root_dir/build.gradle" if [[ -f "$project_root_dir/settings.gradle" ]]; then local build_file_name=$(grep "^rootProject\.buildFileName" "$project_root_dir/settings.gradle" | \ sed -n -e "s/rootProject\.buildFileName = [\'\"]\(.*\)[\'\"]/\1/p") gradle_build_file="$project_root_dir/${build_file_name:-build.gradle}" fi } __gradle-set-cache-name() { # Cache name is constructed from the absolute path of the build file. cache_name=$(echo $gradle_build_file | sed -e 's/\//_/g') } __gradle-set-files-checksum() { # Cache MD5 sum of all Gradle scripts and modified timestamps if builtin command -v md5 > /dev/null; then gradle_files_checksum=$(md5 -q -s "$(cat "$cache_dir/$cache_name" | xargs ls -o 2>/dev/null)") elif builtin command -v md5sum > /dev/null; then gradle_files_checksum=$(cat "$cache_dir/$cache_name" | xargs ls -o 2>/dev/null | md5sum | awk '{print $1}') else echo "Cannot generate completions as neither md5 nor md5sum exist on \$PATH" fi } __gradle-generate-script-cache() { # Invalidate cache after 3 weeks by default local cache_ttl_mins=${GRADLE_CACHE_TTL_MINUTES:-30240} local script_exclude_pattern=${GRADLE_COMPLETION_EXCLUDE_PATTERN:-"/(build|integTest|out)/"} if [[ ! $(find $cache_dir/$cache_name -mmin -$cache_ttl_mins 2>/dev/null) ]]; then # Cache all Gradle scripts local gradle_build_scripts=$(find $project_root_dir -type f -name "*.gradle" -o -name "*.gradle.kts" 2>/dev/null | egrep -v "$script_exclude_pattern") printf "%s\n" "${gradle_build_scripts[@]}" > $cache_dir/$cache_name fi } __gradle-long-options() { local args="--build-cache - Enables the Gradle build cache --build-file - Specifies the build file --configure-on-demand - Only relevant projects are configured --console - Type of console output to generate (plain auto rich) --continue - Continues task execution after a task failure --continuous - Continuous mode. Automatically re-run build after changes --daemon - Use the Gradle Daemon --debug - Log at the debug level --dry-run - Runs the build with all task actions disabled --exclude-task - Specify a task to be excluded --full-stacktrace - Print out the full (very verbose) stacktrace --gradle-user-home - Specifies the Gradle user home directory --gui - Launches the Gradle GUI app (Deprecated) --help - Shows a help message --include-build - Run the build as a composite, including the specified build --info - Set log level to INFO --init-script - Specifies an initialization script --max-workers - Set the maximum number of workers that Gradle may use --no-build-cache - Do not use the Gradle build cache --no-daemon - Do not use the Gradle Daemon --no-rebuild - Do not rebuild project dependencies --no-scan - Do not create a build scan --no-search-upwards - Do not search in parent directories for a settings.gradle --offline - Build without accessing network resources --parallel - Build projects in parallel --profile - Profile build time and create report --project-cache-dir - Specifies the project-specific cache directory --project-dir - Specifies the start directory for Gradle --project-prop - Sets a project property of the root project --quiet - Log errors only --recompile-scripts - Forces scripts to be recompiled, bypassing caching --refresh-dependencies - Refresh the state of dependencies --rerun-tasks - Specifies that any task optimization is ignored --scan - Create a build scan --settings-file - Specifies the settings file --stacktrace - Print out the stacktrace also for user exceptions --status - Print Gradle Daemon status --stop - Stop all Gradle Daemons --system-prop - Set a system property --version - Prints Gradle version info --warn - Log warnings and errors only" COMPREPLY=( $(compgen -W "$args" -- "${COMP_WORDS[COMP_CWORD]}") ) } __gradle-properties() { local args="-Dorg.gradle.cache.reserved.mb= - Reserve Gradle Daemon memory for operations -Dorg.gradle.caching= - Set true to enable Gradle build cache -Dorg.gradle.daemon.debug= - Set true to debug Gradle Daemon -Dorg.gradle.daemon.idletimeout= - Kill Gradle Daemon after # idle millis -Dorg.gradle.debug= - Set true to debug Gradle Client -Dorg.gradle.jvmargs= - Set JVM arguments -Dorg.gradle.java.home= - Set JDK home dir -Dorg.gradle.logging.level= - Set default Gradle log level (quiet warn lifecycle info debug) -Dorg.gradle.parallel= - Set true to enable parallel project builds (incubating) -Dorg.gradle.parallel.intra= - Set true to enable intra-project parallel builds (incubating) -Dorg.gradle.workers.max= - Set the number of workers Gradle is allowed to use" COMPREPLY=( $(compgen -W "$args" -- "${COMP_WORDS[COMP_CWORD]}") ) return 0 } __gradle-short-options() { local args="-? - Shows a help message -a - Do not rebuild project dependencies -b - Specifies the build file -c - Specifies the settings file -d - Log at the debug level -g - Specifies the Gradle user home directory -h - Shows a help message -i - Set log level to INFO -m - Runs the build with all task actions disabled -p - Specifies the start directory for Gradle -q - Log errors only -s - Print out the stacktrace also for user exceptions -t - Continuous mode. Automatically re-run build after changes -u - Do not search in parent directories for a settings.gradle -v - Prints Gradle version info -w - Log warnings and errors only -x - Specify a task to be excluded -D - Set a system property -I - Specifies an initialization script -P - Sets a project property of the root project -S - Print out the full (very verbose) stacktrace" COMPREPLY=( $(compgen -W "$args" -- "${COMP_WORDS[COMP_CWORD]}") ) } __gradle-notify-tasks-cache-build() { # Notify user of cache rebuild echo -e " (Building completion cache. Please wait)\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\c" __gradle-generate-tasks-cache # Remove "please wait" message by writing a bunch of spaces then moving back to the left echo -e " \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\c" } __gradle-generate-tasks-cache() { __gradle-set-files-checksum # Use Gradle wrapper when it exists. local gradle_cmd="gradle" if [[ -x "$project_root_dir/gradlew" ]]; then gradle_cmd="$project_root_dir/gradlew" fi # Run gradle to retrieve possible tasks and cache. # Reuse Gradle Daemon if IDLE but don't start a new one. local gradle_tasks_output if [[ ! -z "$($gradle_cmd --status 2>/dev/null | grep IDLE)" ]]; then gradle_tasks_output="$($gradle_cmd -b $gradle_build_file --daemon -q tasks --all)" else gradle_tasks_output="$($gradle_cmd -b $gradle_build_file --no-daemon -q tasks --all)" fi local output_line local task_description local -a gradle_all_tasks=() local -a root_tasks=() local -a subproject_tasks=() for output_line in $gradle_tasks_output; do if [[ $output_line =~ ^([[:lower:]][[:alnum:][:punct:]]*)([[:space:]]-[[:space:]]([[:print:]]*))? ]]; then task_name="${BASH_REMATCH[1]}" task_description="${BASH_REMATCH[3]}" gradle_all_tasks+=( "$task_name - $task_description" ) # Completion for subproject tasks with ':' prefix if [[ $task_name =~ ^([[:alnum:][:punct:]]+):([[:alnum:]]+) ]]; then gradle_all_tasks+=( ":$task_name - $task_description" ) subproject_tasks+=( "${BASH_REMATCH[2]}" ) else root_tasks+=( "$task_name" ) fi fi done # subproject tasks can be referenced implicitly from root project if [[ $GRADLE_COMPLETION_UNQUALIFIED_TASKS == "true" ]]; then local -a implicit_tasks=() implicit_tasks=( $(comm -23 <(printf "%s\n" "${subproject_tasks[@]}" | sort) <(printf "%s\n" "${root_tasks[@]}" | sort)) ) for task in $(printf "%s\n" "${implicit_tasks[@]}"); do gradle_all_tasks+=( $task ) done fi printf "%s\n" "${gradle_all_tasks[@]}" > $cache_dir/$gradle_files_checksum echo $gradle_files_checksum > $cache_dir/$cache_name.md5 } __gradle-completion-init() { local cache_dir cache_name gradle_build_file gradle_files_checksum project_root_dir local OLDIFS="$IFS" local IFS=$'\n' __gradle-init-cache-dir __gradle-set-project-root-dir __gradle-set-build-file if [[ -f $gradle_build_file ]]; then __gradle-set-cache-name __gradle-generate-script-cache __gradle-set-files-checksum __gradle-notify-tasks-cache-build fi IFS="$OLDIFS" return 0 } _gradle() { local cache_dir cache_name gradle_build_file gradle_files_checksum project_root_dir local cur=${COMP_WORDS[COMP_CWORD]} # Set bash internal field separator to '\n' # This allows us to provide descriptions for options and tasks local OLDIFS="$IFS" local IFS=$'\n' if [[ ${cur} == --* ]]; then __gradle-long-options elif [[ ${cur} == -D* ]]; then __gradle-properties elif [[ ${cur} == -* ]]; then __gradle-short-options else __gradle-init-cache-dir __gradle-set-project-root-dir __gradle-set-build-file if [[ -f $gradle_build_file ]]; then __gradle-set-cache-name __gradle-generate-script-cache __gradle-set-files-checksum # The cache key is md5 sum of all gradle scripts, so it's valid if it exists. if [[ -f $cache_dir/$cache_name.md5 ]]; then local cached_checksum="$(cat $cache_dir/$cache_name.md5)" local -a cached_tasks if [[ -z $cur ]]; then cached_tasks=( $(cat $cache_dir/$cached_checksum) ) else cached_tasks=( $(grep "^$cur" $cache_dir/$cached_checksum) ) fi COMPREPLY=( $(compgen -W "${cached_tasks[*]}" -- "$cur") ) else __gradle-notify-tasks-cache-build fi # Regenerate tasks cache in the background if [[ $gradle_files_checksum != "$(cat $cache_dir/$cache_name.md5)" || ! -f $cache_dir/$gradle_files_checksum ]]; then $(__gradle-generate-tasks-cache 1>&2 2>/dev/null &) fi else # Default tasks available outside Gradle projects local args="buildEnvironment - Displays all buildscript dependencies declared in root project. components - Displays the components produced by root project. dependencies - Displays all dependencies declared in root project. dependencyInsight - Displays the insight into a specific dependency in root project. dependentComponents - Displays the dependent components of components in root project. help - Displays a help message. init - Initializes a new Gradle build. model - Displays the configuration model of root project. projects - Displays the sub-projects of root project. properties - Displays the properties of root project. tasks - Displays the tasks runnable from root project. wrapper - Generates Gradle wrapper files." COMPREPLY=( $(compgen -W "$args" -- "${COMP_WORDS[COMP_CWORD]}") ) fi fi IFS="$OLDIFS" # Remove description ("[:space:]" and after) if only one possibility if [[ ${#COMPREPLY[*]} -eq 1 ]]; then COMPREPLY=( ${COMPREPLY[0]%% *} ) fi return 0 } complete -F _gradle gradle complete -F _gradle gradle.bat complete -F _gradle gradlew complete -F _gradle gradlew.bat complete -F _gradle ./gradlew complete -F _gradle ./gradlew.bat if hash gw 2>/dev/null || alias gw >/dev/null 2>&1; then complete -F _gradle gw fi