-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun.go
126 lines (104 loc) · 3.34 KB
/
run.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package main
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"github.com/spf13/cobra"
)
var runCmd = &cobra.Command{
Use: "run",
Example: runExamples(),
Short: "Execute a jk program",
Args: runArgs,
Run: run,
}
// InlineSpecifier is used as the initial module specifier when exec'ing literal JavaScript
const InlineSpecifier = "<exec>"
// StdinSpecifier is used as the initial module specifier when reading JavaScript from stdin
const StdinSpecifier = "<stdin>"
// ToplevelReferrer is used as the module referrer when using --module
const ToplevelReferrer = "<toplevel>"
func runExamples() string {
b := bytes.Buffer{}
b.WriteString(" specifying where are input files used by script and output generated files\n")
b.WriteString(" jk run -v -i ./inputdir -o ./outputdir ./scriptdir/script.js\n")
b.WriteString(" specifying input parameters\n")
b.WriteString(" jk run -v -p path.k1.k2=value ./scriptdir/script.js\n")
b.WriteString(" specifying input parameters and file containing parameters\n")
b.WriteString(" jk run -v -p key=value -f filename.json script.js\n")
b.WriteString(" run the JavaScript given on the command line, with standard lib available\n")
b.WriteString(" jk run -c log('foo')\n")
b.WriteString(" run the module given, resolved relative to the current directory\n")
b.WriteString(" jk run -m @example/module\n")
b.WriteString(" read the script to run from stdin\n")
b.WriteString(" jk run -\n")
return b.String()
}
const inlineTemplate = `
import { log, write, read } from '@jkcfg/std';
import { dir, info } from '@jkcfg/std/fs';
import * as param from '@jkcfg/std/param';
%s;
`
var runOptions struct {
vmOptions
// control how the argument is interpreted; by default, it's a
// file to load
module, inline bool
}
func init() {
runCmd.PersistentFlags().BoolVarP(&runOptions.module, "module", "m", false, "treat argument as specifying a module to load")
runCmd.PersistentFlags().BoolVarP(&runOptions.inline, "exec", "c", false, "treat argument as specifying literal JavaScript to execute")
initVMFlags(runCmd, &runOptions.vmOptions)
jk.AddCommand(runCmd)
}
func runArgs(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return errors.New("run requires an input script")
}
return nil
}
func run(cmd *cobra.Command, args []string) {
var (
scriptDir string
)
// Before setting anything else up, we have to establish the
// directory relative to which modules will be resolved.
var err error
switch {
case runOptions.module && runOptions.inline:
log.Fatal("supply one or neither of --module,-m and --exec,-c")
case runOptions.module || runOptions.inline || args[0] == "-":
scriptDir, err = filepath.Abs(".")
default:
filename := args[0]
scriptDir, err = filepath.Abs(filepath.Dir(filename))
}
if err != nil {
log.Fatal(err)
}
vm := newVM(&runOptions.vmOptions)
vm.SetWorkingDirectory(scriptDir)
var runErr error
switch {
case runOptions.module:
runErr = vm.RunModule(args[0], ToplevelReferrer)
case runOptions.inline:
runErr = vm.Run(InlineSpecifier, fmt.Sprintf(inlineTemplate, args[0]))
case args[0] == "-":
input, err := ioutil.ReadAll(os.Stdin)
if err != nil {
log.Fatal(err)
}
runErr = vm.Run(StdinSpecifier, string(input))
default: // a file
runErr = vm.RunFile(args[0])
}
if runErr != nil {
log.Fatal(runErr)
}
}