Skip to content

Fix the --watch flag for AssemblyScript #493

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
Jan 4, 2022
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
6 changes: 3 additions & 3 deletions pkg/commands/compute/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,21 +124,21 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) {
case "assemblyscript":
language = NewLanguage(&LanguageOptions{
Name: "assemblyscript",
SourceDirectory: "assembly",
SourceDirectory: ASSourceDirectory,
IncludeFiles: []string{"package.json"},
Toolchain: NewAssemblyScript(c.Flags.Timeout, c.Manifest.File.Scripts.Build, c.Globals.ErrLog),
})
case "javascript":
language = NewLanguage(&LanguageOptions{
Name: "javascript",
SourceDirectory: "src",
SourceDirectory: JSSourceDirectory,
IncludeFiles: []string{"package.json"},
Toolchain: NewJavaScript(c.Flags.Timeout, c.Manifest.File.Scripts.Build, c.Globals.ErrLog),
})
case "rust":
language = NewLanguage(&LanguageOptions{
Name: "rust",
SourceDirectory: "src",
SourceDirectory: RustSourceDirectory,
IncludeFiles: []string{"Cargo.toml"},
Toolchain: NewRust(c.client, c.Globals.File.Language.Rust, c.Globals.ErrLog, c.Flags.Timeout, c.Manifest.File.Scripts.Build),
})
Expand Down
3 changes: 3 additions & 0 deletions pkg/commands/compute/language_assemblyscript.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import (
"github.com/fastly/cli/pkg/filesystem"
)

// ASSourceDirectory represents the source code directory.
const ASSourceDirectory = "assembly"

// AssemblyScript implements a Toolchain for the AssemblyScript language.
//
// NOTE: We embed the JavaScript type as the behaviours across both languages
Expand Down
3 changes: 3 additions & 0 deletions pkg/commands/compute/language_javascript.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import (
"github.com/fastly/cli/pkg/text"
)

// JSSourceDirectory represents the source code directory.
const JSSourceDirectory = "src"

// JsToolchain represents the default JS toolchain.
const JsToolchain = "npm"

Expand Down
7 changes: 3 additions & 4 deletions pkg/commands/compute/language_rust.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import (
toml "github.com/pelletier/go-toml"
)

// RustSourceDirectory represents the source code directory.
const RustSourceDirectory = "src"

// CargoPackage models the package configuration properties of a Rust Cargo
// package which we are interested in and is embedded within CargoManifest and
// CargoLock.
Expand Down Expand Up @@ -104,10 +107,6 @@ func NewRust(client api.HTTPClient, config config.Rust, errlog fsterr.LogInterfa
}
}

// SourceDirectory implements the Toolchain interface and returns the source
// directory for Rust packages.
func (r Rust) SourceDirectory() string { return "src" }

