github.com/fastly/cli@v1.7.2-0.20240304164155-9d0f1d77c3bf/pkg/commands/compute/language_assemblyscript.go (about) 1 package compute 2 3 import ( 4 "encoding/json" 5 "errors" 6 "io" 7 "os" 8 9 fsterr "github.com/fastly/cli/pkg/errors" 10 "github.com/fastly/cli/pkg/text" 11 ) 12 13 // AsDefaultBuildCommand is a build command compiled into the CLI binary so it 14 // can be used as a fallback for customer's who have an existing Compute project and 15 // are simply upgrading their CLI version and might not be familiar with the 16 // changes in the 4.0.0 release with regards to how build logic has moved to the 17 // fastly.toml manifest. 18 // 19 // NOTE: In the 5.x CLI releases we persisted the default to the fastly.toml 20 // We no longer do that. In 6.x we use the default and just inform the user. 21 // This makes the experience less confusing as users didn't expect file changes. 22 const AsDefaultBuildCommand = "npm exec -- asc assembly/index.ts --outFile bin/main.wasm --optimize --noAssert" 23 24 // AsDefaultBuildCommandForWebpack is a build command compiled into the CLI 25 // binary so it can be used as a fallback for customer's who have an existing 26 // Compute project using the 'default' JS Starter Kit, and are simply upgrading 27 // their CLI version and might not be familiar with the changes in the 4.0.0 28 // release with regards to how build logic has moved to the fastly.toml manifest. 29 // 30 // NOTE: For this variation of the build script to be added to the user's 31 // fastly.toml will require a successful check for the webpack dependency. 32 const AsDefaultBuildCommandForWebpack = "npm exec webpack && npm exec -- asc assembly/index.ts --outFile bin/main.wasm --optimize --noAssert" 33 34 // AsSourceDirectory represents the source code directory. 35 const AsSourceDirectory = "assembly" 36 37 // NewAssemblyScript constructs a new AssemblyScript toolchain. 38 func NewAssemblyScript( 39 c *BuildCommand, 40 in io.Reader, 41 manifestFilename string, 42 out io.Writer, 43 spinner text.Spinner, 44 ) *AssemblyScript { 45 return &AssemblyScript{ 46 Shell: Shell{}, 47 48 build: c.Globals.Manifest.File.Scripts.Build, 49 errlog: c.Globals.ErrLog, 50 input: in, 51 manifestFilename: manifestFilename, 52 metadataFilterEnvVars: c.MetadataFilterEnvVars, 53 output: out, 54 postBuild: c.Globals.Manifest.File.Scripts.PostBuild, 55 spinner: spinner, 56 timeout: c.Flags.Timeout, 57 verbose: c.Globals.Verbose(), 58 } 59 } 60 61 // AssemblyScript implements a Toolchain for the AssemblyScript language. 62 type AssemblyScript struct { 63 Shell 64 65 // autoYes is the --auto-yes flag. 66 autoYes bool 67 // build is a shell command defined in fastly.toml using [scripts.build]. 68 build string 69 // defaultBuild indicates if the default build script was used. 70 defaultBuild bool 71 // errlog is an abstraction for recording errors to disk. 72 errlog fsterr.LogInterface 73 // input is the user's terminal stdin stream 74 input io.Reader 75 // manifestFilename is the name of the manifest file. 76 manifestFilename string 77 // metadataFilterEnvVars is a comma-separated list of user defined env vars. 78 metadataFilterEnvVars string 79 // nonInteractive is the --non-interactive flag. 80 nonInteractive bool 81 // output is the users terminal stdout stream 82 output io.Writer 83 // postBuild is a custom script executed after the build but before the Wasm 84 // binary is added to the .tar.gz archive. 85 postBuild string 86 // spinner is a terminal progress status indicator. 87 spinner text.Spinner 88 // timeout is the build execution threshold. 89 timeout int 90 // verbose indicates if the user set --verbose 91 verbose bool 92 } 93 94 // DefaultBuildScript indicates if a custom build script was used. 95 func (a *AssemblyScript) DefaultBuildScript() bool { 96 return a.defaultBuild 97 } 98 99 // Dependencies returns all dependencies used by the project. 100 func (a *AssemblyScript) Dependencies() map[string]string { 101 deps := make(map[string]string) 102 103 lockfile := "npm-shrinkwrap.json" 104 _, err := os.Stat(lockfile) 105 if errors.Is(err, os.ErrNotExist) { 106 lockfile = "package-lock.json" 107 } 108 109 var jlf JavaScriptLockFile 110 if f, err := os.Open(lockfile); err == nil { 111 if err := json.NewDecoder(f).Decode(&jlf); err == nil { 112 for k, v := range jlf.Packages { 113 if k != "" { // avoid "root" package 114 deps[k] = v.Version 115 } 116 } 117 } 118 } 119 120 return deps 121 } 122 123 // Build compiles the user's source code into a Wasm binary. 124 func (a *AssemblyScript) Build() error { 125 if !a.verbose { 126 text.Break(a.output) 127 } 128 text.Deprecated(a.output, "The Fastly AssemblyScript SDK is being deprecated in favor of the more up-to-date and feature-rich JavaScript SDK. You can learn more about the JavaScript SDK on our Developer Hub Page - https://developer.fastly.com/learning/compute/javascript/\n\n") 129 130 if a.build == "" { 131 a.build = AsDefaultBuildCommand 132 a.defaultBuild = true 133 } 134 135 usesWebpack, err := a.checkForWebpack() 136 if err != nil { 137 return err 138 } 139 if usesWebpack { 140 a.build = AsDefaultBuildCommandForWebpack 141 } 142 143 if a.defaultBuild && a.verbose { 144 text.Info(a.output, "No [scripts.build] found in %s. The following default build command for AssemblyScript will be used: `%s`\n\n", a.manifestFilename, a.build) 145 } 146 147 bt := BuildToolchain{ 148 autoYes: a.autoYes, 149 buildFn: a.Shell.Build, 150 buildScript: a.build, 151 errlog: a.errlog, 152 in: a.input, 153 manifestFilename: a.manifestFilename, 154 metadataFilterEnvVars: a.metadataFilterEnvVars, 155 nonInteractive: a.nonInteractive, 156 out: a.output, 157 postBuild: a.postBuild, 158 spinner: a.spinner, 159 timeout: a.timeout, 160 verbose: a.verbose, 161 } 162 163 return bt.Build() 164 } 165 166 func (a AssemblyScript) checkForWebpack() (bool, error) { 167 wd, err := os.Getwd() 168 if err != nil { 169 return false, err 170 } 171 172 home, err := os.UserHomeDir() 173 if err != nil { 174 return false, err 175 } 176 177 found, path, err := search("package.json", wd, home) 178 if err != nil { 179 return false, err 180 } 181 182 if found { 183 // gosec flagged this: 184 // G304 (CWE-22): Potential file inclusion via variable 185 // 186 // Disabling as the path is determined by our own logic. 187 /* #nosec */ 188 data, err := os.ReadFile(path) 189 if err != nil { 190 return false, err 191 } 192 193 var pkg NPMPackage 194 195 err = json.Unmarshal(data, &pkg) 196 if err != nil { 197 return false, err 198 } 199 200 for k := range pkg.DevDependencies { 201 if k == "webpack" { 202 return true, nil 203 } 204 } 205 206 for k := range pkg.Dependencies { 207 if k == "webpack" { 208 return true, nil 209 } 210 } 211 } 212 213 return false, nil 214 }