Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cfdb21313 | ||
|
|
e396f4d06f | ||
|
|
47c1bb6a5b | ||
|
|
adfb0b513e | ||
|
|
98d78b9d8a | ||
|
|
a1c32a56ea | ||
|
|
6584bcf87f | ||
|
|
7ac75af622 | ||
|
|
b3c283b282 | ||
|
|
c2615dd746 | ||
|
|
789518f70d | ||
|
|
ad3008d855 | ||
|
|
3da426603f | ||
|
|
8d26e34b0a | ||
|
|
110d1d7245 | ||
|
|
f7384623df | ||
|
|
5d24e166ab | ||
|
|
d9ec5bcd24 | ||
|
|
bf9cd7625b | ||
|
|
afbf98c974 | ||
|
|
fedb68cde7 | ||
|
|
f787937a30 | ||
|
|
f54fef7e7b | ||
|
|
e36c77aaf3 | ||
|
|
de45e48c37 | ||
|
|
ef0ce8224e | ||
|
|
5b4d5387bf | ||
|
|
5c460b38c9 | ||
|
|
8b836ab446 | ||
|
|
1be1fccc76 | ||
|
|
2c1fda97f0 | ||
|
|
71f7b719b5 | ||
|
|
e39006b511 | ||
|
|
37d07d415a | ||
|
|
b80c8f78fc | ||
|
|
7707179b93 | ||
|
|
4e7d8bacdb | ||
|
|
0c46fa5a56 | ||
|
|
36aca00de3 | ||
|
|
0ec8cf1b53 |
2
.github/workflows/lint.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.18.x
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
||||
2
.github/workflows/release.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: 1.18.x
|
||||
go-version: 1.19.x
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
|
||||
2
.github/workflows/test.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
name: Test
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.17.x, 1.18.x]
|
||||
go-version: [1.18.x, 1.19.x]
|
||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{matrix.platform}}
|
||||
steps:
|
||||
|
||||
30
CHANGELOG.md
@@ -1,12 +1,40 @@
|
||||
# Changelog
|
||||
|
||||
## v3.14.1 - 2022-08-03
|
||||
|
||||
- Always resolve relative include paths relative to the including Taskfile
|
||||
([#822](https://github.com/go-task/task/issues/822), [#823](https://github.com/go-task/task/pull/823)).
|
||||
- Fix ZSH and PowerShell completions to consider all tasks instead of just the
|
||||
public ones (those with descriptions)
|
||||
([#803](https://github.com/go-task/task/pull/803)).
|
||||
|
||||
## v3.14.0 - 2022-07-08
|
||||
|
||||
- Add ability to override the `.task` directory location with the
|
||||
`TASK_TEMP_DIR` environment variable.
|
||||
- Allow to override Task colors using environment variables:
|
||||
`TASK_COLOR_RESET`, `TASK_COLOR_BLUE`, `TASK_COLOR_GREEN`,
|
||||
`TASK_COLOR_CYAN`, `TASK_COLOR_YELLOW`, `TASK_COLOR_MAGENTA`
|
||||
and `TASK_COLOR_RED`
|
||||
([#568](https://github.com/go-task/task/pull/568), [#792](https://github.com/go-task/task/pull/792)).
|
||||
- Fixed bug when using the `output: group` mode where STDOUT and STDERR were
|
||||
being print in separated blocks instead of in the right order
|
||||
([#779](https://github.com/go-task/task/issues/779)).
|
||||
- Starting on this release, ARM architecture binaries are been released to Snap
|
||||
as well
|
||||
([#795](https://github.com/go-task/task/issues/795)).
|
||||
- i386 binaries won't be available anymore on Snap because Ubuntu removed the support
|
||||
for this architecture.
|
||||
- Upgrade mvdan.cc/sh, which fixes a bug with associative arrays
|
||||
([#785](https://github.com/go-task/task/issues/785), [mvdan/sh#884](https://github.com/mvdan/sh/issues/884), [mvdan/sh#893](https://github.com/mvdan/sh/pull/893)).
|
||||
|
||||
## v3.13.0 - 2022-06-13
|
||||
|
||||
- Added `-n` as an alias to `--dry`
|
||||
([#776](https://github.com/go-task/task/issues/776), [#777](https://github.com/go-task/task/pull/777)).
|
||||
- Fix behavior of interrupt (SIGINT, SIGTERM) signals. Task will now give time
|
||||
for the processes running to do cleanup work
|
||||
([#458](https://github.com/go-task/task/issues/458), [#479](https://github.com/go-task/task/pull/479), [#728](https://github.com/go-task/task/issues/728)).
|
||||
([#458](https://github.com/go-task/task/issues/458), [#479](https://github.com/go-task/task/pull/479), [#728](https://github.com/go-task/task/issues/728), [#769](https://github.com/go-task/task/pull/769)).
|
||||
- Add new `--exit-code` (`-x`) flag that will pass-through the exit form the
|
||||
command being ran
|
||||
([#755](https://github.com/go-task/task/pull/755)).
|
||||
|
||||
@@ -65,10 +65,16 @@ tasks:
|
||||
|
||||
test:
|
||||
desc: Runs test suite
|
||||
deps: [install, sleepit:build]
|
||||
deps: [install]
|
||||
cmds:
|
||||
- go test {{catLines .GO_PACKAGES}}
|
||||
|
||||
test:signals:
|
||||
desc: Runs test suite with signals tests included
|
||||
deps: [install, sleepit:build]
|
||||
cmds:
|
||||
- go test {{catLines .GO_PACKAGES}} -tags signals
|
||||
|
||||
test-release:
|
||||
desc: Tests release process without publishing
|
||||
cmds:
|
||||
|
||||
@@ -3,7 +3,7 @@ $scriptBlock = {
|
||||
$curReg = "task{.exe}? (.*?)$"
|
||||
$startsWith = $wordToComplete | Select-String $curReg -AllMatches | ForEach-Object { $_.Matches.Groups[1].Value }
|
||||
$reg = "\* ($startsWith.+?):"
|
||||
$listOutput = $(task -l)
|
||||
$listOutput = $(task --list-all)
|
||||
$listOutput | Select-String $reg -AllMatches | ForEach-Object { $_.Matches.Groups[1].Value + " " }
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ function __task_list() {
|
||||
(( enabled )) || return 0
|
||||
|
||||
scripts=()
|
||||
for item in "${(@)${(f)$("${cmd[@]}" --list)}[2,-1]#\* }"; do
|
||||
for item in "${(@)${(f)$("${cmd[@]}" --list-all)}[2,-1]#\* }"; do
|
||||
task="${item%%:[[:space:]]*}"
|
||||
desc="${item##[^[:space:]]##[[:space:]]##}"
|
||||
scripts+=( "${task//:/\\:}:$desc" )
|
||||
|
||||
@@ -15,7 +15,7 @@ task [--flags] [tasks...] [-- CLI_ARGS...]
|
||||
|
||||
:::tip
|
||||
|
||||
If `--` is given, all remaning arguments to assigned to a special `CLI_ARGS`
|
||||
If `--` is given, all remaning arguments will be assigned to a special `CLI_ARGS`
|
||||
variable
|
||||
|
||||
:::
|
||||
@@ -44,6 +44,21 @@ variable
|
||||
| | `--version` | `bool` | `false` | Show Task version. |
|
||||
| `-w` | `--watch` | `bool` | `false` | Enables watch of the given task. |
|
||||
|
||||
## ENV
|
||||
|
||||
Some environment variables can be overriden to adjust Task behavior.
|
||||
|
||||
| ENV | Default | Description |
|
||||
| - | - | - |
|
||||
| `TASK_TEMP_DIR` | `.task` | Location of the temp dir. Can relative to the project like `tmp/task` or absolute like `/tmp/.task` or `~/.task`. |
|
||||
| `TASK_COLOR_RESET` | `0` | Color used for white. |
|
||||
| `TASK_COLOR_BLUE` | `34` | Color used for blue. |
|
||||
| `TASK_COLOR_GREEN` | `32` | Color used for green. |
|
||||
| `TASK_COLOR_CYAN` | `36` | Color used for cyan. |
|
||||
| `TASK_COLOR_YELLOW` | `33` | Color used for yellow. |
|
||||
| `TASK_COLOR_MAGENTA` | `35` | Color used for magenta. |
|
||||
| `TASK_COLOR_RED` | `31` | Color used for red. |
|
||||
|
||||
## Schema
|
||||
|
||||
### Taskfile
|
||||
@@ -66,7 +81,7 @@ variable
|
||||
|
||||
| Attribute | Type | Default | Description |
|
||||
| - | - | - | - |
|
||||
| `taskfile` | `string` | | The path for the Taskfile or directory to be included. If a directory, Task will look for files named `Taskfile.yml` or `Taskfile.yaml` inside that directory. |
|
||||
| `taskfile` | `string` | | The path for the Taskfile or directory to be included. If a directory, Task will look for files named `Taskfile.yml` or `Taskfile.yaml` inside that directory. If a relative path, resolved relative to the directory containing the including Taskfile. |
|
||||
| `dir` | `string` | The parent Taskfile directory | The working directory of the included tasks when run. |
|
||||
| `optional` | `bool` | `false` | If `true`, no errors will be thrown if the specified file does not exist. |
|
||||
|
||||
@@ -114,6 +129,9 @@ tasks:
|
||||
foobar:
|
||||
- echo "foo"
|
||||
- echo "bar"
|
||||
|
||||
baz:
|
||||
cmd: echo "baz"
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
@@ -5,13 +5,33 @@ sidebar_position: 6
|
||||
|
||||
# Changelog
|
||||
|
||||
## v3.14.0 - 2022-07-08
|
||||
|
||||
- Add ability to override the `.task` directory location with the
|
||||
`TASK_TEMP_DIR` environment variable.
|
||||
- Allow to override Task colors using environment variables:
|
||||
`TASK_COLOR_RESET`, `TASK_COLOR_BLUE`, `TASK_COLOR_GREEN`,
|
||||
`TASK_COLOR_CYAN`, `TASK_COLOR_YELLOW`, `TASK_COLOR_MAGENTA`
|
||||
and `TASK_COLOR_RED`
|
||||
([#568](https://github.com/go-task/task/pull/568), [#792](https://github.com/go-task/task/pull/792)).
|
||||
- Fixed bug when using the `output: group` mode where STDOUT and STDERR were
|
||||
being print in separated blocks instead of in the right order
|
||||
([#779](https://github.com/go-task/task/issues/779)).
|
||||
- Starting on this release, ARM architecture binaries are been released to Snap
|
||||
as well
|
||||
([#795](https://github.com/go-task/task/issues/795)).
|
||||
- i386 binaries won't be available anymore on Snap because Ubuntu removed the support
|
||||
for this architecture.
|
||||
- Upgrade mvdan.cc/sh, which fixes a bug with associative arrays
|
||||
([#785](https://github.com/go-task/task/issues/785), [mvdan/sh#884](https://github.com/mvdan/sh/issues/884), [mvdan/sh#893](https://github.com/mvdan/sh/pull/893)).
|
||||
|
||||
## v3.13.0 - 2022-06-13
|
||||
|
||||
- Added `-n` as an alias to `--dry`
|
||||
([#776](https://github.com/go-task/task/issues/776), [#777](https://github.com/go-task/task/pull/777)).
|
||||
- Fix behavior of interrupt (SIGINT, SIGTERM) signals. Task will now give time
|
||||
for the processes running to do cleanup work
|
||||
([#458](https://github.com/go-task/task/issues/458), [#479](https://github.com/go-task/task/pull/479), [#728](https://github.com/go-task/task/issues/728)).
|
||||
([#458](https://github.com/go-task/task/issues/458), [#479](https://github.com/go-task/task/pull/479), [#728](https://github.com/go-task/task/issues/728), [#769](https://github.com/go-task/task/pull/769)).
|
||||
- Add new `--exit-code` (`-x`) flag that will pass-through the exit form the
|
||||
command being ran
|
||||
([#755](https://github.com/go-task/task/pull/755)).
|
||||
|
||||
@@ -49,6 +49,8 @@ Some installation methods are maintained by third party:
|
||||
- [AUR](https://aur.archlinux.org/packages/taskfile-git)
|
||||
by [@kovetskiy](https://github.com/kovetskiy)
|
||||
- [Scoop](https://github.com/lukesampson/scoop-extras/blob/master/bucket/task.json)
|
||||
- [Fedora](https://packages.fedoraproject.org/pkgs/golang-github-task/go-task/)
|
||||
- [NixOS](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/tools/go-task/default.nix)
|
||||
|
||||
## More
|
||||
|
||||
|
||||
@@ -42,11 +42,10 @@ This installation method is community owned.
|
||||
|
||||
### Scoop
|
||||
|
||||
If you're on Windows and have [Scoop][scoop] installed, use `extras` bucket
|
||||
to install Task like:
|
||||
If you're on Windows and have [Scoop][scoop] installed, getting
|
||||
Task is as simple as running:
|
||||
|
||||
```cmd
|
||||
scoop bucket add extras
|
||||
scoop install task
|
||||
```
|
||||
|
||||
@@ -107,19 +106,25 @@ We also have an [install script][installscript] which is very useful in
|
||||
scenarios like CI. Many thanks to [GoDownloader][godownloader] for enabling the
|
||||
easy generation of this script.
|
||||
|
||||
By default, it installs on the `./bin` directory relative to the working
|
||||
directory:
|
||||
|
||||
```bash
|
||||
# For Default Installation to ./bin with debug logging
|
||||
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d
|
||||
|
||||
# For Installation To /usr/local/bin for userwide access with debug logging
|
||||
# May require sudo sh
|
||||
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
|
||||
|
||||
```
|
||||
|
||||
:::info
|
||||
It is possible to override the installation directory with the `-b` parameter.
|
||||
On Linux, common choices are `~/.local/bin` and `~/bin` to install for the
|
||||
current user or `/usr/local/bin` to install for all users:
|
||||
|
||||
This method will download the binary on the local `./bin` directory by default.
|
||||
```bash
|
||||
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin
|
||||
```
|
||||
|
||||
:::caution
|
||||
|
||||
On macOS and Windows, `~/.local/bin` and `~/bin` are not added to `$PATH` by
|
||||
default.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@@ -38,12 +38,12 @@ guide to check the full schema documentation and Task features.
|
||||
## Features
|
||||
|
||||
- [Easy installation](installation.md): just download a single binary, add to
|
||||
$PATH and you're done! Or you can also install using [Homebrew][homebrew],
|
||||
[Snapcraft][snapcraft], or [Scoop][scoop] if you want;
|
||||
`$PATH` and you're done! Or you can also install using [Homebrew][homebrew],
|
||||
[Snapcraft][snapcraft], or [Scoop][scoop] if you want.
|
||||
- Available on CIs: by adding [this simple command](installation.md#install-script)
|
||||
to install on your CI script and you're done to use Task as part of your CI pipeline;
|
||||
- Truly cross-platform: while most build tools only work well on Linux or macOS,
|
||||
Task also supports Windows thanks to [this shell interpreter for Go][sh];
|
||||
Task also supports Windows thanks to [this shell interpreter for Go][sh].
|
||||
- Great for code generation: you can easily [prevent a task from running](/usage#prevent-unnecessary-work)
|
||||
if a given set of files haven't changed since last run (based either on its
|
||||
timestamp or content).
|
||||
@@ -54,4 +54,4 @@ guide to check the full schema documentation and Task features.
|
||||
[homebrew]: https://brew.sh/
|
||||
[snapcraft]: https://snapcraft.io/
|
||||
[scoop]: https://scoop.sh/
|
||||
[sh]: https://mvdan.cc/sh
|
||||
[sh]: https://github.com/mvdan/sh
|
||||
|
||||
@@ -25,9 +25,9 @@ The exception is the publishing of a new version of the
|
||||
[snap package][snappackage]. This current require two steps after publishing
|
||||
the binaries:
|
||||
|
||||
* Updating the current version on [snapcraft.yaml][snapcraftyaml];
|
||||
* Moving both `i386` and `amd64` new artifacts to the stable channel on
|
||||
the [Snapcraft dashboard][snapcraftdashboard]
|
||||
* Updating the current version on [snapcraft.yaml][snapcraftyaml].
|
||||
* Moving both `amd64`, `armhf` and `arm64` new artifacts to the stable channel on
|
||||
the [Snapcraft dashboard][snapcraftdashboard].
|
||||
|
||||
# Scoop
|
||||
|
||||
|
||||
@@ -136,6 +136,8 @@ namespace. So, you'd call `task docs:serve` to run the `serve` task from
|
||||
`documentation/Taskfile.yml` or `task docker:build` to run the `build` task
|
||||
from the `DockerTasks.yml` file.
|
||||
|
||||
Relative paths are resolved relative to the directory containing the including Taskfile.
|
||||
|
||||
### OS-specific Taskfiles
|
||||
|
||||
With `version: '2'`, task automatically includes any `Taskfile_{{OS}}.yml`
|
||||
@@ -215,7 +217,7 @@ includes:
|
||||
:::info
|
||||
|
||||
Vars declared in the included Taskfile have preference over the
|
||||
included ones! If you want a variable in an included Taskfile to be overridable,
|
||||
variables in the including Taskfile! If you want a variable in an included Taskfile to be overridable,
|
||||
use the [default function](https://go-task.github.io/slim-sprig/defaults.html):
|
||||
`MY_VAR: '{{.MY_VAR | default "my-default-value"}}'`.
|
||||
|
||||
@@ -406,8 +408,6 @@ tasks:
|
||||
Task will compare the checksum of the source files to determine if it's
|
||||
necessary to run the task. If not, it will just print a message like
|
||||
`Task "js" is up to date`.
|
||||
You will probably want to ignore the `.task` folder in your `.gitignore` file
|
||||
(It is there that Task stores the last checksum).
|
||||
|
||||
If you prefer this check to be made by the modification timestamp of the files,
|
||||
instead of its checksum (content), just set the `method` property to `timestamp`.
|
||||
@@ -423,11 +423,31 @@ tasks:
|
||||
- ./*.go
|
||||
generates:
|
||||
- app{{exeExt}}
|
||||
method: checksum
|
||||
method: timestamp
|
||||
```
|
||||
|
||||
:::info
|
||||
|
||||
By default, task stores checksums on a local `.task` directory in the project's
|
||||
directory. Most of the time, you'll want to have this directory on `.gitignore`
|
||||
(or equivalent) so it isn't committed. (If you have a task for code generation
|
||||
that is committed it may make sense to commit the checksum of that task as
|
||||
well, though).
|
||||
|
||||
If you want these files to be stored in another directory, you can set a
|
||||
`TASK_TEMP_DIR` environment variable in your machine. It can contain a relative
|
||||
path like `tmp/task` that will be interpreted as relative to the project
|
||||
directory, or an absolute or home path like `/tmp/.task` or `~/.task`
|
||||
(subdirectories will be created for each project).
|
||||
|
||||
```bash
|
||||
export TASK_TEMP_DIR='~/.task'
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::info
|
||||
|
||||
Each task has only one checksum stored for its `sources`. If you want
|
||||
to distinguish a task by any of its input variables, you can add those
|
||||
variables as part of the task's label, and it will be considered a different
|
||||
@@ -1058,7 +1078,7 @@ version: '3'
|
||||
|
||||
output:
|
||||
group:
|
||||
begin: '::begin::{{.TASK}}'
|
||||
begin: '::group::{{.TASK}}'
|
||||
end: '::endgroup::'
|
||||
|
||||
tasks:
|
||||
@@ -1070,7 +1090,7 @@ tasks:
|
||||
|
||||
```bash
|
||||
$ task default
|
||||
::begin::default
|
||||
::group::default
|
||||
Hello, World!
|
||||
::endgroup::
|
||||
```
|
||||
|
||||
@@ -5,6 +5,7 @@ const lightCodeTheme = require('prism-react-renderer/themes/github');
|
||||
const darkCodeTheme = require('prism-react-renderer/themes/dracula');
|
||||
|
||||
const GITHUB_URL = 'https://github.com/go-task/task';
|
||||
const TWITTER_URL = 'https://twitter.com/taskfiledev';
|
||||
const DISCORD_URL = 'https://discord.gg/6TY36E39UK';
|
||||
|
||||
/** @type {import('@docusaurus/types').Config} */
|
||||
@@ -100,6 +101,11 @@ const config = {
|
||||
label: 'GitHub',
|
||||
position: 'right'
|
||||
},
|
||||
{
|
||||
href: TWITTER_URL,
|
||||
label: 'Twitter',
|
||||
position: 'right'
|
||||
},
|
||||
{
|
||||
href: DISCORD_URL,
|
||||
label: 'Discord',
|
||||
@@ -134,6 +140,10 @@ const config = {
|
||||
label: 'GitHub',
|
||||
href: GITHUB_URL
|
||||
},
|
||||
{
|
||||
label: 'Twitter',
|
||||
href: TWITTER_URL
|
||||
},
|
||||
{
|
||||
label: 'Discord',
|
||||
href: DISCORD_URL
|
||||
|
||||
BIN
docs/static/img/logo.png
vendored
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 13 KiB |
6
docs/static/img/logo.svg
vendored
@@ -1,5 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 375 375" width="500" height="500">
|
||||
<path fill="#29beb0" d="M 187.570312 190.933594 L 187.570312 375 L 30.070312 279.535156 L 30.070312 95.464844 Z"/>
|
||||
<path fill="#69d2c8" d="M 187.570312 190.933594 L 187.570312 375 L 345.070312 279.535156 L 345.070312 95.464844 Z"/>
|
||||
<path fill="#94dfd8" d="M 187.570312 190.933594 L 30.070312 95.464844 L 187.570312 0 L 345.070312 95.464844 Z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500" viewBox="0 0 375 375"><path fill="#29beb0" d="M 187.570312 190.933594 L 187.570312 375 L 30.070312 279.535156 L 30.070312 95.464844 Z"/><path fill="#69d2c8" d="M 187.570312 190.933594 L 187.570312 375 L 345.070312 279.535156 L 345.070312 95.464844 Z"/><path fill="#94dfd8" d="M 187.570312 190.933594 L 30.070312 95.464844 L 187.570312 0 L 345.070312 95.464844 Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 446 B After Width: | Height: | Size: 435 B |
4
docs/static/img/logo_mono.svg
vendored
@@ -1,3 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 375 375" width="500" height="500">
|
||||
<path d="M 29.021972 281.445466 L 183.370289 375 L 183.370289 194.622441 L 29.021972 101.064089 Z M 345.978037 281.445466 L 345.978037 101.064079 L 191.629731 194.622431 L 191.629731 375 Z M 342.140723 93.731759 L 187.5 0 L 32.859297 93.731759 L 187.5 187.467349 Z"/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500" viewBox="0 0 375 375"><path d="M 29.021972 281.445466 L 183.370289 375 L 183.370289 194.622441 L 29.021972 101.064089 Z M 345.978037 281.445466 L 345.978037 101.064079 L 191.629731 194.622431 L 191.629731 375 Z M 342.140723 93.731759 L 187.5 0 L 32.859297 93.731759 L 187.5 187.467349 Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 365 B After Width: | Height: | Size: 360 B |
BIN
docs/static/img/og-image.png
vendored
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 19 KiB |
BIN
docs/static/img/pix.png
vendored
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -1577,33 +1577,46 @@
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@jridgewell/gen-mapping@^0.3.0":
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9"
|
||||
integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
|
||||
integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
|
||||
dependencies:
|
||||
"@jridgewell/set-array" "^1.0.0"
|
||||
"@jridgewell/set-array" "^1.0.1"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@jridgewell/resolve-uri@^3.0.3":
|
||||
version "3.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe"
|
||||
integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
|
||||
integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
|
||||
|
||||
"@jridgewell/set-array@^1.0.0":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea"
|
||||
integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==
|
||||
|
||||
"@jridgewell/set-array@^1.0.1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
|
||||
integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
|
||||
|
||||
"@jridgewell/source-map@^0.3.2":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
|
||||
integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
|
||||
dependencies:
|
||||
"@jridgewell/gen-mapping" "^0.3.0"
|
||||
"@jridgewell/trace-mapping" "^0.3.9"
|
||||
|
||||
"@jridgewell/sourcemap-codec@^1.4.10":
|
||||
version "1.4.13"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c"
|
||||
integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==
|
||||
version "1.4.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
|
||||
integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
|
||||
|
||||
"@jridgewell/trace-mapping@^0.3.9":
|
||||
version "0.3.13"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea"
|
||||
integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==
|
||||
version "0.3.14"
|
||||
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
|
||||
integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==
|
||||
dependencies:
|
||||
"@jridgewell/resolve-uri" "^3.0.3"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
@@ -4960,11 +4973,6 @@ lodash.some@^4.4.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
|
||||
integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=
|
||||
|
||||
lodash.sortby@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
||||
|
||||
lodash.uniq@4.5.0, lodash.uniq@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
@@ -6815,13 +6823,6 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
source-map@~0.8.0-beta.0:
|
||||
version "0.8.0-beta.0"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11"
|
||||
integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==
|
||||
dependencies:
|
||||
whatwg-url "^7.0.0"
|
||||
|
||||
space-separated-tokens@^1.0.0:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899"
|
||||
@@ -7036,13 +7037,13 @@ terser-webpack-plugin@^5.1.3, terser-webpack-plugin@^5.3.1:
|
||||
terser "^5.7.2"
|
||||
|
||||
terser@^5.10.0, terser@^5.7.2:
|
||||
version "5.13.1"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.13.1.tgz#66332cdc5a01b04a224c9fad449fc1a18eaa1799"
|
||||
integrity sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==
|
||||
version "5.14.2"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
|
||||
integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
|
||||
dependencies:
|
||||
"@jridgewell/source-map" "^0.3.2"
|
||||
acorn "^8.5.0"
|
||||
commander "^2.20.0"
|
||||
source-map "~0.8.0-beta.0"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
text-table@^0.2.0:
|
||||
@@ -7092,13 +7093,6 @@ totalist@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
|
||||
integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
|
||||
|
||||
tr46@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
|
||||
integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
tr46@~0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
@@ -7437,11 +7431,6 @@ webidl-conversions@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
|
||||
|
||||
webidl-conversions@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||
integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
|
||||
|
||||
webpack-bundle-analyzer@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.5.0.tgz#1b0eea2947e73528754a6f9af3e91b2b6e0f79d5"
|
||||
@@ -7585,15 +7574,6 @@ whatwg-url@^5.0.0:
|
||||
tr46 "~0.0.3"
|
||||
webidl-conversions "^3.0.0"
|
||||
|
||||
whatwg-url@^7.0.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"
|
||||
integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==
|
||||
dependencies:
|
||||
lodash.sortby "^4.7.0"
|
||||
tr46 "^1.0.1"
|
||||
webidl-conversions "^4.0.2"
|
||||
|
||||
which@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
|
||||
|
||||
9
go.mod
@@ -8,10 +8,10 @@ require (
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/radovskyb/watcher v1.0.7
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.7.2
|
||||
github.com/stretchr/testify v1.8.0
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
mvdan.cc/sh/v3 v3.5.1
|
||||
mvdan.cc/sh/v3 v3.6.0-0.dev.0.20220704111049-a6e3029cd899
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -19,8 +19,9 @@ require (
|
||||
github.com/mattn/go-colorable v0.1.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
||||
)
|
||||
|
||||
go 1.17
|
||||
go 1.18
|
||||
|
||||
37
go.sum
@@ -1,30 +1,17 @@
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
|
||||
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
|
||||
github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
@@ -34,41 +21,35 @@ github.com/mattn/go-zglob v0.0.3 h1:6Ry4EYsScDyt5di4OI6xw1bYhOqfE5S33Z1OPy+d+To=
|
||||
github.com/mattn/go-zglob v0.0.3/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE=
|
||||
github.com/radovskyb/watcher v1.0.7/go.mod h1:78okwvY5wPdzcb1UYnip1pvrZNIVEIh/Cm+ZuvsUYIg=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
mvdan.cc/editorconfig v0.2.0/go.mod h1:lvnnD3BNdBYkhq+B4uBuFFKatfp02eB6HixDvEz91C0=
|
||||
mvdan.cc/sh/v3 v3.5.1 h1:hmP3UOw4f+EYexsJjFxvU38+kn+V/s2CclXHanIBkmQ=
|
||||
mvdan.cc/sh/v3 v3.5.1/go.mod h1:1JcoyAKm1lZw/2bZje/iYKWicU/KMd0rsyJeKHnsK4E=
|
||||
mvdan.cc/sh/v3 v3.6.0-0.dev.0.20220704111049-a6e3029cd899 h1:nwm4t5PtLlFd/H342GP50CtYf7vyMCOZkPx3g9shO0c=
|
||||
mvdan.cc/sh/v3 v3.6.0-0.dev.0.20220704111049-a6e3029cd899/go.mod h1:1JcoyAKm1lZw/2bZje/iYKWicU/KMd0rsyJeKHnsK4E=
|
||||
|
||||
@@ -2,6 +2,8 @@ package logger
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
@@ -9,13 +11,36 @@ import (
|
||||
type Color func() PrintFunc
|
||||
type PrintFunc func(io.Writer, string, ...interface{})
|
||||
|
||||
func Default() PrintFunc { return color.New(color.Reset).FprintfFunc() }
|
||||
func Blue() PrintFunc { return color.New(color.FgBlue).FprintfFunc() }
|
||||
func Green() PrintFunc { return color.New(color.FgGreen).FprintfFunc() }
|
||||
func Cyan() PrintFunc { return color.New(color.FgCyan).FprintfFunc() }
|
||||
func Yellow() PrintFunc { return color.New(color.FgYellow).FprintfFunc() }
|
||||
func Magenta() PrintFunc { return color.New(color.FgMagenta).FprintfFunc() }
|
||||
func Red() PrintFunc { return color.New(color.FgRed).FprintfFunc() }
|
||||
func Default() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_RESET", color.Reset)).FprintfFunc()
|
||||
}
|
||||
func Blue() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_BLUE", color.FgBlue)).FprintfFunc()
|
||||
}
|
||||
func Green() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_GREEN", color.FgGreen)).FprintfFunc()
|
||||
}
|
||||
func Cyan() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_CYAN", color.FgCyan)).FprintfFunc()
|
||||
}
|
||||
func Yellow() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_YELLOW", color.FgYellow)).FprintfFunc()
|
||||
}
|
||||
func Magenta() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_MAGENTA", color.FgMagenta)).FprintfFunc()
|
||||
}
|
||||
func Red() PrintFunc {
|
||||
return color.New(envColor("TASK_COLOR_RED", color.FgRed)).FprintfFunc()
|
||||
}
|
||||
|
||||
func envColor(env string, defaultColor color.Attribute) color.Attribute {
|
||||
override, err := strconv.Atoi(os.Getenv(env))
|
||||
if err == nil {
|
||||
return color.Attribute(override)
|
||||
|
||||
}
|
||||
return defaultColor
|
||||
}
|
||||
|
||||
// Logger is just a wrapper that prints stuff to STDOUT or STDERR,
|
||||
// with optional color.
|
||||
|
||||
@@ -5,24 +5,24 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type Group struct{
|
||||
type Group struct {
|
||||
Begin, End string
|
||||
}
|
||||
|
||||
func (g Group) WrapWriter(w io.Writer, _ string, tmpl Templater) io.Writer {
|
||||
gw := &groupWriter{writer: w}
|
||||
func (g Group) WrapWriter(stdOut, _ io.Writer, _ string, tmpl Templater) (io.Writer, io.Writer, CloseFunc) {
|
||||
gw := &groupWriter{writer: stdOut}
|
||||
if g.Begin != "" {
|
||||
gw.begin = tmpl.Replace(g.Begin) + "\n"
|
||||
}
|
||||
if g.End != "" {
|
||||
gw.end = tmpl.Replace(g.End) + "\n"
|
||||
}
|
||||
return gw
|
||||
return gw, gw, func() error { return gw.close() }
|
||||
}
|
||||
|
||||
type groupWriter struct {
|
||||
writer io.Writer
|
||||
buff bytes.Buffer
|
||||
writer io.Writer
|
||||
buff bytes.Buffer
|
||||
begin, end string
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func (gw *groupWriter) Write(p []byte) (int, error) {
|
||||
return gw.buff.Write(p)
|
||||
}
|
||||
|
||||
func (gw *groupWriter) Close() error {
|
||||
func (gw *groupWriter) close() error {
|
||||
if gw.buff.Len() == 0 {
|
||||
// don't print begin/end messages if there's no buffered entries
|
||||
return nil
|
||||
|
||||
@@ -6,6 +6,6 @@ import (
|
||||
|
||||
type Interleaved struct{}
|
||||
|
||||
func (Interleaved) WrapWriter(w io.Writer, _ string, _ Templater) io.Writer {
|
||||
return w
|
||||
func (Interleaved) WrapWriter(stdOut, stdErr io.Writer, _ string, _ Templater) (io.Writer, io.Writer, CloseFunc) {
|
||||
return stdOut, stdErr, func() error { return nil }
|
||||
}
|
||||
|
||||
@@ -15,9 +15,11 @@ type Templater interface {
|
||||
}
|
||||
|
||||
type Output interface {
|
||||
WrapWriter(w io.Writer, prefix string, tmpl Templater) io.Writer
|
||||
WrapWriter(stdOut, stdErr io.Writer, prefix string, tmpl Templater) (io.Writer, io.Writer, CloseFunc)
|
||||
}
|
||||
|
||||
type CloseFunc func() error
|
||||
|
||||
// Build the Output for the requested taskfile.Output.
|
||||
func BuildFor(o *taskfile.Output) (Output, error) {
|
||||
switch o.Name {
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
func TestInterleaved(t *testing.T) {
|
||||
var b bytes.Buffer
|
||||
var o output.Output = output.Interleaved{}
|
||||
var w = o.WrapWriter(&b, "", nil)
|
||||
var w, _, _ = o.WrapWriter(&b, io.Discard, "", nil)
|
||||
|
||||
fmt.Fprintln(w, "foo\nbar")
|
||||
assert.Equal(t, "foo\nbar\n", b.String())
|
||||
@@ -27,14 +27,19 @@ func TestInterleaved(t *testing.T) {
|
||||
func TestGroup(t *testing.T) {
|
||||
var b bytes.Buffer
|
||||
var o output.Output = output.Group{}
|
||||
var w = o.WrapWriter(&b, "", nil).(io.WriteCloser)
|
||||
var stdOut, stdErr, cleanup = o.WrapWriter(&b, io.Discard, "", nil)
|
||||
|
||||
fmt.Fprintln(w, "foo\nbar")
|
||||
fmt.Fprintln(stdOut, "out\nout")
|
||||
assert.Equal(t, "", b.String())
|
||||
fmt.Fprintln(w, "baz")
|
||||
fmt.Fprintln(stdErr, "err\nerr")
|
||||
assert.Equal(t, "", b.String())
|
||||
assert.NoError(t, w.Close())
|
||||
assert.Equal(t, "foo\nbar\nbaz\n", b.String())
|
||||
fmt.Fprintln(stdOut, "out")
|
||||
assert.Equal(t, "", b.String())
|
||||
fmt.Fprintln(stdErr, "err")
|
||||
assert.Equal(t, "", b.String())
|
||||
|
||||
assert.NoError(t, cleanup())
|
||||
assert.Equal(t, "out\nout\nerr\nerr\nout\nerr\n", b.String())
|
||||
}
|
||||
|
||||
func TestGroupWithBeginEnd(t *testing.T) {
|
||||
@@ -53,19 +58,19 @@ func TestGroupWithBeginEnd(t *testing.T) {
|
||||
}
|
||||
t.Run("simple", func(t *testing.T) {
|
||||
var b bytes.Buffer
|
||||
var w = o.WrapWriter(&b, "", &tmpl).(io.WriteCloser)
|
||||
var w, _, cleanup = o.WrapWriter(&b, io.Discard, "", &tmpl)
|
||||
|
||||
fmt.Fprintln(w, "foo\nbar")
|
||||
assert.Equal(t, "", b.String())
|
||||
fmt.Fprintln(w, "baz")
|
||||
assert.Equal(t, "", b.String())
|
||||
assert.NoError(t, w.Close())
|
||||
assert.NoError(t, cleanup())
|
||||
assert.Equal(t, "::group::example-value\nfoo\nbar\nbaz\n::endgroup::\n", b.String())
|
||||
})
|
||||
t.Run("no output", func(t *testing.T) {
|
||||
var b bytes.Buffer
|
||||
var w = o.WrapWriter(&b, "", &tmpl).(io.WriteCloser)
|
||||
assert.NoError(t, w.Close())
|
||||
var _, _, cleanup = o.WrapWriter(&b, io.Discard, "", &tmpl)
|
||||
assert.NoError(t, cleanup())
|
||||
assert.Equal(t, "", b.String())
|
||||
})
|
||||
}
|
||||
@@ -73,7 +78,7 @@ func TestGroupWithBeginEnd(t *testing.T) {
|
||||
func TestPrefixed(t *testing.T) {
|
||||
var b bytes.Buffer
|
||||
var o output.Output = output.Prefixed{}
|
||||
var w = o.WrapWriter(&b, "prefix", nil).(io.WriteCloser)
|
||||
var w, _, cleanup = o.WrapWriter(&b, io.Discard, "prefix", nil)
|
||||
|
||||
t.Run("simple use cases", func(t *testing.T) {
|
||||
b.Reset()
|
||||
@@ -82,6 +87,7 @@ func TestPrefixed(t *testing.T) {
|
||||
assert.Equal(t, "[prefix] foo\n[prefix] bar\n", b.String())
|
||||
fmt.Fprintln(w, "baz")
|
||||
assert.Equal(t, "[prefix] foo\n[prefix] bar\n[prefix] baz\n", b.String())
|
||||
assert.NoError(t, cleanup())
|
||||
})
|
||||
|
||||
t.Run("multiple writes for a single line", func(t *testing.T) {
|
||||
@@ -92,7 +98,7 @@ func TestPrefixed(t *testing.T) {
|
||||
assert.Equal(t, "", b.String())
|
||||
}
|
||||
|
||||
assert.NoError(t, w.Close())
|
||||
assert.NoError(t, cleanup())
|
||||
assert.Equal(t, "[prefix] Test!\n", b.String())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -9,8 +9,9 @@ import (
|
||||
|
||||
type Prefixed struct{}
|
||||
|
||||
func (Prefixed) WrapWriter(w io.Writer, prefix string, _ Templater) io.Writer {
|
||||
return &prefixWriter{writer: w, prefix: prefix}
|
||||
func (Prefixed) WrapWriter(stdOut, _ io.Writer, prefix string, _ Templater) (io.Writer, io.Writer, CloseFunc) {
|
||||
pw := &prefixWriter{writer: stdOut, prefix: prefix}
|
||||
return pw, pw, func() error { return pw.close() }
|
||||
}
|
||||
|
||||
type prefixWriter struct {
|
||||
@@ -28,7 +29,7 @@ func (pw *prefixWriter) Write(p []byte) (int, error) {
|
||||
return n, pw.writeOutputLines(false)
|
||||
}
|
||||
|
||||
func (pw *prefixWriter) Close() error {
|
||||
func (pw *prefixWriter) close() error {
|
||||
return pw.writeOutputLines(true)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
// Checksum validades if a task is up to date by calculating its source
|
||||
// files checksum
|
||||
type Checksum struct {
|
||||
BaseDir string
|
||||
TempDir string
|
||||
TaskDir string
|
||||
Task string
|
||||
Sources []string
|
||||
@@ -43,7 +43,7 @@ func (c *Checksum) IsUpToDate() (bool, error) {
|
||||
}
|
||||
|
||||
if !c.Dry {
|
||||
_ = os.MkdirAll(filepath.Join(c.BaseDir, ".task", "checksum"), 0755)
|
||||
_ = os.MkdirAll(filepath.Join(c.TempDir, "checksum"), 0755)
|
||||
if err = os.WriteFile(checksumFile, []byte(newMd5+"\n"), 0644); err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -107,7 +107,7 @@ func (*Checksum) Kind() string {
|
||||
}
|
||||
|
||||
func (c *Checksum) checksumFilePath() string {
|
||||
return filepath.Join(c.BaseDir, ".task", "checksum", c.normalizeFilename(c.Task))
|
||||
return filepath.Join(c.TempDir, "checksum", c.normalizeFilename(c.Task))
|
||||
}
|
||||
|
||||
var checksumFilenameRegexp = regexp.MustCompile("[^A-z0-9]")
|
||||
|
||||
277
setup.go
Normal file
@@ -0,0 +1,277 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
compilerv2 "github.com/go-task/task/v3/internal/compiler/v2"
|
||||
compilerv3 "github.com/go-task/task/v3/internal/compiler/v3"
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/output"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile/read"
|
||||
)
|
||||
|
||||
func (e *Executor) Setup() error {
|
||||
if err := e.readTaskfile(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v, err := e.Taskfile.ParsedVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.setupTempDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
e.setupStdFiles()
|
||||
e.setupLogger()
|
||||
if err := e.setupOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.setupCompiler(v); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := e.readDotEnvFiles(v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := e.doVersionChecks(v); err != nil {
|
||||
return err
|
||||
}
|
||||
e.setupDefaults(v)
|
||||
e.setupConcurrencyState()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Executor) readTaskfile() error {
|
||||
var err error
|
||||
e.Taskfile, err = read.Taskfile(&read.ReaderNode{
|
||||
Dir: e.Dir,
|
||||
Entrypoint: e.Entrypoint,
|
||||
Parent: nil,
|
||||
Optional: false,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Executor) setupTempDir() error {
|
||||
if e.TempDir != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if os.Getenv("TASK_TEMP_DIR") == "" {
|
||||
e.TempDir = filepath.Join(e.Dir, ".task")
|
||||
} else if filepath.IsAbs(os.Getenv("TASK_TEMP_DIR")) || strings.HasPrefix(os.Getenv("TASK_TEMP_DIR"), "~") {
|
||||
tempDir, err := execext.Expand(os.Getenv("TASK_TEMP_DIR"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projectDir, _ := filepath.Abs(e.Dir)
|
||||
projectName := filepath.Base(projectDir)
|
||||
e.TempDir = filepath.Join(tempDir, projectName)
|
||||
} else {
|
||||
e.TempDir = filepath.Join(e.Dir, os.Getenv("TASK_TEMP_DIR"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Executor) setupStdFiles() {
|
||||
if e.Stdin == nil {
|
||||
e.Stdin = os.Stdin
|
||||
}
|
||||
if e.Stdout == nil {
|
||||
e.Stdout = os.Stdout
|
||||
}
|
||||
if e.Stderr == nil {
|
||||
e.Stderr = os.Stderr
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Executor) setupLogger() {
|
||||
e.Logger = &logger.Logger{
|
||||
Stdout: e.Stdout,
|
||||
Stderr: e.Stderr,
|
||||
Verbose: e.Verbose,
|
||||
Color: e.Color,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Executor) setupOutput() error {
|
||||
if !e.OutputStyle.IsSet() {
|
||||
e.OutputStyle = e.Taskfile.Output
|
||||
}
|
||||
|
||||
var err error
|
||||
e.Output, err = output.BuildFor(&e.OutputStyle)
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Executor) setupCompiler(v float64) error {
|
||||
if v < 3 {
|
||||
var err error
|
||||
e.taskvars, err = read.Taskvars(e.Dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.Compiler = &compilerv2.CompilerV2{
|
||||
Dir: e.Dir,
|
||||
Taskvars: e.taskvars,
|
||||
TaskfileVars: e.Taskfile.Vars,
|
||||
Expansions: e.Taskfile.Expansions,
|
||||
Logger: e.Logger,
|
||||
}
|
||||
} else {
|
||||
e.Compiler = &compilerv3.CompilerV3{
|
||||
Dir: e.Dir,
|
||||
TaskfileEnv: e.Taskfile.Env,
|
||||
TaskfileVars: e.Taskfile.Vars,
|
||||
Logger: e.Logger,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Executor) readDotEnvFiles(v float64) error {
|
||||
if v < 3.0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
env, err := read.Dotenv(e.Compiler, e.Taskfile, e.Dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = env.Range(func(key string, value taskfile.Var) error {
|
||||
if _, ok := e.Taskfile.Env.Mapping[key]; !ok {
|
||||
e.Taskfile.Env.Set(key, value)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Executor) setupDefaults(v float64) {
|
||||
// Color available only on v3
|
||||
if v < 3 {
|
||||
e.Logger.Color = false
|
||||
}
|
||||
|
||||
if e.Taskfile.Method == "" {
|
||||
if v >= 3 {
|
||||
e.Taskfile.Method = "checksum"
|
||||
} else {
|
||||
e.Taskfile.Method = "timestamp"
|
||||
}
|
||||
}
|
||||
|
||||
if e.Taskfile.Run == "" {
|
||||
e.Taskfile.Run = "always"
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Executor) setupConcurrencyState() {
|
||||
e.executionHashes = make(map[string]context.Context)
|
||||
|
||||
e.taskCallCount = make(map[string]*int32, len(e.Taskfile.Tasks))
|
||||
e.mkdirMutexMap = make(map[string]*sync.Mutex, len(e.Taskfile.Tasks))
|
||||
for k := range e.Taskfile.Tasks {
|
||||
e.taskCallCount[k] = new(int32)
|
||||
e.mkdirMutexMap[k] = &sync.Mutex{}
|
||||
}
|
||||
|
||||
if e.Concurrency > 0 {
|
||||
e.concurrencySemaphore = make(chan struct{}, e.Concurrency)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Executor) doVersionChecks(v float64) error {
|
||||
if v < 2 {
|
||||
return fmt.Errorf(`task: Taskfile versions prior to v2 are not supported anymore`)
|
||||
}
|
||||
|
||||
// consider as equal to the greater version if round
|
||||
if v == 2.0 {
|
||||
v = 2.6
|
||||
}
|
||||
if v == 3.0 {
|
||||
v = 3.8
|
||||
}
|
||||
|
||||
if v > 3.8 {
|
||||
return fmt.Errorf(`task: Taskfile versions greater than v3.8 not implemented in the version of Task`)
|
||||
}
|
||||
|
||||
if v < 2.1 && !e.Taskfile.Output.IsSet() {
|
||||
return fmt.Errorf(`task: Taskfile option "output" is only available starting on Taskfile version v2.1`)
|
||||
}
|
||||
if v < 2.2 && e.Taskfile.Includes.Len() > 0 {
|
||||
return fmt.Errorf(`task: Including Taskfiles is only available starting on Taskfile version v2.2`)
|
||||
}
|
||||
if v >= 3.0 && e.Taskfile.Expansions > 2 {
|
||||
return fmt.Errorf(`task: The "expansions" setting is not available anymore on v3.0`)
|
||||
}
|
||||
if v < 3.8 && e.Taskfile.Output.Group.IsSet() {
|
||||
return fmt.Errorf(`task: Taskfile option "output.group" is only available starting on Taskfile version v3.8`)
|
||||
}
|
||||
|
||||
if v <= 2.1 {
|
||||
err := errors.New(`task: Taskfile option "ignore_error" is only available starting on Taskfile version v2.1`)
|
||||
|
||||
for _, task := range e.Taskfile.Tasks {
|
||||
if task.IgnoreError {
|
||||
return err
|
||||
}
|
||||
for _, cmd := range task.Cmds {
|
||||
if cmd.IgnoreError {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v < 2.6 {
|
||||
for _, task := range e.Taskfile.Tasks {
|
||||
if len(task.Preconditions) > 0 {
|
||||
return errors.New(`task: Task option "preconditions" is only available starting on Taskfile version v2.6`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v < 3 {
|
||||
err := e.Taskfile.Includes.Range(func(_ string, taskfile taskfile.IncludedTaskfile) error {
|
||||
if taskfile.AdvancedImport {
|
||||
return errors.New(`task: Import with additional parameters is only available starting on Taskfile version v3`)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if v < 3.7 {
|
||||
if e.Taskfile.Run != "" {
|
||||
return errors.New(`task: Setting the "run" type is only available starting on Taskfile version v3.7`)
|
||||
}
|
||||
|
||||
for _, task := range e.Taskfile.Tasks {
|
||||
if task.Run != "" {
|
||||
return errors.New(`task: Setting the "run" type is only available starting on Taskfile version v3.7`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
//go:build signals
|
||||
// +build signals
|
||||
|
||||
// This file contains tests for signal handling on Unix.
|
||||
// Based on code from https://github.com/marco-m/timeit
|
||||
@@ -95,7 +95,7 @@ func (e *Executor) timestampChecker(t *taskfile.Task) status.Checker {
|
||||
|
||||
func (e *Executor) checksumChecker(t *taskfile.Task) status.Checker {
|
||||
return &status.Checksum{
|
||||
BaseDir: e.Dir,
|
||||
TempDir: e.TempDir,
|
||||
TaskDir: t.Dir,
|
||||
Task: t.Name(),
|
||||
Sources: t.Sources,
|
||||
|
||||
217
task.go
@@ -2,7 +2,6 @@ package task
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -10,15 +9,12 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/go-task/task/v3/internal/compiler"
|
||||
compilerv2 "github.com/go-task/task/v3/internal/compiler/v2"
|
||||
compilerv3 "github.com/go-task/task/v3/internal/compiler/v3"
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/internal/output"
|
||||
"github.com/go-task/task/v3/internal/summary"
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
"github.com/go-task/task/v3/taskfile/read"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
@@ -34,6 +30,7 @@ type Executor struct {
|
||||
Taskfile *taskfile.Taskfile
|
||||
|
||||
Dir string
|
||||
TempDir string
|
||||
Entrypoint string
|
||||
Force bool
|
||||
Watch bool
|
||||
@@ -104,203 +101,6 @@ func (e *Executor) Run(ctx context.Context, calls ...taskfile.Call) error {
|
||||
return g.Wait()
|
||||
}
|
||||
|
||||
// readTaskfile selects and parses the entrypoint.
|
||||
func (e *Executor) readTaskfile() error {
|
||||
var err error
|
||||
e.Taskfile, err = read.Taskfile(&read.ReaderNode{
|
||||
Dir: e.Dir,
|
||||
Entrypoint: e.Entrypoint,
|
||||
Parent: nil,
|
||||
Optional: false,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// Setup setups Executor's internal state
|
||||
func (e *Executor) Setup() error {
|
||||
err := e.readTaskfile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v, err := e.Taskfile.ParsedVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v < 3.0 {
|
||||
e.taskvars, err = read.Taskvars(e.Dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if e.Stdin == nil {
|
||||
e.Stdin = os.Stdin
|
||||
}
|
||||
if e.Stdout == nil {
|
||||
e.Stdout = os.Stdout
|
||||
}
|
||||
if e.Stderr == nil {
|
||||
e.Stderr = os.Stderr
|
||||
}
|
||||
e.Logger = &logger.Logger{
|
||||
Stdout: e.Stdout,
|
||||
Stderr: e.Stderr,
|
||||
Verbose: e.Verbose,
|
||||
Color: e.Color,
|
||||
}
|
||||
|
||||
if v < 2 {
|
||||
return fmt.Errorf(`task: Taskfile versions prior to v2 are not supported anymore`)
|
||||
}
|
||||
|
||||
// consider as equal to the greater version if round
|
||||
if v == 2.0 {
|
||||
v = 2.6
|
||||
}
|
||||
if v == 3.0 {
|
||||
v = 3.8
|
||||
}
|
||||
|
||||
if v > 3.8 {
|
||||
return fmt.Errorf(`task: Taskfile versions greater than v3.8 not implemented in the version of Task`)
|
||||
}
|
||||
|
||||
// Color available only on v3
|
||||
if v < 3 {
|
||||
e.Logger.Color = false
|
||||
}
|
||||
|
||||
if v < 3 {
|
||||
e.Compiler = &compilerv2.CompilerV2{
|
||||
Dir: e.Dir,
|
||||
Taskvars: e.taskvars,
|
||||
TaskfileVars: e.Taskfile.Vars,
|
||||
Expansions: e.Taskfile.Expansions,
|
||||
Logger: e.Logger,
|
||||
}
|
||||
} else {
|
||||
e.Compiler = &compilerv3.CompilerV3{
|
||||
Dir: e.Dir,
|
||||
TaskfileEnv: e.Taskfile.Env,
|
||||
TaskfileVars: e.Taskfile.Vars,
|
||||
Logger: e.Logger,
|
||||
}
|
||||
}
|
||||
|
||||
if v >= 3.0 {
|
||||
env, err := read.Dotenv(e.Compiler, e.Taskfile, e.Dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = env.Range(func(key string, value taskfile.Var) error {
|
||||
if _, ok := e.Taskfile.Env.Mapping[key]; !ok {
|
||||
e.Taskfile.Env.Set(key, value)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if v < 2.1 && !e.Taskfile.Output.IsSet() {
|
||||
return fmt.Errorf(`task: Taskfile option "output" is only available starting on Taskfile version v2.1`)
|
||||
}
|
||||
if v < 2.2 && e.Taskfile.Includes.Len() > 0 {
|
||||
return fmt.Errorf(`task: Including Taskfiles is only available starting on Taskfile version v2.2`)
|
||||
}
|
||||
if v >= 3.0 && e.Taskfile.Expansions > 2 {
|
||||
return fmt.Errorf(`task: The "expansions" setting is not available anymore on v3.0`)
|
||||
}
|
||||
if v < 3.8 && e.Taskfile.Output.Group.IsSet() {
|
||||
return fmt.Errorf(`task: Taskfile option "output.group" is only available starting on Taskfile version v3.8`)
|
||||
}
|
||||
|
||||
if !e.OutputStyle.IsSet() {
|
||||
e.OutputStyle = e.Taskfile.Output
|
||||
}
|
||||
e.Output, err = output.BuildFor(&e.OutputStyle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if e.Taskfile.Method == "" {
|
||||
if v >= 3 {
|
||||
e.Taskfile.Method = "checksum"
|
||||
} else {
|
||||
e.Taskfile.Method = "timestamp"
|
||||
}
|
||||
}
|
||||
|
||||
if v <= 2.1 {
|
||||
err := errors.New(`task: Taskfile option "ignore_error" is only available starting on Taskfile version v2.1`)
|
||||
|
||||
for _, task := range e.Taskfile.Tasks {
|
||||
if task.IgnoreError {
|
||||
return err
|
||||
}
|
||||
for _, cmd := range task.Cmds {
|
||||
if cmd.IgnoreError {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v < 2.6 {
|
||||
for _, task := range e.Taskfile.Tasks {
|
||||
if len(task.Preconditions) > 0 {
|
||||
return errors.New(`task: Task option "preconditions" is only available starting on Taskfile version v2.6`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v < 3 {
|
||||
err := e.Taskfile.Includes.Range(func(_ string, taskfile taskfile.IncludedTaskfile) error {
|
||||
if taskfile.AdvancedImport {
|
||||
return errors.New(`task: Import with additional parameters is only available starting on Taskfile version v3`)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if v < 3.7 {
|
||||
if e.Taskfile.Run != "" {
|
||||
return errors.New(`task: Setting the "run" type is only available starting on Taskfile version v3.7`)
|
||||
}
|
||||
|
||||
for _, task := range e.Taskfile.Tasks {
|
||||
if task.Run != "" {
|
||||
return errors.New(`task: Setting the "run" type is only available starting on Taskfile version v3.7`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if e.Taskfile.Run == "" {
|
||||
e.Taskfile.Run = "always"
|
||||
}
|
||||
|
||||
e.executionHashes = make(map[string]context.Context)
|
||||
|
||||
e.taskCallCount = make(map[string]*int32, len(e.Taskfile.Tasks))
|
||||
e.mkdirMutexMap = make(map[string]*sync.Mutex, len(e.Taskfile.Tasks))
|
||||
for k := range e.Taskfile.Tasks {
|
||||
e.taskCallCount[k] = new(int32)
|
||||
e.mkdirMutexMap[k] = &sync.Mutex{}
|
||||
}
|
||||
|
||||
if e.Concurrency > 0 {
|
||||
e.concurrencySemaphore = make(chan struct{}, e.Concurrency)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunTask runs a task by its name
|
||||
func (e *Executor) RunTask(ctx context.Context, call taskfile.Call) error {
|
||||
t, err := e.CompiledTask(call)
|
||||
@@ -449,19 +249,10 @@ func (e *Executor) runCommand(ctx context.Context, t *taskfile.Task, call taskfi
|
||||
if err != nil {
|
||||
return fmt.Errorf("task: failed to get variables: %w", err)
|
||||
}
|
||||
stdOut := outputWrapper.WrapWriter(e.Stdout, t.Prefix, outputTemplater)
|
||||
stdErr := outputWrapper.WrapWriter(e.Stderr, t.Prefix, outputTemplater)
|
||||
|
||||
stdOut, stdErr, close := outputWrapper.WrapWriter(e.Stdout, e.Stderr, t.Prefix, outputTemplater)
|
||||
defer func() {
|
||||
if _, ok := stdOut.(*os.File); !ok {
|
||||
if closer, ok := stdOut.(io.Closer); ok {
|
||||
closer.Close()
|
||||
}
|
||||
}
|
||||
if _, ok := stdErr.(*os.File); !ok {
|
||||
if closer, ok := stdErr.(io.Closer); ok {
|
||||
closer.Close()
|
||||
}
|
||||
if err := close(); err != nil {
|
||||
e.Logger.Errf(logger.Red, "task: unable to close writter: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
79
task_test.go
@@ -42,6 +42,7 @@ func (fct fileContentTest) Run(t *testing.T) {
|
||||
|
||||
e := &task.Executor{
|
||||
Dir: fct.Dir,
|
||||
TempDir: filepath.Join(fct.Dir, ".task"),
|
||||
Entrypoint: fct.Entrypoint,
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
@@ -51,13 +52,14 @@ func (fct fileContentTest) Run(t *testing.T) {
|
||||
|
||||
for name, expectContent := range fct.Files {
|
||||
t.Run(fct.name(name), func(t *testing.T) {
|
||||
b, err := os.ReadFile(filepath.Join(fct.Dir, name))
|
||||
path := filepath.Join(fct.Dir, name)
|
||||
b, err := os.ReadFile(path)
|
||||
assert.NoError(t, err, "Error reading file")
|
||||
s := string(b)
|
||||
if fct.TrimSpace {
|
||||
s = strings.TrimSpace(s)
|
||||
}
|
||||
assert.Equal(t, expectContent, s, "unexpected file content")
|
||||
assert.Equal(t, expectContent, s, "unexpected file content in %s", path)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -270,10 +272,11 @@ func TestStatus(t *testing.T) {
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := &task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: true,
|
||||
Dir: dir,
|
||||
TempDir: filepath.Join(dir, ".task"),
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: true,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "gen-foo"}))
|
||||
@@ -421,9 +424,10 @@ func TestStatusChecksum(t *testing.T) {
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Dir: dir,
|
||||
TempDir: filepath.Join(dir, ".task"),
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
|
||||
@@ -579,6 +583,7 @@ func TestStatusVariables(t *testing.T) {
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
TempDir: filepath.Join(dir, ".task"),
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Silent: false,
|
||||
@@ -718,10 +723,11 @@ func TestDryChecksum(t *testing.T) {
|
||||
_ = os.Remove(checksumFile)
|
||||
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
Dry: true,
|
||||
Dir: dir,
|
||||
TempDir: filepath.Join(dir, ".task"),
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
Dry: true,
|
||||
}
|
||||
assert.NoError(t, e.Setup())
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "default"}))
|
||||
@@ -769,7 +775,12 @@ func TestIncludesMultiLevel(t *testing.T) {
|
||||
|
||||
func TestIncludeCycle(t *testing.T) {
|
||||
const dir = "testdata/includes_cycle"
|
||||
expectedError := "task: include cycle detected between testdata/includes_cycle/Taskfile.yml <--> testdata/includes_cycle/one/two/Taskfile.yml"
|
||||
|
||||
wd, err := os.Getwd()
|
||||
assert.Nil(t, err)
|
||||
|
||||
message := "task: include cycle detected between %s/%s/one/Taskfile.yml <--> %s/%s/Taskfile.yml"
|
||||
expectedError := fmt.Sprintf(message, wd, dir, wd, dir)
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
@@ -847,27 +858,39 @@ func TestIncludesOptional(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestIncludesOptionalImplicitFalse(t *testing.T) {
|
||||
const dir = "testdata/includes_optional_implicit_false"
|
||||
wd, _ := os.Getwd()
|
||||
|
||||
message := "stat %s/%s/TaskfileOptional.yml: no such file or directory"
|
||||
expected := fmt.Sprintf(message, wd, dir)
|
||||
|
||||
e := task.Executor{
|
||||
Dir: "testdata/includes_optional_implicit_false",
|
||||
Dir: dir,
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
}
|
||||
|
||||
err := e.Setup()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "stat testdata/includes_optional_implicit_false/TaskfileOptional.yml: no such file or directory", err.Error())
|
||||
assert.Equal(t, expected, err.Error())
|
||||
}
|
||||
|
||||
func TestIncludesOptionalExplicitFalse(t *testing.T) {
|
||||
const dir = "testdata/includes_optional_explicit_false"
|
||||
wd, _ := os.Getwd()
|
||||
|
||||
message := "stat %s/%s/TaskfileOptional.yml: no such file or directory"
|
||||
expected := fmt.Sprintf(message, wd, dir)
|
||||
|
||||
e := task.Executor{
|
||||
Dir: "testdata/includes_optional_explicit_false",
|
||||
Dir: dir,
|
||||
Stdout: io.Discard,
|
||||
Stderr: io.Discard,
|
||||
}
|
||||
|
||||
err := e.Setup()
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "stat testdata/includes_optional_explicit_false/TaskfileOptional.yml: no such file or directory", err.Error())
|
||||
assert.Equal(t, expected, err.Error())
|
||||
}
|
||||
|
||||
func TestIncludesFromCustomTaskfile(t *testing.T) {
|
||||
@@ -885,6 +908,26 @@ func TestIncludesFromCustomTaskfile(t *testing.T) {
|
||||
tt.Run(t)
|
||||
}
|
||||
|
||||
func TestIncludesRelativePath(t *testing.T) {
|
||||
const dir = "testdata/includes_rel_path"
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
|
||||
assert.NoError(t, e.Setup())
|
||||
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "common:pwd"}))
|
||||
assert.Contains(t, buff.String(), "testdata/includes_rel_path/common")
|
||||
|
||||
buff.Reset()
|
||||
assert.NoError(t, e.Run(context.Background(), taskfile.Call{Task: "included:common:pwd"}))
|
||||
assert.Contains(t, buff.String(), "testdata/includes_rel_path/common")
|
||||
}
|
||||
|
||||
func TestSupportedFileNames(t *testing.T) {
|
||||
fileNames := []string{
|
||||
"Taskfile.yml",
|
||||
|
||||
@@ -2,17 +2,22 @@ package taskfile
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// IncludedTaskfile represents information about included tasksfile
|
||||
// IncludedTaskfile represents information about included taskfiles
|
||||
type IncludedTaskfile struct {
|
||||
Taskfile string
|
||||
Dir string
|
||||
Optional bool
|
||||
AdvancedImport bool
|
||||
Vars *Vars
|
||||
BaseDir string // The directory from which the including taskfile was loaded; used to resolve relative paths
|
||||
}
|
||||
|
||||
// IncludedTaskfiles represents information about included tasksfiles
|
||||
@@ -107,3 +112,31 @@ func (it *IncludedTaskfile) UnmarshalYAML(unmarshal func(interface{}) error) err
|
||||
it.Vars = includedTaskfile.Vars
|
||||
return nil
|
||||
}
|
||||
|
||||
// FullTaskfilePath returns the fully qualified path to the included taskfile
|
||||
func (it *IncludedTaskfile) FullTaskfilePath() (string, error) {
|
||||
return it.resolvePath(it.Taskfile)
|
||||
}
|
||||
|
||||
// FullDirPath returns the fully qualified path to the included taskfile's working directory
|
||||
func (it *IncludedTaskfile) FullDirPath() (string, error) {
|
||||
return it.resolvePath(it.Dir)
|
||||
}
|
||||
|
||||
func (it *IncludedTaskfile) resolvePath(path string) (string, error) {
|
||||
path, err := execext.Expand(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if filepath.IsAbs(path) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
result, err := filepath.Abs(filepath.Join(it.BaseDir, path))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("task: error resolving path %s relative to %s: %w", path, it.BaseDir, err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/templater"
|
||||
"github.com/go-task/task/v3/taskfile"
|
||||
)
|
||||
@@ -44,6 +43,7 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
||||
}
|
||||
readerNode.Dir = d
|
||||
}
|
||||
|
||||
path, err := exists(filepath.Join(readerNode.Dir, readerNode.Entrypoint))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -60,6 +60,16 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Annotate any included Taskfile reference with a base directory for resolving relative paths
|
||||
_ = t.Includes.Range(func(key string, includedFile taskfile.IncludedTaskfile) error {
|
||||
// Set the base directory for resolving relative paths, but only if not already set
|
||||
if includedFile.BaseDir == "" {
|
||||
includedFile.BaseDir = readerNode.Dir
|
||||
t.Includes.Set(key, includedFile)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
err = t.Includes.Range(func(namespace string, includedTask taskfile.IncludedTaskfile) error {
|
||||
if v >= 3.0 {
|
||||
tr := templater.Templater{Vars: &taskfile.Vars{}, RemoveNoValue: true}
|
||||
@@ -69,19 +79,18 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
||||
Optional: includedTask.Optional,
|
||||
AdvancedImport: includedTask.AdvancedImport,
|
||||
Vars: includedTask.Vars,
|
||||
BaseDir: includedTask.BaseDir,
|
||||
}
|
||||
if err := tr.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
path, err := execext.Expand(includedTask.Taskfile)
|
||||
path, err := includedTask.FullTaskfilePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !filepath.IsAbs(path) {
|
||||
path = filepath.Join(readerNode.Dir, path)
|
||||
}
|
||||
|
||||
path, err = exists(path)
|
||||
if err != nil {
|
||||
if includedTask.Optional {
|
||||
@@ -114,21 +123,27 @@ func Taskfile(readerNode *ReaderNode) (*taskfile.Taskfile, error) {
|
||||
}
|
||||
|
||||
if includedTask.AdvancedImport {
|
||||
dir, err := includedTask.FullDirPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for k, v := range includedTaskfile.Vars.Mapping {
|
||||
o := v
|
||||
o.Dir = filepath.Join(readerNode.Dir, includedTask.Dir)
|
||||
o.Dir = dir
|
||||
includedTaskfile.Vars.Mapping[k] = o
|
||||
}
|
||||
for k, v := range includedTaskfile.Env.Mapping {
|
||||
o := v
|
||||
o.Dir = filepath.Join(readerNode.Dir, includedTask.Dir)
|
||||
o.Dir = dir
|
||||
includedTaskfile.Env.Mapping[k] = o
|
||||
}
|
||||
|
||||
for _, task := range includedTaskfile.Tasks {
|
||||
if !filepath.IsAbs(task.Dir) {
|
||||
task.Dir = filepath.Join(includedTask.Dir, task.Dir)
|
||||
task.Dir = filepath.Join(dir, task.Dir)
|
||||
}
|
||||
|
||||
task.IncludeVars = includedTask.Vars
|
||||
task.IncludedTaskfileVars = includedTaskfile.Vars
|
||||
}
|
||||
@@ -176,19 +191,29 @@ func readTaskfile(file string) (*taskfile.Taskfile, error) {
|
||||
return &t, yaml.NewDecoder(f).Decode(&t)
|
||||
}
|
||||
|
||||
// exists finds a Taskfile at the stated location, returning a fully qualified path to the file
|
||||
func exists(path string) (string, error) {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if fi.Mode().IsRegular() {
|
||||
return path, nil
|
||||
// File exists, return a fully qualified path
|
||||
result, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
for _, n := range defaultTaskfiles {
|
||||
fpath := filepath.Join(path, n)
|
||||
if _, err := os.Stat(fpath); err == nil {
|
||||
return fpath, nil
|
||||
result, err := filepath.Abs(fpath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
testdata/includes_rel_path/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
included:
|
||||
taskfile: ./included
|
||||
dir: ./included
|
||||
|
||||
common:
|
||||
taskfile: ./common
|
||||
dir: ./common
|
||||
4
testdata/includes_rel_path/common/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
pwd: pwd
|
||||
6
testdata/includes_rel_path/included/Taskfile.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
version: '3'
|
||||
|
||||
includes:
|
||||
common:
|
||||
taskfile: ../common
|
||||
dir: ../common
|
||||