@@ -6,11 +6,13 @@ import (
66 "fmt"
77 "os"
88 "os/exec"
9+ "path"
910 "path/filepath"
1011 "strings"
1112)
1213
1314type EnvFile struct {
15+ // TODO: Should use FileName in the struct and derive from the path.
1416 Path string
1517 // Dir is derived from Path, and is not stored in the database.
1618 Dir string
@@ -23,18 +25,25 @@ type EnvFile struct {
2325type EnvFileSyncResult int
2426
2527const (
26- // The struct has been updated from the filesystem
27- // and should be updated in the database.
28- BackedUp EnvFileSyncResult = iota
29- // The filesystem has been restored to match the struct
30- // no further action is required.
31- Restored
32- Error
3328 // The filesystem contents matches the struct
3429 // no further action is required.
35- Noop
30+ Noop EnvFileSyncResult = 0
31+ // The directory changed, but the file contents matched.
32+ // The database must be updated.
33+ DirUpdated EnvFileSyncResult = 1
34+ // The filesystem has been restored to match the struct
35+ // no further action is required.
36+ Restored EnvFileSyncResult = 1 << 1
37+ // The filesystem has been restored to match the struct.
38+ // The directory changed, so the database must be updated
39+ RestoredAndDirUpdated EnvFileSyncResult = Restored | DirUpdated
40+ // The struct has been updated from the filesystem
41+ // and should be updated in the database.
42+ BackedUp EnvFileSyncResult = 1 << 2
43+ Error EnvFileSyncResult = 1 << 3
3644)
3745
46+ // Determines the source of truth when calling [EnvFile.Sync] or [EnvFile.Restore]
3847type syncDirection int
3948
4049const (
@@ -105,18 +114,33 @@ func getGitRemotes(dir string) []string {
105114}
106115
107116// 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
117+ // dir to determine which side to use a the source of truth.
118+ func (f * EnvFile ) sync (dir syncDirection , db * Db ) (result EnvFileSyncResult , err error ) {
119+ if result != Noop {
120+ panic ("Invalid state" )
121+ }
122+
118123 if _ , err := os .Stat (f .Dir ); err != nil {
119- return Error , fmt .Errorf ("directory missing" )
124+ // Directory doesn't exist
125+
126+ var movedDirs []string
127+
128+ if db != nil {
129+ movedDirs , err = db .findMovedDirs (f )
130+ }
131+ if err != nil {
132+ return Error , err
133+ } else {
134+ switch len (movedDirs ) {
135+ case 0 :
136+ return Error , fmt .Errorf ("directory missing" )
137+ case 1 :
138+ f .updateDir (movedDirs [0 ])
139+ result |= DirUpdated
140+ default :
141+ return Error , fmt .Errorf ("multiple directories found" )
142+ }
143+ }
120144 }
121145
122146 if _ , err := os .Stat (f .Path ); err != nil {
@@ -125,7 +149,7 @@ func (f *EnvFile) sync(dir syncDirection) (result EnvFileSyncResult, err error)
125149 return Error , fmt .Errorf ("failed to write file: %w" , err )
126150 }
127151
128- return Restored , err
152+ return result | Restored , nil
129153 } else {
130154 return Error , err
131155 }
@@ -141,14 +165,16 @@ func (f *EnvFile) sync(dir syncDirection) (result EnvFileSyncResult, err error)
141165
142166 // Compare the hashes
143167 if currentSha == f .Sha256 {
144- return Noop , nil
168+ // No op, or DirUpdated
169+ return result , nil
145170 } else {
146171 switch dir {
147172 case TrustDatabase :
148173 if err := os .WriteFile (f .Path , []byte (f .contents ), 0644 ); err != nil {
149174 return Error , fmt .Errorf ("failed to write file: %w" , err )
150175 }
151- return Restored , nil
176+
177+ return result | Restored , nil
152178 case TrustFilesystem :
153179 // Overwrite the database
154180 if err = f .Backup (); err != nil {
@@ -163,17 +189,38 @@ func (f *EnvFile) sync(dir syncDirection) (result EnvFileSyncResult, err error)
163189 }
164190}
165191
192+ func (f * EnvFile ) sharesRemote (remotes []string ) bool {
193+ rMap := make (map [string ]bool )
194+ for _ , remote := range f .Remotes {
195+ rMap [remote ] = true
196+ }
197+
198+ for _ , remote := range remotes {
199+ if rMap [remote ] {
200+ return true
201+ }
202+ }
203+
204+ return false
205+ }
206+
207+ func (f * EnvFile ) updateDir (newDir string ) {
208+ f .Dir = newDir
209+ f .Path = path .Join (newDir , path .Base (f .Path ))
210+ f .Remotes = getGitRemotes (newDir )
211+ }
212+
166213// Try to reconcile the EnvFile with the filesystem.
167214//
168215// If Updated is returned, [Db.Insert] should be called on file.
169216func (file * EnvFile ) Sync () (result EnvFileSyncResult , err error ) {
170- return file .sync (TrustFilesystem )
217+ return file .sync (TrustFilesystem , nil )
171218}
172219
173220// Install the file into the file system. If the file already exists,
174221// it will be overwritten.
175222func (file EnvFile ) Restore () error {
176- _ , err := file .sync (TrustDatabase )
223+ _ , err := file .sync (TrustDatabase , nil )
177224
178225 return err
179226}
0 commit comments