Skip to content

Commit 8d4daf6

Browse files
author
Tony Worm
committed
hof/runtime: add support for loading user files
1 parent 9a49fa7 commit 8d4daf6

File tree

8 files changed

+140
-24
lines changed

8 files changed

+140
-24
lines changed

.hof/shadow/cli/cmd/hof/flags/root.go

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type RootPflagpole struct {
1818
IncludeData bool
1919
WithContext bool
2020
InjectEnv bool
21+
UserFiles []string
2122
AllErrors bool
2223
IngoreErrors bool
2324
Stats bool
@@ -37,6 +38,7 @@ func SetupRootPflags(fset *pflag.FlagSet, fpole *RootPflagpole) {
3738
fset.BoolVarP(&(fpole.IncludeData), "include-data", "D", false, "auto include all data files found with cue files")
3839
fset.BoolVarP(&(fpole.WithContext), "with-context", "", false, "add extra context for data files, usable in the -l/path flag")
3940
fset.BoolVarP(&(fpole.InjectEnv), "inject-env", "V", false, "inject all ENV VARs as default tag vars")
41+
fset.StringArrayVarP(&(fpole.UserFiles), "user-files", "U", nil, "file globs to embed into the root value")
4042
fset.BoolVarP(&(fpole.AllErrors), "all-errors", "E", false, "print all available errors")
4143
fset.BoolVarP(&(fpole.IngoreErrors), "ignore-errors", "i", false, "turn off output and assume defaults at prompts")
4244
fset.BoolVarP(&(fpole.Stats), "stats", "", false, "print generator statistics")

cmd/hof/flags/root.go

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type RootPflagpole struct {
1818
IncludeData bool
1919
WithContext bool
2020
InjectEnv bool
21+
UserFiles []string
2122
AllErrors bool
2223
IngoreErrors bool
2324
Stats bool
@@ -37,6 +38,7 @@ func SetupRootPflags(fset *pflag.FlagSet, fpole *RootPflagpole) {
3738
fset.BoolVarP(&(fpole.IncludeData), "include-data", "D", false, "auto include all data files found with cue files")
3839
fset.BoolVarP(&(fpole.WithContext), "with-context", "", false, "add extra context for data files, usable in the -l/path flag")
3940
fset.BoolVarP(&(fpole.InjectEnv), "inject-env", "V", false, "inject all ENV VARs as default tag vars")
41+
fset.StringArrayVarP(&(fpole.UserFiles), "user-files", "U", nil, "file globs to embed into the root value")
4042
fset.BoolVarP(&(fpole.AllErrors), "all-errors", "E", false, "print all available errors")
4143
fset.BoolVarP(&(fpole.IngoreErrors), "ignore-errors", "i", false, "turn off output and assume defaults at prompts")
4244
fset.BoolVarP(&(fpole.Stats), "stats", "", false, "print generator statistics")

design/pflags.cue

+7
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ CliPflags: [...schema.Flag] & [ {
6767
Type: "bool"
6868
Default: ""
6969
Help: "inject all ENV VARs as default tag vars"
70+
}, {
71+
Name: "UserFiles"
72+
Long: "user-files"
73+
Short: "U"
74+
Type: "[]string"
75+
Default: "nil"
76+
Help: "file globs to embed into the root value"
7077
}, {
7178
Name: "AllErrors"
7279
Long: "all-errors"

lib/runtime/load.go

+113-23
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ func (R *Runtime) Load() (err error) {
4747
return err
4848
}
4949

50+
err = R.prepPlacedUserfiles()
51+
if err != nil {
52+
return err
53+
}
54+
5055
if !R.Flags.IngoreErrors {
5156
err = R.Value.Validate()
5257
if err != nil {
@@ -93,7 +98,7 @@ func (R *Runtime) prepPlacedDatafiles() {
9398
fname, fpath := parts[0], parts[1]
9499
R.dataMappings[fname] = fpath
95100
entries = append(entries, fname)
96-
continue
101+
continue
97102
}
98103
}
99104

@@ -108,6 +113,113 @@ func (R *Runtime) prepPlacedDatafiles() {
108113
R.Entrypoints = entries
109114
}
110115

116+
func (R *Runtime) prepPlacedUserfiles() error {
117+
start := time.Now()
118+
defer func() {
119+
end := time.Now()
120+
R.Stats.Add("files/load", end.Sub(start))
121+
}()
122+
123+
buildFile := func (trimPath, filePath string) (*ast.Field, error) {
124+
// prep inputs
125+
d, err := os.ReadFile(filePath)
126+
if err != nil {
127+
return nil, fmt.Errorf("while loading user file: %w", err)
128+
}
129+
s := string(d)
130+
l := strings.TrimPrefix(filePath, trimPath)
131+
132+
// build file field
133+
ff := new(ast.Field)
134+
ff.Constraint = token.STRING
135+
ff.Label = ast.NewIdent(l)
136+
ff.Value = ast.NewString(s)
137+
138+
return ff, nil
139+
}
140+
141+
embedFiles := func (cuePath, trimPath, filePath string) error {
142+
files := []string{filePath}
143+
// expand globs
144+
if strings.Contains(filePath, "*") {
145+
fs, err := yagu.FilesFromGlobs([]string{filePath})
146+
if err != nil {
147+
return fmt.Errorf("warning: error while globing %q: %v", filePath, err)
148+
}
149+
150+
files = fs
151+
} else {
152+
// maybe handle directory
153+
stat, err := os.Stat(filePath)
154+
if err != nil {
155+
return err
156+
}
157+
158+
if stat.IsDir() {
159+
fs, err := yagu.FilesFromGlobs([]string{filePath + "/*"})
160+
if err != nil {
161+
return fmt.Errorf("warning: error while loading dir %q: %v", filePath, err)
162+
}
163+
164+
files = fs
165+
}
166+
}
167+
168+
fields := []interface{}{}
169+
for _, file := range files {
170+
fld, err := buildFile(trimPath, file)
171+
if err != nil {
172+
return err
173+
}
174+
fields = append(fields, fld)
175+
}
176+
177+
// build CUE struct
178+
st := ast.NewStruct(fields...)
179+
// fmt.Sprintf("%+v\n", st)
180+
181+
cp := cue.ParsePath(cuePath)
182+
R.Value = R.Value.FillPath(cp, st)
183+
184+
return nil
185+
}
186+
187+
// handle the flag for placing user files
188+
for _, U := range R.Flags.UserFiles {
189+
// fmt.Println(U)
190+
parts := strings.Split(U, "=")
191+
if len(parts) != 2 {
192+
return fmt.Errorf("-U/--user-files flag should have format <cue-path>=<glob>")
193+
}
194+
195+
cuePath, filePath := parts[0], parts[1]
196+
197+
trimPath := ""
198+
if strings.Contains(filePath, "%") {
199+
parts := strings.Split(filePath, "%")
200+
if len(parts) != 2 {
201+
return fmt.Errorf("-U/--user-files only supports one % to trim prefix")
202+
}
203+
trimPath = parts[0] + "/"
204+
filePath = strings.Replace(filePath, "%", "/", 1)
205+
}
206+
207+
err := embedFiles(cuePath, trimPath, filePath)
208+
if err != nil {
209+
return err
210+
}
211+
}
212+
213+
// look for @userfiles attributes and do similar
214+
215+
if R.Flags.Verbosity > 1 {
216+
fmt.Println("user files:", R.userFiles)
217+
fmt.Println("mod files: ", R.modFiles)
218+
}
219+
220+
return nil
221+
}
222+
111223
func (R *Runtime) load() (err error) {
112224
beg := time.Now()
113225
defer func() {
@@ -133,28 +245,6 @@ func (R *Runtime) load() (err error) {
133245
R.Entrypoints = append(R.Entrypoints, "-")
134246
}
135247

136-
// fi, err := os.Stdin.Stat()
137-
138-
//if fi.Size() == 0 {
139-
// fmt.Println("stdin(0)...")
140-
// R.CueConfig.Stdin = &bytes.Buffer{}
141-
142-
//} else {
143-
// d, err := io.ReadAll(os.Stdin)
144-
// if err != nil {
145-
// return err
146-
// }
147-
// r := bytes.NewReader(d)
148-
// fmt.Println(len(d), r.Len(), r.Size(), fi.Size())
149-
// R.CueConfig.Stdin = r
150-
151-
// //if .... {
152-
// //fmt.Println("no stdin...")
153-
// //}
154-
// // R.CueConfig.Stdin = os.Stdin
155-
//}
156-
157-
158248
//
159249
//
160250
// load instances from entrypoints and config, this is the main CUE loader step

lib/runtime/runtime.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ type Runtime struct {
5757
dataMappings map[string]string
5858

5959
// internal bookkeeping
60-
loadedFiles []string
60+
loadedFiles []string // cue+data (?)
61+
62+
// non-data files loaded <cue-path> => <file-path>
63+
userFiles map[string]string // non-data files loaded by user
64+
modFiles map[string]string // non-data files loaded by modules
6165

6266
// The CUE value after all loading
6367
Value cue.Value
@@ -112,6 +116,8 @@ func New(entrypoints []string, rflags flags.RootPflagpole) (*Runtime, error) {
112116
origEntrypoints: entrypoints,
113117
CueConfig: cfg,
114118
dataMappings: make(map[string]string),
119+
userFiles: make(map[string]string),
120+
modFiles: make(map[string]string),
115121
Stats: make(RuntimeStats),
116122
}
117123

test/userfiles/content/cow.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mooooo

test/userfiles/content/foo.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Foo
2+
3+
bar

test/userfiles/main.cue

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package main
2+
3+
hello: "world"
4+
5+
files: {}

0 commit comments

Comments
 (0)