@@ -13,7 +13,6 @@ import (
1313 "github.com/openbootdotdev/openboot/internal/system"
1414)
1515
16- // Capture orchestrates a full environment snapshot.
1716func Capture () (* Snapshot , error ) {
1817 hostname , err := os .Hostname ()
1918 if err != nil {
@@ -92,134 +91,55 @@ type ScanStep struct {
9291 Count int `json:"count"` // items found (only meaningful on "done")
9392}
9493
95- // CaptureWithProgress orchestrates a full environment snapshot with progress callbacks.
96- // The callback is invoked before and after each capture step.
97- // If callback is nil, it is not invoked.
94+ type captureStep struct {
95+ name string
96+ capture func () (interface {}, error )
97+ count func (interface {}) int
98+ }
99+
98100func CaptureWithProgress (callback func (step ScanStep )) (* Snapshot , error ) {
99101 hostname , err := os .Hostname ()
100102 if err != nil {
101103 hostname = "unknown"
102104 }
103105
104- // Step 0: Homebrew Formulae
105- if callback != nil {
106- callback (ScanStep {Name : "Homebrew Formulae" , Index : 0 , Total : 8 , Status : "scanning" , Count : 0 })
107- }
108- formulae , err := CaptureFormulae ()
109- if err != nil {
110- if callback != nil {
111- callback (ScanStep {Name : "Homebrew Formulae" , Index : 0 , Total : 8 , Status : "error" , Count : 0 })
112- }
113- } else {
114- if callback != nil {
115- callback (ScanStep {Name : "Homebrew Formulae" , Index : 0 , Total : 8 , Status : "done" , Count : len (formulae )})
116- }
117- }
118-
119- // Step 1: Homebrew Casks
120- if callback != nil {
121- callback (ScanStep {Name : "Homebrew Casks" , Index : 1 , Total : 8 , Status : "scanning" , Count : 0 })
122- }
123- casks , err := CaptureCasks ()
124- if err != nil {
125- if callback != nil {
126- callback (ScanStep {Name : "Homebrew Casks" , Index : 1 , Total : 8 , Status : "error" , Count : 0 })
127- }
128- } else {
129- if callback != nil {
130- callback (ScanStep {Name : "Homebrew Casks" , Index : 1 , Total : 8 , Status : "done" , Count : len (casks )})
131- }
132- }
133-
134- // Step 2: Homebrew Taps
135- if callback != nil {
136- callback (ScanStep {Name : "Homebrew Taps" , Index : 2 , Total : 8 , Status : "scanning" , Count : 0 })
137- }
138- taps , err := CaptureTaps ()
139- if err != nil {
140- if callback != nil {
141- callback (ScanStep {Name : "Homebrew Taps" , Index : 2 , Total : 8 , Status : "error" , Count : 0 })
142- }
143- } else {
144- if callback != nil {
145- callback (ScanStep {Name : "Homebrew Taps" , Index : 2 , Total : 8 , Status : "done" , Count : len (taps )})
146- }
147- }
148-
149- // Step 3: NPM Global Packages
150- if callback != nil {
151- callback (ScanStep {Name : "NPM Global Packages" , Index : 3 , Total : 8 , Status : "scanning" , Count : 0 })
152- }
153- npmPkgs , err := CaptureNpm ()
154- if err != nil {
155- if callback != nil {
156- callback (ScanStep {Name : "NPM Global Packages" , Index : 3 , Total : 8 , Status : "error" , Count : 0 })
157- }
158- } else {
159- if callback != nil {
160- callback (ScanStep {Name : "NPM Global Packages" , Index : 3 , Total : 8 , Status : "done" , Count : len (npmPkgs )})
161- }
106+ steps := []captureStep {
107+ {"Homebrew Formulae" , func () (interface {}, error ) { return CaptureFormulae () }, func (v interface {}) int { return len (v .([]string )) }},
108+ {"Homebrew Casks" , func () (interface {}, error ) { return CaptureCasks () }, func (v interface {}) int { return len (v .([]string )) }},
109+ {"Homebrew Taps" , func () (interface {}, error ) { return CaptureTaps () }, func (v interface {}) int { return len (v .([]string )) }},
110+ {"NPM Global Packages" , func () (interface {}, error ) { return CaptureNpm () }, func (v interface {}) int { return len (v .([]string )) }},
111+ {"macOS Preferences" , func () (interface {}, error ) { return CaptureMacOSPrefs () }, func (v interface {}) int { return len (v .([]MacOSPref )) }},
112+ {"Shell Environment" , func () (interface {}, error ) { return CaptureShell () }, func (v interface {}) int { return 1 }},
113+ {"Git Configuration" , func () (interface {}, error ) { return CaptureGit () }, func (v interface {}) int { return 1 }},
114+ {"Dev Tools" , func () (interface {}, error ) { return CaptureDevTools () }, func (v interface {}) int { return len (v .([]DevTool )) }},
162115 }
163116
164- // Step 4: macOS Preferences
165- if callback != nil {
166- callback (ScanStep {Name : "macOS Preferences" , Index : 4 , Total : 8 , Status : "scanning" , Count : 0 })
167- }
168- prefs , err := CaptureMacOSPrefs ()
169- if err != nil {
170- if callback != nil {
171- callback (ScanStep {Name : "macOS Preferences" , Index : 4 , Total : 8 , Status : "error" , Count : 0 })
172- }
173- } else {
117+ results := make ([]interface {}, len (steps ))
118+ for i , step := range steps {
174119 if callback != nil {
175- callback (ScanStep {Name : "macOS Preferences" , Index : 4 , Total : 8 , Status : "done " , Count : len ( prefs ) })
120+ callback (ScanStep {Name : step . name , Index : i , Total : len ( steps ) , Status : "scanning " , Count : 0 })
176121 }
177- }
178122
179- // Step 5: Shell Environment
180- if callback != nil {
181- callback (ScanStep {Name : "Shell Environment" , Index : 5 , Total : 8 , Status : "scanning" , Count : 0 })
182- }
183- shellSnap , err := CaptureShell ()
184- if err != nil {
185- if callback != nil {
186- callback (ScanStep {Name : "Shell Environment" , Index : 5 , Total : 8 , Status : "error" , Count : 0 })
187- }
188- } else {
189- if callback != nil {
190- callback (ScanStep {Name : "Shell Environment" , Index : 5 , Total : 8 , Status : "done" , Count : 1 })
191- }
192- }
123+ result , err := step .capture ()
124+ results [i ] = result
193125
194- // Step 6: Git Configuration
195- if callback != nil {
196- callback (ScanStep {Name : "Git Configuration" , Index : 6 , Total : 8 , Status : "scanning" , Count : 0 })
197- }
198- gitSnap , err := CaptureGit ()
199- if err != nil {
200- if callback != nil {
201- callback (ScanStep {Name : "Git Configuration" , Index : 6 , Total : 8 , Status : "error" , Count : 0 })
202- }
203- } else {
204126 if callback != nil {
205- callback (ScanStep {Name : "Git Configuration" , Index : 6 , Total : 8 , Status : "done" , Count : 1 })
127+ if err != nil {
128+ callback (ScanStep {Name : step .name , Index : i , Total : len (steps ), Status : "error" , Count : 0 })
129+ } else {
130+ callback (ScanStep {Name : step .name , Index : i , Total : len (steps ), Status : "done" , Count : step .count (result )})
131+ }
206132 }
207133 }
208134
209- // Step 7: Dev Tools
210- if callback != nil {
211- callback (ScanStep {Name : "Dev Tools" , Index : 7 , Total : 8 , Status : "scanning" , Count : 0 })
212- }
213- devTools , err := CaptureDevTools ()
214- if err != nil {
215- if callback != nil {
216- callback (ScanStep {Name : "Dev Tools" , Index : 7 , Total : 8 , Status : "error" , Count : 0 })
217- }
218- } else {
219- if callback != nil {
220- callback (ScanStep {Name : "Dev Tools" , Index : 7 , Total : 8 , Status : "done" , Count : len (devTools )})
221- }
222- }
135+ formulae := results [0 ].([]string )
136+ casks := results [1 ].([]string )
137+ taps := results [2 ].([]string )
138+ npmPkgs := results [3 ].([]string )
139+ prefs := results [4 ].([]MacOSPref )
140+ shellSnap := results [5 ].(* ShellSnapshot )
141+ gitSnap := results [6 ].(* GitSnapshot )
142+ devTools := results [7 ].([]DevTool )
223143
224144 return & Snapshot {
225145 Version : 1 ,
@@ -284,7 +204,7 @@ func isBrewInstalled() bool {
284204 return err == nil
285205}
286206
287- // CaptureFormulae returns user-intentional formulae via `brew leaves`.
207+ // CaptureFormulae returns user-installed formulae ( via `brew leaves`, excludes dependencies) .
288208func CaptureFormulae () ([]string , error ) {
289209 if ! isBrewInstalled () {
290210 return []string {}, nil
@@ -299,7 +219,6 @@ func CaptureFormulae() ([]string, error) {
299219 return parseLines (string (output )), nil
300220}
301221
302- // CaptureCasks returns installed casks via `brew list --cask`.
303222func CaptureCasks () ([]string , error ) {
304223 if ! isBrewInstalled () {
305224 return []string {}, nil
@@ -314,7 +233,6 @@ func CaptureCasks() ([]string, error) {
314233 return parseLines (string (output )), nil
315234}
316235
317- // CaptureTaps returns active Homebrew taps.
318236func CaptureTaps () ([]string , error ) {
319237 if ! isBrewInstalled () {
320238 return []string {}, nil
@@ -329,7 +247,6 @@ func CaptureTaps() ([]string, error) {
329247 return parseLines (string (output )), nil
330248}
331249
332- // CaptureMacOSPrefs reads the current values of whitelisted macOS preferences.
333250func CaptureMacOSPrefs () ([]MacOSPref , error ) {
334251 prefs := []MacOSPref {}
335252
@@ -351,7 +268,6 @@ func CaptureMacOSPrefs() ([]MacOSPref, error) {
351268 return prefs , nil
352269}
353270
354- // CaptureShell detects the default shell, Oh-My-Zsh, plugins, and theme.
355271func CaptureShell () (* ShellSnapshot , error ) {
356272 snap := & ShellSnapshot {
357273 Default : os .Getenv ("SHELL" ),
@@ -393,7 +309,6 @@ func CaptureShell() (*ShellSnapshot, error) {
393309 return snap , nil
394310}
395311
396- // CaptureGit reads global git user.name and user.email.
397312func CaptureGit () (* GitSnapshot , error ) {
398313 snap := & GitSnapshot {}
399314
@@ -408,7 +323,7 @@ func CaptureGit() (*GitSnapshot, error) {
408323 return snap , nil
409324}
410325
411- // RestoreGit writes global git user.name and user. email from a snapshot, skipping values already configured.
326+ // RestoreGit sets git user.name/ email if not already configured.
412327func RestoreGit (git GitSnapshot ) error {
413328 existingName , existingEmail := system .GetExistingGitConfig ()
414329
@@ -444,7 +359,6 @@ var devToolCommands = []struct {
444359 {"docker" , []string {"--version" }},
445360}
446361
447- // CaptureDevTools detects installed development tools and their versions.
448362func CaptureDevTools () ([]DevTool , error ) {
449363 tools := []DevTool {}
450364
0 commit comments