-
Notifications
You must be signed in to change notification settings - Fork 1.5k
js: Error with a list of unknown k6/* modules
#5240
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,8 @@ package modules | |||||
| import ( | ||||||
| "fmt" | ||||||
| "net/url" | ||||||
| "slices" | ||||||
| "strconv" | ||||||
| "strings" | ||||||
|
|
||||||
| "github.com/grafana/sobek" | ||||||
|
|
@@ -28,15 +30,16 @@ type moduleCacheElement struct { | |||||
|
|
||||||
| // ModuleResolver knows how to get base Module that can be initialized | ||||||
| type ModuleResolver struct { | ||||||
| cache map[string]moduleCacheElement | ||||||
| goModules map[string]any | ||||||
| loadCJS FileLoader | ||||||
| compiler *compiler.Compiler | ||||||
| locked bool | ||||||
| reverse map[any]*url.URL // maybe use sobek.ModuleRecord as key | ||||||
| base *url.URL | ||||||
| usage *usage.Usage | ||||||
| logger logrus.FieldLogger | ||||||
| cache map[string]moduleCacheElement | ||||||
| goModules map[string]any | ||||||
| loadCJS FileLoader | ||||||
| compiler *compiler.Compiler | ||||||
| locked bool | ||||||
| reverse map[any]*url.URL // maybe use sobek.ModuleRecord as key | ||||||
| base *url.URL | ||||||
| usage *usage.Usage | ||||||
| logger logrus.FieldLogger | ||||||
| unknownModules []string | ||||||
| } | ||||||
|
|
||||||
| // NewModuleResolver returns a new module resolution instance that will resolve. | ||||||
|
|
@@ -66,13 +69,14 @@ func (mr *ModuleResolver) resolveSpecifier(basePWD *url.URL, arg string) (*url.U | |||||
| return specifier, nil | ||||||
| } | ||||||
|
|
||||||
| func (mr *ModuleResolver) requireModule(name string) (sobek.ModuleRecord, error) { | ||||||
| func (mr *ModuleResolver) initializeGoModule(name string) (sobek.ModuleRecord, error) { | ||||||
| if mr.locked { | ||||||
| return nil, fmt.Errorf(notPreviouslyResolvedModule, name) | ||||||
| } | ||||||
| mod, ok := mr.goModules[name] | ||||||
| if !ok { | ||||||
| return nil, fmt.Errorf("unknown module: %s", name) | ||||||
| mr.unknownModules = append(mr.unknownModules, name) | ||||||
| return &unknownModule{name: name, requested: make(map[string]struct{})}, nil | ||||||
| } | ||||||
| // we don't want to report extensions and we would have hit cache if this isn't the first time | ||||||
| if !strings.HasPrefix(name, "k6/x/") { | ||||||
|
|
@@ -150,7 +154,7 @@ func (mr *ModuleResolver) resolve(basePWD *url.URL, arg string) (sobek.ModuleRec | |||||
| if cached, ok := mr.cache[arg]; ok { | ||||||
| return cached.mod, cached.err | ||||||
| } | ||||||
| mod, err := mr.requireModule(arg) | ||||||
| mod, err := mr.initializeGoModule(arg) | ||||||
| mr.cache[arg] = moduleCacheElement{mod: mod, err: err} | ||||||
| return mod, err | ||||||
| default: | ||||||
|
|
@@ -229,6 +233,9 @@ func (mr *ModuleResolver) LoadMainModule(pwd *url.URL, specifier string, data [] | |||||
| panic("somehow running source data for " + specifier + " didn't produce a cyclic module record") | ||||||
| } | ||||||
|
|
||||||
| if len(mr.unknownModules) > 0 { | ||||||
| return newUnknownModulesError(mr.unknownModules) | ||||||
| } | ||||||
| return nil | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -271,8 +278,9 @@ func (ms *ModuleSystem) RunSourceData(source *loader.SourceData) (*RunSourceData | |||||
| } | ||||||
| ci, ok := mod.(sobek.CyclicModuleRecord) | ||||||
| if !ok { | ||||||
| panic("somehow running source data for " + source.URL.String() + " didn't produce a cyclide module record") | ||||||
| panic("somehow running source data for " + source.URL.String() + " didn't produce a cyclic module record") | ||||||
| } | ||||||
|
|
||||||
| rt := ms.vu.Runtime() | ||||||
| promise := rt.CyclicModuleRecordEvaluate(ci, ms.resolver.sobekModuleResolver) | ||||||
|
|
||||||
|
|
@@ -328,3 +336,33 @@ func ExportGloballyModule(rt *sobek.Runtime, modSys *ModuleSystem, moduleName st | |||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| // UnknownModulesError is returned when loading a module was not possbile due to one or more of dependencies | ||||||
| // that couldn't be resolved. | ||||||
| type UnknownModulesError struct { | ||||||
| unknownModules []string | ||||||
| } | ||||||
|
|
||||||
| func newUnknownModulesError(list []string) UnknownModulesError { | ||||||
| slices.Sort(list) | ||||||
| return UnknownModulesError{unknownModules: list} | ||||||
| } | ||||||
|
|
||||||
| func (u UnknownModulesError) Error() string { | ||||||
| return fmt.Sprintf("unknown modules [%s] were tried to be loaded, but couldn't - "+ | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there is still a bit of improvement to be done to have a better DX. A revisited version of original Ankur's proposal.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that we are going overboard on this. There are more changes to come, and this error is either never going to be seen. Or it will be seen before it either loads a new binary or returns a next error about extension resolutions. I would prefer all the DX/UX work to be done after we move to the new implementation, which already fix bugs that are reported and people have problems with. I do not think that if someone has disabled auto extension resolution, they would not know about extensions. |
||||||
| "this likely means automatic extension resolution is required or a custom k6 binary with the required extensions", | ||||||
| u.formatList()) | ||||||
| } | ||||||
|
|
||||||
| // List returns the list of unknown modules that lead to the error | ||||||
| func (u UnknownModulesError) List() []string { | ||||||
| return slices.Clone(u.unknownModules) | ||||||
| } | ||||||
|
|
||||||
| func (u UnknownModulesError) formatList() string { | ||||||
| list := make([]string, len(u.unknownModules)) | ||||||
| for i, m := range u.unknownModules { | ||||||
| list[i] = strconv.Quote(m) | ||||||
| } | ||||||
| return strings.Join(list, ", ") | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package modules | ||
|
|
||
| import "github.com/grafana/sobek" | ||
|
|
||
| type unknownModule struct { | ||
| name string | ||
| requested map[string]struct{} | ||
| } | ||
|
|
||
| func (um *unknownModule) Link() error { return nil } | ||
|
|
||
| func (um *unknownModule) Evaluate(_ *sobek.Runtime) *sobek.Promise { panic("this shouldn't be called") } | ||
|
|
||
| func (um *unknownModule) InitializeEnvironment() error { return nil } | ||
|
|
||
| func (um *unknownModule) Instantiate(_ *sobek.Runtime) (sobek.CyclicModuleInstance, error) { | ||
| return &unknownModuleInstance{module: um}, nil | ||
| } | ||
|
|
||
| func (um *unknownModule) RequestedModules() []string { return nil } | ||
|
|
||
| func (um *unknownModule) ResolveExport(name string, _ ...sobek.ResolveSetElement) (*sobek.ResolvedBinding, bool) { | ||
| um.requested[name] = struct{}{} | ||
| return &sobek.ResolvedBinding{ | ||
| Module: um, | ||
| BindingName: name, | ||
| }, false | ||
| } | ||
|
|
||
| func (um *unknownModule) GetExportedNames(_ func([]string), _ ...sobek.ModuleRecord) bool { | ||
| return false | ||
| } | ||
|
|
||
| type unknownModuleInstance struct { | ||
| module *unknownModule | ||
| } | ||
|
|
||
| func (umi *unknownModuleInstance) GetBindingValue(_ string) sobek.Value { | ||
| return nil | ||
| } | ||
|
|
||
| func (umi *unknownModuleInstance) HasTLA() bool { return false } | ||
|
|
||
| func (umi *unknownModuleInstance) ExecuteModule(_ *sobek.Runtime, _, _ func(any) error, | ||
| ) (sobek.CyclicModuleInstance, error) { | ||
| return umi, nil | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit; ofc non-blocking.