Skip to content

Commit

Permalink
std: Introduce an Std object to carry the stdlib context
Browse files Browse the repository at this point in the history
I'd like to add state to the stdlib that persists between std.Execute() calls.
I could add global variables in pkg/std or introduce an object to carry that
state between Execute calls. Went for the latter.

This bit of refactoring will be very useful soon: I need to store
plugin-related state because I want plugins, which are somewhat expensive to
start as they are sub-processes, to be around for the duration of the Std
object.
  • Loading branch information
dlespiau committed Oct 28, 2019
1 parent 259cc37 commit 9e04ec2
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 23 deletions.
3 changes: 1 addition & 2 deletions generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ func generate(cmd *cobra.Command, args []string) {
generateOptions.inputDirectory = inputDir
}

vm := newVM(&generateOptions.vmOptions)
vm := newVM(&generateOptions.vmOptions, ".")
vm.parameters.SetBool("jk.generate.stdout", generateOptions.stdout)
vm.SetWorkingDirectory(".")

if err := vm.Run("@jkcfg/std/cmd/<generate>", fmt.Sprintf(string(std.Module("cmd/generate-module.js")), args[0])); err != nil {
if !skipException(err) {
Expand Down
21 changes: 18 additions & 3 deletions pkg/std/std.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ type sender interface {
// returned will be serialised to JSON.
type RPCFunc func([]interface{}) (interface{}, error)

// ExecuteOptions global input parameters to the standards library.
type ExecuteOptions struct {
// Options are global configuration options to tweak the behavior of the
// standard library.
type Options struct {
// Verbose indicates if some operations, such as write, should print out what
// they are doing.
Verbose bool
Expand All @@ -49,6 +50,18 @@ type ExecuteOptions struct {
ExtMethods map[string]RPCFunc
}

// Std represents the standard library.
type Std struct {
options Options
}

// NewStd creates a new instance of the standard library.
func NewStd(options Options) *Std {
return &Std{
options: options,
}
}

// stdError builds an Error flatbuffer we can return to the javascript side.
func stdError(b *flatbuffers.Builder, err error) flatbuffers.UOffsetT {
off := b.CreateString(err.Error())
Expand Down Expand Up @@ -100,7 +113,9 @@ func requireThreeStrings(fn func(string, string, string) (interface{}, error)) R
}

// Execute parses a message from v8 and execute the corresponding function.
func Execute(msg []byte, res sender, options ExecuteOptions) []byte {
func (std *Std) Execute(msg []byte, res sender) []byte {
options := std.options

message := __std.GetRootAsMessage(msg, 0)

union := flatbuffers.Table{}
Expand Down
3 changes: 1 addition & 2 deletions run.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@ func establishScriptDir(opts scriptOptions, scriptArg string) string {

func run(cmd *cobra.Command, args []string) {
scriptDir := establishScriptDir(runOptions.scriptOptions, args[0])
vm := newVM(&runOptions.vmOptions)
vm.SetWorkingDirectory(scriptDir)
vm := newVM(&runOptions.vmOptions, scriptDir)

var runErr error

Expand Down
3 changes: 1 addition & 2 deletions transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ func transform(cmd *cobra.Command, args []string) {
// We must use the current directory as the working directory (for
// the purpose of resolving modules), because we're potentially
// going to supply a path _relative to here_ as an import.
vm := newVM(&transformOptions.vmOptions)
vm.SetWorkingDirectory(".")
vm := newVM(&transformOptions.vmOptions, ".")

// Encode the inputs as a map of path to .. the same path (for
// now). This is in part to get around the limitations of
Expand Down
36 changes: 22 additions & 14 deletions vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,28 +98,28 @@ type vm struct {

worker *v8.Worker
recorder *record.Recorder
std *std.Std
resources *std.ModuleResources

extMethods map[string]std.RPCFunc
}

func (vm *vm) onMessageReceived(msg []byte) []byte {
return std.Execute(msg, vm.worker, std.ExecuteOptions{
Verbose: vm.verbose,
Parameters: vm.parameters,
OutputDirectory: vm.outputDirectory,
Root: std.ReadBase{Path: vm.inputDir, Resources: vm.resources, Recorder: vm.recorder},
DryRun: vm.emitDependencies,
ExtMethods: vm.extMethods,
})
return vm.std.Execute(msg, vm.worker)
}

func newVM(opts *vmOptions) *vm {
func newVM(opts *vmOptions, workingDirectory string) *vm {
vm := &vm{
vmOptions: *opts,
resources: std.NewModuleResources(),
}

/*
* Set scriptDir/inputDir based on workingDirectory and global options.
* This needs to be done early on as these values are used by both the
* stdlib and the module resolving mechanism.
*/
vm.setWorkingDirectory(workingDirectory)

/* Setup a recorder object to gather the list of dependencies */
if opts.emitDependencies {
recorder := &record.Recorder{}
// Add the parameter files to the list of dependencies.
Expand All @@ -135,6 +135,16 @@ func newVM(opts *vmOptions) *vm {
vm.recorder = recorder
}

/* create the stdlib */
vm.std = std.NewStd(std.Options{
Verbose: vm.verbose,
Parameters: vm.parameters,
OutputDirectory: vm.outputDirectory,
Root: std.ReadBase{Path: vm.inputDir, Resources: vm.resources, Recorder: vm.recorder},
DryRun: vm.emitDependencies,
ExtMethods: rpcExtMethods,
})

worker := v8.New(vm.onMessageReceived)
if err := worker.Load("errorHandler", errorHandler); err != nil {
log.Fatal(err)
Expand All @@ -144,14 +154,12 @@ func newVM(opts *vmOptions) *vm {
}
vm.worker = worker

vm.extMethods = rpcExtMethods

resolve.Debug(opts.debugImports)

return vm
}

func (vm *vm) SetWorkingDirectory(dir string) {
func (vm *vm) setWorkingDirectory(dir string) {
scriptDir, err := filepath.Abs(dir)
if err != nil {
log.Fatal(err)
Expand Down

0 comments on commit 9e04ec2

Please sign in to comment.