Skip to content

Add tools distribution for node #124

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions pkg/repos/runtimes/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package runtimes
import (
"github.com/gptscript-ai/gptscript/pkg/engine"
"github.com/gptscript-ai/gptscript/pkg/repos"
"github.com/gptscript-ai/gptscript/pkg/repos/runtimes/node"
"github.com/gptscript-ai/gptscript/pkg/repos/runtimes/python"
)

Expand All @@ -17,6 +18,10 @@ var Runtimes = []repos.Runtime{
&python.Runtime{
Version: "3.10",
},
&node.Runtime{
Version: "21",
Default: true,
},
}

func Default(cacheDir string) engine.RuntimeManager {
Expand Down
18 changes: 18 additions & 0 deletions pkg/repos/runtimes/env/env.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package env

import (
"fmt"
"os"
"strings"
)

func execEquals(bin, check string) bool {
return bin == check ||
bin == check+".exe"
Expand All @@ -20,3 +26,15 @@ func Matches(cmd []string, bin string) bool {
}
return false
}

func AppendPath(env []string, binPath string) []string {
var newEnv []string
for _, path := range env {
v, ok := strings.CutPrefix(path, "PATH=")
if ok {
newEnv = append(newEnv, fmt.Sprintf("PATH=%s%s%s",
binPath, string(os.PathListSeparator), v))
}
}
return newEnv
}
117 changes: 117 additions & 0 deletions pkg/repos/runtimes/node/SHASUMS256.txt.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

43a881788549e1b3425eb5f2b92608f438f146e08213de09c5bd5ff841cae7ae node-v20.11.1-aix-ppc64.tar.gz
3f8e77b775372c0b27d2b85ce899d80339691f480e64dde43d4eb01504a58679 node-v20.11.1-arm64.msi
e0065c61f340e85106a99c4b54746c5cee09d59b08c5712f67f99e92aa44995d node-v20.11.1-darwin-arm64.tar.gz
fd771bf3881733bfc0622128918ae6baf2ed1178146538a53c30ac2f7006af5b node-v20.11.1-darwin-arm64.tar.xz
c52e7fb0709dbe63a4cbe08ac8af3479188692937a7bd8e776e0eedfa33bb848 node-v20.11.1-darwin-x64.tar.gz
ed69f1f300beb75fb4cad45d96aacd141c3ddca03b6d77c76b42cb258202363d node-v20.11.1-darwin-x64.tar.xz
0aa42c91b441e945ff43bd3a837759c58b436de57dcd033d02e5cbcd2fba1f87 node-v20.11.1-headers.tar.gz
edce238817acf5adce3123366b55304aff2a1f0849231d1b49f42370e454b6f8 node-v20.11.1-headers.tar.xz
e34ab2fc2726b4abd896bcbff0250e9b2da737cbd9d24267518a802ed0606f3b node-v20.11.1-linux-arm64.tar.gz
c957f29eb4e341903520caf362534f0acd1db7be79c502ae8e283994eed07fe1 node-v20.11.1-linux-arm64.tar.xz
e42791f76ece283c7a4b97fbf716da72c5128c54a9779f10f03ae74a4bcfb8f6 node-v20.11.1-linux-armv7l.tar.gz
28e0120d2d150a8f41717899d33167b8b32053778665583d49ff971bfd188d1b node-v20.11.1-linux-armv7l.tar.xz
9823305ac3a66925a9b61d8032f6bbb4c3e33c28e7f957ebb27e49732feffb23 node-v20.11.1-linux-ppc64le.tar.gz
51343cacf5cdf5c4b5e93e919d19dd373d6ef43d5f2c666eae299f26e31d08b5 node-v20.11.1-linux-ppc64le.tar.xz
4c66b2f247fdd8720853321526d7cda483018fcb32014b75c30f3a54ecacaea7 node-v20.11.1-linux-s390x.tar.gz
b32616b705cd0ddbb230b95c693e3d7a37becc2ced9bcadea8dc824cceed6be0 node-v20.11.1-linux-s390x.tar.xz
bf3a779bef19452da90fb88358ec2c57e0d2f882839b20dc6afc297b6aafc0d7 node-v20.11.1-linux-x64.tar.gz
d8dab549b09672b03356aa2257699f3de3b58c96e74eb26a8b495fbdc9cf6fbe node-v20.11.1-linux-x64.tar.xz
f1cd449fcbeb1b948e8498cb8edd9655fa319d109a7f4c5bd96a9b122b91538a node-v20.11.1-win-arm64.7z
e85461ec124956a2853c4ee6e13c4f4889d63c88beb3d530c1ee0c4b51dc10e7 node-v20.11.1-win-arm64.zip
fb9b5348259988a562a48eed7349e7e716c0bec78d98ad0a336b2993a8b3bf34 node-v20.11.1-win-x64.7z
bc032628d77d206ffa7f133518a6225a9c5d6d9210ead30d67e294ff37044bda node-v20.11.1-win-x64.zip
c2b1863d8979546804a39fc63d0a9bc9c6e49cb2f6c9d1e52844a24629b24765 node-v20.11.1-win-x86.7z
b98e95f78416d1359b647cfa09ba2a48b76d41b56a776df822bf36ffe8e76a2d node-v20.11.1-win-x86.zip
c54f5f7e2416e826fd84e878f28e3b53363ae9c3f60a140af4434b2453b5ae89 node-v20.11.1-x64.msi
63e2aed4dabb96eed6903a3974e006d3c29c218472aac60ae3c3c7de00df13b1 node-v20.11.1-x86.msi
c46019a095a1549d000e85da13f17972a448e0be5854a51786ecccde7278a012 node-v20.11.1.pkg
4af1ba6ea848cc05908b8a62b02fb27684dd52b2a7988ee82b0cfa72deb90b94 node-v20.11.1.tar.gz
77813edbf3f7f16d2d35d3353443dee4e61d5ee84d9e3138c7538a3c0ca5209e node-v20.11.1.tar.xz
a5a9d30a8f7d56e00ccb27c1a7d24c8d0bc96a2689ebba8eb7527698793496f1 win-arm64/node.exe
93529170cebe57c0f4830a4cc6a261b6cc9bcf0cd8b3e88ac4995a5015031d79 win-arm64/node.lib
c14c6e927406b8683cbfb8a67ca4c8fd5093ca7812b5b1627e3d6a53d3674565 win-arm64/node_pdb.7z
68034cd09d8dfaa755d1b280da13e20388cc486ac57b037b3e11dfe2d6b74284 win-arm64/node_pdb.zip
bc585910690318aaebe3c57669cb83ca9d1e5791efd63195e238f54686e6c2ec win-x64/node.exe
53a982d490cb9fcc4b231a8b95147de423b36186bc6f4ba5697b20117fdcbd5d win-x64/node.lib
ccac9f2f5219ed858aeddb306d6493478ba9675c7cbf009e83742437d6752c4f win-x64/node_pdb.7z
bec5da4035c84580843978a59ef9bcc1c0eaca881cf9e1c94e63a1862cf14421 win-x64/node_pdb.zip
3829137e062b1e2eb9947ef05e4b717ae578a8fce1c5c60fe4f6ae7ef2ec0240 win-x86/node.exe
c5321bb65dcecb3989f9b8f6ec56369c16627ca4bade0c78afb6b88f7dde50e4 win-x86/node.lib
20ca60ced1fc21f15ea952b4406aec6bde39d20eab11cf042040628841b2249e win-x86/node_pdb.7z
bef05cebedce5949ae35e87e7d4789c16fa73caf478483fcf92e5dbb9ba5d774 win-x86/node_pdb.zip
-----BEGIN PGP SIGNATURE-----

iQGzBAEBCAAdFiEEiQwI24V5Fi/uDfnbi+q0389VXvQFAmXM+TcACgkQi+q0389V
XvQl3AwAqqm2uBMDzd+BlR1sG7y/eUtUYPVdwmCh0DeFXPHxuaIbFf0PGMEgcV8u
kn3OBF4pnSCPZNbJYJsLO1S+b/5Vk+Vlkq1WkOxqQHUHmM9GcJUuShadl0YaDNen
WXXMoYKWqMRJ6fQ3tRRh+vbMSXtsLqXT8TMVJq+Qb7a7yj4QRjw/Dd+8uKGGIhBY
U04HWsz33RJLu6AUnhF03eO1N8E1V48JptklDx5ZkY8GYa3F6jQsFld+jhmkZ9tg
4q9NDNijVpj56UsUhLAYD0J9IKS18tvQxNrKmBGUSZjFOByVhbUdLXnSMtW1i1U9
cYhP6Q5wg/fnjqCfQ90TauoJZOblKIL/PHlf6cQGPrrRa1bz3xGyCAIve5KFhLxf
Vfj1ctk2ktzmuNhjAu5G/1VALQUNpiTm4Yz433JpoMMZ3mTHN+fuALOX4TQbdLRz
HKphTz02436348XC9bNz2cvjm74cy9fqwjQ/y84AmxiTJMFPg0XqICg4tu9rd49d
8FJc4TLZ
=r/CD
-----END PGP SIGNATURE-----

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

c31d5b60c4a284c6855bd468d4aae4436a16b351362b2971d3c0db2a471d3f24 node-v21.7.0-aix-ppc64.tar.gz
7d7dc37aa30b6dbb52d698d01cfed1d99056c82396eadd41a49fc55a873c423d node-v21.7.0-arm64.msi
f48ad51cf3c2814bbf61c8c26efd810e5e22dcac980786fd7ac5b54365233d2c node-v21.7.0-darwin-arm64.tar.gz
0805239d8a7402dae49e0033b7ad8208fed498dbeee9a3194863e52f6f3c6d7f node-v21.7.0-darwin-arm64.tar.xz
3f81adca80b523b413e26f03f855f4a2ae52d9af20f0cda2e259dd26a0608607 node-v21.7.0-darwin-x64.tar.gz
6a755416292854f2be38e74704ccf09edeba247718e9f047f5e1939b0dba17bd node-v21.7.0-darwin-x64.tar.xz
628d9e4f866e3828b77ce812dc99f33d3e7c673d0c499f13eadff6fa6ccb4383 node-v21.7.0-headers.tar.gz
627d6552d2120660a51f74fff0d40573f4a35d8545462250d30592ce0ba4eec7 node-v21.7.0-headers.tar.xz
520a3e5c83a05a782b1f4959f150c2fdc03e2ea056e855ef6bbb74f6ccf7aa7d node-v21.7.0-linux-arm64.tar.gz
73ce1e4e956532e0916fc7014f5b649573bd2b5870fef5cfc26cc42f58358ae7 node-v21.7.0-linux-arm64.tar.xz
723abb32135ad4baa6e9671447a72f5c9a5bfc681fc540b0e4864e965171b6ed node-v21.7.0-linux-armv7l.tar.gz
8a367a3bf667f0bb3abb9e8121326911d47a31886419ad052d5a52d8c6531d9d node-v21.7.0-linux-armv7l.tar.xz
c2290cb35b11ee2b0f0ae34ad3c8372652688ff2dc3d9a89ada46c2b84ea5dda node-v21.7.0-linux-ppc64le.tar.gz
b85348211a4d195de2f850a17cdec77aedc8fc1c402864b2bc3501608e6c9c47 node-v21.7.0-linux-ppc64le.tar.xz
90b8678ed113950613edeae5eaf298cf795c72005fac6ffd9b7fbb90ddd86738 node-v21.7.0-linux-s390x.tar.gz
99a09f4c790f3210a6d26032bf69713ba199cf2e73af43e04b1b1d9bd1c8db76 node-v21.7.0-linux-s390x.tar.xz
0fce039e2b6af00766492127a49f959ae92ed22fede4c49e9a8c2543aadbd6e2 node-v21.7.0-linux-x64.tar.gz
68510c3851133a21c6a6f9940e58c5bc8fed39f1d91a08e34c5070dd0615fef1 node-v21.7.0-linux-x64.tar.xz
d680d5c3d0b2476a97d11b30cbbdaf1d7f92ffd1cc89e5c640782a6b52480666 node-v21.7.0-win-arm64.7z
11b11b9a3f2db7b5076cf16655e05cd63dc3d8843cd4836ecb12e11315f03441 node-v21.7.0-win-arm64.zip
31c8b4721f37e30ca8e2131a4cb848fc7347f67bf87618e82959b58481f17bc4 node-v21.7.0-win-x64.7z
204de88f4073b08ae3dbe4c412b071eee565fc681e163be205d5cc88065f0322 node-v21.7.0-win-x64.zip
b17ef0c5557e61610774cae5beb0f877699ab419c4672e9c6e3bb3da3d571ed1 node-v21.7.0-win-x86.7z
6aba3fe2258d5c0c40a89e81dfe90113a67489f2a67fd05b7f216b63b4c7bb02 node-v21.7.0-win-x86.zip
512945cf8816e1e906143ea2ee6816f8744a3d114ea38f3540c3ebe685fe3e3a node-v21.7.0-x64.msi
4bedb6069c94a71fd6f0b8fbea280468d5ecdcf209eef6da1a45808e8b15cba6 node-v21.7.0-x86.msi
ccac99782e587c6090b6ad82979210fa0c352322636a6cf290d37eb41152d0b5 node-v21.7.0.pkg
26d6b600e1076f132d4175a90ddc1a709263e75d81967300aa1ffbd86103b991 node-v21.7.0.tar.gz
e41eefe1e59624ee7f312c38f8f7dfc11595641acb2293d21176f03d2763e9d4 node-v21.7.0.tar.xz
25511d1e05d7d0b049945c5ef1cf2a4daa5d6ad16692ccd2c1399142a1c57a65 win-arm64/node.exe
7920932f7be355dbf4568492ab7d104fc059f689ba1a46ac0d6568884c8d201a win-arm64/node.lib
40c423a2b126fc5b6858f8617f0f8537fd8f8d2fa73a5c918607f3ccd386f8c9 win-arm64/node_pdb.7z
dec9eaa91a431ea0f3c243605f0556dbe6459df5c04c10df7935d678a6b3fca4 win-arm64/node_pdb.zip
c486fe72a3663379105538e886ef9d2deacad1deaa64b338e570cb086be592d3 win-x64/node.exe
96d09c2055c2f252122c86b65d2aabd5f90b1a075844f24bf8bcdbab05baf53e win-x64/node.lib
08990dd6bcce80710d59ef76cd74ab98b5bed36b0d2584ca3acbc029f92db4fc win-x64/node_pdb.7z
1a27a25c92f6339b3aa77588063cca537af389aee26bfdf1d0ef505d790e63a3 win-x64/node_pdb.zip
4aaa5b3a95ee4ab932a80b9708c31662a9c4a99d19fea7cb1f7b0ff79d8399ed win-x86/node.exe
6e2502e84c3a0e2da643f6399b59381ade5b525f544a5bcabae923188b8f9998 win-x86/node.lib
d0cd5494364039f558c76d4fc7a1db69739149873e10a5200fb9e2a0ab12fe10 win-x86/node_pdb.7z
354031f3f9576733ebeeccbcafcc691c8326427153a48978ff5cd6f2c8ef5d36 win-x86/node_pdb.zip
-----BEGIN PGP SIGNATURE-----

iQGzBAEBCAAdFiEEiQwI24V5Fi/uDfnbi+q0389VXvQFAmXouAIACgkQi+q0389V
XvRp+wv+IPHjBUmVC6YzAxFhRD4GHVUgjckfSbP2jH/acre1mYgm9LJ//7l2GaJy
oEOO85WaHgaKCHCdv9GBc3dDbbt1n9J2IGmBqcdE8e9cRko5qhBoVUvW7p7Ki7ci
nAq5DS3YkpWAocsY/k+LyR0Ky8mW466ARAucTp9kuZmxB2FW53B0bYK57++1qGuo
tr9kJPoGYQB0cUiTSwTaMbOIdl/4CL+a9J7mIrpaDVW5g3PnNy5y1vgDvtuU7Qcn
uEucciBlOn0Ib4mBnky+NX1ThL9WNwLjaivxdioFgc0E4sMwf0CjF3vMUuEvI8qi
PJ5lYndsHI4fdh1SbcgoFNZzTkMZbTr9xcZIGLzLkMX8r+ztLTiFtiLIUSQq0jgm
fqKQghuDN2SVi7WW4KAa7K1285zmV7L27N9mnNWH4ujTqCW73Wdo2XkG/TwM3yEC
5o+YookAV6RHT1X6RPJ8rQaC0BrBgpm/MQH1kvH4vUyF2HRVZ2ZgEYorvKtOwf9D
f7v3IC9J
=/YNz
-----END PGP SIGNATURE-----
5 changes: 5 additions & 0 deletions pkg/repos/runtimes/node/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package node

import "github.com/gptscript-ai/gptscript/pkg/mvl"

var log = mvl.Package()
155 changes: 155 additions & 0 deletions pkg/repos/runtimes/node/node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package node

import (
"bufio"
"bytes"
"context"
_ "embed"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"runtime"
"strings"

"github.com/gptscript-ai/gptscript/pkg/debugcmd"
"github.com/gptscript-ai/gptscript/pkg/hash"
"github.com/gptscript-ai/gptscript/pkg/repos/download"
runtimeEnv "github.com/gptscript-ai/gptscript/pkg/repos/runtimes/env"
)

//go:embed SHASUMS256.txt.asc
var releasesData []byte

const downloadURL = "https://nodejs.org/dist/%s/"

type Runtime struct {
// version something like "3.12"
Version string
// If true this is the version that will be used for python or python3
Default bool
}

func (r *Runtime) ID() string {
return "node" + r.Version
}

func (r *Runtime) Supports(cmd []string) bool {
for _, testCmd := range []string{"node", "npx", "npm"} {
if r.supports(testCmd, cmd) {
return true
}
}
return false
}

func (r *Runtime) supports(testCmd string, cmd []string) bool {
if runtimeEnv.Matches(cmd, testCmd+r.Version) {
return true
}
if !r.Default {
return false
}
return runtimeEnv.Matches(cmd, testCmd)
}

func (r *Runtime) Setup(ctx context.Context, dataRoot, toolSource string, env []string) ([]string, error) {
binPath, err := r.getRuntime(ctx, dataRoot)
if err != nil {
return nil, err
}

newEnv := runtimeEnv.AppendPath(env, binPath)
if err := r.runNPM(ctx, toolSource, binPath, append(env, newEnv...)); err != nil {
return nil, err
}

return newEnv, nil
}

func osName() string {
if runtime.GOOS == "windows" {
return "win"
}
return runtime.GOOS
}

func arch() string {
if runtime.GOARCH == "amd64" {
return "x64"
}
return runtime.GOARCH
}

func (r *Runtime) getReleaseAndDigest() (string, string, error) {
scanner := bufio.NewScanner(bytes.NewReader(releasesData))
key := osName() + "-" + arch()
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, "node-v"+r.Version) && strings.Contains(line, key) {
parts := strings.Split(line, " ")
digest := strings.TrimSpace(parts[0])
file := strings.TrimSpace(parts[1])
version := strings.Split(file, "-")[1]

return fmt.Sprintf(downloadURL, version) + file, digest, nil
}
}

