Skip to content

Commit 2280480

Browse files
committed
cli/daemon: support watching embedded files
1 parent 5b7c86d commit 2280480

File tree

2 files changed

+148
-8
lines changed

2 files changed

+148
-8
lines changed

cli/daemon/run/embedded_files.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package run
2+
3+
import (
4+
"encr.dev/pkg/watcher"
5+
"fmt"
6+
"log"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
)
11+
12+
var embeddedFiles = make(map[string][]string)
13+
14+
func IgnoreEventEmbedded(event watcher.Event) (bool, error) {
15+
switch event.EventType {
16+
case watcher.CREATED:
17+
return true, handleCreatedFile(event.Path)
18+
case watcher.DELETED:
19+
return true, handleDeletedFile(event.Path)
20+
case watcher.MODIFIED:
21+
return handleModifiedFile(event.Path)
22+
default:
23+
return true, nil
24+
}
25+
}
26+
27+
func handleModifiedFile(path string) (bool, error) {
28+
if strings.HasSuffix(path, ".go") {
29+
return true, updateEmbeddedFiles(path)
30+
}
31+
32+
embedded, err := isFileEmbedded(path)
33+
if err != nil {
34+
return true, err
35+
}
36+
37+
return !embedded, nil
38+
}
39+
40+
func initializeEmbeddedFilesTracker(root string) error {
41+
if len(embeddedFiles) > 0 {
42+
return nil
43+
}
44+
45+
log.Printf("Initializing embedded files: %v", root)
46+
return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
47+
if err != nil || info.IsDir() || filepath.Ext(path) != ".go" {
48+
return err
49+
}
50+
return updateEmbeddedFiles(path)
51+
})
52+
}
53+
54+
func handleCreatedFile(path string) error {
55+
if strings.HasSuffix(path, ".go") {
56+
return updateEmbeddedFiles(path)
57+
}
58+
return nil
59+
}
60+
61+
func handleDeletedFile(path string) error {
62+
delete(embeddedFiles, path)
63+
return nil
64+
}
65+
66+
func isFileEmbedded(fpath string) (bool, error) {
67+
for _, files := range embeddedFiles {
68+
for _, file := range files {
69+
if file == fpath {
70+
return true, nil
71+
}
72+
}
73+
}
74+
return false, nil
75+
}
76+
77+
func updateEmbeddedFiles(path string) error {
78+
embeds, err := parseEmbeddedFiles(path)
79+
if err != nil {
80+
return fmt.Errorf("failed to parse embedded files: %w", err)
81+
}
82+
embeddedFiles[path] = embeds
83+
return nil
84+
}
85+
86+
// parseEmbeddedFiles returns all the embedded files for a given source file
87+
func parseEmbeddedFiles(sourceFile string) ([]string, error) {
88+
data, err := os.ReadFile(sourceFile)
89+
if err != nil {
90+
return nil, fmt.Errorf("failed to read source file: %w", err)
91+
}
92+
93+
var embeddedPaths []string
94+
sourceDir := filepath.Dir(sourceFile)
95+
lines := strings.Split(string(data), "\n")
96+
97+
for _, line := range lines {
98+
line = strings.TrimSpace(line)
99+
if strings.HasPrefix(line, "//go:embed") {
100+
parts := strings.Fields(line)
101+
if len(parts) > 1 {
102+
dir := parts[1]
103+
filepaths, err := getFilePathsFromDir(filepath.Join(sourceDir, dir))
104+
if err != nil {
105+
return nil, err
106+
}
107+
embeddedPaths = append(embeddedPaths, filepaths...)
108+
}
109+
}
110+
}
111+
return embeddedPaths, nil
112+
}
113+
114+
// getFilePathsFromDir retrieves all file paths from a directory recursively
115+
func getFilePathsFromDir(dir string) ([]string, error) {
116+
var filePaths []string
117+
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
118+
if err != nil || info.IsDir() {
119+
return err
120+
}
121+
filePaths = append(filePaths, path)
122+
return nil
123+
})
124+
if err != nil {
125+
return nil, fmt.Errorf("failed to walk through directory %s: %w", dir, err)
126+
}
127+
return filePaths, nil
128+
}

cli/daemon/run/watch.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ import (
1111
// watch watches the given app for changes, and reports
1212
// them on c.
1313
func (mgr *Manager) watch(run *Run) error {
14+
15+
// Initialize embedded files tracker
16+
if err := initializeEmbeddedFilesTracker(run.App.Root()); err != nil {
17+
return err
18+
}
19+
1420
sub, err := run.App.Watch(func(i *apps.Instance, event []watcher.Event) {
1521
if IgnoreEvents(event) {
1622
return
@@ -44,23 +50,29 @@ func (mgr *Manager) watch(run *Run) error {
4450
}
4551

4652
// IgnoreEvents will return true if _all_ events are on files that should be ignored
47-
// as the do not impact the running app, or are the result of Encore itself generating code.
53+
// as they do not impact the running app, or are the result of Encore itself generating code.
4854
func IgnoreEvents(events []watcher.Event) bool {
4955
for _, event := range events {
50-
if !ignoreEvent(event) {
56+
filename := filepath.Base(event.Path)
57+
if strings.HasPrefix(strings.ToLower(filename), "encore.gen.") ||
58+
strings.HasSuffix(filename, "~") {
59+
// Ignore generated code and temporary files
60+
return true
61+
}
62+
63+
ignore, err := IgnoreEventEmbedded(event)
64+
if err != nil {
65+
return false
66+
}
67+
68+
if !ignoreEvent(event) || !ignore {
5169
return false
5270
}
5371
}
5472
return true
5573
}
5674

5775
func ignoreEvent(ev watcher.Event) bool {
58-
filename := filepath.Base(ev.Path)
59-
if strings.HasPrefix(strings.ToLower(filename), "encore.gen.") {
60-
// Ignore generated code
61-
return true
62-
}
63-
6476
// Ignore files which wouldn't impact the running app
6577
ext := filepath.Ext(ev.Path)
6678
switch ext {

0 commit comments

Comments
 (0)