@@ -4,11 +4,8 @@ import (
44 "context"
55 "encoding/json"
66 "fmt"
7- "io"
87 "os"
9- "strings"
108
11- "github.com/formancehq/numscript/internal/flags"
129 "github.com/formancehq/numscript/internal/interpreter"
1310 "github.com/formancehq/numscript/internal/parser"
1411
@@ -20,132 +17,62 @@ const (
2017 OutputFormatJson = "json"
2118)
2219
23- type runArgs struct {
24- VariablesOpt string
25- BalancesOpt string
26- MetaOpt string
27- RawOpt string
28- StdinFlag bool
29- OutFormatOpt string
30- Flags []string
20+ type InputsFile struct {
21+ FeatureFlags []string `json:"featureFlags"`
22+ Variables map [string ]string `json:"variables"`
23+ Meta interpreter.AccountsMetadata `json:"metadata"`
24+ Balances interpreter.Balances `json:"balances"`
3125}
3226
33- type inputOpts struct {
34- Script string `json:"script"`
35- Variables map [string ]string `json:"variables"`
36- Meta interpreter.AccountsMetadata `json:"metadata"`
37- Balances interpreter.Balances `json:"balances"`
27+ type RunArgs struct {
28+ InputsPath string
29+ OutFormatOpt string
3830}
3931
40- func (o * inputOpts ) fromRaw (opts runArgs ) error {
41- if opts .RawOpt == "" {
42- return nil
43- }
44-
45- err := json .Unmarshal ([]byte (opts .RawOpt ), o )
32+ func run (scriptPath string , opts RunArgs ) error {
33+ numscriptContent , err := os .ReadFile (scriptPath )
4634 if err != nil {
47- return fmt . Errorf ( "invalid raw input JSON: %w" , err )
35+ return err
4836 }
49- return nil
50- }
5137
52- func (o * inputOpts ) fromStdin (opts runArgs ) error {
53- if ! opts .StdinFlag {
54- return nil
38+ parseResult := parser .Parse (string (numscriptContent ))
39+ if len (parseResult .Errors ) != 0 {
40+ fmt .Fprint (os .Stderr , parser .ParseErrorsToString (parseResult .Errors , string (numscriptContent )))
41+ return fmt .Errorf ("parsing failed" )
5542 }
5643
57- bytes , err := io . ReadAll ( os . Stdin )
58- if err != nil {
59- return fmt . Errorf ( "error reading from stdin: %w" , err )
44+ inputsPath := opts . InputsPath
45+ if inputsPath == "" {
46+ inputsPath = scriptPath + ".inputs.json"
6047 }
6148
62- err = json . Unmarshal ( bytes , o )
49+ inputsContent , err := os . ReadFile ( inputsPath )
6350 if err != nil {
64- return fmt .Errorf ("invalid stdin JSON: %w" , err )
65- }
66- return nil
67- }
68-
69- func (o * inputOpts ) fromOptions (path string , opts runArgs ) error {
70- if path != "" {
71- numscriptContent , err := os .ReadFile (path )
72- if err != nil {
73- return fmt .Errorf ("error reading script file: %w" , err )
74- }
75- o .Script = string (numscriptContent )
76- }
77-
78- if opts .BalancesOpt != "" {
79- content , err := os .ReadFile (opts .BalancesOpt )
80- if err != nil {
81- return fmt .Errorf ("error reading balances file: %w" , err )
82- }
83- if err := json .Unmarshal (content , & o .Balances ); err != nil {
84- return fmt .Errorf ("invalid balances JSON: %w" , err )
85- }
86- }
87-
88- if opts .MetaOpt != "" {
89- content , err := os .ReadFile (opts .MetaOpt )
90- if err != nil {
91- return fmt .Errorf ("error reading metadata file: %w" , err )
92- }
93- if err := json .Unmarshal (content , & o .Meta ); err != nil {
94- return fmt .Errorf ("invalid metadata JSON: %w" , err )
95- }
96- }
97-
98- if opts .VariablesOpt != "" {
99- content , err := os .ReadFile (opts .VariablesOpt )
100- if err != nil {
101- return fmt .Errorf ("error reading variables file: %w" , err )
102- }
103- if err := json .Unmarshal (content , & o .Variables ); err != nil {
104- return fmt .Errorf ("invalid variables JSON: %w" , err )
105- }
106- }
107- return nil
108- }
109-
110- func run (path string , opts runArgs ) error {
111- opt := inputOpts {
112- Variables : make (map [string ]string ),
113- Meta : make (interpreter.AccountsMetadata ),
114- Balances : make (interpreter.Balances ),
115- }
116-
117- if err := opt .fromRaw (opts ); err != nil {
118- return err
119- }
120- if err := opt .fromOptions (path , opts ); err != nil {
121- return err
122- }
123- if err := opt .fromStdin (opts ); err != nil {
12451 return err
12552 }
12653
127- parseResult := parser . Parse ( opt . Script )
128- if len ( parseResult . Errors ) != 0 {
129- fmt . Fprint ( os . Stderr , parser . ParseErrorsToString ( parseResult . Errors , opt . Script ))
130- return fmt .Errorf ("parsing failed" )
54+ var inputs InputsFile
55+ err = json . Unmarshal ( inputsContent , & inputs )
56+ if err != nil {
57+ return fmt .Errorf ("failed to parse inputs file '%s' as JSON: %w" , inputsPath , err )
13158 }
13259
13360 featureFlags := map [string ]struct {}{}
134- for _ , flag := range opts . Flags {
61+ for _ , flag := range inputs . FeatureFlags {
13562 featureFlags [flag ] = struct {}{}
13663 }
13764
138- result , err := interpreter .RunProgram (context .Background (), parseResult .Value , opt .Variables , interpreter.StaticStore {
139- Balances : opt .Balances ,
140- Meta : opt .Meta ,
65+ result , iErr := interpreter .RunProgram (context .Background (), parseResult .Value , inputs .Variables , interpreter.StaticStore {
66+ Balances : inputs .Balances ,
67+ Meta : inputs .Meta ,
14168 }, featureFlags )
14269
143- if err != nil {
144- rng := err .GetRange ()
145- fmt .Fprint (os .Stderr , err .Error ())
70+ if iErr != nil {
71+ rng := iErr .GetRange ()
72+ fmt .Fprint (os .Stderr , iErr .Error ())
14673 if rng .Start != rng .End {
14774 fmt .Fprint (os .Stderr , "\n " )
148- fmt .Fprint (os .Stderr , err .GetRange ().ShowOnSource (parseResult .Source ))
75+ fmt .Fprint (os .Stderr , iErr .GetRange ().ShowOnSource (parseResult .Source ))
14976 }
15077 return fmt .Errorf ("execution failed" )
15178 }
@@ -183,35 +110,36 @@ func showPretty(result *interpreter.ExecutionResult) error {
183110}
184111
185112func getRunCmd () * cobra.Command {
186- opts := runArgs {}
113+ opts := RunArgs {}
187114
188115 cmd := cobra.Command {
189116 Use : "run" ,
190117 Short : "Evaluate a numscript file" ,
191- Long : "Evaluate a numscript file, using the balances, the current metadata and the variables values as input." ,
118+ Long : `Evaluate a numscript file, taking as inputs a json file containing balances, variables and metadata.
119+
120+ The inputs file has to have the same name as the numscript file plus a ".inputs.json" suffix, for example:
121+ run folder/my-script.num
122+ will expect a 'folder/my-script.num.inputs.json' file where to read inputs from.
123+
124+ You can use explicitly specify where the inputs file should be using the optional --inputs argument.
125+ ` ,
126+ Args : cobra .ExactArgs (1 ),
192127 RunE : func (cmd * cobra.Command , args []string ) error {
193- var path string
194- if len (args ) > 0 {
195- path = args [0 ]
128+ path := args [0 ]
129+
130+ err := run (path , opts )
131+ if err != nil {
132+ cmd .SilenceErrors = true
133+ cmd .SilenceUsage = true
134+ return err
196135 }
197- return run (path , opts )
136+
137+ return nil
198138 },
199139 }
200140
201- // Input args
202- cmd .Flags ().StringVarP (& opts .VariablesOpt , "variables" , "v" , "" , "Path of a json file containing the variables" )
203- cmd .Flags ().StringVarP (& opts .BalancesOpt , "balances" , "b" , "" , "Path of a json file containing the balances" )
204- cmd .Flags ().StringVarP (& opts .MetaOpt , "meta" , "m" , "" , "Path of a json file containing the accounts metadata" )
205- cmd .Flags ().StringVarP (& opts .RawOpt , "raw" , "r" , "" , "Raw json input containing script, variables, balances, metadata" )
206- cmd .Flags ().BoolVar (& opts .StdinFlag , "stdin" , false , "Take input from stdin (same format as the --raw option)" )
207-
208- // Feature flag
209- cmd .Flags ().StringSliceVar (& opts .Flags , "flags" , nil , fmt .Sprintf ("the feature flags to pass to the interpreter. Currently available flags: %s" ,
210- strings .Join (flags .AllFlags , ", " ),
211- ))
212-
213- // Output options
214- cmd .Flags ().StringVar (& opts .OutFormatOpt , "output-format" , OutputFormatPretty , "Set the output format. Available options: pretty, json." )
141+ cmd .Flags ().StringVar (& opts .InputsPath , "inputs" , "" , "Path of a json file containing the inputs" )
142+ cmd .Flags ().StringVarP (& opts .OutFormatOpt , "output-format" , "o" , OutputFormatPretty , "Set the output format. Available options: pretty, json." )
215143
216144 return & cmd
217145}
0 commit comments