mirror of
https://github.com/go-task/task.git
synced 2025-06-02 23:27:37 +02:00
Merge branch 'master' into v3
This commit is contained in:
commit
acfbbaa549
26
.github/workflows/release.yml
vendored
Normal file
26
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: goreleaser
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
goreleaser:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v1
|
||||||
|
with:
|
||||||
|
go-version: 1.14.x
|
||||||
|
|
||||||
|
- name: Run GoReleaser
|
||||||
|
uses: goreleaser/goreleaser-action@v1
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
args: release --rm-dist
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -5,7 +5,7 @@ jobs:
|
|||||||
name: Test
|
name: Test
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [1.12.x, 1.13.x]
|
go-version: [1.13.x, 1.14.x]
|
||||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
runs-on: ${{matrix.platform}}
|
runs-on: ${{matrix.platform}}
|
||||||
steps:
|
steps:
|
||||||
|
17
.travis.yml
17
.travis.yml
@ -1,17 +0,0 @@
|
|||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- 1.12.x
|
|
||||||
- 1.13.x
|
|
||||||
|
|
||||||
env:
|
|
||||||
- GO111MODULE=on
|
|
||||||
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- rpm
|
|
||||||
|
|
||||||
script:
|
|
||||||
- go install -v ./cmd/task
|
|
||||||
- task ci
|
|
@ -1,421 +0,0 @@
|
|||||||
// This small web app is used to redirect from the old taskfile.org domain
|
|
||||||
// to the new taskfile.dev without breaking CIs that uses cURL to download
|
|
||||||
// "/install.sh" without the -L flag (which follow redirects).
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.URL.Path == "/install.sh" {
|
|
||||||
println("Dumping install.sh")
|
|
||||||
|
|
||||||
w.Write(installShContent)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
println("Redirecting to https://taskfile.dev" + r.URL.Path)
|
|
||||||
|
|
||||||
w.Header().Set("Location", "https://taskfile.dev"+r.URL.Path)
|
|
||||||
w.WriteHeader(301)
|
|
||||||
})
|
|
||||||
|
|
||||||
println("Listening :8080")
|
|
||||||
|
|
||||||
panic(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
var installShContent = []byte(`#!/bin/sh
|
|
||||||
set -e
|
|
||||||
# Code generated by godownloader on 2018-04-07T17:47:38Z. DO NOT EDIT.
|
|
||||||
#
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
this=$1
|
|
||||||
cat <<EOF
|
|
||||||
$this: download go binaries for go-task/task
|
|
||||||
|
|
||||||
Usage: $this [-b] bindir [-d] [tag]
|
|
||||||
-b sets bindir or installation directory, Defaults to ./bin
|
|
||||||
-d turns on debug logging
|
|
||||||
[tag] is a tag from
|
|
||||||
https://github.com/go-task/task/releases
|
|
||||||
If tag is missing, then the latest will be used.
|
|
||||||
|
|
||||||
Generated by godownloader
|
|
||||||
https://github.com/goreleaser/godownloader
|
|
||||||
|
|
||||||
EOF
|
|
||||||
exit 2
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_args() {
|
|
||||||
#BINDIR is ./bin unless set be ENV
|
|
||||||
# over-ridden by flag below
|
|
||||||
|
|
||||||
BINDIR=${BINDIR:-./bin}
|
|
||||||
while getopts "b:dh?" arg; do
|
|
||||||
case "$arg" in
|
|
||||||
b) BINDIR="$OPTARG" ;;
|
|
||||||
d) log_set_priority 10 ;;
|
|
||||||
h | \?) usage "$0" ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
shift $((OPTIND - 1))
|
|
||||||
TAG=$1
|
|
||||||
}
|
|
||||||
# this function wraps all the destructive operations
|
|
||||||
# if a curl|bash cuts off the end of the script due to
|
|
||||||
# network, either nothing will happen or will syntax error
|
|
||||||
# out preventing half-done work
|
|
||||||
execute() {
|
|
||||||
tmpdir=$(mktmpdir)
|
|
||||||
log_debug "downloading files into ${tmpdir}"
|
|
||||||
http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}"
|
|
||||||
http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}"
|
|
||||||
hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/${CHECKSUM}"
|
|
||||||
srcdir="${tmpdir}"
|
|
||||||
(cd "${tmpdir}" && untar "${TARBALL}")
|
|
||||||
install -d "${BINDIR}"
|
|
||||||
for binexe in "task" ; do
|
|
||||||
if [ "$OS" = "windows" ]; then
|
|
||||||
binexe="${binexe}.exe"
|
|
||||||
fi
|
|
||||||
install "${srcdir}/${binexe}" "${BINDIR}/"
|
|
||||||
log_info "installed ${BINDIR}/${binexe}"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
is_supported_platform() {
|
|
||||||
platform=$1
|
|
||||||
found=1
|
|
||||||
case "$platform" in
|
|
||||||
windows/386) found=0 ;;
|
|
||||||
windows/amd64) found=0 ;;
|
|
||||||
darwin/386) found=0 ;;
|
|
||||||
darwin/amd64) found=0 ;;
|
|
||||||
linux/386) found=0 ;;
|
|
||||||
linux/amd64) found=0 ;;
|
|
||||||
esac
|
|
||||||
case "$platform" in
|
|
||||||
darwin/386) found=1 ;;
|
|
||||||
esac
|
|
||||||
return $found
|
|
||||||
}
|
|
||||||
check_platform() {
|
|
||||||
if is_supported_platform "$PLATFORM"; then
|
|
||||||
# optional logging goes here
|
|
||||||
true
|
|
||||||
else
|
|
||||||
log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
tag_to_version() {
|
|
||||||
if [ -z "${TAG}" ]; then
|
|
||||||
log_info "checking GitHub for latest tag"
|
|
||||||
else
|
|
||||||
log_info "checking GitHub for tag '${TAG}'"
|
|
||||||
fi
|
|
||||||
REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true
|
|
||||||
if test -z "$REALTAG"; then
|
|
||||||
log_crit "unable to find '${TAG}' - use 'latest' or see https://github.com/${PREFIX}/releases for details"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# if version starts with 'v', remove it
|
|
||||||
TAG="$REALTAG"
|
|
||||||
VERSION=${TAG#v}
|
|
||||||
}
|
|
||||||
adjust_format() {
|
|
||||||
# change format (tar.gz or zip) based on ARCH
|
|
||||||
case ${ARCH} in
|
|
||||||
windows) FORMAT=zip ;;
|
|
||||||
esac
|
|
||||||
true
|
|
||||||
}
|
|
||||||
adjust_os() {
|
|
||||||
# adjust archive name based on OS
|
|
||||||
true
|
|
||||||
}
|
|
||||||
adjust_arch() {
|
|
||||||
# adjust archive name based on ARCH
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
cat /dev/null <<EOF
|
|
||||||
------------------------------------------------------------------------
|
|
||||||
https://github.com/client9/shlib - portable posix shell functions
|
|
||||||
Public domain - http://unlicense.org
|
|
||||||
https://github.com/client9/shlib/blob/master/LICENSE.md
|
|
||||||
but credit (and pull requests) appreciated.
|
|
||||||
------------------------------------------------------------------------
|
|
||||||
EOF
|
|
||||||
is_command() {
|
|
||||||
command -v "$1" >/dev/null
|
|
||||||
}
|
|
||||||
echoerr() {
|
|
||||||
echo "$@" 1>&2
|
|
||||||
}
|
|
||||||
log_prefix() {
|
|
||||||
echo "$0"
|
|
||||||
}
|
|
||||||
_logp=6
|
|
||||||
log_set_priority() {
|
|
||||||
_logp="$1"
|
|
||||||
}
|
|
||||||
log_priority() {
|
|
||||||
if test -z "$1"; then
|
|
||||||
echo "$_logp"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
[ "$1" -le "$_logp" ]
|
|
||||||
}
|
|
||||||
log_tag() {
|
|
||||||
case $1 in
|
|
||||||
0) echo "emerg" ;;
|
|
||||||
1) echo "alert" ;;
|
|
||||||
2) echo "crit" ;;
|
|
||||||
3) echo "err" ;;
|
|
||||||
4) echo "warning" ;;
|
|
||||||
5) echo "notice" ;;
|
|
||||||
6) echo "info" ;;
|
|
||||||
7) echo "debug" ;;
|
|
||||||
*) echo "$1" ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
log_debug() {
|
|
||||||
log_priority 7 || return 0
|
|
||||||
echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
|
|
||||||
}
|
|
||||||
log_info() {
|
|
||||||
log_priority 6 || return 0
|
|
||||||
echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
|
|
||||||
}
|
|
||||||
log_err() {
|
|
||||||
log_priority 3 || return 0
|
|
||||||
echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
|
|
||||||
}
|
|
||||||
log_crit() {
|
|
||||||
log_priority 2 || return 0
|
|
||||||
echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
|
|
||||||
}
|
|
||||||
uname_os() {
|
|
||||||
os=$(uname -s | tr '[:upper:]' '[:lower:]')
|
|
||||||
case "$os" in
|
|
||||||
msys_nt) os="windows" ;;
|
|
||||||
esac
|
|
||||||
echo "$os"
|
|
||||||
}
|
|
||||||
uname_arch() {
|
|
||||||
arch=$(uname -m)
|
|
||||||
case $arch in
|
|
||||||
x86_64) arch="amd64" ;;
|
|
||||||
x86) arch="386" ;;
|
|
||||||
i686) arch="386" ;;
|
|
||||||
i386) arch="386" ;;
|
|
||||||
aarch64) arch="arm64" ;;
|
|
||||||
armv5*) arch="arm5" ;;
|
|
||||||
armv6*) arch="arm6" ;;
|
|
||||||
armv7*) arch="arm7" ;;
|
|
||||||
esac
|
|
||||||
echo ${arch}
|
|
||||||
}
|
|
||||||
uname_os_check() {
|
|
||||||
os=$(uname_os)
|
|
||||||
case "$os" in
|
|
||||||
darwin) return 0 ;;
|
|
||||||
dragonfly) return 0 ;;
|
|
||||||
freebsd) return 0 ;;
|
|
||||||
linux) return 0 ;;
|
|
||||||
android) return 0 ;;
|
|
||||||
nacl) return 0 ;;
|
|
||||||
netbsd) return 0 ;;
|
|
||||||
openbsd) return 0 ;;
|
|
||||||
plan9) return 0 ;;
|
|
||||||
solaris) return 0 ;;
|
|
||||||
windows) return 0 ;;
|
|
||||||
esac
|
|
||||||
log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
uname_arch_check() {
|
|
||||||
arch=$(uname_arch)
|
|
||||||
case "$arch" in
|
|
||||||
386) return 0 ;;
|
|
||||||
amd64) return 0 ;;
|
|
||||||
arm64) return 0 ;;
|
|
||||||
armv5) return 0 ;;
|
|
||||||
armv6) return 0 ;;
|
|
||||||
armv7) return 0 ;;
|
|
||||||
ppc64) return 0 ;;
|
|
||||||
ppc64le) return 0 ;;
|
|
||||||
mips) return 0 ;;
|
|
||||||
mipsle) return 0 ;;
|
|
||||||
mips64) return 0 ;;
|
|
||||||
mips64le) return 0 ;;
|
|
||||||
s390x) return 0 ;;
|
|
||||||
amd64p32) return 0 ;;
|
|
||||||
esac
|
|
||||||
log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
untar() {
|
|
||||||
tarball=$1
|
|
||||||
case "${tarball}" in
|
|
||||||
*.tar.gz | *.tgz) tar -xzf "${tarball}" ;;
|
|
||||||
*.tar) tar -xf "${tarball}" ;;
|
|
||||||
*.zip) unzip "${tarball}" ;;
|
|
||||||
*)
|
|
||||||
log_err "untar unknown archive format for ${tarball}"
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
mktmpdir() {
|
|
||||||
test -z "$TMPDIR" && TMPDIR="$(mktemp -d)"
|
|
||||||
mkdir -p "${TMPDIR}"
|
|
||||||
echo "${TMPDIR}"
|
|
||||||
}
|
|
||||||
http_download_curl() {
|
|
||||||
local_file=$1
|
|
||||||
source_url=$2
|
|
||||||
header=$3
|
|
||||||
if [ -z "$header" ]; then
|
|
||||||
code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
|
|
||||||
else
|
|
||||||
code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
|
|
||||||
fi
|
|
||||||
if [ "$code" != "200" ]; then
|
|
||||||
log_debug "http_download_curl received HTTP status $code"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
http_download_wget() {
|
|
||||||
local_file=$1
|
|
||||||
source_url=$2
|
|
||||||
header=$3
|
|
||||||
if [ -z "$header" ]; then
|
|
||||||
wget -q -O "$local_file" "$source_url"
|
|
||||||
else
|
|
||||||
wget -q --header "$header" -O "$local_file" "$source_url"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
http_download() {
|
|
||||||
log_debug "http_download $2"
|
|
||||||
if is_command curl; then
|
|
||||||
http_download_curl "$@"
|
|
||||||
return
|
|
||||||
elif is_command wget; then
|
|
||||||
http_download_wget "$@"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
log_crit "http_download unable to find wget or curl"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
http_copy() {
|
|
||||||
tmp=$(mktemp)
|
|
||||||
http_download "${tmp}" "$1" "$2" || return 1
|
|
||||||
body=$(cat "$tmp")
|
|
||||||
rm -f "${tmp}"
|
|
||||||
echo "$body"
|
|
||||||
}
|
|
||||||
github_release() {
|
|
||||||
owner_repo=$1
|
|
||||||
version=$2
|
|
||||||
test -z "$version" && version="latest"
|
|
||||||
giturl="https://github.com/${owner_repo}/releases/${version}"
|
|
||||||
json=$(http_copy "$giturl" "Accept:application/json")
|
|
||||||
test -z "$json" && return 1
|
|
||||||
version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//')
|
|
||||||
test -z "$version" && return 1
|
|
||||||
echo "$version"
|
|
||||||
}
|
|
||||||
hash_sha256() {
|
|
||||||
TARGET=${1:-/dev/stdin}
|
|
||||||
if is_command gsha256sum; then
|
|
||||||
hash=$(gsha256sum "$TARGET") || return 1
|
|
||||||
echo "$hash" | cut -d ' ' -f 1
|
|
||||||
elif is_command sha256sum; then
|
|
||||||
hash=$(sha256sum "$TARGET") || return 1
|
|
||||||
echo "$hash" | cut -d ' ' -f 1
|
|
||||||
elif is_command shasum; then
|
|
||||||
hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
|
|
||||||
echo "$hash" | cut -d ' ' -f 1
|
|
||||||
elif is_command openssl; then
|
|
||||||
hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
|
|
||||||
echo "$hash" | cut -d ' ' -f a
|
|
||||||
else
|
|
||||||
log_crit "hash_sha256 unable to find command to compute sha-256 hash"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
hash_sha256_verify() {
|
|
||||||
TARGET=$1
|
|
||||||
checksums=$2
|
|
||||||
if [ -z "$checksums" ]; then
|
|
||||||
log_err "hash_sha256_verify checksum file not specified in arg2"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
BASENAME=${TARGET##*/}
|
|
||||||
want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
|
|
||||||
if [ -z "$want" ]; then
|
|
||||||
log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
got=$(hash_sha256 "$TARGET")
|
|
||||||
if [ "$want" != "$got" ]; then
|
|
||||||
log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
cat /dev/null <<EOF
|
|
||||||
------------------------------------------------------------------------
|
|
||||||
End of functions from https://github.com/client9/shlib
|
|
||||||
------------------------------------------------------------------------
|
|
||||||
EOF
|
|
||||||
|
|
||||||
PROJECT_NAME="task"
|
|
||||||
OWNER=go-task
|
|
||||||
REPO="task"
|
|
||||||
BINARY=task
|
|
||||||
FORMAT=tar.gz
|
|
||||||
OS=$(uname_os)
|
|
||||||
ARCH=$(uname_arch)
|
|
||||||
PREFIX="$OWNER/$REPO"
|
|
||||||
|
|
||||||
# use in logging routines
|
|
||||||
log_prefix() {
|
|
||||||
echo "$PREFIX"
|
|
||||||
}
|
|
||||||
PLATFORM="${OS}/${ARCH}"
|
|
||||||
GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download
|
|
||||||
|
|
||||||
uname_os_check "$OS"
|
|
||||||
uname_arch_check "$ARCH"
|
|
||||||
|
|
||||||
parse_args "$@"
|
|
||||||
|
|
||||||
check_platform
|
|
||||||
|
|
||||||
tag_to_version
|
|
||||||
|
|
||||||
adjust_format
|
|
||||||
|
|
||||||
adjust_os
|
|
||||||
|
|
||||||
adjust_arch
|
|
||||||
|
|
||||||
log_info "found version: ${VERSION} for ${TAG}/${OS}/${ARCH}"
|
|
||||||
|
|
||||||
NAME=${BINARY}_${OS}_${ARCH}
|
|
||||||
TARBALL=${NAME}.${FORMAT}
|
|
||||||
TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL}
|
|
||||||
CHECKSUM=task_checksums.txt
|
|
||||||
CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM}
|
|
||||||
|
|
||||||
|
|
||||||
execute
|
|
||||||
`)
|
|
@ -6,7 +6,7 @@ _task_completion()
|
|||||||
# Remove colon from word breaks
|
# Remove colon from word breaks
|
||||||
COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
|
COMP_WORDBREAKS=${COMP_WORDBREAKS//:}
|
||||||
|
|
||||||
scripts=$(task -l | sed '1d' | sed 's/^\* //' | awk '{ print $1 }');
|
scripts=$(task -l | sed '1d' | awk '{ print $2 }' | sed 's/:$//');
|
||||||
|
|
||||||
curr_arg="${COMP_WORDS[COMP_CWORD]:-"."}"
|
curr_arg="${COMP_WORDS[COMP_CWORD]:-"."}"
|
||||||
|
|
||||||
|
10
completion/ps/task.ps1
Normal file
10
completion/ps/task.ps1
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
$scriptBlock = {
|
||||||
|
param($commandName, $wordToComplete, $cursorPosition)
|
||||||
|
$curReg = "task{.exe}? (.*?)$"
|
||||||
|
$startsWith = $wordToComplete | Select-String $curReg -AllMatches | ForEach-Object { $_.Matches.Groups[1].Value }
|
||||||
|
$reg = "\* ($startsWith.+?):"
|
||||||
|
$listOutput = $(task -l)
|
||||||
|
$listOutput | Select-String $reg -AllMatches | ForEach-Object { $_.Matches.Groups[1].Value + " " }
|
||||||
|
}
|
||||||
|
|
||||||
|
Register-ArgumentCompleter -Native -CommandName task -ScriptBlock $scriptBlock
|
@ -40,6 +40,19 @@ scoop install task
|
|||||||
This installation method is community owned. After a new release of Task, it
|
This installation method is community owned. After a new release of Task, it
|
||||||
may take some time until it's available on Scoop.
|
may take some time until it's available on Scoop.
|
||||||
|
|
||||||
|
## Arch Linux
|
||||||
|
|
||||||
|
If you're on Arch Linux you can install Task from
|
||||||
|
[AUR](https://aur.archlinux.org/packages/taskfile-git) using your favorite
|
||||||
|
package manager such as `yay`, `pacaur` or `yaourt`:
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
yay -S taskfile-git
|
||||||
|
```
|
||||||
|
|
||||||
|
This installation method is community owned, but since it's `-git` version of
|
||||||
|
the package, it's always latest available version based on the Git repository.
|
||||||
|
|
||||||
## Go
|
## Go
|
||||||
|
|
||||||
Task now uses [Go Modules](https://github.com/golang/go/wiki/Modules), which
|
Task now uses [Go Modules](https://github.com/golang/go/wiki/Modules), which
|
||||||
|
2
go.mod
2
go.mod
@ -10,7 +10,7 @@ require (
|
|||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
||||||
gopkg.in/yaml.v2 v2.2.2
|
gopkg.in/yaml.v2 v2.2.2
|
||||||
mvdan.cc/sh/v3 v3.0.0-beta1
|
mvdan.cc/sh/v3 v3.0.2
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.13
|
go 1.13
|
||||||
|
4
go.sum
4
go.sum
@ -53,5 +53,5 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
mvdan.cc/editorconfig v0.1.1-0.20191109213504-890940e3f00e/go.mod h1:Ge4atmRUYqueGppvJ7JNrtqpqokoJEFxYbP0Z+WeKS8=
|
mvdan.cc/editorconfig v0.1.1-0.20191109213504-890940e3f00e/go.mod h1:Ge4atmRUYqueGppvJ7JNrtqpqokoJEFxYbP0Z+WeKS8=
|
||||||
mvdan.cc/sh/v3 v3.0.0-beta1 h1:UqiwBEXEPzelaGxuvixaOtzc7WzKtrElePJ8HqvW7K8=
|
mvdan.cc/sh/v3 v3.0.2 h1:NU+UpTZHRdIZ9igRo8zi/7+5/NpetYlhlyDhz1/AdMM=
|
||||||
mvdan.cc/sh/v3 v3.0.0-beta1/go.mod h1:rBIndNJFYPp8xSppiZcGIk6B5d1g3OEARxEaXjPxwVI=
|
mvdan.cc/sh/v3 v3.0.2/go.mod h1:rBIndNJFYPp8xSppiZcGIk6B5d1g3OEARxEaXjPxwVI=
|
||||||
|
4
help.go
4
help.go
@ -30,6 +30,10 @@ func (e *Executor) tasksWithDesc() (tasks []*taskfile.Task) {
|
|||||||
tasks = make([]*taskfile.Task, 0, len(e.Taskfile.Tasks))
|
tasks = make([]*taskfile.Task, 0, len(e.Taskfile.Tasks))
|
||||||
for _, task := range e.Taskfile.Tasks {
|
for _, task := range e.Taskfile.Tasks {
|
||||||
if task.Desc != "" {
|
if task.Desc != "" {
|
||||||
|
compiledTask, err := e.CompiledTask(taskfile.Call{Task: task.Task})
|
||||||
|
if err == nil {
|
||||||
|
task = compiledTask
|
||||||
|
}
|
||||||
tasks = append(tasks, task)
|
tasks = append(tasks, task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,12 @@ import (
|
|||||||
|
|
||||||
func PrintTasks(l *logger.Logger, t *taskfile.Taskfile, c []taskfile.Call) {
|
func PrintTasks(l *logger.Logger, t *taskfile.Taskfile, c []taskfile.Call) {
|
||||||
for i, call := range c {
|
for i, call := range c {
|
||||||
printSpaceBetweenSummaries(l, i)
|
PrintSpaceBetweenSummaries(l, i)
|
||||||
PrintTask(l, t.Tasks[call.Task])
|
PrintTask(l, t.Tasks[call.Task])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printSpaceBetweenSummaries(l *logger.Logger, i int) {
|
func PrintSpaceBetweenSummaries(l *logger.Logger, i int) {
|
||||||
spaceRequired := i > 0
|
spaceRequired := i > 0
|
||||||
if !spaceRequired {
|
if !spaceRequired {
|
||||||
return
|
return
|
||||||
|
9
task.go
9
task.go
@ -70,7 +70,14 @@ func (e *Executor) Run(ctx context.Context, calls ...taskfile.Call) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if e.Summary {
|
if e.Summary {
|
||||||
summary.PrintTasks(e.Logger, e.Taskfile, calls)
|
for i, c := range calls {
|
||||||
|
compiledTask, err := e.CompiledTask(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
summary.PrintSpaceBetweenSummaries(e.Logger, i)
|
||||||
|
summary.PrintTask(e.Logger, compiledTask)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) {
|
|||||||
new := taskfile.Task{
|
new := taskfile.Task{
|
||||||
Task: origTask.Task,
|
Task: origTask.Task,
|
||||||
Desc: r.Replace(origTask.Desc),
|
Desc: r.Replace(origTask.Desc),
|
||||||
|
Summary: r.Replace(origTask.Summary),
|
||||||
Sources: r.ReplaceSlice(origTask.Sources),
|
Sources: r.ReplaceSlice(origTask.Sources),
|
||||||
Generates: r.ReplaceSlice(origTask.Generates),
|
Generates: r.ReplaceSlice(origTask.Generates),
|
||||||
Dir: r.Replace(origTask.Dir),
|
Dir: r.Replace(origTask.Dir),
|
||||||
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@ -37,7 +37,7 @@ golang.org/x/xerrors
|
|||||||
golang.org/x/xerrors/internal
|
golang.org/x/xerrors/internal
|
||||||
# gopkg.in/yaml.v2 v2.2.2
|
# gopkg.in/yaml.v2 v2.2.2
|
||||||
gopkg.in/yaml.v2
|
gopkg.in/yaml.v2
|
||||||
# mvdan.cc/sh/v3 v3.0.0-beta1
|
# mvdan.cc/sh/v3 v3.0.2
|
||||||
mvdan.cc/sh/v3/expand
|
mvdan.cc/sh/v3/expand
|
||||||
mvdan.cc/sh/v3/interp
|
mvdan.cc/sh/v3/interp
|
||||||
mvdan.cc/sh/v3/pattern
|
mvdan.cc/sh/v3/pattern
|
||||||
|
12
vendor/mvdan.cc/sh/v3/expand/braces.go
vendored
12
vendor/mvdan.cc/sh/v3/expand/braces.go
vendored
@ -24,13 +24,13 @@ func Braces(word *syntax.Word) []*syntax.Word {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if br.Sequence {
|
if br.Sequence {
|
||||||
var from, to int
|
chars := false
|
||||||
if br.Chars {
|
from, err1 := strconv.Atoi(br.Elems[0].Lit())
|
||||||
|
to, err2 := strconv.Atoi(br.Elems[1].Lit())
|
||||||
|
if err1 != nil || err2 != nil {
|
||||||
|
chars = true
|
||||||
from = int(br.Elems[0].Lit()[0])
|
from = int(br.Elems[0].Lit()[0])
|
||||||
to = int(br.Elems[1].Lit()[0])
|
to = int(br.Elems[1].Lit()[0])
|
||||||
} else {
|
|
||||||
from, _ = strconv.Atoi(br.Elems[0].Lit())
|
|
||||||
to, _ = strconv.Atoi(br.Elems[1].Lit())
|
|
||||||
}
|
}
|
||||||
upward := from <= to
|
upward := from <= to
|
||||||
incr := 1
|
incr := 1
|
||||||
@ -54,7 +54,7 @@ func Braces(word *syntax.Word) []*syntax.Word {
|
|||||||
next := *word
|
next := *word
|
||||||
next.Parts = next.Parts[i+1:]
|
next.Parts = next.Parts[i+1:]
|
||||||
lit := &syntax.Lit{}
|
lit := &syntax.Lit{}
|
||||||
if br.Chars {
|
if chars {
|
||||||
lit.Value = string(n)
|
lit.Value = string(n)
|
||||||
} else {
|
} else {
|
||||||
lit.Value = strconv.Itoa(n)
|
lit.Value = strconv.Itoa(n)
|
||||||
|
17
vendor/mvdan.cc/sh/v3/expand/expand.go
vendored
17
vendor/mvdan.cc/sh/v3/expand/expand.go
vendored
@ -159,6 +159,8 @@ func Document(cfg *Config, word *syntax.Word) (string, error) {
|
|||||||
return cfg.fieldJoin(field), nil
|
return cfg.fieldJoin(field), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const patMode = pattern.Filenames | pattern.Braces
|
||||||
|
|
||||||
// Pattern expands a single shell word as a pattern, using syntax.QuotePattern
|
// Pattern expands a single shell word as a pattern, using syntax.QuotePattern
|
||||||
// on any non-quoted parts of the input word. The result can be used on
|
// on any non-quoted parts of the input word. The result can be used on
|
||||||
// syntax.TranslatePattern directly.
|
// syntax.TranslatePattern directly.
|
||||||
@ -174,7 +176,7 @@ func Pattern(cfg *Config, word *syntax.Word) (string, error) {
|
|||||||
buf := cfg.strBuilder()
|
buf := cfg.strBuilder()
|
||||||
for _, part := range field {
|
for _, part := range field {
|
||||||
if part.quote > quoteNone {
|
if part.quote > quoteNone {
|
||||||
buf.WriteString(pattern.QuoteMeta(part.val))
|
buf.WriteString(pattern.QuoteMeta(part.val, patMode))
|
||||||
} else {
|
} else {
|
||||||
buf.WriteString(part.val)
|
buf.WriteString(part.val)
|
||||||
}
|
}
|
||||||
@ -345,11 +347,11 @@ func (cfg *Config) escapedGlobField(parts []fieldPart) (escaped string, glob boo
|
|||||||
buf := cfg.strBuilder()
|
buf := cfg.strBuilder()
|
||||||
for _, part := range parts {
|
for _, part := range parts {
|
||||||
if part.quote > quoteNone {
|
if part.quote > quoteNone {
|
||||||
buf.WriteString(pattern.QuoteMeta(part.val))
|
buf.WriteString(pattern.QuoteMeta(part.val, patMode))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buf.WriteString(part.val)
|
buf.WriteString(part.val)
|
||||||
if pattern.HasMeta(part.val) {
|
if pattern.HasMeta(part.val, patMode) {
|
||||||
glob = true
|
glob = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,9 +369,10 @@ func Fields(cfg *Config, words ...*syntax.Word) ([]string, error) {
|
|||||||
fields := make([]string, 0, len(words))
|
fields := make([]string, 0, len(words))
|
||||||
dir := cfg.envGet("PWD")
|
dir := cfg.envGet("PWD")
|
||||||
for _, word := range words {
|
for _, word := range words {
|
||||||
afterBraces := []*syntax.Word{word}
|
word := *word // make a copy, since SplitBraces replaces the Parts slice
|
||||||
if syntax.SplitBraces(word) {
|
afterBraces := []*syntax.Word{&word}
|
||||||
afterBraces = Braces(word)
|
if syntax.SplitBraces(&word) {
|
||||||
|
afterBraces = Braces(&word)
|
||||||
}
|
}
|
||||||
for _, word2 := range afterBraces {
|
for _, word2 := range afterBraces {
|
||||||
wfields, err := cfg.wordFields(word2.Parts)
|
wfields, err := cfg.wordFields(word2.Parts)
|
||||||
@ -540,7 +543,6 @@ func (cfg *Config) wordFields(wps []syntax.WordPart) ([][]fieldPart, error) {
|
|||||||
}
|
}
|
||||||
curField = append(curField, fp)
|
curField = append(curField, fp)
|
||||||
case *syntax.DblQuoted:
|
case *syntax.DblQuoted:
|
||||||
allowEmpty = true
|
|
||||||
if len(x.Parts) == 1 {
|
if len(x.Parts) == 1 {
|
||||||
pe, _ := x.Parts[0].(*syntax.ParamExp)
|
pe, _ := x.Parts[0].(*syntax.ParamExp)
|
||||||
if elems := cfg.quotedElems(pe); elems != nil {
|
if elems := cfg.quotedElems(pe); elems != nil {
|
||||||
@ -556,6 +558,7 @@ func (cfg *Config) wordFields(wps []syntax.WordPart) ([][]fieldPart, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
allowEmpty = true
|
||||||
wfield, err := cfg.wordField(x.Parts, quoteDouble)
|
wfield, err := cfg.wordField(x.Parts, quoteDouble)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
5
vendor/mvdan.cc/sh/v3/interp/interp.go
vendored
5
vendor/mvdan.cc/sh/v3/interp/interp.go
vendored
@ -745,7 +745,6 @@ func (r *Runner) sub() *Runner {
|
|||||||
Env: r.Env,
|
Env: r.Env,
|
||||||
Dir: r.Dir,
|
Dir: r.Dir,
|
||||||
Params: r.Params,
|
Params: r.Params,
|
||||||
Funcs: r.Funcs,
|
|
||||||
execHandler: r.execHandler,
|
execHandler: r.execHandler,
|
||||||
openHandler: r.openHandler,
|
openHandler: r.openHandler,
|
||||||
stdin: r.stdin,
|
stdin: r.stdin,
|
||||||
@ -766,6 +765,10 @@ func (r *Runner) sub() *Runner {
|
|||||||
for k, v := range r.cmdVars {
|
for k, v := range r.cmdVars {
|
||||||
r2.cmdVars[k] = v
|
r2.cmdVars[k] = v
|
||||||
}
|
}
|
||||||
|
r2.Funcs = make(map[string]*syntax.Stmt, len(r.Funcs))
|
||||||
|
for k, v := range r.Funcs {
|
||||||
|
r2.Funcs[k] = v
|
||||||
|
}
|
||||||
r2.dirStack = append(r2.dirBootstrap[:0], r.dirStack...)
|
r2.dirStack = append(r2.dirBootstrap[:0], r.dirStack...)
|
||||||
r2.fillExpandConfig(r.ectx)
|
r2.fillExpandConfig(r.ectx)
|
||||||
r2.didReset = true
|
r2.didReset = true
|
||||||
|
21
vendor/mvdan.cc/sh/v3/pattern/pattern.go
vendored
21
vendor/mvdan.cc/sh/v3/pattern/pattern.go
vendored
@ -16,8 +16,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: support Mode in the other APIs too
|
// Mode can be used to supply a number of options to the package's functions.
|
||||||
|
// Not all functions change their behavior with all of the options below.
|
||||||
type Mode uint
|
type Mode uint
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -254,13 +254,17 @@ func charClass(s string) (string, error) {
|
|||||||
// This can be useful to avoid extra work, like TranslatePattern. Note that this
|
// This can be useful to avoid extra work, like TranslatePattern. Note that this
|
||||||
// function cannot be used to avoid QuotePattern, as backslashes are quoted by
|
// function cannot be used to avoid QuotePattern, as backslashes are quoted by
|
||||||
// that function but ignored here.
|
// that function but ignored here.
|
||||||
func HasMeta(pat string) bool {
|
func HasMeta(pat string, mode Mode) bool {
|
||||||
for i := 0; i < len(pat); i++ {
|
for i := 0; i < len(pat); i++ {
|
||||||
switch pat[i] {
|
switch pat[i] {
|
||||||
case '\\':
|
case '\\':
|
||||||
i++
|
i++
|
||||||
case '*', '?', '[':
|
case '*', '?', '[':
|
||||||
return true
|
return true
|
||||||
|
case '{':
|
||||||
|
if mode&Braces != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -270,11 +274,16 @@ func HasMeta(pat string) bool {
|
|||||||
// given text. The returned string is a pattern that matches the literal text.
|
// given text. The returned string is a pattern that matches the literal text.
|
||||||
//
|
//
|
||||||
// For example, QuoteMeta(`foo*bar?`) returns `foo\*bar\?`.
|
// For example, QuoteMeta(`foo*bar?`) returns `foo\*bar\?`.
|
||||||
func QuoteMeta(pat string) string {
|
func QuoteMeta(pat string, mode Mode) string {
|
||||||
any := false
|
any := false
|
||||||
loop:
|
loop:
|
||||||
for _, r := range pat {
|
for _, r := range pat {
|
||||||
switch r {
|
switch r {
|
||||||
|
case '{':
|
||||||
|
if mode&Braces == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
case '*', '?', '[', '\\':
|
case '*', '?', '[', '\\':
|
||||||
any = true
|
any = true
|
||||||
break loop
|
break loop
|
||||||
@ -288,6 +297,10 @@ loop:
|
|||||||
switch r {
|
switch r {
|
||||||
case '*', '?', '[', '\\':
|
case '*', '?', '[', '\\':
|
||||||
buf.WriteByte('\\')
|
buf.WriteByte('\\')
|
||||||
|
case '{':
|
||||||
|
if mode&Braces != 0 {
|
||||||
|
buf.WriteByte('\\')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
buf.WriteRune(r)
|
buf.WriteRune(r)
|
||||||
}
|
}
|
||||||
|
57
vendor/mvdan.cc/sh/v3/shell/source.go
vendored
57
vendor/mvdan.cc/sh/v3/shell/source.go
vendored
@ -1,57 +0,0 @@
|
|||||||
// Copyright (c) 2018, Daniel Martí <mvdan@mvdan.cc>
|
|
||||||
// See LICENSE for licensing information
|
|
||||||
|
|
||||||
package shell
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"mvdan.cc/sh/v3/expand"
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
|
||||||
"mvdan.cc/sh/v3/syntax"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SourceFile sources a shell file from disk and returns the variables
|
|
||||||
// declared in it. It is a convenience function that uses a default shell
|
|
||||||
// parser, parses a file from disk, and calls SourceNode.
|
|
||||||
//
|
|
||||||
// This function should be used with caution, as it can interpret arbitrary
|
|
||||||
// code. Untrusted shell programs shoudn't be sourced outside of a sandbox
|
|
||||||
// environment.
|
|
||||||
func SourceFile(ctx context.Context, path string) (map[string]expand.Variable, error) {
|
|
||||||
f, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not open: %v", err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
file, err := syntax.NewParser().Parse(f, path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not parse: %v", err)
|
|
||||||
}
|
|
||||||
return SourceNode(ctx, file)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SourceNode sources a shell program from a node and returns the
|
|
||||||
// variables declared in it. It accepts the same set of node types that
|
|
||||||
// interp/Runner.Run does.
|
|
||||||
//
|
|
||||||
// This function should be used with caution, as it can interpret arbitrary
|
|
||||||
// code. Untrusted shell programs shoudn't be sourced outside of a sandbox
|
|
||||||
// environment.
|
|
||||||
func SourceNode(ctx context.Context, node syntax.Node) (map[string]expand.Variable, error) {
|
|
||||||
r, _ := interp.New()
|
|
||||||
if err := r.Run(ctx, node); err != nil {
|
|
||||||
return nil, fmt.Errorf("could not run: %v", err)
|
|
||||||
}
|
|
||||||
// delete the internal shell vars that the user is not
|
|
||||||
// interested in
|
|
||||||
delete(r.Vars, "PWD")
|
|
||||||
delete(r.Vars, "UID")
|
|
||||||
delete(r.Vars, "HOME")
|
|
||||||
delete(r.Vars, "PATH")
|
|
||||||
delete(r.Vars, "IFS")
|
|
||||||
delete(r.Vars, "OPTIND")
|
|
||||||
return r.Vars, nil
|
|
||||||
}
|
|
1
vendor/mvdan.cc/sh/v3/syntax/braces.go
vendored
1
vendor/mvdan.cc/sh/v3/syntax/braces.go
vendored
@ -129,7 +129,6 @@ func SplitBraces(word *Word) bool {
|
|||||||
broken = true
|
broken = true
|
||||||
}
|
}
|
||||||
if !broken {
|
if !broken {
|
||||||
br.Chars = chars[0]
|
|
||||||
acc.Parts = append(acc.Parts, br)
|
acc.Parts = append(acc.Parts, br)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
2
vendor/mvdan.cc/sh/v3/syntax/lexer.go
vendored
2
vendor/mvdan.cc/sh/v3/syntax/lexer.go
vendored
@ -256,6 +256,7 @@ skipSpace:
|
|||||||
for r != '\n' && r != utf8.RuneSelf {
|
for r != '\n' && r != utf8.RuneSelf {
|
||||||
if r == escNewl {
|
if r == escNewl {
|
||||||
p.litBs = append(p.litBs, '\\', '\n')
|
p.litBs = append(p.litBs, '\\', '\n')
|
||||||
|
break
|
||||||
}
|
}
|
||||||
r = p.rune()
|
r = p.rune()
|
||||||
}
|
}
|
||||||
@ -316,6 +317,7 @@ skipSpace:
|
|||||||
} else {
|
} else {
|
||||||
p.tok = rightParen
|
p.tok = rightParen
|
||||||
p.quote = noState
|
p.quote = noState
|
||||||
|
p.rune() // we are tokenizing manually
|
||||||
}
|
}
|
||||||
default: // including '(', '|'
|
default: // including '(', '|'
|
||||||
p.advanceLitRe(r)
|
p.advanceLitRe(r)
|
||||||
|
9
vendor/mvdan.cc/sh/v3/syntax/nodes.go
vendored
9
vendor/mvdan.cc/sh/v3/syntax/nodes.go
vendored
@ -409,9 +409,9 @@ type Word struct {
|
|||||||
func (w *Word) Pos() Pos { return w.Parts[0].Pos() }
|
func (w *Word) Pos() Pos { return w.Parts[0].Pos() }
|
||||||
func (w *Word) End() Pos { return w.Parts[len(w.Parts)-1].End() }
|
func (w *Word) End() Pos { return w.Parts[len(w.Parts)-1].End() }
|
||||||
|
|
||||||
// Lit returns the word as a literal value, if the word consists of *syntax.Lit
|
// Lit returns the word as a literal value, if the word consists of *Lit nodes
|
||||||
// nodes only. An empty string is returned otherwise. Words with multiple
|
// only. An empty string is returned otherwise. Words with multiple literals,
|
||||||
// literals, which can appear in some edge cases, are handled properly.
|
// which can appear in some edge cases, are handled properly.
|
||||||
//
|
//
|
||||||
// For example, the word "foo" will return "foo", but the word "foo${bar}" will
|
// For example, the word "foo" will return "foo", but the word "foo${bar}" will
|
||||||
// return "".
|
// return "".
|
||||||
@ -859,12 +859,11 @@ type LetClause struct {
|
|||||||
func (l *LetClause) Pos() Pos { return l.Let }
|
func (l *LetClause) Pos() Pos { return l.Let }
|
||||||
func (l *LetClause) End() Pos { return l.Exprs[len(l.Exprs)-1].End() }
|
func (l *LetClause) End() Pos { return l.Exprs[len(l.Exprs)-1].End() }
|
||||||
|
|
||||||
// BraceExp represents a Bash brace expression, such as "{x,y}" or "{1..10}".
|
// BraceExp represents a Bash brace expression, such as "{a,f}" or "{1..10}".
|
||||||
//
|
//
|
||||||
// This node will only appear as a result of SplitBraces.
|
// This node will only appear as a result of SplitBraces.
|
||||||
type BraceExp struct {
|
type BraceExp struct {
|
||||||
Sequence bool // {x..y[..incr]} instead of {x,y[,...]}
|
Sequence bool // {x..y[..incr]} instead of {x,y[,...]}
|
||||||
Chars bool // sequence is of chars, not numbers (TODO: remove)
|
|
||||||
Elems []*Word
|
Elems []*Word
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
vendor/mvdan.cc/sh/v3/syntax/parser.go
vendored
16
vendor/mvdan.cc/sh/v3/syntax/parser.go
vendored
@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
// ParserOption is a function which can be passed to NewParser
|
// ParserOption is a function which can be passed to NewParser
|
||||||
// to alter its behaviour. To apply option to existing Parser
|
// to alter its behaviour. To apply option to existing Parser
|
||||||
// call it directly, for example syntax.KeepComments(true)(parser).
|
// call it directly, for example KeepComments(true)(parser).
|
||||||
type ParserOption func(*Parser)
|
type ParserOption func(*Parser)
|
||||||
|
|
||||||
// KeepComments makes the parser parse comments and attach them to
|
// KeepComments makes the parser parse comments and attach them to
|
||||||
@ -524,9 +524,13 @@ func (p *Parser) unquotedWordPart(buf *bytes.Buffer, wp WordPart, quotes bool) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) doHeredocs() {
|
func (p *Parser) doHeredocs() {
|
||||||
|
hdocs := p.heredocs[p.buriedHdocs:]
|
||||||
|
if len(hdocs) == 0 {
|
||||||
|
// Nothing do do; don't even issue a read.
|
||||||
|
return
|
||||||
|
}
|
||||||
p.rune() // consume '\n', since we know p.tok == _Newl
|
p.rune() // consume '\n', since we know p.tok == _Newl
|
||||||
old := p.quote
|
old := p.quote
|
||||||
hdocs := p.heredocs[p.buriedHdocs:]
|
|
||||||
p.heredocs = p.heredocs[:p.buriedHdocs]
|
p.heredocs = p.heredocs[:p.buriedHdocs]
|
||||||
for i, r := range hdocs {
|
for i, r := range hdocs {
|
||||||
if p.err != nil {
|
if p.err != nil {
|
||||||
@ -840,7 +844,7 @@ func (p *Parser) invalidStmtStart() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) getWord() *Word {
|
func (p *Parser) getWord() *Word {
|
||||||
if parts := p.wordParts(); len(parts) > 0 {
|
if parts := p.wordParts(); len(parts) > 0 && p.err == nil {
|
||||||
return p.word(parts)
|
return p.word(parts)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -1546,13 +1550,15 @@ func (p *Parser) hasValidIdent() bool {
|
|||||||
}
|
}
|
||||||
if end := p.eqlOffs; end > 0 {
|
if end := p.eqlOffs; end > 0 {
|
||||||
if p.val[end-1] == '+' && p.lang != LangPOSIX {
|
if p.val[end-1] == '+' && p.lang != LangPOSIX {
|
||||||
end--
|
end-- // a+=x
|
||||||
}
|
}
|
||||||
if ValidName(p.val[:end]) {
|
if ValidName(p.val[:end]) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
} else if !ValidName(p.val) {
|
||||||
|
return false // *[i]=x
|
||||||
}
|
}
|
||||||
return p.r == '['
|
return p.r == '[' // a[i]=x
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) getAssign(needEqual bool) *Assign {
|
func (p *Parser) getAssign(needEqual bool) *Assign {
|
||||||
|
11
vendor/mvdan.cc/sh/v3/syntax/printer.go
vendored
11
vendor/mvdan.cc/sh/v3/syntax/printer.go
vendored
@ -15,7 +15,7 @@ import (
|
|||||||
|
|
||||||
// PrinterOption is a function which can be passed to NewPrinter
|
// PrinterOption is a function which can be passed to NewPrinter
|
||||||
// to alter its behaviour. To apply option to existing Printer
|
// to alter its behaviour. To apply option to existing Printer
|
||||||
// call it directly, for example syntax.KeepPadding(true)(printer).
|
// call it directly, for example KeepPadding(true)(printer).
|
||||||
type PrinterOption func(*Printer)
|
type PrinterOption func(*Printer)
|
||||||
|
|
||||||
// Indent sets the number of spaces used for indentation. If set to 0,
|
// Indent sets the number of spaces used for indentation. If set to 0,
|
||||||
@ -414,13 +414,13 @@ func (p *Printer) flushHeredocs() {
|
|||||||
bufWriter: &extra,
|
bufWriter: &extra,
|
||||||
line: r.Hdoc.Pos().Line(),
|
line: r.Hdoc.Pos().Line(),
|
||||||
}
|
}
|
||||||
p.tabsPrinter.word(r.Hdoc)
|
p.tabsPrinter.wordParts(r.Hdoc.Parts, true)
|
||||||
p.indent()
|
p.indent()
|
||||||
} else {
|
} else {
|
||||||
p.indent()
|
p.indent()
|
||||||
}
|
}
|
||||||
} else if r.Hdoc != nil {
|
} else if r.Hdoc != nil {
|
||||||
p.word(r.Hdoc)
|
p.wordParts(r.Hdoc.Parts, true)
|
||||||
}
|
}
|
||||||
p.unquotedWord(r.Word)
|
p.unquotedWord(r.Word)
|
||||||
if r.Hdoc != nil {
|
if r.Hdoc != nil {
|
||||||
@ -478,6 +478,11 @@ func (p *Printer) semiRsrv(s string, pos Pos) {
|
|||||||
|
|
||||||
func (p *Printer) flushComments() {
|
func (p *Printer) flushComments() {
|
||||||
for i, c := range p.pendingComments {
|
for i, c := range p.pendingComments {
|
||||||
|
if i == 0 {
|
||||||
|
// Flush any pending heredocs first. Otherwise, the
|
||||||
|
// comments would become part of a heredoc body.
|
||||||
|
p.flushHeredocs()
|
||||||
|
}
|
||||||
p.firstLine = false
|
p.firstLine = false
|
||||||
// We can't call any of the newline methods, as they call this
|
// We can't call any of the newline methods, as they call this
|
||||||
// function and we'd recurse forever.
|
// function and we'd recurse forever.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user