Single Fetcher.Fetch on the Guard that holds DenyPrefixes. skipTlsVerification is ignored. No 502. keys add writes the secret only to --out. Release binary has no -test-allow-prefix.
185 lines
4.1 KiB
Go
185 lines
4.1 KiB
Go
package gojq
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// ModuleLoader is the interface for loading modules.
|
|
//
|
|
// Implement following optional methods. Use [NewModuleLoader] to load local modules.
|
|
//
|
|
// LoadInitModules() ([]*Query, error)
|
|
// LoadModule(string) (*Query, error)
|
|
// LoadModuleWithMeta(string, map[string]any) (*Query, error)
|
|
// LoadJSON(string) (any, error)
|
|
// LoadJSONWithMeta(string, map[string]any) (any, error)
|
|
type ModuleLoader any
|
|
|
|
// NewModuleLoader creates a new [ModuleLoader] loading local modules in the paths.
|
|
// Note that user can load modules outside the paths using "search" path of metadata.
|
|
// Empty paths are ignored, so specify "." for the current working directory.
|
|
func NewModuleLoader(paths []string) ModuleLoader {
|
|
ps := make([]string, 0, len(paths))
|
|
for _, path := range paths {
|
|
if path = resolvePath(path, ""); path != "" {
|
|
ps = append(ps, path)
|
|
}
|
|
}
|
|
return &moduleLoader{ps}
|
|
}
|
|
|
|
type moduleLoader struct {
|
|
paths []string
|
|
}
|
|
|
|
func (l *moduleLoader) LoadInitModules() ([]*Query, error) {
|
|
var qs []*Query
|
|
for _, path := range l.paths {
|
|
if filepath.Base(path) != ".jq" {
|
|
continue
|
|
}
|
|
fi, err := os.Stat(path)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
continue
|
|
}
|
|
return nil, err
|
|
}
|
|
if fi.IsDir() {
|
|
continue
|
|
}
|
|
cnt, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
q, err := parseModule(string(cnt), filepath.Dir(path))
|
|
if err != nil {
|
|
return nil, &queryParseError{path, string(cnt), err}
|
|
}
|
|
qs = append(qs, q)
|
|
}
|
|
return qs, nil
|
|
}
|
|
|
|
func (l *moduleLoader) LoadModuleWithMeta(name string, meta map[string]any) (*Query, error) {
|
|
path, err := l.lookupModule(name, ".jq", meta)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cnt, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
q, err := parseModule(string(cnt), filepath.Dir(path))
|
|
if err != nil {
|
|
return nil, &queryParseError{path, string(cnt), err}
|
|
}
|
|
return q, nil
|
|
}
|
|
|
|
func (l *moduleLoader) LoadJSONWithMeta(name string, meta map[string]any) (any, error) {
|
|
path, err := l.lookupModule(name, ".json", meta)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
vals := []any{}
|
|
dec := json.NewDecoder(f)
|
|
dec.UseNumber()
|
|
for {
|
|
var val any
|
|
if err := dec.Decode(&val); err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if _, err := f.Seek(0, io.SeekStart); err != nil {
|
|
return nil, err
|
|
}
|
|
cnt, er := io.ReadAll(f)
|
|
if er != nil {
|
|
return nil, er
|
|
}
|
|
return nil, &jsonParseError{path, string(cnt), err}
|
|
}
|
|
vals = append(vals, val)
|
|
}
|
|
return vals, nil
|
|
}
|
|
|
|
func (l *moduleLoader) lookupModule(name, extension string, meta map[string]any) (string, error) {
|
|
paths := l.paths
|
|
if path, ok := meta["search"].(string); ok {
|
|
if path = resolvePath(path, ""); path != "" {
|
|
paths = append([]string{path}, paths...)
|
|
}
|
|
}
|
|
for _, base := range paths {
|
|
path := filepath.Join(base, name+extension)
|
|
if _, err := os.Stat(path); err == nil {
|
|
return path, err
|
|
}
|
|
path = filepath.Join(base, name, filepath.Base(name)+extension)
|
|
if _, err := os.Stat(path); err == nil {
|
|
return path, err
|
|
}
|
|
}
|
|
return "", fmt.Errorf("module not found: %q", name)
|
|
}
|
|
|
|
func parseModule(cnt, dir string) (*Query, error) {
|
|
q, err := Parse(cnt)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, i := range q.Imports {
|
|
if i.Meta != nil {
|
|
for _, e := range i.Meta.KeyVals {
|
|
if e.Key == "search" || e.KeyString == "search" {
|
|
if path, ok := e.Val.toString(); ok {
|
|
if path = resolvePath(path, dir); path != "" {
|
|
e.Val.Str = path
|
|
} else {
|
|
e.Val.Null = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return q, nil
|
|
}
|
|
|
|
func resolvePath(path, dir string) string {
|
|
switch {
|
|
case filepath.IsAbs(path):
|
|
return path
|
|
case strings.HasPrefix(path, "~/"):
|
|
dir, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return filepath.Join(dir, path[2:])
|
|
case strings.HasPrefix(path, "$ORIGIN/"):
|
|
exe, err := os.Executable()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
exe, err = filepath.EvalSymlinks(exe)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return filepath.Join(filepath.Dir(exe), path[8:])
|
|
default:
|
|
return filepath.Join(dir, path)
|
|
}
|
|
}
|