Skip to content

Commit e88a572

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

File tree

2 files changed

+147
-8
lines changed

2 files changed

+147
-8
lines changed

cli/daemon/run/embedded_files.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package run
2+
3+
import (
4+
"encr.dev/pkg/watcher"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
)
10+
11+
var embeddedFiles = make(map[string][]string)
12+
13+
// ignoreEventEmbedded checks whether the event is related to an embedded file
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+
return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
46+
if err != nil || info.IsDir() || filepath.Ext(path) != ".go" {
47+
return err
48+
}
49+
return updateEmbeddedFiles(path)
50+
})
51+
}
52+
53+
func handleCreatedFile(path string) error {
54+
if strings.HasSuffix(path, ".go") {
55+
return updateEmbeddedFiles(path)
56+
}
57+
return nil
58+
}
59+
60+
func handleDeletedFile(path string) error {
61+
delete(embeddedFiles, path)
62+
return nil
63+
}
64+
65+
func isFileEmbedded(fpath string) (bool, error) {
66+
for _, files := range embeddedFiles {
67+
for _, file := range files {
68+
if file == fpath {
69+
return true, nil
70+
}
71+
}
72+
}
73+
return false, nil
74+
}
75+
76+
func updateEmbeddedFiles(path string) error {
77+
embeds, err := parseEmbeddedFiles(path)
78+
if err != nil {
79+
return fmt.Errorf("failed to parse embedded files: %w", err)
80+
}
81+
embeddedFiles[path] = embeds
82+
return nil
83+
}
84+
85+
// parseEmbeddedFiles returns all the embedded files for a given source file
86+
func parseEmbeddedFiles(sourceFile string) ([]string, error) {
87+
data, err := os.ReadFile(sourceFile)
88+
if err != nil {
89+
return nil, fmt.Errorf("failed to read source file: %w", err)
90+
}
91+
92+
var embeddedPaths []string
93+
sourceDir := filepath.Dir(sourceFile)
94+
lines := strings.Split(string(data), "\n")
95+
96+
for _, line := range lines {
97+
line = strings.TrimSpace(line)
98+
if strings.HasPrefix(line, "//go:embed") {
99+
parts := strings.Fields(line)
100+
if len(parts) > 1 {
101+
dir := parts[1]
102+
filepaths, err := getFilePathsFromDir(filepath.Join(sourceDir, dir))
103+
if err != nil {
104+
return nil, err
105+
}
106+
embeddedPaths = append(embeddedPaths, filepaths...)
107+
}
108+
}
109+
}
110+
return embeddedPaths, nil
111+
}
112+
113+
// getFilePathsFromDir retrieves all file paths from a directory recursively
114+
func getFilePathsFromDir(dir string) ([]string, error) {
115+
var filePaths []string
116+
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
117+
if err != nil || info.IsDir() {
118+
return err
119+
}
120+
filePaths = append(filePaths, path)
121+
return nil
122+
})
123+
if err != nil {
124+
return nil, fmt.Errorf("failed to walk through directory %s: %w", dir, err)
125+
}
126+
return filePaths, nil
127+
}

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)