From a6f9722fe2e727ba69023b992268a6cb407316da Mon Sep 17 00:00:00 2001 From: Pete Davison Date: Thu, 25 Jan 2024 12:22:10 +0000 Subject: [PATCH 1/5] feat: stdin node --- setup.go | 17 +++++++---------- taskfile/node.go | 25 +++++++++++++++++++++++++ taskfile/node_stdin.go | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 taskfile/node_stdin.go diff --git a/setup.go b/setup.go index 073ba0bdf0..9f27b3a961 100644 --- a/setup.go +++ b/setup.go @@ -67,22 +67,19 @@ func (e *Executor) setCurrentDir() error { return err } e.Dir = wd + } else { + var err error + e.Dir, err = filepath.Abs(e.Dir) + if err != nil { + return err + } } - // Search for a taskfile - root, err := taskfile.ExistsWalk(e.Dir) - if err != nil { - return err - } - e.Dir = filepath.Dir(root) - e.Entrypoint = filepath.Base(root) - return nil } func (e *Executor) readTaskfile() error { - uri := filepath.Join(e.Dir, e.Entrypoint) - node, err := taskfile.NewNode(uri, e.Insecure) + node, err := taskfile.NewRootNode(e.Dir, e.Entrypoint, e.Insecure) if err != nil { return err } diff --git a/taskfile/node.go b/taskfile/node.go index b8c0debeca..7957ca379b 100644 --- a/taskfile/node.go +++ b/taskfile/node.go @@ -2,6 +2,8 @@ package taskfile import ( "context" + "os" + "path/filepath" "strings" "github.com/go-task/task/v3/errors" @@ -16,6 +18,29 @@ type Node interface { Remote() bool } +func NewRootNode( + dir string, + entrypoint string, + insecure bool, +) (Node, error) { + // Check if there is something to read on STDIN + stat, _ := os.Stdin.Stat() + if (stat.Mode()&os.ModeCharDevice) == 0 && stat.Size() > 0 { + return NewStdinNode() + } + // If no entrypoint is specified, search for a taskfile + if entrypoint == "" { + root, err := ExistsWalk(dir) + if err != nil { + return nil, err + } + return NewNode(root, insecure) + } + // Use the specified entrypoint + uri := filepath.Join(dir, entrypoint) + return NewNode(uri, insecure) +} + func NewNode( uri string, insecure bool, diff --git a/taskfile/node_stdin.go b/taskfile/node_stdin.go new file mode 100644 index 0000000000..b942ce87b9 --- /dev/null +++ b/taskfile/node_stdin.go @@ -0,0 +1,40 @@ +package taskfile + +import ( + "bufio" + "context" + "fmt" + "os" +) + +// A StdinNode is a node that reads a taskfile from the standard input stream. +type StdinNode struct { + *BaseNode +} + +func NewStdinNode() (*StdinNode, error) { + base := NewBaseNode() + return &StdinNode{ + BaseNode: base, + }, nil +} + +func (node *StdinNode) Location() string { + return "__stdin__" +} + +func (node *StdinNode) Remote() bool { + return false +} + +func (node *StdinNode) Read(ctx context.Context) ([]byte, error) { + var stdin []byte + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + stdin = fmt.Appendln(stdin, scanner.Text()) + } + if err := scanner.Err(); err != nil { + return nil, err + } + return stdin, nil +} From ce0da54e1b6c6c90f6a5f4dc693e57a5817ed698 Mon Sep 17 00:00:00 2001 From: Pete Davison Date: Thu, 25 Jan 2024 12:36:31 +0000 Subject: [PATCH 2/5] fix: resolve directory correctly when using --dir --- taskfile/node.go | 3 ++- taskfile/node_file.go | 4 ++++ taskfile/node_http.go | 4 ++++ taskfile/node_stdin.go | 8 +++++++- taskfile/reader.go | 5 ++--- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/taskfile/node.go b/taskfile/node.go index 7957ca379b..8b9dc2879e 100644 --- a/taskfile/node.go +++ b/taskfile/node.go @@ -16,6 +16,7 @@ type Node interface { Location() string Optional() bool Remote() bool + BaseDir() string } func NewRootNode( @@ -26,7 +27,7 @@ func NewRootNode( // Check if there is something to read on STDIN stat, _ := os.Stdin.Stat() if (stat.Mode()&os.ModeCharDevice) == 0 && stat.Size() > 0 { - return NewStdinNode() + return NewStdinNode(dir) } // If no entrypoint is specified, search for a taskfile if entrypoint == "" { diff --git a/taskfile/node_file.go b/taskfile/node_file.go index bc96148e0a..45a2a9c3f7 100644 --- a/taskfile/node_file.go +++ b/taskfile/node_file.go @@ -52,3 +52,7 @@ func (node *FileNode) Read(ctx context.Context) ([]byte, error) { defer f.Close() return io.ReadAll(f) } + +func (node *FileNode) BaseDir() string { + return node.Dir +} diff --git a/taskfile/node_http.go b/taskfile/node_http.go index c19d46729c..f4c2ab11f1 100644 --- a/taskfile/node_http.go +++ b/taskfile/node_http.go @@ -65,3 +65,7 @@ func (node *HTTPNode) Read(ctx context.Context) ([]byte, error) { return b, nil } + +func (node *HTTPNode) BaseDir() string { + return "" +} diff --git a/taskfile/node_stdin.go b/taskfile/node_stdin.go index b942ce87b9..c16a64a505 100644 --- a/taskfile/node_stdin.go +++ b/taskfile/node_stdin.go @@ -10,12 +10,14 @@ import ( // A StdinNode is a node that reads a taskfile from the standard input stream. type StdinNode struct { *BaseNode + Dir string } -func NewStdinNode() (*StdinNode, error) { +func NewStdinNode(dir string) (*StdinNode, error) { base := NewBaseNode() return &StdinNode{ BaseNode: base, + Dir: dir, }, nil } @@ -38,3 +40,7 @@ func (node *StdinNode) Read(ctx context.Context) ([]byte, error) { } return stdin, nil } + +func (node *StdinNode) BaseDir() string { + return node.Dir +} diff --git a/taskfile/reader.go b/taskfile/reader.go index a09e495c54..c8ca8bdf66 100644 --- a/taskfile/reader.go +++ b/taskfile/reader.go @@ -48,12 +48,11 @@ func Read( return nil, &errors.TaskfileVersionCheckError{URI: node.Location()} } - // Annotate any included Taskfile reference with a base directory for resolving relative paths - if node, isFileNode := node.(*FileNode); isFileNode { + if dir := node.BaseDir(); dir != "" { _ = tf.Includes.Range(func(namespace string, include ast.Include) error { // Set the base directory for resolving relative paths, but only if not already set if include.BaseDir == "" { - include.BaseDir = node.Dir + include.BaseDir = dir tf.Includes.Set(namespace, include) } return nil From a62669f90770bd9fab6bd73c78c0f588e73c567f Mon Sep 17 00:00:00 2001 From: Pete Davison Date: Thu, 25 Jan 2024 14:53:13 +0000 Subject: [PATCH 3/5] feat: add missing syntax highlighters --- docs/docs/api_reference.md | 2 +- docs/docs/faq.md | 2 +- docs/docs/installation.md | 43 +++++++++++++++++++------------------- docs/docs/usage.md | 30 +++++++++++++------------- docs/docusaurus.config.ts | 7 ++++++- 5 files changed, 45 insertions(+), 39 deletions(-) diff --git a/docs/docs/api_reference.md b/docs/docs/api_reference.md index 7a5e02c900..9d9c44f368 100644 --- a/docs/docs/api_reference.md +++ b/docs/docs/api_reference.md @@ -11,7 +11,7 @@ toc_max_heading_level: 5 Task command line tool has the following syntax: -```bash +```shell task [--flags] [tasks...] [-- CLI_ARGS...] ``` diff --git a/docs/docs/faq.md b/docs/docs/faq.md index 0e809afbae..6a8a96e6b7 100644 --- a/docs/docs/faq.md +++ b/docs/docs/faq.md @@ -69,7 +69,7 @@ tasks: - ./foo-printer.bash ``` -```bash +```shell #!/bin/bash a=foo echo $a diff --git a/docs/docs/installation.md b/docs/docs/installation.md index 2b666a9fbd..c9fc489e7c 100644 --- a/docs/docs/installation.md +++ b/docs/docs/installation.md @@ -14,7 +14,7 @@ Task offers many installation methods. Check out the available methods below. If you're on macOS or Linux and have [Homebrew][homebrew] installed, getting Task is as simple as running: -```bash +```shell brew install go-task/tap/go-task ``` @@ -25,24 +25,25 @@ Recently, Task was also made available [on the official Homebrew repository](https://formulae.brew.sh/formula/go-task), so you also have that option if you prefer: -```bash +```shell brew install go-task ``` ### Tea -If you're on macOS or Linux and have [tea][tea] installed, getting -Task is as simple as running: +If you're on macOS or Linux and have [tea][tea] installed, getting Task is as +simple as running: -```bash +```shell tea task ``` or, if you have tea’s magic enabled: -```bash +```shell task ``` + This installation method is community owned. After a new release of Task, they are automatically released by tea in a minimum of time. @@ -51,7 +52,7 @@ are automatically released by tea in a minimum of time. Task is available in [Snapcraft][snapcraft], but keep in mind that your Linux distribution should allow classic confinement for Snaps to Task work right: -```bash +```shell sudo snap install task --classic ``` @@ -60,7 +61,7 @@ sudo snap install task --classic If you're on Windows and have [Chocolatey][choco] installed, getting Task is as simple as running: -```bash +```shell choco install go-task ``` @@ -71,7 +72,7 @@ This installation method is community owned. If you're on Windows and have [Scoop][scoop] installed, getting Task is as simple as running: -```cmd +```shell scoop install task ``` @@ -84,7 +85,7 @@ If you're on Arch Linux you can install Task from [AUR](https://aur.archlinux.org/packages/go-task-bin) using your favorite package manager such as `yay`, `pacaur` or `yaourt`: -```cmd +```shell yay -S go-task-bin ``` @@ -93,7 +94,7 @@ Alternatively, there's the source code instead of downloading the binary from the [releases page](https://github.com/go-task/task/releases): -```cmd +```shell yay -S go-task ``` @@ -105,7 +106,7 @@ If you're on Fedora Linux you can install Task from the official [Fedora](https://packages.fedoraproject.org/pkgs/golang-github-task/go-task/) repository using `dnf`: -```cmd +```shell sudo dnf install go-task ``` @@ -118,7 +119,7 @@ take some time until it's available in If you're on NixOS or have Nix installed you can install Task from [nixpkgs](https://github.com/NixOS/nixpkgs): -```cmd +```shell nix-env -iA nixpkgs.go-task ``` @@ -131,7 +132,7 @@ take some time until it's available in You can also use Node and npm to install Task by installing [this package](https://www.npmjs.com/package/@go-task/cli). -```bash +```shell npm install -g @go-task/cli ``` @@ -141,7 +142,7 @@ If you are using Windows and installed the [winget](https://github.com/microsoft/winget-cli) package management tool, you can install Task from [winget-pkgs](https://github.com/microsoft/winget-pkgs). -```bash +```shell winget install Task.Task ``` @@ -165,7 +166,7 @@ easy generation of this script. By default, it installs on the `./bin` directory relative to the working directory: -```bash +```shell sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d ``` @@ -173,7 +174,7 @@ 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: -```bash +```shell sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin ``` @@ -209,13 +210,13 @@ setup. You can find the minimum required version of Go in the You can then install the latest release globally by running: -```bash +```shell go install github.com/go-task/task/v3/cmd/task@latest ``` Or you can install into another directory: -```bash +```shell env GOBIN=/bin go install github.com/go-task/task/v3/cmd/task@latest ``` @@ -239,7 +240,7 @@ First, ensure that you installed bash-completion using your package manager. Make the completion file executable: -``` +```shell chmod +x path/to/task.bash ``` @@ -278,7 +279,7 @@ mv path/to/task.fish ~/.config/fish/completions/task.fish Open your profile script with: -``` +```powershell mkdir -Path (Split-Path -Parent $profile) -ErrorAction SilentlyContinue notepad $profile ``` diff --git a/docs/docs/usage.md b/docs/docs/usage.md index 98f09705d3..8bbbb4ef06 100644 --- a/docs/docs/usage.md +++ b/docs/docs/usage.md @@ -27,7 +27,7 @@ tasks: Running the tasks is as simple as running: -```bash +```shell task assets build ``` @@ -162,11 +162,11 @@ variables, as you can see in the [Variables](#variables) section. You can also ask Task to include `.env` like files by using the `dotenv:` setting: -```bash title=".env" +```shell title=".env" KEYNAME=VALUE ``` -```bash title="testing/.env" +```shell title="testing/.env" ENDPOINT=testing.com ``` @@ -699,7 +699,7 @@ 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 +```shell export TASK_TEMP_DIR='~/.task' ``` @@ -950,7 +950,7 @@ listed below in order of importance (i.e. most important first): Example of sending parameters with environment variables: -```bash +```shell $ TASK_VARIABLE=a-value task do-something ``` @@ -964,7 +964,7 @@ Since some shells do not support the above syntax to set environment variables (Windows) tasks also accept a similar style when not at the beginning of the command. -```bash +```shell $ task write-file FILE=file.txt "CONTENT=Hello, World!" print "MESSAGE=All done!" ``` @@ -1192,7 +1192,7 @@ If `--` is given in the CLI, all following parameters are added to a special The below example will run `yarn install`. -```bash +```shell $ task yarn -- install ``` @@ -1353,7 +1353,7 @@ tasks: would print the following output: -```bash +```shell * build: Build the go binary. * test: Run all the go tests. ``` @@ -1486,7 +1486,7 @@ tasks: - echo 'dangerous command' ``` -```bash +```shell ❯ task dangerous task: "This is a dangerous command... Do you want to continue?" [y/N] ``` @@ -1495,7 +1495,7 @@ Warning prompts are called before executing a task. If a prompt is denied Task will exit with [exit code](/api#exit-codes) 205. If approved, Task will continue as normal. -```bash +```shell ❯ task example not dangerous command task: "This is a dangerous command. Do you want to continue?" [y/N] @@ -1532,14 +1532,14 @@ tasks: Normally this will be printed: -```sh +```shell echo "Print something" Print something ``` With silent mode on, the below will be printed instead: -```sh +```shell Print something ``` @@ -1686,7 +1686,7 @@ tasks: silent: true ``` -```bash +```shell $ task default ::group::default Hello, World! @@ -1711,7 +1711,7 @@ tasks: errors: echo 'output-of-errors' && exit 1 ``` -```bash +```shell $ task passes $ task errors output-of-errors @@ -1744,7 +1744,7 @@ tasks: silent: true ``` -```bash +```shell $ task default [print-foo] foo [print-bar] bar diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index b72ab4e7d4..693cdd3564 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -254,7 +254,12 @@ const config: Config = { }, prism: { theme: lightCodeTheme, - darkTheme: darkCodeTheme + darkTheme: darkCodeTheme, + additionalLanguages: [ + "bash", // aka. shell + "json", + "powershell" + ] }, // NOTE(@andreynering): Don't worry, these keys are meant to be public =) algolia: { From 3df49ab51ab10a5e777e5547983d20b22eebe38b Mon Sep 17 00:00:00 2001 From: Pete Davison Date: Thu, 25 Jan 2024 14:55:36 +0000 Subject: [PATCH 4/5] docs: added reading from stdin section to usage --- docs/docs/usage.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/docs/usage.md b/docs/docs/usage.md index 8bbbb4ef06..c07ec91e6a 100644 --- a/docs/docs/usage.md +++ b/docs/docs/usage.md @@ -118,6 +118,18 @@ tasks: ::: +### Reading a Taskfile from stdin + +Taskfile also supports reading from stdin. This is useful if you are generating +Taskfiles dynamically and don't want write them to disk. This works just like +any other program that supports stdin. For example: + +```shell +task < <(cat ./Taskfile.yml) +# OR +cat ./Taskfile.yml | task +``` + ## Environment variables ### Task From 7abbc15c27f11593fb1a0fe3738a9b09963986b0 Mon Sep 17 00:00:00 2001 From: Pete Davison Date: Thu, 22 Feb 2024 18:59:06 +0000 Subject: [PATCH 5/5] feat: more permissive file modes --- taskfile/taskfile.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/taskfile/taskfile.go b/taskfile/taskfile.go index f43a93f301..ae9e9d89c5 100644 --- a/taskfile/taskfile.go +++ b/taskfile/taskfile.go @@ -35,7 +35,10 @@ func Exists(path string) (string, error) { if err != nil { return "", err } - if fi.Mode().IsRegular() { + if fi.Mode().IsRegular() || + fi.Mode()&os.ModeDevice != 0 || + fi.Mode()&os.ModeSymlink != 0 || + fi.Mode()&os.ModeNamedPipe != 0 { return filepath.Abs(path) }