return "", "", fmt.Errorf("failed to find %s release for os=%s arch=%s", r.ID(), osName(), arch())
}

func (r *Runtime) runNPM(ctx context.Context, toolSource, binDir string, env []string) error {
cmd := debugcmd.New(ctx, filepath.Join(binDir, "npm"), "install")
cmd.Env = env
cmd.Dir = toolSource
return cmd.Run()
}

func (r *Runtime) binDir(rel string) (string, error) {
entries, err := os.ReadDir(rel)
if err != nil {
return "", err
}

for _, entry := range entries {
if entry.IsDir() {
return filepath.Join(rel, entry.Name(), "bin"), nil
}
}

return "", fmt.Errorf("failed to find sub dir for node in %s", rel)
}

func (r *Runtime) getRuntime(ctx context.Context, cwd string) (string, error) {
url, sha, err := r.getReleaseAndDigest()
if err != nil {
return "", err
}

target := filepath.Join(cwd, "node", hash.ID(url, sha))
if _, err := os.Stat(target); err == nil {
return r.binDir(target)
} else if !errors.Is(err, fs.ErrNotExist) {
return "", err
}

log.Infof("Downloading Node %s.x", r.Version)
tmp := target + ".download"
defer os.RemoveAll(tmp)

if err := os.MkdirAll(tmp, 0755); err != nil {
return "", err
}

if err := download.Extract(ctx, url, sha, tmp); err != nil {
return "", err
}

if err := os.Rename(tmp, target); err != nil {
return "", err
}

return r.binDir(target)
}
37 changes: 37 additions & 0 deletions pkg/repos/runtimes/node/node_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package node

import (
"context"
"os"
"strings"
"testing"

"github.com/adrg/xdg"
"github.com/samber/lo"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

var (
testCacheHome = lo.Must(xdg.CacheFile("gptscript-test-cache/runtime"))
)

func TestRuntime(t *testing.T) {
r := Runtime{
Version: "20",
}

s, err := r.Setup(context.Background(), testCacheHome, "testdata", os.Environ())
require.NoError(t, err)
assert.True(t, strings.HasSuffix(s[0], "/bin"), "missing /bin: %s", s)
}

func TestRuntime21(t *testing.T) {
r := Runtime{
Version: "21",
}

s, err := r.Setup(context.Background(), testCacheHome, "testdata", os.Environ())
require.NoError(t, err)
assert.True(t, strings.HasSuffix(s[0], "/bin"), "missing /bin: %s", s)
}
18 changes: 18 additions & 0 deletions pkg/repos/runtimes/node/testdata/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "gptscript-browser-plugin",
"version": "1.0.0",
"description": "## Project Description",
"main": "index.js",
"directories": {
"example": "examples"
},
"scripts": {
"server": "tsnd --respawn src/server.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.2"
}
}
Loading