@@ -2,6 +2,7 @@ package app
22
33import (
44 "crypto/sha256"
5+ "errors"
56 "fmt"
67 "os"
78 "os/exec"
@@ -24,7 +25,7 @@ type EnvFileSyncResult int
2425const (
2526 // The struct has been updated from the filesystem
2627 // and should be updated in the database.
27- Updated EnvFileSyncResult = iota
28+ BackedUp EnvFileSyncResult = iota
2829 // The filesystem has been restored to match the struct
2930 // no further action is required.
3031 Restored
@@ -34,6 +35,13 @@ const (
3435 Noop
3536)
3637
38+ type syncDirection int
39+
40+ const (
41+ TrustDatabase syncDirection = iota
42+ TrustFilesystem
43+ )
44+
3745func NewEnvFile (path string ) EnvFile {
3846 // Get absolute path and directory
3947 absPath , err := filepath .Abs (path )
@@ -96,85 +104,78 @@ func getGitRemotes(dir string) []string {
96104 return remotes
97105}
98106
99- // Try to reconcile the EnvFile with the filesystem.
100- //
101- // If Updated is returned, [Db.Insert] should be called on file.
102- func (file * EnvFile ) Sync () (result EnvFileSyncResult , err error ) {
103- // TODO: If the directory doesn't exist, look for other directories with the same remote(s)
104- // TODO: If one is found, update file.Dir and File.Path
105- // TODO: If nothing if found, return an error
106- // TODO: If more than one is found, return a different error
107-
108- // Check if the path exists in the file system
109- _ , err = os .Stat (file .Path )
110- if err == nil {
111- contents , err := os .ReadFile (file .Path )
107+ // Reconcile the state of the database with the state of the filesystem, using
108+ // dir to determine which side to use a the source of truth
109+ func (f * EnvFile ) sync (dir syncDirection ) (result EnvFileSyncResult , err error ) {
110+ // How Sync should work
111+ //
112+ // If the directory doesn't exist, look for other directories with the same remote(s)
113+ // -> If one is found, update file.Dir and File.Path, then continue with "changed" flag
114+ // -> If multiple are found, return an error
115+ // -> If none are found, return a different error
116+
117+ // Ensure the directory exists
118+ if _ , err := os .Stat (f .Dir ); err != nil {
119+ return Error , fmt .Errorf ("directory missing" )
120+ }
121+
122+ if _ , err := os .Stat (f .Path ); err != nil {
123+ if errors .Is (err , os .ErrNotExist ) {
124+ if err := os .WriteFile (f .Path , []byte (f .contents ), 0644 ); err != nil {
125+ return Error , fmt .Errorf ("failed to write file: %w" , err )
126+ }
127+
128+ return Restored , err
129+ } else {
130+ return Error , err
131+ }
132+ } else {
133+ // File exists, check its hash
134+ contents , err := os .ReadFile (f .Path )
112135 if err != nil {
113136 return Error , fmt .Errorf ("failed to read file for SHA comparison: %w" , err )
114137 }
115138
116- // Check if sha matches by reading the current file and calculating its hash
117139 hash := sha256 .Sum256 (contents )
118140 currentSha := fmt .Sprintf ("%x" , hash )
119- if file .Sha256 == currentSha {
120- // Nothing to do
141+
142+ // Compare the hashes
143+ if currentSha == f .Sha256 {
121144 return Noop , nil
122145 } else {
123- if err = file .Backup (); err != nil {
124- return Error , err
125- } else {
126- return Updated , nil
146+ switch dir {
147+ case TrustDatabase :
148+ if err := os .WriteFile (f .Path , []byte (f .contents ), 0644 ); err != nil {
149+ return Error , fmt .Errorf ("failed to write file: %w" , err )
150+ }
151+ return Restored , nil
152+ case TrustFilesystem :
153+ // Overwrite the database
154+ if err = f .Backup (); err != nil {
155+ return Error , err
156+ } else {
157+ return BackedUp , nil
158+ }
159+ default :
160+ panic ("unknown sync direction" )
127161 }
128162 }
129- } else {
130- if err = file .Restore (); err != nil {
131- return Error , err
132- } else {
133- return Restored , nil
134- }
135163 }
136164}
137165
166+ // Try to reconcile the EnvFile with the filesystem.
167+ //
168+ // If Updated is returned, [Db.Insert] should be called on file.
169+ func (file * EnvFile ) Sync () (result EnvFileSyncResult , err error ) {
170+ return file .sync (TrustFilesystem )
171+ }
172+
138173// Install the file into the file system. If the file already exists,
139174// it will be overwritten.
140175func (file EnvFile ) Restore () error {
141- // TODO: Duplicate work is being done when called from the Sync function.
142- if _ , err := os .Stat (file .Path ); err == nil {
143- // file already exists
176+ _ , err := file .sync (TrustDatabase )
144177
145- // Read existing file and calculate its hash
146- existingContents , err := os .ReadFile (file .Path )
147- if err != nil {
148- return fmt .Errorf ("failed to read existing file for hash comparison: %w" , err )
149- }
150-
151- hash := sha256 .Sum256 (existingContents )
152- existingSha := fmt .Sprintf ("%x" , hash )
153-
154- if existingSha == file .Sha256 {
155- return fmt .Errorf ("file already exists: %s" , file .Path )
156- } else {
157- if err := os .WriteFile (file .Path , []byte (file .contents ), 0644 ); err != nil {
158- return fmt .Errorf ("failed to write file: %w" , err )
159- }
160-
161- return nil
162- }
163- } else {
164- // file doesn't exist
165-
166- // Ensure the directory exists
167- if _ , err := os .Stat (file .Dir ); err != nil {
168- return fmt .Errorf ("directory missing" )
169- }
170-
171- // Write the contents to the file
172- if err := os .WriteFile (file .Path , []byte (file .contents ), 0644 ); err != nil {
173- return fmt .Errorf ("failed to write file: %w" , err )
174- }
175-
176- return nil
177- }
178+ return err
178179}
179180
180181// Update the EnvFile using the file system.
0 commit comments