// IncludeFiles implements the Toolchain interface and returns a list of
// additional files to include in the package archive for Rust packages.
func (r Rust) IncludeFiles() []string { return []string{"Cargo.toml"} }
Expand Down
82 changes: 57 additions & 25 deletions pkg/commands/compute/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"github.com/fastly/cli/pkg/cmd"
"github.com/fastly/cli/pkg/commands/update"
"github.com/fastly/cli/pkg/config"
"github.com/fastly/cli/pkg/errors"
fsterr "github.com/fastly/cli/pkg/errors"
fstexec "github.com/fastly/cli/pkg/exec"
"github.com/fastly/cli/pkg/filesystem"
"github.com/fastly/cli/pkg/manifest"
Expand Down Expand Up @@ -79,7 +79,7 @@ func NewServeCommand(parent cmd.Registerer, globals *config.Data, build *BuildCo
// Exec implements the command interface.
func (c *ServeCommand) Exec(in io.Reader, out io.Writer) (err error) {
if c.skipBuild && c.watch {
return errors.ErrIncompatibleServeFlags
return fsterr.ErrIncompatibleServeFlags
}

if !c.skipBuild {
Expand All @@ -91,19 +91,21 @@ func (c *ServeCommand) Exec(in io.Reader, out io.Writer) (err error) {

progress := text.ResetProgress(out, c.Globals.Verbose())

bin, err := getViceroy(progress, out, c.viceroyVersioner)
bin, err := getViceroy(progress, out, c.viceroyVersioner, c.Globals.ErrLog)
if err != nil {
return err
}

progress.Step("Running local server...")
progress.Done()

srcDir := sourceDirectory(c.lang, c.manifest.File.Language, c.watch, out)

for {
err = local(bin, c.file, c.addr, c.env.Value, c.watch, c.Globals.Verbose(), progress, out)
err = local(bin, srcDir, c.file, c.addr, c.env.Value, c.watch, c.Globals.Verbose(), progress, out, c.Globals.ErrLog)
if err != nil {
if err != errors.ErrViceroyRestart {
if err == errors.ErrSignalInterrupt || err == errors.ErrSignalKilled {
if err != fsterr.ErrViceroyRestart {
if err == fsterr.ErrSignalInterrupt || err == fsterr.ErrSignalKilled {
text.Info(out, "Local server stopped")
return nil
}
Expand Down Expand Up @@ -159,7 +161,7 @@ func (c *ServeCommand) Build(in io.Reader, out io.Writer) error {
//
// In the case of a network failure we fallback to the latest installed version of the
// Viceroy binary as long as one is installed and has the correct permissions.
func getViceroy(progress text.Progress, out io.Writer, versioner update.Versioner) (bin string, err error) {
func getViceroy(progress text.Progress, out io.Writer, versioner update.Versioner, errLog fsterr.LogInterface) (bin string, err error) {
progress.Step("Checking latest Viceroy release...")

defer func(progress text.Progress) {
Expand Down Expand Up @@ -187,19 +189,23 @@ func getViceroy(progress text.Progress, out io.Writer, versioner update.Versione

stdoutStderr, err := cmd.CombinedOutput()
if err != nil {
errLog.Add(err)

// We presume an error means Viceroy needs to be installed.
install = true
}

latest, err := versioner.LatestVersion(context.Background())
if err != nil {
errLog.Add(err)

// When we have an error getting the latest version information for Viceroy
// and the user doesn't have a pre-existing install of Viceroy, then we're
// forced to return the error.
if install {
return bin, errors.RemediationError{
return bin, fsterr.RemediationError{
Inner: fmt.Errorf("error fetching latest version: %w", err),
Remediation: errors.NetworkRemediation,
Remediation: fsterr.NetworkRemediation,
}
}
return bin, nil
Expand All @@ -212,18 +218,21 @@ func getViceroy(progress text.Progress, out io.Writer, versioner update.Versione
if install {
err := installViceroy(progress, versioner, latest, bin)
if err != nil {
errLog.Add(err)
return bin, err
}
} else {
version := strings.TrimSpace(string(stdoutStderr))
err := updateViceroy(progress, version, out, versioner, latest, bin)
if err != nil {
errLog.Add(err)
return bin, err
}
}

err = setBinPerms(bin)
if err != nil {
errLog.Add(err)
return bin, err
}
return bin, nil
Expand Down Expand Up @@ -273,9 +282,9 @@ func updateViceroy(progress text.Progress, version string, out io.Writer, versio

var installedViceroyVersion string

viceroyError := errors.RemediationError{
viceroyError := fsterr.RemediationError{
Inner: fmt.Errorf("a Viceroy version was not found"),
Remediation: errors.BugRemediation,
Remediation: fsterr.BugRemediation,
}

// version output has the expected format: `viceroy 0.1.0`
Expand All @@ -297,9 +306,9 @@ func updateViceroy(progress text.Progress, version string, out io.Writer, versio
if err != nil {
progress.Fail()

return errors.RemediationError{
return fsterr.RemediationError{
Inner: fmt.Errorf("error reading current version: %w", err),
Remediation: errors.BugRemediation,
Remediation: fsterr.BugRemediation,
}
}

Expand Down Expand Up @@ -345,14 +354,38 @@ func setBinPerms(bin string) error {
return nil
}

// sourceDirectory identifies the source code directory for the given language.
func sourceDirectory(flag cmd.OptionalString, lang string, watch bool, out io.Writer) string {
if flag.WasSet {
lang = flag.Value
}
lang = strings.ToLower(strings.TrimSpace(lang))

defaultDir := "src"

switch lang {
case "assemblyscript":
return ASSourceDirectory
case "javascript":
return JSSourceDirectory
case "rust":
return RustSourceDirectory
}
if watch {
text.Info(out, "The --watch flag defaults to watching file modifications in a ./src directory.")
}
return defaultDir
}

// local spawns a subprocess that runs the compiled binary.
func local(bin, file, addr, env string, watch, verbose bool, progress text.Progress, out io.Writer) error {
func local(bin, srcDir, file, addr, env string, watch, verbose bool, progress text.Progress, out io.Writer, errLog fsterr.LogInterface) error {
if env != "" {
env = "." + env
}

wd, err := os.Getwd()
if err != nil {
errLog.Add(err)
return err
}

Expand All @@ -377,7 +410,7 @@ func local(bin, file, addr, env string, watch, verbose bool, progress text.Progr

restart := make(chan bool)
if watch {
go watchFiles(cmd, out, restart)
go watchFiles(srcDir, cmd, out, restart)
}

// NOTE: Once we run the viceroy executable, then it can be stopped by one of
Expand All @@ -401,17 +434,18 @@ func local(bin, file, addr, env string, watch, verbose bool, progress text.Progr
// How big an issue this is depends on how many file modifications a user
// makes, because having lots of signal listeners could exhaust resources.
if err := cmd.Exec(); err != nil {
errLog.Add(err)
e := strings.TrimSpace(err.Error())
if strings.Contains(e, "interrupt") {
return errors.ErrSignalInterrupt
return fsterr.ErrSignalInterrupt
}
if strings.Contains(e, "killed") {
select {
case <-restart:
cmd.SignalCh <- syscall.SIGTERM
return errors.ErrViceroyRestart
return fsterr.ErrViceroyRestart
case <-time.After(1 * time.Second):
return errors.ErrSignalKilled
return fsterr.ErrSignalKilled
}
}
return err
Expand All @@ -420,9 +454,9 @@ func local(bin, file, addr, env string, watch, verbose bool, progress text.Progr
return nil
}

// watchFiles watches the 'src' directory and restarts the viceroy executable
// when changes are detected.
func watchFiles(cmd *fstexec.Streaming, out io.Writer, restart chan<- bool) {
// watchFiles watches the language source directory and restarts the viceroy
// executable when changes are detected.
func watchFiles(dir string, cmd *fstexec.Streaming, out io.Writer, restart chan<- bool) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
Expand Down Expand Up @@ -502,9 +536,7 @@ func watchFiles(cmd *fstexec.Streaming, out io.Writer, restart chan<- bool) {
}
}()

root := "src"

filepath.WalkDir(root, func(path string, entry fs.DirEntry, err error) error {
filepath.WalkDir(dir, func(path string, entry fs.DirEntry, err error) error {
if err != nil {
log.Fatal(err)
}
Expand All @@ -517,7 +549,7 @@ func watchFiles(cmd *fstexec.Streaming, out io.Writer, restart chan<- bool) {
return nil
})

text.Info(out, "Watching ./%s for changes", root)
text.Info(out, "Watching ./%s for changes", dir)
text.Break(out)
<-done
}
5 changes: 4 additions & 1 deletion pkg/commands/compute/serve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"
"testing"

fsterr "github.com/fastly/cli/pkg/errors"
"github.com/fastly/cli/pkg/mock"
"github.com/fastly/cli/pkg/text"
)
Expand Down Expand Up @@ -42,7 +43,9 @@ func TestGetViceroy(t *testing.T) {
DownloadedFile: downloadedFile,
}

_, err := getViceroy(progress, &out, versioner)
errlog := fsterr.MockLog{}

_, err := getViceroy(progress, &out, versioner, errlog)
if err != nil {
t.Fatal(err)
}
Expand Down