lang: gapi, docs: Add a --skip-unify option to speed up run

This is useful for run and dangerous for deploy. If we make type
unification blazing fast, we should probably get rid of this option.
This commit is contained in:
James Shubin
2024-02-08 10:31:38 -05:00
parent 5b8a1ce821
commit edf47a1737
2 changed files with 60 additions and 27 deletions

View File

@@ -231,6 +231,27 @@ It will also print how long it took on either success or failure. Keep in mind
that even if you pass type unification, an `mgmt` run can still fail later on
for other reasons, although these are mostly runtime considerations.
### Why is type unification happening twice with `mgmt run`?
When you use the `run` action, it runs all of the compile time checks (including
type unification) that are possible, and then packages everything up into a
deployable object and runs the same mechanism that `mgmt deploy` uses, sending
the deploy to itself. At this point, mgmt starts up as a server, and receives
the deploy. It will then need to run type unification again before running the
code.
You can skip the first type unification check by adding the `--skip-unify`
option to the lang frontend when using the `run` command.
You can also skip this check when running the `deploy` action, but if your code
doesn't pass, you might be deploying broken code. This is not recommended.
#### Example:
```
./mgmt run --tmp-prefix lang --skip-unify examples/lang/hello0.mcl
```
### Why does my file resource error with `no such file or directory`?
If you create a file resource and only specify the content like this:

View File

@@ -106,6 +106,16 @@ func (obj *GAPI) CliFlags(command string) []cli.Flag {
result = append(result, runFlags...)
}
if command == gapi.CommandRun || command == gapi.CommandDeploy {
flags := []cli.Flag{
&cli.BoolFlag{
Name: "skip-unify",
Usage: "skip type unification",
},
}
result = append(result, flags...)
}
switch command {
case gapi.CommandGet:
flags := []cli.Flag{
@@ -316,36 +326,38 @@ func (obj *GAPI) Cli(cliInfo *gapi.CliInfo) (*gapi.Deploy, error) {
return nil, errwrap.Wrapf(err, "could not set scope")
}
// apply type unification
unificationLogf := func(format string, v ...interface{}) {
if debug { // unification only has debug messages...
logf("unification: "+format, v...)
if !c.Bool("skip-unify") {
// apply type unification
unificationLogf := func(format string, v ...interface{}) {
if debug { // unification only has debug messages...
logf("unification: "+format, v...)
}
}
}
logf("running type unification...")
startTime := time.Now()
unifier := &unification.Unifier{
AST: iast,
Solver: unification.SimpleInvariantSolverLogger(unificationLogf),
Debug: debug,
Logf: unificationLogf,
}
unifyErr := unifier.Unify()
delta := time.Since(startTime)
formatted := delta.String()
if delta.Milliseconds() > 1000 { // 1 second
formatted = delta.Truncate(time.Millisecond).String()
}
if unifyErr != nil {
if c.Bool("only-unify") {
logf("type unification failed after %s", formatted)
logf("running type unification...")
startTime := time.Now()
unifier := &unification.Unifier{
AST: iast,
Solver: unification.SimpleInvariantSolverLogger(unificationLogf),
Debug: debug,
Logf: unificationLogf,
}
unifyErr := unifier.Unify()
delta := time.Since(startTime)
formatted := delta.String()
if delta.Milliseconds() > 1000 { // 1 second
formatted = delta.Truncate(time.Millisecond).String()
}
if unifyErr != nil {
if c.Bool("only-unify") {
logf("type unification failed after %s", formatted)
}
return nil, errwrap.Wrapf(unifyErr, "could not unify types")
}
return nil, errwrap.Wrapf(unifyErr, "could not unify types")
}
if c.Bool("only-unify") {
logf("type unification succeeded in %s", formatted)
return nil, nil // we end early
if c.Bool("only-unify") {
logf("type unification succeeded in %s", formatted)
return nil, nil // we end early
}
}
// get the list of needed files (this is available after SetScope)