[tint][tools] Add a 'tintd install' command Installs the tintd vscode extension for local development via a symlink to the build directory Bug: tint:2127 Change-Id: If813eebd58d9eb2fbc2a3f41a69174d88d263fb9 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/179100 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/tools/src/cmd/tintd/common/cmds.go b/tools/src/cmd/tintd/common/cmds.go new file mode 100644 index 0000000..44edcd5 --- /dev/null +++ b/tools/src/cmd/tintd/common/cmds.go
@@ -0,0 +1,44 @@ +// Copyright 2024 The Dawn & Tint Authors +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package common + +import ( + "dawn.googlesource.com/dawn/tools/src/subcmd" +) + +// The registered commands +var commands []Command + +// Command is the type of a single cts command +type Command = subcmd.Command[any] + +// Register registers the command for use by the 'cts' tool +func Register(c Command) { commands = append(commands, c) } + +// Commands returns all the commands registered +func Commands() []Command { return commands }
diff --git a/tools/src/cmd/tintd/install/install.go b/tools/src/cmd/tintd/install/install.go new file mode 100644 index 0000000..fadf860 --- /dev/null +++ b/tools/src/cmd/tintd/install/install.go
@@ -0,0 +1,144 @@ +// Copyright 2024 The Dawn & Tint Authors +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Package install installs the tintd vscode extension for local development +// via a symlink to the build directory +package install + +import ( + "bytes" + "context" + "encoding/json" + "flag" + "fmt" + "os" + "os/exec" + "path/filepath" + + "dawn.googlesource.com/dawn/tools/src/cmd/tintd/common" + "dawn.googlesource.com/dawn/tools/src/fileutils" +) + +func init() { + common.Register(&Cmd{}) +} + +type Cmd struct { + flags struct { + buildDir string + npmPath string + } +} + +func (Cmd) Name() string { + return "install" +} + +func (Cmd) Desc() string { + return `install installs the tintd vscode extension for local development via a symlink to the build directory` +} + +func (c *Cmd) RegisterFlags(ctx context.Context, _ any) ([]string, error) { + dawnRoot := fileutils.DawnRoot() + npmPath, _ := exec.LookPath("npm") + flag.StringVar(&c.flags.buildDir, "build", filepath.Join(dawnRoot, "out", "active"), "the output build directory") + flag.StringVar(&c.flags.npmPath, "npm", npmPath, "path to npm") + + return nil, nil +} + +func (c Cmd) Run(ctx context.Context, _ any) error { + pkgDir := c.findPackage() + if pkgDir == "" { + return fmt.Errorf("could not find extension package directory at '%v'", c.flags.buildDir) + } + + if !fileutils.IsExe(c.flags.npmPath) { + return fmt.Errorf("could not find npm") + } + + // Build the package + npmCmd := exec.Command(c.flags.npmPath, "install") + npmCmd.Dir = pkgDir + if out, err := npmCmd.CombinedOutput(); err != nil { + return fmt.Errorf("npm install failed:\n%v\n%v", err, string(out)) + } + + // Load the package to get the name and version + pkg := struct { + Name string + Version string + }{} + packageJSONPath := filepath.Join(pkgDir, "package.json") + packageJSON, err := os.ReadFile(packageJSONPath) + if err != nil { + return fmt.Errorf("could not open '%v'", packageJSONPath) + } + if err := json.NewDecoder(bytes.NewReader(packageJSON)).Decode(&pkg); err != nil { + return fmt.Errorf("could not parse '%v': %v", packageJSONPath, err) + } + + // Symlink to vscode extensions directory + home, err := os.UserHomeDir() + if err != nil { + return fmt.Errorf("failed to obtain home directory: %w", err) + } + vscodeBaseExtsDir := filepath.Join(home, ".vscode", "extensions") + if !fileutils.IsDir(vscodeBaseExtsDir) { + return fmt.Errorf("vscode extensions directory not found at '%v'", vscodeBaseExtsDir) + } + + vscodeTintdDir := filepath.Join(vscodeBaseExtsDir, fmt.Sprintf("google.%v-%v", pkg.Name, pkg.Version)) + os.RemoveAll(vscodeTintdDir) + + if err := os.Symlink(pkgDir, vscodeTintdDir); err != nil { + return fmt.Errorf("failed to create symlink '%v' <- '%v': %w", pkgDir, vscodeTintdDir, err) + } + + return nil +} + +// findPackage looks for and returns the tintd package directory. Returns an empty string if not found. +func (c Cmd) findPackage() string { + searchPaths := []string{ + filepath.Join(c.flags.buildDir, "gen/vscode"), + c.flags.buildDir, + } + files := []string{"tintd", "package.json"} + +nextDir: + for _, dir := range searchPaths { + for _, file := range files { + if !fileutils.IsFile(filepath.Join(dir, file)) { + continue nextDir + } + } + return dir + } + + return "" // Not found +}
diff --git a/tools/src/cmd/tintd/main.go b/tools/src/cmd/tintd/main.go new file mode 100644 index 0000000..55fc9e9 --- /dev/null +++ b/tools/src/cmd/tintd/main.go
@@ -0,0 +1,55 @@ +// Copyright 2024 The Dawn & Tint Authors +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// tintd is a collection of sub-commands for the tintd language server +// +// To view available commands run: '<dawn>/tools/run tintd --help' +package main + +import ( + "context" + "fmt" + "os" + + "dawn.googlesource.com/dawn/tools/src/cmd/tintd/common" + "dawn.googlesource.com/dawn/tools/src/subcmd" + + // Register sub-commands + _ "dawn.googlesource.com/dawn/tools/src/cmd/tintd/install" +) + +func main() { + ctx := context.Background() + + var noArg any + if err := subcmd.Run(ctx, noArg, common.Commands()...); err != nil { + if err != subcmd.ErrInvalidCLA { + fmt.Fprintln(os.Stderr, err) + } + os.Exit(1) + } +}