this repo has no description
1package processor
2
3import (
4 "fmt"
5 "os"
6
7 "github.com/aottr/nox/internal/cache"
8 "github.com/aottr/nox/internal/config"
9 "github.com/aottr/nox/internal/crypto"
10 "github.com/aottr/nox/internal/git"
11 "github.com/aottr/nox/internal/logging"
12 "github.com/aottr/nox/internal/state"
13)
14
15func SyncApp(ctx *config.RuntimeContext) error {
16
17 log := logging.Get()
18 var err error
19 cfg, appName, identities, st := ctx.Config, ctx.App, ctx.Identities, ctx.State
20
21 if appName == "" {
22 return fmt.Errorf("app name is required")
23 }
24
25 // retrieve app config and repository
26 app := cfg.Apps[appName]
27 gitConf := app.GitConfig
28 if !gitConf.IsValid() {
29 gitConf = cfg.GitConfig
30 }
31
32 key := cache.RepoKey{Repo: gitConf.Repo, Branch: gitConf.Branch}
33 repo, err := cache.GlobalCache.GetOrFetch(key)
34 if err != nil {
35 return fmt.Errorf("failed to fetch repo for app %s: %w", appName, err)
36 }
37
38 // iterate over files and decrypt
39 for _, file := range app.Files {
40 content, err := git.GetFileContentFromTree(repo.Tree, file.Path)
41 if err != nil {
42 return fmt.Errorf("failed to get file %s: %w", file, err)
43 }
44
45 hash := state.HashContent(content)
46 cacheKey := state.GenerateKey(appName, file.Path)
47
48 // skip if file is up to date and force is not set
49 if !ctx.Force && !ctx.DryRun {
50 if prevHash, ok := st.Data[cacheKey]; ok && prevHash == hash {
51 log.Debug(fmt.Sprintf("file %s is up to date", file.Path))
52 continue
53 }
54 }
55
56 // decrypt file
57 plaintext, err := crypto.DecryptBytes(content, identities)
58 if err != nil {
59 log.Warn("failed to decrypt file %s: %v", file.Path, err)
60 continue
61 }
62
63 // skip writing file if dry run is set
64 if ctx.DryRun {
65 log.Debug(fmt.Sprintf("dry run, not writing file %s", file.Output))
66 os.Stdout.Write(plaintext)
67 continue
68 }
69 if err := WriteToFile(plaintext, file); err != nil {
70 log.Error("failed to write file %s: %v", file.Output, err)
71 continue
72 }
73
74 log.Debug(fmt.Sprintf("decrypted %s for app %s (size: %d bytes)", file, appName, len(plaintext)))
75
76 // update state
77 st.Data[cacheKey] = hash
78 st.Touch()
79 }
80
81 if err := state.Save(st); err != nil {
82 return fmt.Errorf("failed to save state: %w", err)
83 }
84 return nil
85}
86
87func SyncApps(ctx *config.RuntimeContext) error {
88 for appName := range ctx.Config.Apps {
89 ctx.App = appName
90 logging.Get().Debug(fmt.Sprintf("Processing app: %s", appName))
91 if err := SyncApp(ctx); err != nil {
92 return err
93 }
94 }
95 return nil
96}