mirror of
https://github.com/go-task/task.git
synced 2025-05-31 23:19:42 +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
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.12.x, 1.13.x]
|
||||
go-version: [1.13.x, 1.14.x]
|
||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{matrix.platform}}
|
||||
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
|
||||
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]:-"."}"
|
||||
|
||||
|
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
|
||||
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
|
||||
|
||||
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
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
||||
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
|
||||
|
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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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.0-beta1/go.mod h1:rBIndNJFYPp8xSppiZcGIk6B5d1g3OEARxEaXjPxwVI=
|
||||
mvdan.cc/sh/v3 v3.0.2 h1:NU+UpTZHRdIZ9igRo8zi/7+5/NpetYlhlyDhz1/AdMM=
|
||||
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))
|
||||
for _, task := range e.Taskfile.Tasks {
|
||||
if task.Desc != "" {
|
||||
compiledTask, err := e.CompiledTask(taskfile.Call{Task: task.Task})
|
||||
if err == nil {
|
||||
task = compiledTask
|
||||
}
|
||||
tasks = append(tasks, task)
|
||||
}
|
||||
}
|
||||
|
@ -9,12 +9,12 @@ import (
|
||||
|
||||
func PrintTasks(l *logger.Logger, t *taskfile.Taskfile, c []taskfile.Call) {
|
||||
for i, call := range c {
|
||||
printSpaceBetweenSummaries(l, i)
|
||||
PrintSpaceBetweenSummaries(l, i)
|
||||
PrintTask(l, t.Tasks[call.Task])
|
||||
}
|
||||
}
|
||||
|
||||
func printSpaceBetweenSummaries(l *logger.Logger, i int) {
|
||||
func PrintSpaceBetweenSummaries(l *logger.Logger, i int) {
|
||||
spaceRequired := i > 0
|
||||
if !spaceRequired {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ func (e *Executor) CompiledTask(call taskfile.Call) (*taskfile.Task, error) {
|
||||
new := taskfile.Task{
|
||||
Task: origTask.Task,
|
||||
Desc: r.Replace(origTask.Desc),
|
||||
Summary: r.Replace(origTask.Summary),
|
||||
Sources: r.ReplaceSlice(origTask.Sources),
|
||||
Generates: r.ReplaceSlice(origTask.Generates),
|
||||
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
|
||||
# gopkg.in/yaml.v2 v2.2.2
|
||||
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/interp
|
||||
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
|
||||
}
|
||||
if br.Sequence {
|
||||
var from, to int
|
||||
if br.Chars {
|
||||
chars := false
|
||||
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])
|
||||
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
|
||||
incr := 1
|
||||
@ -54,7 +54,7 @@ func Braces(word *syntax.Word) []*syntax.Word {
|
||||
next := *word
|
||||
next.Parts = next.Parts[i+1:]
|
||||
lit := &syntax.Lit{}
|
||||
if br.Chars {
|
||||
if chars {
|
||||
lit.Value = string(n)
|
||||
} else {
|
||||
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
|
||||
}
|
||||
|
||||
const patMode = pattern.Filenames | pattern.Braces
|
||||
|
||||
// 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
|
||||
// syntax.TranslatePattern directly.
|
||||
@ -174,7 +176,7 @@ func Pattern(cfg *Config, word *syntax.Word) (string, error) {
|
||||
buf := cfg.strBuilder()
|
||||
for _, part := range field {
|
||||
if part.quote > quoteNone {
|
||||
buf.WriteString(pattern.QuoteMeta(part.val))
|
||||
buf.WriteString(pattern.QuoteMeta(part.val, patMode))
|
||||
} else {
|
||||
buf.WriteString(part.val)
|
||||
}
|
||||
@ -345,11 +347,11 @@ func (cfg *Config) escapedGlobField(parts []fieldPart) (escaped string, glob boo
|
||||
buf := cfg.strBuilder()
|
||||
for _, part := range parts {
|
||||
if part.quote > quoteNone {
|
||||
buf.WriteString(pattern.QuoteMeta(part.val))
|
||||
buf.WriteString(pattern.QuoteMeta(part.val, patMode))
|
||||
continue
|
||||
}
|
||||
buf.WriteString(part.val)
|
||||
if pattern.HasMeta(part.val) {
|
||||
if pattern.HasMeta(part.val, patMode) {
|
||||
glob = true
|
||||
}
|
||||
}
|
||||
@ -367,9 +369,10 @@ func Fields(cfg *Config, words ...*syntax.Word) ([]string, error) {
|
||||
fields := make([]string, 0, len(words))
|
||||
dir := cfg.envGet("PWD")
|
||||
for _, word := range words {
|
||||
afterBraces := []*syntax.Word{word}
|
||||
if syntax.SplitBraces(word) {
|
||||
afterBraces = Braces(word)
|
||||
word := *word // make a copy, since SplitBraces replaces the Parts slice
|
||||
afterBraces := []*syntax.Word{&word}
|
||||
if syntax.SplitBraces(&word) {
|
||||
afterBraces = Braces(&word)
|
||||
}
|
||||
for _, word2 := range afterBraces {
|
||||
wfields, err := cfg.wordFields(word2.Parts)
|
||||
@ -540,7 +543,6 @@ func (cfg *Config) wordFields(wps []syntax.WordPart) ([][]fieldPart, error) {
|
||||
}
|
||||
curField = append(curField, fp)
|
||||
case *syntax.DblQuoted:
|
||||
allowEmpty = true
|
||||
if len(x.Parts) == 1 {
|
||||
pe, _ := x.Parts[0].(*syntax.ParamExp)
|
||||
if elems := cfg.quotedElems(pe); elems != nil {
|
||||
@ -556,6 +558,7 @@ func (cfg *Config) wordFields(wps []syntax.WordPart) ([][]fieldPart, error) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
allowEmpty = true
|
||||
wfield, err := cfg.wordField(x.Parts, quoteDouble)
|
||||
if err != nil {
|
||||
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,
|
||||
Dir: r.Dir,
|
||||
Params: r.Params,
|
||||
Funcs: r.Funcs,
|
||||
execHandler: r.execHandler,
|
||||
openHandler: r.openHandler,
|
||||
stdin: r.stdin,
|
||||
@ -766,6 +765,10 @@ func (r *Runner) sub() *Runner {
|
||||
for k, v := range r.cmdVars {
|
||||
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.fillExpandConfig(r.ectx)
|
||||
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"
|
||||
)
|
||||
|
||||
// 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
|
||||
|
||||
const (
|
||||
@ -254,13 +254,17 @@ func charClass(s string) (string, error) {
|
||||
// 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
|
||||
// that function but ignored here.
|
||||
func HasMeta(pat string) bool {
|
||||
func HasMeta(pat string, mode Mode) bool {
|
||||
for i := 0; i < len(pat); i++ {
|
||||
switch pat[i] {
|
||||
case '\\':
|
||||
i++
|
||||
case '*', '?', '[':
|
||||
return true
|
||||
case '{':
|
||||
if mode&Braces != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
@ -270,11 +274,16 @@ func HasMeta(pat string) bool {
|
||||
// given text. The returned string is a pattern that matches the literal text.
|
||||
//
|
||||
// For example, QuoteMeta(`foo*bar?`) returns `foo\*bar\?`.
|
||||
func QuoteMeta(pat string) string {
|
||||
func QuoteMeta(pat string, mode Mode) string {
|
||||
any := false
|
||||
loop:
|
||||
for _, r := range pat {
|
||||
switch r {
|
||||
case '{':
|
||||
if mode&Braces == 0 {
|
||||
continue
|
||||
}
|
||||
fallthrough
|
||||
case '*', '?', '[', '\\':
|
||||
any = true
|
||||
break loop
|
||||
@ -288,6 +297,10 @@ loop:
|
||||
switch r {
|
||||
case '*', '?', '[', '\\':
|
||||
buf.WriteByte('\\')
|
||||
case '{':
|
||||
if mode&Braces != 0 {
|
||||
buf.WriteByte('\\')
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
if !broken {
|
||||
br.Chars = chars[0]
|
||||
acc.Parts = append(acc.Parts, br)
|
||||
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 {
|
||||
if r == escNewl {
|
||||
p.litBs = append(p.litBs, '\\', '\n')
|
||||
break
|
||||
}
|
||||
r = p.rune()
|
||||
}
|
||||
@ -316,6 +317,7 @@ skipSpace:
|
||||
} else {
|
||||
p.tok = rightParen
|
||||
p.quote = noState
|
||||
p.rune() // we are tokenizing manually
|
||||
}
|
||||
default: // including '(', '|'
|
||||
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) 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
|
||||
// nodes only. An empty string is returned otherwise. Words with multiple
|
||||
// literals, which can appear in some edge cases, are handled properly.
|
||||
// Lit returns the word as a literal value, if the word consists of *Lit nodes
|
||||
// only. An empty string is returned otherwise. Words with multiple literals,
|
||||
// which can appear in some edge cases, are handled properly.
|
||||
//
|
||||
// For example, the word "foo" will return "foo", but the word "foo${bar}" will
|
||||
// return "".
|
||||
@ -859,12 +859,11 @@ type LetClause struct {
|
||||
func (l *LetClause) Pos() Pos { return l.Let }
|
||||
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.
|
||||
type BraceExp struct {
|
||||
Sequence bool // {x..y[..incr]} instead of {x,y[,...]}
|
||||
Chars bool // sequence is of chars, not numbers (TODO: remove)
|
||||
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
|
||||
// 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)
|
||||
|
||||
// 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() {
|
||||
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
|
||||
old := p.quote
|
||||
hdocs := p.heredocs[p.buriedHdocs:]
|
||||
p.heredocs = p.heredocs[:p.buriedHdocs]
|
||||
for i, r := range hdocs {
|
||||
if p.err != nil {
|
||||
@ -840,7 +844,7 @@ func (p *Parser) invalidStmtStart() {
|
||||
}
|
||||
|
||||
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 nil
|
||||
@ -1546,13 +1550,15 @@ func (p *Parser) hasValidIdent() bool {
|
||||
}
|
||||
if end := p.eqlOffs; end > 0 {
|
||||
if p.val[end-1] == '+' && p.lang != LangPOSIX {
|
||||
end--
|
||||
end-- // a+=x
|
||||
}
|
||||
if ValidName(p.val[:end]) {
|
||||
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 {
|
||||
|
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
|
||||
// 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)
|
||||
|
||||
// Indent sets the number of spaces used for indentation. If set to 0,
|
||||
@ -414,13 +414,13 @@ func (p *Printer) flushHeredocs() {
|
||||
bufWriter: &extra,
|
||||
line: r.Hdoc.Pos().Line(),
|
||||
}
|
||||
p.tabsPrinter.word(r.Hdoc)
|
||||
p.tabsPrinter.wordParts(r.Hdoc.Parts, true)
|
||||
p.indent()
|
||||
} else {
|
||||
p.indent()
|
||||
}
|
||||
} else if r.Hdoc != nil {
|
||||
p.word(r.Hdoc)
|
||||
p.wordParts(r.Hdoc.Parts, true)
|
||||
}
|
||||
p.unquotedWord(r.Word)
|
||||
if r.Hdoc != nil {
|
||||
@ -478,6 +478,11 @@ func (p *Printer) semiRsrv(s string, pos Pos) {
|
||||
|
||||
func (p *Printer) flushComments() {
|
||||
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
|
||||
// We can't call any of the newline methods, as they call this
|
||||
// function and we'd recurse forever.
|
||||
|
Loading…
x
Reference in New Issue
Block a user