detached 11be03a

feat(installer): add network check and improve AUR helper installation

- Add early network connectivity check at welcome screen to fail fast
- Implement hybrid AUR helper installation (Chaotic-AUR fast path + source fallback)
- Add timeout support (10min) for AUR builds to prevent indefinite hangs
- Explicitly install language dependencies (cargo/rust for paru, go for yay)
- Track Chaotic-AUR enablement status for intelligent fallback logic
- Add StateNetworkCheck UI state with spinner and error handling
- Implement ChrootExecWithContext for timeout-aware command execution
- Regenerate mocks for updated interfaces
commit
11be03add53588d039ac3540a9887acdf402b4da
author
bnema · · 2025-10-28 18:58 UTC
parent
52072ec
signature
GPG Unverified2B82207D370127A0 The key is unknown
9 files · +728 -258
M internal/interfaces/interfaces.go +6 -0
@@ -1,6 +1,7 @@
11 package interfaces
22
33 import (
4+ "context"
45 "io"
56 "net/http"
67 "os"
@@ -38,6 +39,7 @@ type ChrootExecutor interface {
3839 ChrootExec(logPath, mountPoint, command string, args ...string) error
3940 ChrootSystemctl(logPath, mountPoint, action, service string) error
4041 ChrootExecWithStdin(logPath, mountPoint, command, stdin string) error
42+ ChrootExecWithContext(ctx context.Context, logPath, mountPoint, command string) error
4143 ChrootPacman(logPath, mountPoint, operation string, packages ...string) error
4244 DownloadAndInstallPackages(logPath, chrootPath string, urls ...string) error
4345 }
@@ -131,6 +133,10 @@ func (d *DefaultChrootExecutor) ChrootExecWithStdin(logPath, mountPoint, command
131133 return system.ChrootExecWithStdin(logPath, mountPoint, command, stdin)
132134 }
133135
136+func (d *DefaultChrootExecutor) ChrootExecWithContext(ctx context.Context, logPath, mountPoint, command string) error {
137+ return system.ChrootExecWithContext(ctx, logPath, mountPoint, command)
138+}
139+
134140 func (d *DefaultChrootExecutor) ChrootPacman(logPath, mountPoint, operation string, packages ...string) error {
135141 return system.ChrootPacman(logPath, mountPoint, operation, packages...)
136142 }
@@ -1,6 +1,7 @@
1 package interfaces1 package interfaces
2 2
3 import (3 import (
4+ "context"
4 "io"5 "io"
5 "net/http"6 "net/http"
6 "os"7 "os"
@@ -38,6 +39,7 @@ type ChrootExecutor interface {
38 ChrootExec(logPath, mountPoint, command string, args ...string) error39 ChrootExec(logPath, mountPoint, command string, args ...string) error
39 ChrootSystemctl(logPath, mountPoint, action, service string) error40 ChrootSystemctl(logPath, mountPoint, action, service string) error
40 ChrootExecWithStdin(logPath, mountPoint, command, stdin string) error41 ChrootExecWithStdin(logPath, mountPoint, command, stdin string) error
42+ ChrootExecWithContext(ctx context.Context, logPath, mountPoint, command string) error
41 ChrootPacman(logPath, mountPoint, operation string, packages ...string) error43 ChrootPacman(logPath, mountPoint, operation string, packages ...string) error
42 DownloadAndInstallPackages(logPath, chrootPath string, urls ...string) error44 DownloadAndInstallPackages(logPath, chrootPath string, urls ...string) error
43 }45 }
@@ -131,6 +133,10 @@ func (d *DefaultChrootExecutor) ChrootExecWithStdin(logPath, mountPoint, command
131 return system.ChrootExecWithStdin(logPath, mountPoint, command, stdin)133 return system.ChrootExecWithStdin(logPath, mountPoint, command, stdin)
132 }134 }
133 135
136+func (d *DefaultChrootExecutor) ChrootExecWithContext(ctx context.Context, logPath, mountPoint, command string) error {
137+ return system.ChrootExecWithContext(ctx, logPath, mountPoint, command)
138+}
139+
134 func (d *DefaultChrootExecutor) ChrootPacman(logPath, mountPoint, operation string, packages ...string) error {140 func (d *DefaultChrootExecutor) ChrootPacman(logPath, mountPoint, operation string, packages ...string) error {
135 return system.ChrootPacman(logPath, mountPoint, operation, packages...)141 return system.ChrootPacman(logPath, mountPoint, operation, packages...)
136 }142 }
A internal/phases/mocks/mock_interfaces.go +477 -0
@@ -0,0 +1,477 @@
1+// Code generated by MockGen. DO NOT EDIT.
2+// Source: internal/interfaces/interfaces.go
3+//
4+// Generated by this command:
5+//
6+// mockgen -source=internal/interfaces/interfaces.go -destination=internal/phases/mocks/mock_interfaces.go -package=mocks
7+//
8+
9+// Package mocks is a generated GoMock package.
10+package mocks
11+
12+import (
13+ context "context"
14+ io "io"
15+ http "net/http"
16+ os "os"
17+ reflect "reflect"
18+
19+ system "github.com/bnema/archup/internal/system"
20+ gomock "go.uber.org/mock/gomock"
21+)
22+
23+// MockFileSystem is a mock of FileSystem interface.
24+type MockFileSystem struct {
25+ ctrl *gomock.Controller
26+ recorder *MockFileSystemMockRecorder
27+ isgomock struct{}
28+}
29+
30+// MockFileSystemMockRecorder is the mock recorder for MockFileSystem.
31+type MockFileSystemMockRecorder struct {
32+ mock *MockFileSystem
33+}
34+
35+// NewMockFileSystem creates a new mock instance.
36+func NewMockFileSystem(ctrl *gomock.Controller) *MockFileSystem {
37+ mock := &MockFileSystem{ctrl: ctrl}
38+ mock.recorder = &MockFileSystemMockRecorder{mock}
39+ return mock
40+}
41+
42+// EXPECT returns an object that allows the caller to indicate expected use.
43+func (m *MockFileSystem) EXPECT() *MockFileSystemMockRecorder {
44+ return m.recorder
45+}
46+
47+// Chmod mocks base method.
48+func (m *MockFileSystem) Chmod(name string, mode os.FileMode) error {
49+ m.ctrl.T.Helper()
50+ ret := m.ctrl.Call(m, "Chmod", name, mode)
51+ ret0, _ := ret[0].(error)
52+ return ret0
53+}
54+
55+// Chmod indicates an expected call of Chmod.
56+func (mr *MockFileSystemMockRecorder) Chmod(name, mode any) *gomock.Call {
57+ mr.mock.ctrl.T.Helper()
58+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chmod", reflect.TypeOf((*MockFileSystem)(nil).Chmod), name, mode)
59+}
60+
61+// Create mocks base method.
62+func (m *MockFileSystem) Create(name string) (io.WriteCloser, error) {
63+ m.ctrl.T.Helper()
64+ ret := m.ctrl.Call(m, "Create", name)
65+ ret0, _ := ret[0].(io.WriteCloser)
66+ ret1, _ := ret[1].(error)
67+ return ret0, ret1
68+}
69+
70+// Create indicates an expected call of Create.
71+func (mr *MockFileSystemMockRecorder) Create(name any) *gomock.Call {
72+ mr.mock.ctrl.T.Helper()
73+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockFileSystem)(nil).Create), name)
74+}
75+
76+// IsNotExist mocks base method.
77+func (m *MockFileSystem) IsNotExist(err error) bool {
78+ m.ctrl.T.Helper()
79+ ret := m.ctrl.Call(m, "IsNotExist", err)
80+ ret0, _ := ret[0].(bool)
81+ return ret0
82+}
83+
84+// IsNotExist indicates an expected call of IsNotExist.
85+func (mr *MockFileSystemMockRecorder) IsNotExist(err any) *gomock.Call {
86+ mr.mock.ctrl.T.Helper()
87+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsNotExist", reflect.TypeOf((*MockFileSystem)(nil).IsNotExist), err)
88+}
89+
90+// MkdirAll mocks base method.
91+func (m *MockFileSystem) MkdirAll(path string, perm os.FileMode) error {
92+ m.ctrl.T.Helper()
93+ ret := m.ctrl.Call(m, "MkdirAll", path, perm)
94+ ret0, _ := ret[0].(error)
95+ return ret0
96+}
97+
98+// MkdirAll indicates an expected call of MkdirAll.
99+func (mr *MockFileSystemMockRecorder) MkdirAll(path, perm any) *gomock.Call {
100+ mr.mock.ctrl.T.Helper()
101+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MkdirAll", reflect.TypeOf((*MockFileSystem)(nil).MkdirAll), path, perm)
102+}
103+
104+// Open mocks base method.
105+func (m *MockFileSystem) Open(name string) (io.ReadCloser, error) {
106+ m.ctrl.T.Helper()
107+ ret := m.ctrl.Call(m, "Open", name)
108+ ret0, _ := ret[0].(io.ReadCloser)
109+ ret1, _ := ret[1].(error)
110+ return ret0, ret1
111+}
112+
113+// Open indicates an expected call of Open.
114+func (mr *MockFileSystemMockRecorder) Open(name any) *gomock.Call {
115+ mr.mock.ctrl.T.Helper()
116+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Open", reflect.TypeOf((*MockFileSystem)(nil).Open), name)
117+}
118+
119+// ReadFile mocks base method.
120+func (m *MockFileSystem) ReadFile(filename string) ([]byte, error) {
121+ m.ctrl.T.Helper()
122+ ret := m.ctrl.Call(m, "ReadFile", filename)
123+ ret0, _ := ret[0].([]byte)
124+ ret1, _ := ret[1].(error)
125+ return ret0, ret1
126+}
127+
128+// ReadFile indicates an expected call of ReadFile.
129+func (mr *MockFileSystemMockRecorder) ReadFile(filename any) *gomock.Call {
130+ mr.mock.ctrl.T.Helper()
131+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadFile", reflect.TypeOf((*MockFileSystem)(nil).ReadFile), filename)
132+}
133+
134+// RemoveAll mocks base method.
135+func (m *MockFileSystem) RemoveAll(path string) error {
136+ m.ctrl.T.Helper()
137+ ret := m.ctrl.Call(m, "RemoveAll", path)
138+ ret0, _ := ret[0].(error)
139+ return ret0
140+}
141+
142+// RemoveAll indicates an expected call of RemoveAll.
143+func (mr *MockFileSystemMockRecorder) RemoveAll(path any) *gomock.Call {
144+ mr.mock.ctrl.T.Helper()
145+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveAll", reflect.TypeOf((*MockFileSystem)(nil).RemoveAll), path)
146+}
147+
148+// Stat mocks base method.
149+func (m *MockFileSystem) Stat(name string) (os.FileInfo, error) {
150+ m.ctrl.T.Helper()
151+ ret := m.ctrl.Call(m, "Stat", name)
152+ ret0, _ := ret[0].(os.FileInfo)
153+ ret1, _ := ret[1].(error)
154+ return ret0, ret1
155+}
156+
157+// Stat indicates an expected call of Stat.
158+func (mr *MockFileSystemMockRecorder) Stat(name any) *gomock.Call {
159+ mr.mock.ctrl.T.Helper()
160+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stat", reflect.TypeOf((*MockFileSystem)(nil).Stat), name)
161+}
162+
163+// WriteFile mocks base method.
164+func (m *MockFileSystem) WriteFile(filename string, data []byte, perm os.FileMode) error {
165+ m.ctrl.T.Helper()
166+ ret := m.ctrl.Call(m, "WriteFile", filename, data, perm)
167+ ret0, _ := ret[0].(error)
168+ return ret0
169+}
170+
171+// WriteFile indicates an expected call of WriteFile.
172+func (mr *MockFileSystemMockRecorder) WriteFile(filename, data, perm any) *gomock.Call {
173+ mr.mock.ctrl.T.Helper()
174+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteFile", reflect.TypeOf((*MockFileSystem)(nil).WriteFile), filename, data, perm)
175+}
176+
177+// MockCommandExecutor is a mock of CommandExecutor interface.
178+type MockCommandExecutor struct {
179+ ctrl *gomock.Controller
180+ recorder *MockCommandExecutorMockRecorder
181+ isgomock struct{}
182+}
183+
184+// MockCommandExecutorMockRecorder is the mock recorder for MockCommandExecutor.
185+type MockCommandExecutorMockRecorder struct {
186+ mock *MockCommandExecutor
187+}
188+
189+// NewMockCommandExecutor creates a new mock instance.
190+func NewMockCommandExecutor(ctrl *gomock.Controller) *MockCommandExecutor {
191+ mock := &MockCommandExecutor{ctrl: ctrl}
192+ mock.recorder = &MockCommandExecutorMockRecorder{mock}
193+ return mock
194+}
195+
196+// EXPECT returns an object that allows the caller to indicate expected use.
197+func (m *MockCommandExecutor) EXPECT() *MockCommandExecutorMockRecorder {
198+ return m.recorder
199+}
200+
201+// Execute mocks base method.
202+func (m *MockCommandExecutor) Execute(name string, args ...string) ([]byte, error) {
203+ m.ctrl.T.Helper()
204+ varargs := []any{name}
205+ for _, a := range args {
206+ varargs = append(varargs, a)
207+ }
208+ ret := m.ctrl.Call(m, "Execute", varargs...)
209+ ret0, _ := ret[0].([]byte)
210+ ret1, _ := ret[1].(error)
211+ return ret0, ret1
212+}
213+
214+// Execute indicates an expected call of Execute.
215+func (mr *MockCommandExecutorMockRecorder) Execute(name any, args ...any) *gomock.Call {
216+ mr.mock.ctrl.T.Helper()
217+ varargs := append([]any{name}, args...)
218+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockCommandExecutor)(nil).Execute), varargs...)
219+}
220+
221+// MockSystemExecutor is a mock of SystemExecutor interface.
222+type MockSystemExecutor struct {
223+ ctrl *gomock.Controller
224+ recorder *MockSystemExecutorMockRecorder
225+ isgomock struct{}
226+}
227+
228+// MockSystemExecutorMockRecorder is the mock recorder for MockSystemExecutor.
229+type MockSystemExecutorMockRecorder struct {
230+ mock *MockSystemExecutor
231+}
232+
233+// NewMockSystemExecutor creates a new mock instance.
234+func NewMockSystemExecutor(ctrl *gomock.Controller) *MockSystemExecutor {
235+ mock := &MockSystemExecutor{ctrl: ctrl}
236+ mock.recorder = &MockSystemExecutorMockRecorder{mock}
237+ return mock
238+}
239+
240+// EXPECT returns an object that allows the caller to indicate expected use.
241+func (m *MockSystemExecutor) EXPECT() *MockSystemExecutorMockRecorder {
242+ return m.recorder
243+}
244+
245+// DetectCPUInfo mocks base method.
246+func (m *MockSystemExecutor) DetectCPUInfo() (*system.CPUInfo, error) {
247+ m.ctrl.T.Helper()
248+ ret := m.ctrl.Call(m, "DetectCPUInfo")
249+ ret0, _ := ret[0].(*system.CPUInfo)
250+ ret1, _ := ret[1].(error)
251+ return ret0, ret1
252+}
253+
254+// DetectCPUInfo indicates an expected call of DetectCPUInfo.
255+func (mr *MockSystemExecutorMockRecorder) DetectCPUInfo() *gomock.Call {
256+ mr.mock.ctrl.T.Helper()
257+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DetectCPUInfo", reflect.TypeOf((*MockSystemExecutor)(nil).DetectCPUInfo))
258+}
259+
260+// RunSimple mocks base method.
261+func (m *MockSystemExecutor) RunSimple(command string, args ...string) system.CommandResult {
262+ m.ctrl.T.Helper()
263+ varargs := []any{command}
264+ for _, a := range args {
265+ varargs = append(varargs, a)
266+ }
267+ ret := m.ctrl.Call(m, "RunSimple", varargs...)
268+ ret0, _ := ret[0].(system.CommandResult)
269+ return ret0
270+}
271+
272+// RunSimple indicates an expected call of RunSimple.
273+func (mr *MockSystemExecutorMockRecorder) RunSimple(command any, args ...any) *gomock.Call {
274+ mr.mock.ctrl.T.Helper()
275+ varargs := append([]any{command}, args...)
276+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunSimple", reflect.TypeOf((*MockSystemExecutor)(nil).RunSimple), varargs...)
277+}
278+
279+// MockChrootExecutor is a mock of ChrootExecutor interface.
280+type MockChrootExecutor struct {
281+ ctrl *gomock.Controller
282+ recorder *MockChrootExecutorMockRecorder
283+ isgomock struct{}
284+}
285+
286+// MockChrootExecutorMockRecorder is the mock recorder for MockChrootExecutor.
287+type MockChrootExecutorMockRecorder struct {
288+ mock *MockChrootExecutor
289+}
290+
291+// NewMockChrootExecutor creates a new mock instance.
292+func NewMockChrootExecutor(ctrl *gomock.Controller) *MockChrootExecutor {
293+ mock := &MockChrootExecutor{ctrl: ctrl}
294+ mock.recorder = &MockChrootExecutorMockRecorder{mock}
295+ return mock
296+}
297+
298+// EXPECT returns an object that allows the caller to indicate expected use.
299+func (m *MockChrootExecutor) EXPECT() *MockChrootExecutorMockRecorder {
300+ return m.recorder
301+}
302+
303+// ChrootExec mocks base method.
304+func (m *MockChrootExecutor) ChrootExec(logPath, mountPoint, command string, args ...string) error {
305+ m.ctrl.T.Helper()
306+ varargs := []any{logPath, mountPoint, command}
307+ for _, a := range args {
308+ varargs = append(varargs, a)
309+ }
310+ ret := m.ctrl.Call(m, "ChrootExec", varargs...)
311+ ret0, _ := ret[0].(error)
312+ return ret0
313+}
314+
315+// ChrootExec indicates an expected call of ChrootExec.
316+func (mr *MockChrootExecutorMockRecorder) ChrootExec(logPath, mountPoint, command any, args ...any) *gomock.Call {
317+ mr.mock.ctrl.T.Helper()
318+ varargs := append([]any{logPath, mountPoint, command}, args...)
319+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChrootExec", reflect.TypeOf((*MockChrootExecutor)(nil).ChrootExec), varargs...)
320+}
321+
322+// ChrootExecWithContext mocks base method.
323+func (m *MockChrootExecutor) ChrootExecWithContext(ctx context.Context, logPath, mountPoint, command string) error {
324+ m.ctrl.T.Helper()
325+ ret := m.ctrl.Call(m, "ChrootExecWithContext", ctx, logPath, mountPoint, command)
326+ ret0, _ := ret[0].(error)
327+ return ret0
328+}
329+
330+// ChrootExecWithContext indicates an expected call of ChrootExecWithContext.
331+func (mr *MockChrootExecutorMockRecorder) ChrootExecWithContext(ctx, logPath, mountPoint, command any) *gomock.Call {
332+ mr.mock.ctrl.T.Helper()
333+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChrootExecWithContext", reflect.TypeOf((*MockChrootExecutor)(nil).ChrootExecWithContext), ctx, logPath, mountPoint, command)
334+}
335+
336+// ChrootExecWithStdin mocks base method.
337+func (m *MockChrootExecutor) ChrootExecWithStdin(logPath, mountPoint, command, stdin string) error {
338+ m.ctrl.T.Helper()
339+ ret := m.ctrl.Call(m, "ChrootExecWithStdin", logPath, mountPoint, command, stdin)
340+ ret0, _ := ret[0].(error)
341+ return ret0
342+}
343+
344+// ChrootExecWithStdin indicates an expected call of ChrootExecWithStdin.
345+func (mr *MockChrootExecutorMockRecorder) ChrootExecWithStdin(logPath, mountPoint, command, stdin any) *gomock.Call {
346+ mr.mock.ctrl.T.Helper()
347+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChrootExecWithStdin", reflect.TypeOf((*MockChrootExecutor)(nil).ChrootExecWithStdin), logPath, mountPoint, command, stdin)
348+}
349+
350+// ChrootPacman mocks base method.
351+func (m *MockChrootExecutor) ChrootPacman(logPath, mountPoint, operation string, packages ...string) error {
352+ m.ctrl.T.Helper()
353+ varargs := []any{logPath, mountPoint, operation}
354+ for _, a := range packages {
355+ varargs = append(varargs, a)
356+ }
357+ ret := m.ctrl.Call(m, "ChrootPacman", varargs...)
358+ ret0, _ := ret[0].(error)
359+ return ret0
360+}
361+
362+// ChrootPacman indicates an expected call of ChrootPacman.
363+func (mr *MockChrootExecutorMockRecorder) ChrootPacman(logPath, mountPoint, operation any, packages ...any) *gomock.Call {
364+ mr.mock.ctrl.T.Helper()
365+ varargs := append([]any{logPath, mountPoint, operation}, packages...)
366+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChrootPacman", reflect.TypeOf((*MockChrootExecutor)(nil).ChrootPacman), varargs...)
367+}
368+
369+// ChrootSystemctl mocks base method.
370+func (m *MockChrootExecutor) ChrootSystemctl(logPath, mountPoint, action, service string) error {
371+ m.ctrl.T.Helper()
372+ ret := m.ctrl.Call(m, "ChrootSystemctl", logPath, mountPoint, action, service)
373+ ret0, _ := ret[0].(error)
374+ return ret0
375+}
376+
377+// ChrootSystemctl indicates an expected call of ChrootSystemctl.
378+func (mr *MockChrootExecutorMockRecorder) ChrootSystemctl(logPath, mountPoint, action, service any) *gomock.Call {
379+ mr.mock.ctrl.T.Helper()
380+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChrootSystemctl", reflect.TypeOf((*MockChrootExecutor)(nil).ChrootSystemctl), logPath, mountPoint, action, service)
381+}
382+
383+// DownloadAndInstallPackages mocks base method.
384+func (m *MockChrootExecutor) DownloadAndInstallPackages(logPath, chrootPath string, urls ...string) error {
385+ m.ctrl.T.Helper()
386+ varargs := []any{logPath, chrootPath}
387+ for _, a := range urls {
388+ varargs = append(varargs, a)
389+ }
390+ ret := m.ctrl.Call(m, "DownloadAndInstallPackages", varargs...)
391+ ret0, _ := ret[0].(error)
392+ return ret0
393+}
394+
395+// DownloadAndInstallPackages indicates an expected call of DownloadAndInstallPackages.
396+func (mr *MockChrootExecutorMockRecorder) DownloadAndInstallPackages(logPath, chrootPath any, urls ...any) *gomock.Call {
397+ mr.mock.ctrl.T.Helper()
398+ varargs := append([]any{logPath, chrootPath}, urls...)
399+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownloadAndInstallPackages", reflect.TypeOf((*MockChrootExecutor)(nil).DownloadAndInstallPackages), varargs...)
400+}
401+
402+// MockHTTPClient is a mock of HTTPClient interface.
403+type MockHTTPClient struct {
404+ ctrl *gomock.Controller
405+ recorder *MockHTTPClientMockRecorder
406+ isgomock struct{}
407+}
408+
409+// MockHTTPClientMockRecorder is the mock recorder for MockHTTPClient.
410+type MockHTTPClientMockRecorder struct {
411+ mock *MockHTTPClient
412+}
413+
414+// NewMockHTTPClient creates a new mock instance.
415+func NewMockHTTPClient(ctrl *gomock.Controller) *MockHTTPClient {
416+ mock := &MockHTTPClient{ctrl: ctrl}
417+ mock.recorder = &MockHTTPClientMockRecorder{mock}
418+ return mock
419+}
420+
421+// EXPECT returns an object that allows the caller to indicate expected use.
422+func (m *MockHTTPClient) EXPECT() *MockHTTPClientMockRecorder {
423+ return m.recorder
424+}
425+
426+// Get mocks base method.
427+func (m *MockHTTPClient) Get(url string) (*http.Response, error) {
428+ m.ctrl.T.Helper()
429+ ret := m.ctrl.Call(m, "Get", url)
430+ ret0, _ := ret[0].(*http.Response)
431+ ret1, _ := ret[1].(error)
432+ return ret0, ret1
433+}
434+
435+// Get indicates an expected call of Get.
436+func (mr *MockHTTPClientMockRecorder) Get(url any) *gomock.Call {
437+ mr.mock.ctrl.T.Helper()
438+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockHTTPClient)(nil).Get), url)
439+}
440+
441+// MockConfigSaver is a mock of ConfigSaver interface.
442+type MockConfigSaver struct {
443+ ctrl *gomock.Controller
444+ recorder *MockConfigSaverMockRecorder
445+ isgomock struct{}
446+}
447+
448+// MockConfigSaverMockRecorder is the mock recorder for MockConfigSaver.
449+type MockConfigSaverMockRecorder struct {
450+ mock *MockConfigSaver
451+}
452+
453+// NewMockConfigSaver creates a new mock instance.
454+func NewMockConfigSaver(ctrl *gomock.Controller) *MockConfigSaver {
455+ mock := &MockConfigSaver{ctrl: ctrl}
456+ mock.recorder = &MockConfigSaverMockRecorder{mock}
457+ return mock
458+}
459+
460+// EXPECT returns an object that allows the caller to indicate expected use.
461+func (m *MockConfigSaver) EXPECT() *MockConfigSaverMockRecorder {
462+ return m.recorder
463+}
464+
465+// Save mocks base method.
466+func (m *MockConfigSaver) Save() error {
467+ m.ctrl.T.Helper()
468+ ret := m.ctrl.Call(m, "Save")
469+ ret0, _ := ret[0].(error)
470+ return ret0
471+}
472+
473+// Save indicates an expected call of Save.
474+func (mr *MockConfigSaverMockRecorder) Save() *gomock.Call {
475+ mr.mock.ctrl.T.Helper()
476+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockConfigSaver)(nil).Save))
477+}
@@ -0,0 +1,477 @@
1+// Code generated by MockGen. DO NOT EDIT.
2+// Source: internal/interfaces/interfaces.go
3+//
4+// Generated by this command:
5+//
6+// mockgen -source=internal/interfaces/interfaces.go -destination=internal/phases/mocks/mock_interfaces.go -package=mocks
7+//
8+
9+// Package mocks is a generated GoMock package.
10+package mocks
11+
12+import (
13+ context "context"
14+ io "io"
15+ http "net/http"
16+ os "os"
17+ reflect "reflect"
18+
19+ system "github.com/bnema/archup/internal/system"
20+ gomock "go.uber.org/mock/gomock"
21+)
22+
23+// MockFileSystem is a mock of FileSystem interface.
24+type MockFileSystem struct {
25+ ctrl *gomock.Controller
26+ recorder *MockFileSystemMockRecorder
27+ isgomock struct{}
28+}
29+
30+// MockFileSystemMockRecorder is the mock recorder for MockFileSystem.
31+type MockFileSystemMockRecorder struct {
32+ mock *MockFileSystem
33+}
34+
35+// NewMockFileSystem creates a new mock instance.
36+func NewMockFileSystem(ctrl *gomock.Controller) *MockFileSystem {
37+ mock := &MockFileSystem{ctrl: ctrl}
38+ mock.recorder = &MockFileSystemMockRecorder{mock}
39+ return mock
40+}
41+
42+// EXPECT returns an object that allows the caller to indicate expected use.
43+func (m *MockFileSystem) EXPECT() *MockFileSystemMockRecorder {
44+ return m.recorder
45+}
46+
47+// Chmod mocks base method.
48+func (m *MockFileSystem) Chmod(name string, mode os.FileMode) error {
49+ m.ctrl.T.Helper()
50+ ret := m.ctrl.Call(m, "Chmod", name, mode)
51+ ret0, _ := ret[0].(error)
52+ return ret0
53+}
54+
55+// Chmod indicates an expected call of Chmod.
56+func (mr *MockFileSystemMockRecorder) Chmod(name, mode any) *gomock.Call {
57+ mr.mock.ctrl.T.Helper()
58+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chmod", reflect.TypeOf((*MockFileSystem)(nil).Chmod), name, mode)
59+}
60+
61+// Create mocks base method.
62+func (m *MockFileSystem) Create(name string) (io.WriteCloser, error) {
63+ m.ctrl.T.Helper()
64+ ret := m.ctrl.Call(m, "Create", name)
65+ ret0, _ := ret[0].(io.WriteCloser)
66+ ret1, _ := ret[1].(error)
67+ return ret0, ret1
68+}
69+
70+// Create indicates an expected call of Create.
71+func (mr *MockFileSystemMockRecorder) Create(name any) *gomock.Call {
72+ mr.mock.ctrl.T.Helper()
73+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockFileSystem)(nil).Create), name)
74+}
75+
76+// IsNotExist mocks base method.
77+func (m *MockFileSystem) IsNotExist(err error) bool {
78+ m.ctrl.T.Helper()
79+ ret := m.ctrl.Call(m, "IsNotExist", err)
80+ ret0, _ := ret[0].(bool)
81+ return ret0
82+}
83+
84+// IsNotExist indicates an expected call of IsNotExist.
85+func (mr *MockFileSystemMockRecorder) IsNotExist(err any) *gomock.Call {
86+ mr.mock.ctrl.T.Helper()
87+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsNotExist", reflect.TypeOf((*MockFileSystem)(nil).IsNotExist), err)
88+}
89+
90+// MkdirAll mocks base method.
91+func (m *MockFileSystem) MkdirAll(path string, perm os.FileMode) error {
92+ m.ctrl.T.Helper()
93+ ret := m.ctrl.Call(m, "MkdirAll", path, perm)
94+ ret0, _ := ret[0].(error)
95+ return ret0
96+}
97+
98+// MkdirAll indicates an expected call of MkdirAll.
99+func (mr *MockFileSystemMockRecorder) MkdirAll(path, perm any) *gomock.Call {
100+ mr.mock.ctrl.T.Helper()
101+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MkdirAll", reflect.TypeOf((*MockFileSystem)(nil).MkdirAll), path, perm)
102+}
103+
104+// Open mocks base method.
105+func (m *MockFileSystem) Open(name string) (io.ReadCloser, error) {
106+ m.ctrl.T.Helper()
107+ ret := m.ctrl.Call(m, "Open", name)
108+ ret0, _ := ret[0].(io.ReadCloser)
109+ ret1, _ := ret[1].(error)
110+ return ret0, ret1
111+}
112+
113+// Open indicates an expected call of Open.
114+func (mr *MockFileSystemMockRecorder) Open(name any) *gomock.Call {
115+ mr.mock.ctrl.T.Helper()
116+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Open", reflect.TypeOf((*MockFileSystem)(nil).Open), name)
117+}
118+
119+// ReadFile mocks base method.
120+func (m *MockFileSystem) ReadFile(filename string) ([]byte, error) {
121+ m.ctrl.T.Helper()
122+ ret := m.ctrl.Call(m, "ReadFile", filename)
123+ ret0, _ := ret[0].([]byte)
124+ ret1, _ := ret[1].(error)
125+ return ret0, ret1
126+}
127+
128+// ReadFile indicates an expected call of ReadFile.
129+func (mr *MockFileSystemMockRecorder) ReadFile(filename any) *gomock.Call {
130+ mr.mock.ctrl.T.Helper()
131+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadFile", reflect.TypeOf((*MockFileSystem)(nil).ReadFile), filename)
132+}
133+
134+// RemoveAll mocks base method.
135+func (m *MockFileSystem) RemoveAll(path string) error {
136+ m.ctrl.T.Helper()
137+ ret := m.ctrl.Call(m, "RemoveAll", path)
138+ ret0, _ := ret[0].(error)
139+ return ret0
140+}
141+
142+// RemoveAll indicates an expected call of RemoveAll.
143+func (mr *MockFileSystemMockRecorder) RemoveAll(path any) *gomock.Call {
144+ mr.mock.ctrl.T.Helper()
145+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveAll", reflect.TypeOf((*MockFileSystem)(nil).RemoveAll), path)
146+}
147+
148+// Stat mocks base method.
149+func (m *MockFileSystem) Stat(name string) (os.FileInfo, error) {
150+ m.ctrl.T.Helper()
151+ ret := m.ctrl.Call(m, "Stat", name)
152+ ret0, _ := ret[0].(os.FileInfo)
153+ ret1, _ := ret[1].(error)
154+ return ret0, ret1
155+}
156+
157+// Stat indicates an expected call of Stat.
158+func (mr *MockFileSystemMockRecorder) Stat(name any) *gomock.Call {
159+ mr.mock.ctrl.T.Helper()
160+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stat", reflect.TypeOf((*MockFileSystem)(nil).Stat), name)
161+}
162+
163+// WriteFile mocks base method.
164+func (m *MockFileSystem) WriteFile(filename string, data []byte, perm os.FileMode) error {
165+ m.ctrl.T.Helper()
166+ ret := m.ctrl.Call(m, "WriteFile", filename, data, perm)
167+ ret0, _ := ret[0].(error)
168+ return ret0
169+}
170+
171+// WriteFile indicates an expected call of WriteFile.
172+func (mr *MockFileSystemMockRecorder) WriteFile(filename, data, perm any) *gomock.Call {
173+ mr.mock.ctrl.T.Helper()
174+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteFile", reflect.TypeOf((*MockFileSystem)(nil).WriteFile), filename, data, perm)
175+}
176+
177+// MockCommandExecutor is a mock of CommandExecutor interface.
178+type MockCommandExecutor struct {
179+ ctrl *gomock.Controller
180+ recorder *MockCommandExecutorMockRecorder
181+ isgomock struct{}
182+}
183+
184+// MockCommandExecutorMockRecorder is the mock recorder for MockCommandExecutor.
185+type MockCommandExecutorMockRecorder struct {
186+ mock *MockCommandExecutor
187+}
188+
189+// NewMockCommandExecutor creates a new mock instance.
190+func NewMockCommandExecutor(ctrl *gomock.Controller) *MockCommandExecutor {
191+ mock := &MockCommandExecutor{ctrl: ctrl}
192+ mock.recorder = &MockCommandExecutorMockRecorder{mock}
193+ return mock
194+}
195+
196+// EXPECT returns an object that allows the caller to indicate expected use.
197+func (m *MockCommandExecutor) EXPECT() *MockCommandExecutorMockRecorder {
198+ return m.recorder
199+}
200+
201+// Execute mocks base method.
202+func (m *MockCommandExecutor) Execute(name string, args ...string) ([]byte, error) {
203+ m.ctrl.T.Helper()
204+ varargs := []any{name}
205+ for _, a := range args {
206+ varargs = append(varargs, a)
207+ }
208+ ret := m.ctrl.Call(m, "Execute", varargs...)
209+ ret0, _ := ret[0].([]byte)
210+ ret1, _ := ret[1].(error)
211+ return ret0, ret1
212+}
213+
214+// Execute indicates an expected call of Execute.
215+func (mr *MockCommandExecutorMockRecorder) Execute(name any, args ...any) *gomock.Call {
216+ mr.mock.ctrl.T.Helper()
217+ varargs := append([]any{name}, args...)
218+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockCommandExecutor)(nil).Execute), varargs...)
219+}
220+
221+// MockSystemExecutor is a mock of SystemExecutor interface.
222+type MockSystemExecutor struct {
223+ ctrl *gomock.Controller
224+ recorder *MockSystemExecutorMockRecorder
225+ isgomock struct{}
226+}
227+
228+// MockSystemExecutorMockRecorder is the mock recorder for MockSystemExecutor.
229+type MockSystemExecutorMockRecorder struct {
230+ mock *MockSystemExecutor
231+}
232+
233+// NewMockSystemExecutor creates a new mock instance.
234+func NewMockSystemExecutor(ctrl *gomock.Controller) *MockSystemExecutor {
235+ mock := &MockSystemExecutor{ctrl: ctrl}
236+ mock.recorder = &MockSystemExecutorMockRecorder{mock}
237+ return mock
238+}
239+
240+// EXPECT returns an object that allows the caller to indicate expected use.
241+func (m *MockSystemExecutor) EXPECT() *MockSystemExecutorMockRecorder {
242+ return m.recorder
243+}
244+
245+// DetectCPUInfo mocks base method.
246+func (m *MockSystemExecutor) DetectCPUInfo() (*system.CPUInfo, error) {
247+ m.ctrl.T.Helper()
248+ ret := m.ctrl.Call(m, "DetectCPUInfo")
249+ ret0, _ := ret[0].(*system.CPUInfo)
250+ ret1, _ := ret[1].(error)
251+ return ret0, ret1
252+}
253+
254+// DetectCPUInfo indicates an expected call of DetectCPUInfo.
255+func (mr *MockSystemExecutorMockRecorder) DetectCPUInfo() *gomock.Call {
256+ mr.mock.ctrl.T.Helper()
257+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DetectCPUInfo", reflect.TypeOf((*MockSystemExecutor)(nil).DetectCPUInfo))
258+}
259+
260+// RunSimple mocks base method.
261+func (m *MockSystemExecutor) RunSimple(command string, args ...string) system.CommandResult {
262+ m.ctrl.T.Helper()
263+ varargs := []any{command}
264+ for _, a := range args {
265+ varargs = append(varargs, a)
266+ }
267+ ret := m.ctrl.Call(m, "RunSimple", varargs...)
268+ ret0, _ := ret[0].(system.CommandResult)
269+ return ret0
270+}
271+
272+// RunSimple indicates an expected call of RunSimple.
273+func (mr *MockSystemExecutorMockRecorder) RunSimple(command any, args ...any) *gomock.Call {
274+ mr.mock.ctrl.T.Helper()
275+ varargs := append([]any{command}, args...)
276+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunSimple", reflect.TypeOf((*MockSystemExecutor)(nil).RunSimple), varargs...)
277+}
278+
279+// MockChrootExecutor is a mock of ChrootExecutor interface.
280+type MockChrootExecutor struct {
281+ ctrl *gomock.Controller
282+ recorder *MockChrootExecutorMockRecorder
283+ isgomock struct{}
284+}
285+
286+// MockChrootExecutorMockRecorder is the mock recorder for MockChrootExecutor.
287+type MockChrootExecutorMockRecorder struct {
288+ mock *MockChrootExecutor
289+}
290+
291+// NewMockChrootExecutor creates a new mock instance.
292+func NewMockChrootExecutor(ctrl *gomock.Controller) *MockChrootExecutor {
293+ mock := &MockChrootExecutor{ctrl: ctrl}
294+ mock.recorder = &MockChrootExecutorMockRecorder{mock}
295+ return mock
296+}
297+
298+// EXPECT returns an object that allows the caller to indicate expected use.
299+func (m *MockChrootExecutor) EXPECT() *MockChrootExecutorMockRecorder {
300+ return m.recorder
301+}
302+
303+// ChrootExec mocks base method.
304+func (m *MockChrootExecutor) ChrootExec(logPath, mountPoint, command string, args ...string) error {
305+ m.ctrl.T.Helper()
306+ varargs := []any{logPath, mountPoint, command}
307+ for _, a := range args {
308+ varargs = append(varargs, a)
309+ }
310+ ret := m.ctrl.Call(m, "ChrootExec", varargs...)
311+ ret0, _ := ret[0].(error)
312+ return ret0
313+}
314+
315+// ChrootExec indicates an expected call of ChrootExec.
316+func (mr *MockChrootExecutorMockRecorder) ChrootExec(logPath, mountPoint, command any, args ...any) *gomock.Call {
317+ mr.mock.ctrl.T.Helper()
318+ varargs := append([]any{logPath, mountPoint, command}, args...)
319+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChrootExec", reflect.TypeOf((*MockChrootExecutor)(nil).ChrootExec), varargs...)
320+}
321+
322+// ChrootExecWithContext mocks base method.
323+func (m *MockChrootExecutor) ChrootExecWithContext(ctx context.Context, logPath, mountPoint, command string) error {
324+ m.ctrl.T.Helper()
325+ ret := m.ctrl.Call(m, "ChrootExecWithContext", ctx, logPath, mountPoint, command)
326+ ret0, _ := ret[0].(error)
327+ return ret0
328+}
329+
330+// ChrootExecWithContext indicates an expected call of ChrootExecWithContext.
331+func (mr *MockChrootExecutorMockRecorder) ChrootExecWithContext(ctx, logPath, mountPoint, command any) *gomock.Call {
332+ mr.mock.ctrl.T.Helper()
333+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChrootExecWithContext", reflect.TypeOf((*MockChrootExecutor)(nil).ChrootExecWithContext), ctx, logPath, mountPoint, command)
334+}
335+
336+// ChrootExecWithStdin mocks base method.
337+func (m *MockChrootExecutor) ChrootExecWithStdin(logPath, mountPoint, command, stdin string) error {
338+ m.ctrl.T.Helper()
339+ ret := m.ctrl.Call(m, "ChrootExecWithStdin", logPath, mountPoint, command, stdin)
340+ ret0, _ := ret[0].(error)
341+ return ret0
342+}
343+
344+// ChrootExecWithStdin indicates an expected call of ChrootExecWithStdin.
345+func (mr *MockChrootExecutorMockRecorder) ChrootExecWithStdin(logPath, mountPoint, command, stdin any) *gomock.Call {
346+ mr.mock.ctrl.T.Helper()
347+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChrootExecWithStdin", reflect.TypeOf((*MockChrootExecutor)(nil).ChrootExecWithStdin), logPath, mountPoint, command, stdin)
348+}
349+
350+// ChrootPacman mocks base method.
351+func (m *MockChrootExecutor) ChrootPacman(logPath, mountPoint, operation string, packages ...string) error {
352+ m.ctrl.T.Helper()
353+ varargs := []any{logPath, mountPoint, operation}
354+ for _, a := range packages {
355+ varargs = append(varargs, a)
356+ }
357+ ret := m.ctrl.Call(m, "ChrootPacman", varargs...)
358+ ret0, _ := ret[0].(error)
359+ return ret0
360+}
361+
362+// ChrootPacman indicates an expected call of ChrootPacman.
363+func (mr *MockChrootExecutorMockRecorder) ChrootPacman(logPath, mountPoint, operation any, packages ...any) *gomock.Call {
364+ mr.mock.ctrl.T.Helper()
365+ varargs := append([]any{logPath, mountPoint, operation}, packages...)
366+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChrootPacman", reflect.TypeOf((*MockChrootExecutor)(nil).ChrootPacman), varargs...)
367+}
368+
369+// ChrootSystemctl mocks base method.
370+func (m *MockChrootExecutor) ChrootSystemctl(logPath, mountPoint, action, service string) error {
371+ m.ctrl.T.Helper()
372+ ret := m.ctrl.Call(m, "ChrootSystemctl", logPath, mountPoint, action, service)
373+ ret0, _ := ret[0].(error)
374+ return ret0
375+}
376+
377+// ChrootSystemctl indicates an expected call of ChrootSystemctl.
378+func (mr *MockChrootExecutorMockRecorder) ChrootSystemctl(logPath, mountPoint, action, service any) *gomock.Call {
379+ mr.mock.ctrl.T.Helper()
380+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChrootSystemctl", reflect.TypeOf((*MockChrootExecutor)(nil).ChrootSystemctl), logPath, mountPoint, action, service)
381+}
382+
383+// DownloadAndInstallPackages mocks base method.
384+func (m *MockChrootExecutor) DownloadAndInstallPackages(logPath, chrootPath string, urls ...string) error {
385+ m.ctrl.T.Helper()
386+ varargs := []any{logPath, chrootPath}
387+ for _, a := range urls {
388+ varargs = append(varargs, a)
389+ }
390+ ret := m.ctrl.Call(m, "DownloadAndInstallPackages", varargs...)
391+ ret0, _ := ret[0].(error)
392+ return ret0
393+}
394+
395+// DownloadAndInstallPackages indicates an expected call of DownloadAndInstallPackages.
396+func (mr *MockChrootExecutorMockRecorder) DownloadAndInstallPackages(logPath, chrootPath any, urls ...any) *gomock.Call {
397+ mr.mock.ctrl.T.Helper()
398+ varargs := append([]any{logPath, chrootPath}, urls...)
399+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownloadAndInstallPackages", reflect.TypeOf((*MockChrootExecutor)(nil).DownloadAndInstallPackages), varargs...)
400+}
401+
402+// MockHTTPClient is a mock of HTTPClient interface.
403+type MockHTTPClient struct {
404+ ctrl *gomock.Controller
405+ recorder *MockHTTPClientMockRecorder
406+ isgomock struct{}
407+}
408+
409+// MockHTTPClientMockRecorder is the mock recorder for MockHTTPClient.
410+type MockHTTPClientMockRecorder struct {
411+ mock *MockHTTPClient
412+}
413+
414+// NewMockHTTPClient creates a new mock instance.
415+func NewMockHTTPClient(ctrl *gomock.Controller) *MockHTTPClient {
416+ mock := &MockHTTPClient{ctrl: ctrl}
417+ mock.recorder = &MockHTTPClientMockRecorder{mock}
418+ return mock
419+}
420+
421+// EXPECT returns an object that allows the caller to indicate expected use.
422+func (m *MockHTTPClient) EXPECT() *MockHTTPClientMockRecorder {
423+ return m.recorder
424+}
425+
426+// Get mocks base method.
427+func (m *MockHTTPClient) Get(url string) (*http.Response, error) {
428+ m.ctrl.T.Helper()
429+ ret := m.ctrl.Call(m, "Get", url)
430+ ret0, _ := ret[0].(*http.Response)
431+ ret1, _ := ret[1].(error)
432+ return ret0, ret1
433+}
434+
435+// Get indicates an expected call of Get.
436+func (mr *MockHTTPClientMockRecorder) Get(url any) *gomock.Call {
437+ mr.mock.ctrl.T.Helper()
438+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockHTTPClient)(nil).Get), url)
439+}
440+
441+// MockConfigSaver is a mock of ConfigSaver interface.
442+type MockConfigSaver struct {
443+ ctrl *gomock.Controller
444+ recorder *MockConfigSaverMockRecorder
445+ isgomock struct{}
446+}
447+
448+// MockConfigSaverMockRecorder is the mock recorder for MockConfigSaver.
449+type MockConfigSaverMockRecorder struct {
450+ mock *MockConfigSaver
451+}
452+
453+// NewMockConfigSaver creates a new mock instance.
454+func NewMockConfigSaver(ctrl *gomock.Controller) *MockConfigSaver {
455+ mock := &MockConfigSaver{ctrl: ctrl}
456+ mock.recorder = &MockConfigSaverMockRecorder{mock}
457+ return mock
458+}
459+
460+// EXPECT returns an object that allows the caller to indicate expected use.
461+func (m *MockConfigSaver) EXPECT() *MockConfigSaverMockRecorder {
462+ return m.recorder
463+}
464+
465+// Save mocks base method.
466+func (m *MockConfigSaver) Save() error {
467+ m.ctrl.T.Helper()
468+ ret := m.ctrl.Call(m, "Save")
469+ ret0, _ := ret[0].(error)
470+ return ret0
471+}
472+
473+// Save indicates an expected call of Save.
474+func (mr *MockConfigSaverMockRecorder) Save() *gomock.Call {
475+ mr.mock.ctrl.T.Helper()
476+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockConfigSaver)(nil).Save))
477+}
M internal/phases/mocks/mock_phase.go +19 -235
@@ -3,7 +3,7 @@
33 //
44 // Generated by this command:
55 //
6-// mockgen -source=internal/phases/phase.go -destination=internal/phases/mocks/mock_phase.go -package=mocks -typed -self_package=github.com/bnema/archup/internal/phases
6+// mockgen -source=internal/phases/phase.go -destination=internal/phases/mocks/mock_phase.go -package=mocks
77 //
88
99 // Package mocks is a generated GoMock package.
@@ -49,33 +49,9 @@ func (m *MockPhase) CanSkip() bool {
4949 }
5050
5151 // CanSkip indicates an expected call of CanSkip.
52-func (mr *MockPhaseMockRecorder) CanSkip() *MockPhaseCanSkipCall {
52+func (mr *MockPhaseMockRecorder) CanSkip() *gomock.Call {
5353 mr.mock.ctrl.T.Helper()
54- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanSkip", reflect.TypeOf((*MockPhase)(nil).CanSkip))
55- return &MockPhaseCanSkipCall{Call: call}
56-}
57-
58-// MockPhaseCanSkipCall wrap *gomock.Call
59-type MockPhaseCanSkipCall struct {
60- *gomock.Call
61-}
62-
63-// Return rewrite *gomock.Call.Return
64-func (c *MockPhaseCanSkipCall) Return(arg0 bool) *MockPhaseCanSkipCall {
65- c.Call = c.Call.Return(arg0)
66- return c
67-}
68-
69-// Do rewrite *gomock.Call.Do
70-func (c *MockPhaseCanSkipCall) Do(f func() bool) *MockPhaseCanSkipCall {
71- c.Call = c.Call.Do(f)
72- return c
73-}
74-
75-// DoAndReturn rewrite *gomock.Call.DoAndReturn
76-func (c *MockPhaseCanSkipCall) DoAndReturn(f func() bool) *MockPhaseCanSkipCall {
77- c.Call = c.Call.DoAndReturn(f)
78- return c
54+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanSkip", reflect.TypeOf((*MockPhase)(nil).CanSkip))
7955 }
8056
8157 // Description mocks base method.
@@ -87,33 +63,9 @@ func (m *MockPhase) Description() string {
8763 }
8864
8965 // Description indicates an expected call of Description.
90-func (mr *MockPhaseMockRecorder) Description() *MockPhaseDescriptionCall {
66+func (mr *MockPhaseMockRecorder) Description() *gomock.Call {
9167 mr.mock.ctrl.T.Helper()
92- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Description", reflect.TypeOf((*MockPhase)(nil).Description))
93- return &MockPhaseDescriptionCall{Call: call}
94-}
95-
96-// MockPhaseDescriptionCall wrap *gomock.Call
97-type MockPhaseDescriptionCall struct {
98- *gomock.Call
99-}
100-
101-// Return rewrite *gomock.Call.Return
102-func (c *MockPhaseDescriptionCall) Return(arg0 string) *MockPhaseDescriptionCall {
103- c.Call = c.Call.Return(arg0)
104- return c
105-}
106-
107-// Do rewrite *gomock.Call.Do
108-func (c *MockPhaseDescriptionCall) Do(f func() string) *MockPhaseDescriptionCall {
109- c.Call = c.Call.Do(f)
110- return c
111-}
112-
113-// DoAndReturn rewrite *gomock.Call.DoAndReturn
114-func (c *MockPhaseDescriptionCall) DoAndReturn(f func() string) *MockPhaseDescriptionCall {
115- c.Call = c.Call.DoAndReturn(f)
116- return c
68+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Description", reflect.TypeOf((*MockPhase)(nil).Description))
11769 }
11870
11971 // Execute mocks base method.
@@ -125,33 +77,9 @@ func (m *MockPhase) Execute(progressChan chan<- phases.ProgressUpdate) phases.Ph
12577 }
12678
12779 // Execute indicates an expected call of Execute.
128-func (mr *MockPhaseMockRecorder) Execute(progressChan any) *MockPhaseExecuteCall {
80+func (mr *MockPhaseMockRecorder) Execute(progressChan any) *gomock.Call {
12981 mr.mock.ctrl.T.Helper()
130- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockPhase)(nil).Execute), progressChan)
131- return &MockPhaseExecuteCall{Call: call}
132-}
133-
134-// MockPhaseExecuteCall wrap *gomock.Call
135-type MockPhaseExecuteCall struct {
136- *gomock.Call
137-}
138-
139-// Return rewrite *gomock.Call.Return
140-func (c *MockPhaseExecuteCall) Return(arg0 phases.PhaseResult) *MockPhaseExecuteCall {
141- c.Call = c.Call.Return(arg0)
142- return c
143-}
144-
145-// Do rewrite *gomock.Call.Do
146-func (c *MockPhaseExecuteCall) Do(f func(chan<- phases.ProgressUpdate) phases.PhaseResult) *MockPhaseExecuteCall {
147- c.Call = c.Call.Do(f)
148- return c
149-}
150-
151-// DoAndReturn rewrite *gomock.Call.DoAndReturn
152-func (c *MockPhaseExecuteCall) DoAndReturn(f func(chan<- phases.ProgressUpdate) phases.PhaseResult) *MockPhaseExecuteCall {
153- c.Call = c.Call.DoAndReturn(f)
154- return c
82+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockPhase)(nil).Execute), progressChan)
15583 }
15684
15785 // Name mocks base method.
@@ -163,33 +91,9 @@ func (m *MockPhase) Name() string {
16391 }
16492
16593 // Name indicates an expected call of Name.
166-func (mr *MockPhaseMockRecorder) Name() *MockPhaseNameCall {
94+func (mr *MockPhaseMockRecorder) Name() *gomock.Call {
16795 mr.mock.ctrl.T.Helper()
168- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockPhase)(nil).Name))
169- return &MockPhaseNameCall{Call: call}
170-}
171-
172-// MockPhaseNameCall wrap *gomock.Call
173-type MockPhaseNameCall struct {
174- *gomock.Call
175-}
176-
177-// Return rewrite *gomock.Call.Return
178-func (c *MockPhaseNameCall) Return(arg0 string) *MockPhaseNameCall {
179- c.Call = c.Call.Return(arg0)
180- return c
181-}
182-
183-// Do rewrite *gomock.Call.Do
184-func (c *MockPhaseNameCall) Do(f func() string) *MockPhaseNameCall {
185- c.Call = c.Call.Do(f)
186- return c
187-}
188-
189-// DoAndReturn rewrite *gomock.Call.DoAndReturn
190-func (c *MockPhaseNameCall) DoAndReturn(f func() string) *MockPhaseNameCall {
191- c.Call = c.Call.DoAndReturn(f)
192- return c
96+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockPhase)(nil).Name))
19397 }
19498
19599 // PostCheck mocks base method.
@@ -201,33 +105,9 @@ func (m *MockPhase) PostCheck() error {
201105 }
202106
203107 // PostCheck indicates an expected call of PostCheck.
204-func (mr *MockPhaseMockRecorder) PostCheck() *MockPhasePostCheckCall {
108+func (mr *MockPhaseMockRecorder) PostCheck() *gomock.Call {
205109 mr.mock.ctrl.T.Helper()
206- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostCheck", reflect.TypeOf((*MockPhase)(nil).PostCheck))
207- return &MockPhasePostCheckCall{Call: call}
208-}
209-
210-// MockPhasePostCheckCall wrap *gomock.Call
211-type MockPhasePostCheckCall struct {
212- *gomock.Call
213-}
214-
215-// Return rewrite *gomock.Call.Return
216-func (c *MockPhasePostCheckCall) Return(arg0 error) *MockPhasePostCheckCall {
217- c.Call = c.Call.Return(arg0)
218- return c
219-}
220-
221-// Do rewrite *gomock.Call.Do
222-func (c *MockPhasePostCheckCall) Do(f func() error) *MockPhasePostCheckCall {
223- c.Call = c.Call.Do(f)
224- return c
225-}
226-
227-// DoAndReturn rewrite *gomock.Call.DoAndReturn
228-func (c *MockPhasePostCheckCall) DoAndReturn(f func() error) *MockPhasePostCheckCall {
229- c.Call = c.Call.DoAndReturn(f)
230- return c
110+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostCheck", reflect.TypeOf((*MockPhase)(nil).PostCheck))
231111 }
232112
233113 // PreCheck mocks base method.
@@ -239,33 +119,9 @@ func (m *MockPhase) PreCheck() error {
239119 }
240120
241121 // PreCheck indicates an expected call of PreCheck.
242-func (mr *MockPhaseMockRecorder) PreCheck() *MockPhasePreCheckCall {
122+func (mr *MockPhaseMockRecorder) PreCheck() *gomock.Call {
243123 mr.mock.ctrl.T.Helper()
244- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PreCheck", reflect.TypeOf((*MockPhase)(nil).PreCheck))
245- return &MockPhasePreCheckCall{Call: call}
246-}
247-
248-// MockPhasePreCheckCall wrap *gomock.Call
249-type MockPhasePreCheckCall struct {
250- *gomock.Call
251-}
252-
253-// Return rewrite *gomock.Call.Return
254-func (c *MockPhasePreCheckCall) Return(arg0 error) *MockPhasePreCheckCall {
255- c.Call = c.Call.Return(arg0)
256- return c
257-}
258-
259-// Do rewrite *gomock.Call.Do
260-func (c *MockPhasePreCheckCall) Do(f func() error) *MockPhasePreCheckCall {
261- c.Call = c.Call.Do(f)
262- return c
263-}
264-
265-// DoAndReturn rewrite *gomock.Call.DoAndReturn
266-func (c *MockPhasePreCheckCall) DoAndReturn(f func() error) *MockPhasePreCheckCall {
267- c.Call = c.Call.DoAndReturn(f)
268- return c
124+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PreCheck", reflect.TypeOf((*MockPhase)(nil).PreCheck))
269125 }
270126
271127 // Rollback mocks base method.
@@ -277,33 +133,9 @@ func (m *MockPhase) Rollback() error {
277133 }
278134
279135 // Rollback indicates an expected call of Rollback.
280-func (mr *MockPhaseMockRecorder) Rollback() *MockPhaseRollbackCall {
136+func (mr *MockPhaseMockRecorder) Rollback() *gomock.Call {
281137 mr.mock.ctrl.T.Helper()
282- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rollback", reflect.TypeOf((*MockPhase)(nil).Rollback))
283- return &MockPhaseRollbackCall{Call: call}
284-}
285-
286-// MockPhaseRollbackCall wrap *gomock.Call
287-type MockPhaseRollbackCall struct {
288- *gomock.Call
289-}
290-
291-// Return rewrite *gomock.Call.Return
292-func (c *MockPhaseRollbackCall) Return(arg0 error) *MockPhaseRollbackCall {
293- c.Call = c.Call.Return(arg0)
294- return c
295-}
296-
297-// Do rewrite *gomock.Call.Do
298-func (c *MockPhaseRollbackCall) Do(f func() error) *MockPhaseRollbackCall {
299- c.Call = c.Call.Do(f)
300- return c
301-}
302-
303-// DoAndReturn rewrite *gomock.Call.DoAndReturn
304-func (c *MockPhaseRollbackCall) DoAndReturn(f func() error) *MockPhaseRollbackCall {
305- c.Call = c.Call.DoAndReturn(f)
306- return c
138+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rollback", reflect.TypeOf((*MockPhase)(nil).Rollback))
307139 }
308140
309141 // SetStatus mocks base method.
@@ -313,33 +145,9 @@ func (m *MockPhase) SetStatus(status phases.PhaseStatus) {
313145 }
314146
315147 // SetStatus indicates an expected call of SetStatus.
316-func (mr *MockPhaseMockRecorder) SetStatus(status any) *MockPhaseSetStatusCall {
148+func (mr *MockPhaseMockRecorder) SetStatus(status any) *gomock.Call {
317149 mr.mock.ctrl.T.Helper()
318- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetStatus", reflect.TypeOf((*MockPhase)(nil).SetStatus), status)
319- return &MockPhaseSetStatusCall{Call: call}
320-}
321-
322-// MockPhaseSetStatusCall wrap *gomock.Call
323-type MockPhaseSetStatusCall struct {
324- *gomock.Call
325-}
326-
327-// Return rewrite *gomock.Call.Return
328-func (c *MockPhaseSetStatusCall) Return() *MockPhaseSetStatusCall {
329- c.Call = c.Call.Return()
330- return c
331-}
332-
333-// Do rewrite *gomock.Call.Do
334-func (c *MockPhaseSetStatusCall) Do(f func(phases.PhaseStatus)) *MockPhaseSetStatusCall {
335- c.Call = c.Call.Do(f)
336- return c
337-}
338-
339-// DoAndReturn rewrite *gomock.Call.DoAndReturn
340-func (c *MockPhaseSetStatusCall) DoAndReturn(f func(phases.PhaseStatus)) *MockPhaseSetStatusCall {
341- c.Call = c.Call.DoAndReturn(f)
342- return c
150+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetStatus", reflect.TypeOf((*MockPhase)(nil).SetStatus), status)
343151 }
344152
345153 // Status mocks base method.
@@ -351,31 +159,7 @@ func (m *MockPhase) Status() phases.PhaseStatus {
351159 }
352160
353161 // Status indicates an expected call of Status.
354-func (mr *MockPhaseMockRecorder) Status() *Mockphases.PhaseStatusCall {
162+func (mr *MockPhaseMockRecorder) Status() *gomock.Call {
355163 mr.mock.ctrl.T.Helper()
356- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockPhase)(nil).Status))
357- return &Mockphases.PhaseStatusCall{Call: call}
358-}
359-
360-// Mockphases.PhaseStatusCall wrap *gomock.Call
361-type Mockphases.PhaseStatusCall struct {
362- *gomock.Call
363-}
364-
365-// Return rewrite *gomock.Call.Return
366-func (c *Mockphases.PhaseStatusCall) Return(arg0 phases.PhaseStatus) *Mockphases.PhaseStatusCall {
367- c.Call = c.Call.Return(arg0)
368- return c
369-}
370-
371-// Do rewrite *gomock.Call.Do
372-func (c *Mockphases.PhaseStatusCall) Do(f func() phases.PhaseStatus) *Mockphases.PhaseStatusCall {
373- c.Call = c.Call.Do(f)
374- return c
375-}
376-
377-// DoAndReturn rewrite *gomock.Call.DoAndReturn
378-func (c *Mockphases.PhaseStatusCall) DoAndReturn(f func() phases.PhaseStatus) *Mockphases.PhaseStatusCall {
379- c.Call = c.Call.DoAndReturn(f)
380- return c
164+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockPhase)(nil).Status))
381165 }
@@ -3,7 +3,7 @@
3 //3 //
4 // Generated by this command:4 // Generated by this command:
5 //5 //
6-// mockgen -source=internal/phases/phase.go -destination=internal/phases/mocks/mock_phase.go -package=mocks -typed -self_package=github.com/bnema/archup/internal/phases6+// mockgen -source=internal/phases/phase.go -destination=internal/phases/mocks/mock_phase.go -package=mocks
7 //7 //
8 8
9 // Package mocks is a generated GoMock package.9 // Package mocks is a generated GoMock package.
@@ -49,33 +49,9 @@ func (m *MockPhase) CanSkip() bool {
49 }49 }
50 50
51 // CanSkip indicates an expected call of CanSkip.51 // CanSkip indicates an expected call of CanSkip.
52-func (mr *MockPhaseMockRecorder) CanSkip() *MockPhaseCanSkipCall {52+func (mr *MockPhaseMockRecorder) CanSkip() *gomock.Call {
53 mr.mock.ctrl.T.Helper()53 mr.mock.ctrl.T.Helper()
54- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanSkip", reflect.TypeOf((*MockPhase)(nil).CanSkip))54+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanSkip", reflect.TypeOf((*MockPhase)(nil).CanSkip))
55- return &MockPhaseCanSkipCall{Call: call}
56-}
57-
58-// MockPhaseCanSkipCall wrap *gomock.Call
59-type MockPhaseCanSkipCall struct {
60- *gomock.Call
61-}
62-
63-// Return rewrite *gomock.Call.Return
64-func (c *MockPhaseCanSkipCall) Return(arg0 bool) *MockPhaseCanSkipCall {
65- c.Call = c.Call.Return(arg0)
66- return c
67-}
68-
69-// Do rewrite *gomock.Call.Do
70-func (c *MockPhaseCanSkipCall) Do(f func() bool) *MockPhaseCanSkipCall {
71- c.Call = c.Call.Do(f)
72- return c
73-}
74-
75-// DoAndReturn rewrite *gomock.Call.DoAndReturn
76-func (c *MockPhaseCanSkipCall) DoAndReturn(f func() bool) *MockPhaseCanSkipCall {
77- c.Call = c.Call.DoAndReturn(f)
78- return c
79 }55 }
80 56
81 // Description mocks base method.57 // Description mocks base method.
@@ -87,33 +63,9 @@ func (m *MockPhase) Description() string {
87 }63 }
88 64
89 // Description indicates an expected call of Description.65 // Description indicates an expected call of Description.
90-func (mr *MockPhaseMockRecorder) Description() *MockPhaseDescriptionCall {66+func (mr *MockPhaseMockRecorder) Description() *gomock.Call {
91 mr.mock.ctrl.T.Helper()67 mr.mock.ctrl.T.Helper()
92- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Description", reflect.TypeOf((*MockPhase)(nil).Description))68+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Description", reflect.TypeOf((*MockPhase)(nil).Description))
93- return &MockPhaseDescriptionCall{Call: call}
94-}
95-
96-// MockPhaseDescriptionCall wrap *gomock.Call
97-type MockPhaseDescriptionCall struct {
98- *gomock.Call
99-}
100-
101-// Return rewrite *gomock.Call.Return
102-func (c *MockPhaseDescriptionCall) Return(arg0 string) *MockPhaseDescriptionCall {
103- c.Call = c.Call.Return(arg0)
104- return c
105-}
106-
107-// Do rewrite *gomock.Call.Do
108-func (c *MockPhaseDescriptionCall) Do(f func() string) *MockPhaseDescriptionCall {
109- c.Call = c.Call.Do(f)
110- return c
111-}
112-
113-// DoAndReturn rewrite *gomock.Call.DoAndReturn
114-func (c *MockPhaseDescriptionCall) DoAndReturn(f func() string) *MockPhaseDescriptionCall {
115- c.Call = c.Call.DoAndReturn(f)
116- return c
117 }69 }
118 70
119 // Execute mocks base method.71 // Execute mocks base method.
@@ -125,33 +77,9 @@ func (m *MockPhase) Execute(progressChan chan<- phases.ProgressUpdate) phases.Ph
125 }77 }
126 78
127 // Execute indicates an expected call of Execute.79 // Execute indicates an expected call of Execute.
128-func (mr *MockPhaseMockRecorder) Execute(progressChan any) *MockPhaseExecuteCall {80+func (mr *MockPhaseMockRecorder) Execute(progressChan any) *gomock.Call {
129 mr.mock.ctrl.T.Helper()81 mr.mock.ctrl.T.Helper()
130- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockPhase)(nil).Execute), progressChan)82+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockPhase)(nil).Execute), progressChan)
131- return &MockPhaseExecuteCall{Call: call}
132-}
133-
134-// MockPhaseExecuteCall wrap *gomock.Call
135-type MockPhaseExecuteCall struct {
136- *gomock.Call
137-}
138-
139-// Return rewrite *gomock.Call.Return
140-func (c *MockPhaseExecuteCall) Return(arg0 phases.PhaseResult) *MockPhaseExecuteCall {
141- c.Call = c.Call.Return(arg0)
142- return c
143-}
144-
145-// Do rewrite *gomock.Call.Do
146-func (c *MockPhaseExecuteCall) Do(f func(chan<- phases.ProgressUpdate) phases.PhaseResult) *MockPhaseExecuteCall {
147- c.Call = c.Call.Do(f)
148- return c
149-}
150-
151-// DoAndReturn rewrite *gomock.Call.DoAndReturn
152-func (c *MockPhaseExecuteCall) DoAndReturn(f func(chan<- phases.ProgressUpdate) phases.PhaseResult) *MockPhaseExecuteCall {
153- c.Call = c.Call.DoAndReturn(f)
154- return c
155 }83 }
156 84
157 // Name mocks base method.85 // Name mocks base method.
@@ -163,33 +91,9 @@ func (m *MockPhase) Name() string {
163 }91 }
164 92
165 // Name indicates an expected call of Name.93 // Name indicates an expected call of Name.
166-func (mr *MockPhaseMockRecorder) Name() *MockPhaseNameCall {94+func (mr *MockPhaseMockRecorder) Name() *gomock.Call {
167 mr.mock.ctrl.T.Helper()95 mr.mock.ctrl.T.Helper()
168- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockPhase)(nil).Name))96+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockPhase)(nil).Name))
169- return &MockPhaseNameCall{Call: call}
170-}
171-
172-// MockPhaseNameCall wrap *gomock.Call
173-type MockPhaseNameCall struct {
174- *gomock.Call
175-}
176-
177-// Return rewrite *gomock.Call.Return
178-func (c *MockPhaseNameCall) Return(arg0 string) *MockPhaseNameCall {
179- c.Call = c.Call.Return(arg0)
180- return c
181-}
182-
183-// Do rewrite *gomock.Call.Do
184-func (c *MockPhaseNameCall) Do(f func() string) *MockPhaseNameCall {
185- c.Call = c.Call.Do(f)
186- return c
187-}
188-
189-// DoAndReturn rewrite *gomock.Call.DoAndReturn
190-func (c *MockPhaseNameCall) DoAndReturn(f func() string) *MockPhaseNameCall {
191- c.Call = c.Call.DoAndReturn(f)
192- return c
193 }97 }
194 98
195 // PostCheck mocks base method.99 // PostCheck mocks base method.
@@ -201,33 +105,9 @@ func (m *MockPhase) PostCheck() error {
201 }105 }
202 106
203 // PostCheck indicates an expected call of PostCheck.107 // PostCheck indicates an expected call of PostCheck.
204-func (mr *MockPhaseMockRecorder) PostCheck() *MockPhasePostCheckCall {108+func (mr *MockPhaseMockRecorder) PostCheck() *gomock.Call {
205 mr.mock.ctrl.T.Helper()109 mr.mock.ctrl.T.Helper()
206- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostCheck", reflect.TypeOf((*MockPhase)(nil).PostCheck))110+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PostCheck", reflect.TypeOf((*MockPhase)(nil).PostCheck))
207- return &MockPhasePostCheckCall{Call: call}
208-}
209-
210-// MockPhasePostCheckCall wrap *gomock.Call
211-type MockPhasePostCheckCall struct {
212- *gomock.Call
213-}
214-
215-// Return rewrite *gomock.Call.Return
216-func (c *MockPhasePostCheckCall) Return(arg0 error) *MockPhasePostCheckCall {
217- c.Call = c.Call.Return(arg0)
218- return c
219-}
220-
221-// Do rewrite *gomock.Call.Do
222-func (c *MockPhasePostCheckCall) Do(f func() error) *MockPhasePostCheckCall {
223- c.Call = c.Call.Do(f)
224- return c
225-}
226-
227-// DoAndReturn rewrite *gomock.Call.DoAndReturn
228-func (c *MockPhasePostCheckCall) DoAndReturn(f func() error) *MockPhasePostCheckCall {
229- c.Call = c.Call.DoAndReturn(f)
230- return c
231 }111 }
232 112
233 // PreCheck mocks base method.113 // PreCheck mocks base method.
@@ -239,33 +119,9 @@ func (m *MockPhase) PreCheck() error {
239 }119 }
240 120
241 // PreCheck indicates an expected call of PreCheck.121 // PreCheck indicates an expected call of PreCheck.
242-func (mr *MockPhaseMockRecorder) PreCheck() *MockPhasePreCheckCall {122+func (mr *MockPhaseMockRecorder) PreCheck() *gomock.Call {
243 mr.mock.ctrl.T.Helper()123 mr.mock.ctrl.T.Helper()
244- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PreCheck", reflect.TypeOf((*MockPhase)(nil).PreCheck))124+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PreCheck", reflect.TypeOf((*MockPhase)(nil).PreCheck))
245- return &MockPhasePreCheckCall{Call: call}
246-}
247-
248-// MockPhasePreCheckCall wrap *gomock.Call
249-type MockPhasePreCheckCall struct {
250- *gomock.Call
251-}
252-
253-// Return rewrite *gomock.Call.Return
254-func (c *MockPhasePreCheckCall) Return(arg0 error) *MockPhasePreCheckCall {
255- c.Call = c.Call.Return(arg0)
256- return c
257-}
258-
259-// Do rewrite *gomock.Call.Do
260-func (c *MockPhasePreCheckCall) Do(f func() error) *MockPhasePreCheckCall {
261- c.Call = c.Call.Do(f)
262- return c
263-}
264-
265-// DoAndReturn rewrite *gomock.Call.DoAndReturn
266-func (c *MockPhasePreCheckCall) DoAndReturn(f func() error) *MockPhasePreCheckCall {
267- c.Call = c.Call.DoAndReturn(f)
268- return c
269 }125 }
270 126
271 // Rollback mocks base method.127 // Rollback mocks base method.
@@ -277,33 +133,9 @@ func (m *MockPhase) Rollback() error {
277 }133 }
278 134
279 // Rollback indicates an expected call of Rollback.135 // Rollback indicates an expected call of Rollback.
280-func (mr *MockPhaseMockRecorder) Rollback() *MockPhaseRollbackCall {136+func (mr *MockPhaseMockRecorder) Rollback() *gomock.Call {
281 mr.mock.ctrl.T.Helper()137 mr.mock.ctrl.T.Helper()
282- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rollback", reflect.TypeOf((*MockPhase)(nil).Rollback))138+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Rollback", reflect.TypeOf((*MockPhase)(nil).Rollback))
283- return &MockPhaseRollbackCall{Call: call}
284-}
285-
286-// MockPhaseRollbackCall wrap *gomock.Call
287-type MockPhaseRollbackCall struct {
288- *gomock.Call
289-}
290-
291-// Return rewrite *gomock.Call.Return
292-func (c *MockPhaseRollbackCall) Return(arg0 error) *MockPhaseRollbackCall {
293- c.Call = c.Call.Return(arg0)
294- return c
295-}
296-
297-// Do rewrite *gomock.Call.Do
298-func (c *MockPhaseRollbackCall) Do(f func() error) *MockPhaseRollbackCall {
299- c.Call = c.Call.Do(f)
300- return c
301-}
302-
303-// DoAndReturn rewrite *gomock.Call.DoAndReturn
304-func (c *MockPhaseRollbackCall) DoAndReturn(f func() error) *MockPhaseRollbackCall {
305- c.Call = c.Call.DoAndReturn(f)
306- return c
307 }139 }
308 140
309 // SetStatus mocks base method.141 // SetStatus mocks base method.
@@ -313,33 +145,9 @@ func (m *MockPhase) SetStatus(status phases.PhaseStatus) {
313 }145 }
314 146
315 // SetStatus indicates an expected call of SetStatus.147 // SetStatus indicates an expected call of SetStatus.
316-func (mr *MockPhaseMockRecorder) SetStatus(status any) *MockPhaseSetStatusCall {148+func (mr *MockPhaseMockRecorder) SetStatus(status any) *gomock.Call {
317 mr.mock.ctrl.T.Helper()149 mr.mock.ctrl.T.Helper()
318- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetStatus", reflect.TypeOf((*MockPhase)(nil).SetStatus), status)150+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetStatus", reflect.TypeOf((*MockPhase)(nil).SetStatus), status)
319- return &MockPhaseSetStatusCall{Call: call}
320-}
321-
322-// MockPhaseSetStatusCall wrap *gomock.Call
323-type MockPhaseSetStatusCall struct {
324- *gomock.Call
325-}
326-
327-// Return rewrite *gomock.Call.Return
328-func (c *MockPhaseSetStatusCall) Return() *MockPhaseSetStatusCall {
329- c.Call = c.Call.Return()
330- return c
331-}
332-
333-// Do rewrite *gomock.Call.Do
334-func (c *MockPhaseSetStatusCall) Do(f func(phases.PhaseStatus)) *MockPhaseSetStatusCall {
335- c.Call = c.Call.Do(f)
336- return c
337-}
338-
339-// DoAndReturn rewrite *gomock.Call.DoAndReturn
340-func (c *MockPhaseSetStatusCall) DoAndReturn(f func(phases.PhaseStatus)) *MockPhaseSetStatusCall {
341- c.Call = c.Call.DoAndReturn(f)
342- return c
343 }151 }
344 152
345 // Status mocks base method.153 // Status mocks base method.
@@ -351,31 +159,7 @@ func (m *MockPhase) Status() phases.PhaseStatus {
351 }159 }
352 160
353 // Status indicates an expected call of Status.161 // Status indicates an expected call of Status.
354-func (mr *MockPhaseMockRecorder) Status() *Mockphases.PhaseStatusCall {162+func (mr *MockPhaseMockRecorder) Status() *gomock.Call {
355 mr.mock.ctrl.T.Helper()163 mr.mock.ctrl.T.Helper()
356- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockPhase)(nil).Status))164+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Status", reflect.TypeOf((*MockPhase)(nil).Status))
357- return &Mockphases.PhaseStatusCall{Call: call}
358-}
359-
360-// Mockphases.PhaseStatusCall wrap *gomock.Call
361-type Mockphases.PhaseStatusCall struct {
362- *gomock.Call
363-}
364-
365-// Return rewrite *gomock.Call.Return
366-func (c *Mockphases.PhaseStatusCall) Return(arg0 phases.PhaseStatus) *Mockphases.PhaseStatusCall {
367- c.Call = c.Call.Return(arg0)
368- return c
369-}
370-
371-// Do rewrite *gomock.Call.Do
372-func (c *Mockphases.PhaseStatusCall) Do(f func() phases.PhaseStatus) *Mockphases.PhaseStatusCall {
373- c.Call = c.Call.Do(f)
374- return c
375-}
376-
377-// DoAndReturn rewrite *gomock.Call.DoAndReturn
378-func (c *Mockphases.PhaseStatusCall) DoAndReturn(f func() phases.PhaseStatus) *Mockphases.PhaseStatusCall {
379- c.Call = c.Call.DoAndReturn(f)
380- return c
381 }165 }
M internal/phases/repos.go +90 -23
@@ -2,9 +2,11 @@ package phases
22
33 import (
44 "bufio"
5+ "context"
56 "fmt"
67 "path/filepath"
78 "strings"
9+ "time"
810
911 "github.com/bnema/archup/internal/config"
1012 "github.com/bnema/archup/internal/interfaces"
@@ -46,10 +48,11 @@ func IsValidAURHelper(helper string) bool {
4648 // ReposPhase handles repository configuration
4749 type ReposPhase struct {
4850 *BasePhase
49- fs interfaces.FileSystem
50- sysExec interfaces.SystemExecutor
51- chrExec interfaces.ChrootExecutor
52- chaoticConfig map[string]string
51+ fs interfaces.FileSystem
52+ sysExec interfaces.SystemExecutor
53+ chrExec interfaces.ChrootExecutor
54+ chaoticConfig map[string]string
55+ chaoticAUREnabled bool
5356 }
5457
5558 // NewReposPhase creates a new repos phase
@@ -401,6 +404,7 @@ func (p *ReposPhase) enableChaoticAUR(progressChan chan<- ProgressUpdate) error
401404 }
402405
403406 p.SendOutput(progressChan, "[OK] Chaotic-AUR enabled successfully")
407+ p.chaoticAUREnabled = true
404408
405409 return nil
406410 }
@@ -512,38 +516,101 @@ func (p *ReposPhase) loadExtraPackages() ([]string, error) {
512516 }
513517
514518 // installAURHelper installs the selected AUR helper
519+// Uses Chaotic-AUR if available, falls back to building from source
515520 func (p *ReposPhase) installAURHelper(progressChan chan<- ProgressUpdate) error {
516- p.SendOutput(progressChan, fmt.Sprintf("Building %s from AUR...", p.config.AURHelper))
521+ helper := p.config.AURHelper
522+
523+ // Strategy 1: Try Chaotic-AUR if available
524+ if p.chaoticAUREnabled {
525+ p.SendOutput(progressChan, fmt.Sprintf("Attempting to install %s from Chaotic-AUR...", helper))
526+ tryCmd := fmt.Sprintf("pacman -S --noconfirm --needed %s", helper)
527+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, tryCmd); {
528+ case err == nil:
529+ p.SendOutput(progressChan, fmt.Sprintf("[OK] %s installed from Chaotic-AUR", helper))
530+ p.logger.Info("AUR helper installed from Chaotic-AUR", "helper", helper)
531+ return nil
532+ default:
533+ p.logger.Warn("Failed to install from Chaotic-AUR, building from source", "error", err)
534+ p.SendOutput(progressChan, "[WARN] Chaotic-AUR installation failed, building from source...")
535+ }
536+ }
537+
538+ // Strategy 2: Build from source with proper dependency verification
539+ p.SendOutput(progressChan, fmt.Sprintf("Building %s from AUR...", helper))
540+ if err := p.ensureBuildDeps(progressChan, helper); err != nil {
541+ return fmt.Errorf("failed to ensure build dependencies: %w", err)
542+ }
543+
544+ if err := p.buildFromAUR(progressChan, helper); err != nil {
545+ return fmt.Errorf("failed to build %s: %w", helper, err)
546+ }
547+
548+ p.SendOutput(progressChan, fmt.Sprintf("[OK] %s built and installed successfully", helper))
549+ p.logger.Info("AUR helper built from source", "helper", helper)
550+
551+ return nil
552+}
517553
518- // Ensure build dependencies are installed
554+// ensureBuildDeps verifies and installs build dependencies
555+func (p *ReposPhase) ensureBuildDeps(progressChan chan<- ProgressUpdate, helper string) error {
519556 p.SendOutput(progressChan, "Verifying build dependencies...")
520- depsCmd := "pacman -S --needed --noconfirm base-devel git"
521- switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, depsCmd); {
557+
558+ // Always need base-devel and git
559+ baseCmd := "pacman -S --needed --noconfirm base-devel git"
560+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, baseCmd); {
522561 case err != nil:
523- p.logger.Warn("Failed to install build dependencies", "error", err)
524- // Don't fail, they might already be installed
562+ p.logger.Warn("Failed to install base-devel", "error", err)
563+ return fmt.Errorf("failed to install base-devel: %w", err)
525564 }
526565
527- // Build AUR helper from source as configured user, then install as root
528- buildCmd := fmt.Sprintf(`
529- set -e
566+ // Install language-specific dependencies
567+ var langDeps string
568+ switch helper {
569+ case "yay":
570+ langDeps = "go"
571+ case "paru":
572+ langDeps = "rust cargo"
573+ }
530574
531- # Build as user (clone, build, etc.)
532- su - %s -c 'cd /tmp && rm -rf %s && git clone https://aur.archlinux.org/%s.git && cd %s && makepkg -s --noconfirm' || exit 1
575+ if langDeps != "" {
576+ p.SendOutput(progressChan, fmt.Sprintf("Installing %s dependencies...", helper))
577+ depCmd := fmt.Sprintf("pacman -S --needed --noconfirm %s", langDeps)
578+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, depCmd); {
579+ case err != nil:
580+ p.logger.Warn("Failed to install language dependencies", "helper", helper, "deps", langDeps, "error", err)
581+ return fmt.Errorf("failed to install %s: %w", langDeps, err)
582+ }
583+ }
533584
534- # Install built package as root
535- pacman -U --noconfirm /tmp/%s/*.pkg.tar.zst || exit 1
585+ p.SendOutput(progressChan, "[OK] Build dependencies verified")
586+ return nil
587+}
536588
537- # Clean up build directory
538- rm -rf /tmp/%s
539- `, p.config.Username, p.config.AURHelper, p.config.AURHelper, p.config.AURHelper, p.config.AURHelper, p.config.AURHelper)
589+// buildFromAUR builds an AUR package from source with timeout
590+func (p *ReposPhase) buildFromAUR(progressChan chan<- ProgressUpdate, helper string) error {
591+ // Build as user with timeout (10 minutes max)
592+ p.SendOutput(progressChan, fmt.Sprintf("Compiling %s (this may take a few minutes)...", helper))
593+ buildCmd := fmt.Sprintf("su - %s -c 'cd /tmp && rm -rf %s && git clone https://aur.archlinux.org/%s.git && cd %s && makepkg -s --noconfirm'", p.config.Username, helper, helper, helper)
540594
541- switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, buildCmd); {
595+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
596+ defer cancel()
597+
598+ switch err := p.chrExec.ChrootExecWithContext(ctx, p.logger.LogPath(), config.PathMnt, buildCmd); {
599+ case err != nil:
600+ return fmt.Errorf("build failed or timed out: %w", err)
601+ }
602+
603+ // Install built package
604+ p.SendOutput(progressChan, fmt.Sprintf("Installing %s...", helper))
605+ installCmd := fmt.Sprintf("pacman -U --noconfirm /tmp/%s/*.pkg.tar.zst", helper)
606+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, installCmd); {
542607 case err != nil:
543- return fmt.Errorf("failed to build %s: %w", p.config.AURHelper, err)
608+ return fmt.Errorf("failed to install %s: %w", helper, err)
544609 }
545610
546- p.SendOutput(progressChan, fmt.Sprintf("[OK] %s built and installed successfully", p.config.AURHelper))
611+ // Cleanup
612+ cleanCmd := fmt.Sprintf("rm -rf /tmp/%s", helper)
613+ _ = p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cleanCmd)
547614
548615 return nil
549616 }
@@ -2,9 +2,11 @@ package phases
2 2
3 import (3 import (
4 "bufio"4 "bufio"
5+ "context"
5 "fmt"6 "fmt"
6 "path/filepath"7 "path/filepath"
7 "strings"8 "strings"
9+ "time"
8 10
9 "github.com/bnema/archup/internal/config"11 "github.com/bnema/archup/internal/config"
10 "github.com/bnema/archup/internal/interfaces"12 "github.com/bnema/archup/internal/interfaces"
@@ -46,10 +48,11 @@ func IsValidAURHelper(helper string) bool {
46 // ReposPhase handles repository configuration48 // ReposPhase handles repository configuration
47 type ReposPhase struct {49 type ReposPhase struct {
48 *BasePhase50 *BasePhase
49- fs interfaces.FileSystem51+ fs interfaces.FileSystem
50- sysExec interfaces.SystemExecutor52+ sysExec interfaces.SystemExecutor
51- chrExec interfaces.ChrootExecutor53+ chrExec interfaces.ChrootExecutor
52- chaoticConfig map[string]string54+ chaoticConfig map[string]string
55+ chaoticAUREnabled bool
53 }56 }
54 57
55 // NewReposPhase creates a new repos phase58 // NewReposPhase creates a new repos phase
@@ -401,6 +404,7 @@ func (p *ReposPhase) enableChaoticAUR(progressChan chan<- ProgressUpdate) error
401 }404 }
402 405
403 p.SendOutput(progressChan, "[OK] Chaotic-AUR enabled successfully")406 p.SendOutput(progressChan, "[OK] Chaotic-AUR enabled successfully")
407+ p.chaoticAUREnabled = true
404 408
405 return nil409 return nil
406 }410 }
@@ -512,38 +516,101 @@ func (p *ReposPhase) loadExtraPackages() ([]string, error) {
512 }516 }
513 517
514 // installAURHelper installs the selected AUR helper518 // installAURHelper installs the selected AUR helper
519+// Uses Chaotic-AUR if available, falls back to building from source
515 func (p *ReposPhase) installAURHelper(progressChan chan<- ProgressUpdate) error {520 func (p *ReposPhase) installAURHelper(progressChan chan<- ProgressUpdate) error {
516- p.SendOutput(progressChan, fmt.Sprintf("Building %s from AUR...", p.config.AURHelper))521+ helper := p.config.AURHelper
522+
523+ // Strategy 1: Try Chaotic-AUR if available
524+ if p.chaoticAUREnabled {
525+ p.SendOutput(progressChan, fmt.Sprintf("Attempting to install %s from Chaotic-AUR...", helper))
526+ tryCmd := fmt.Sprintf("pacman -S --noconfirm --needed %s", helper)
527+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, tryCmd); {
528+ case err == nil:
529+ p.SendOutput(progressChan, fmt.Sprintf("[OK] %s installed from Chaotic-AUR", helper))
530+ p.logger.Info("AUR helper installed from Chaotic-AUR", "helper", helper)
531+ return nil
532+ default:
533+ p.logger.Warn("Failed to install from Chaotic-AUR, building from source", "error", err)
534+ p.SendOutput(progressChan, "[WARN] Chaotic-AUR installation failed, building from source...")
535+ }
536+ }
537+
538+ // Strategy 2: Build from source with proper dependency verification
539+ p.SendOutput(progressChan, fmt.Sprintf("Building %s from AUR...", helper))
540+ if err := p.ensureBuildDeps(progressChan, helper); err != nil {
541+ return fmt.Errorf("failed to ensure build dependencies: %w", err)
542+ }
543+
544+ if err := p.buildFromAUR(progressChan, helper); err != nil {
545+ return fmt.Errorf("failed to build %s: %w", helper, err)
546+ }
547+
548+ p.SendOutput(progressChan, fmt.Sprintf("[OK] %s built and installed successfully", helper))
549+ p.logger.Info("AUR helper built from source", "helper", helper)
550+
551+ return nil
552+}
517 553
518- // Ensure build dependencies are installed554+// ensureBuildDeps verifies and installs build dependencies
555+func (p *ReposPhase) ensureBuildDeps(progressChan chan<- ProgressUpdate, helper string) error {
519 p.SendOutput(progressChan, "Verifying build dependencies...")556 p.SendOutput(progressChan, "Verifying build dependencies...")
520- depsCmd := "pacman -S --needed --noconfirm base-devel git"557+
521- switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, depsCmd); {558+ // Always need base-devel and git
559+ baseCmd := "pacman -S --needed --noconfirm base-devel git"
560+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, baseCmd); {
522 case err != nil:561 case err != nil:
523- p.logger.Warn("Failed to install build dependencies", "error", err)562+ p.logger.Warn("Failed to install base-devel", "error", err)
524- // Don't fail, they might already be installed563+ return fmt.Errorf("failed to install base-devel: %w", err)
525 }564 }
526 565
527- // Build AUR helper from source as configured user, then install as root566+ // Install language-specific dependencies
528- buildCmd := fmt.Sprintf(`567+ var langDeps string
529- set -e568+ switch helper {
569+ case "yay":
570+ langDeps = "go"
571+ case "paru":
572+ langDeps = "rust cargo"
573+ }
530 574
531- # Build as user (clone, build, etc.)575+ if langDeps != "" {
532- su - %s -c 'cd /tmp && rm -rf %s && git clone https://aur.archlinux.org/%s.git && cd %s && makepkg -s --noconfirm' || exit 1576+ p.SendOutput(progressChan, fmt.Sprintf("Installing %s dependencies...", helper))
577+ depCmd := fmt.Sprintf("pacman -S --needed --noconfirm %s", langDeps)
578+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, depCmd); {
579+ case err != nil:
580+ p.logger.Warn("Failed to install language dependencies", "helper", helper, "deps", langDeps, "error", err)
581+ return fmt.Errorf("failed to install %s: %w", langDeps, err)
582+ }
583+ }
533 584
534- # Install built package as root585+ p.SendOutput(progressChan, "[OK] Build dependencies verified")
535- pacman -U --noconfirm /tmp/%s/*.pkg.tar.zst || exit 1586+ return nil
587+}
536 588
537- # Clean up build directory589+// buildFromAUR builds an AUR package from source with timeout
538- rm -rf /tmp/%s590+func (p *ReposPhase) buildFromAUR(progressChan chan<- ProgressUpdate, helper string) error {
539- `, p.config.Username, p.config.AURHelper, p.config.AURHelper, p.config.AURHelper, p.config.AURHelper, p.config.AURHelper)591+ // Build as user with timeout (10 minutes max)
592+ p.SendOutput(progressChan, fmt.Sprintf("Compiling %s (this may take a few minutes)...", helper))
593+ buildCmd := fmt.Sprintf("su - %s -c 'cd /tmp && rm -rf %s && git clone https://aur.archlinux.org/%s.git && cd %s && makepkg -s --noconfirm'", p.config.Username, helper, helper, helper)
540 594
541- switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, buildCmd); {595+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
596+ defer cancel()
597+
598+ switch err := p.chrExec.ChrootExecWithContext(ctx, p.logger.LogPath(), config.PathMnt, buildCmd); {
599+ case err != nil:
600+ return fmt.Errorf("build failed or timed out: %w", err)
601+ }
602+
603+ // Install built package
604+ p.SendOutput(progressChan, fmt.Sprintf("Installing %s...", helper))
605+ installCmd := fmt.Sprintf("pacman -U --noconfirm /tmp/%s/*.pkg.tar.zst", helper)
606+ switch err := p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, installCmd); {
542 case err != nil:607 case err != nil:
543- return fmt.Errorf("failed to build %s: %w", p.config.AURHelper, err)608+ return fmt.Errorf("failed to install %s: %w", helper, err)
544 }609 }
545 610
546- p.SendOutput(progressChan, fmt.Sprintf("[OK] %s built and installed successfully", p.config.AURHelper))611+ // Cleanup
612+ cleanCmd := fmt.Sprintf("rm -rf /tmp/%s", helper)
613+ _ = p.chrExec.ChrootExec(p.logger.LogPath(), config.PathMnt, cleanCmd)
547 614
548 return nil615 return nil
549 }616 }
M internal/system/chroot.go +28 -0
@@ -1,6 +1,7 @@
11 package system
22
33 import (
4+ "context"
45 "fmt"
56 "os"
67 "os/exec"
@@ -22,6 +23,33 @@ func ChrootExec(logPath, mountPoint, command string, args ...string) error {
2223 return nil
2324 }
2425
26+// ChrootExecWithContext executes a command inside chroot with timeout support via context
27+// The context deadline will terminate the command if it takes too long
28+func ChrootExecWithContext(ctx context.Context, logPath, mountPoint, command string) error {
29+ cmd := exec.CommandContext(ctx, "arch-chroot", mountPoint, "bash", "-c", command)
30+
31+ // Set up logging
32+ if logPath != "" {
33+ logFile, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
34+ if err == nil {
35+ defer logFile.Close()
36+ cmd.Stdout = logFile
37+ cmd.Stderr = logFile
38+ }
39+ }
40+
41+ // Execute the command
42+ if err := cmd.Run(); err != nil {
43+ // Check if it was a context deadline exceeded
44+ if ctx.Err() == context.DeadlineExceeded {
45+ return fmt.Errorf("command timed out: %w", err)
46+ }
47+ return fmt.Errorf("failed to execute in chroot: %w", err)
48+ }
49+
50+ return nil
51+}
52+
2553 // ChrootExecWithStdin executes a command inside chroot with stdin input
2654 // This is secure for passing sensitive data like passwords without exposing them in process listings
2755 func ChrootExecWithStdin(logPath, mountPoint, command, stdin string) error {
@@ -1,6 +1,7 @@
1 package system1 package system
2 2
3 import (3 import (
4+ "context"
4 "fmt"5 "fmt"
5 "os"6 "os"
6 "os/exec"7 "os/exec"
@@ -22,6 +23,33 @@ func ChrootExec(logPath, mountPoint, command string, args ...string) error {
22 return nil23 return nil
23 }24 }
24 25
26+// ChrootExecWithContext executes a command inside chroot with timeout support via context
27+// The context deadline will terminate the command if it takes too long
28+func ChrootExecWithContext(ctx context.Context, logPath, mountPoint, command string) error {
29+ cmd := exec.CommandContext(ctx, "arch-chroot", mountPoint, "bash", "-c", command)
30+
31+ // Set up logging
32+ if logPath != "" {
33+ logFile, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
34+ if err == nil {
35+ defer logFile.Close()
36+ cmd.Stdout = logFile
37+ cmd.Stderr = logFile
38+ }
39+ }
40+
41+ // Execute the command
42+ if err := cmd.Run(); err != nil {
43+ // Check if it was a context deadline exceeded
44+ if ctx.Err() == context.DeadlineExceeded {
45+ return fmt.Errorf("command timed out: %w", err)
46+ }
47+ return fmt.Errorf("failed to execute in chroot: %w", err)
48+ }
49+
50+ return nil
51+}
52+
25 // ChrootExecWithStdin executes a command inside chroot with stdin input53 // ChrootExecWithStdin executes a command inside chroot with stdin input
26 // This is secure for passing sensitive data like passwords without exposing them in process listings54 // This is secure for passing sensitive data like passwords without exposing them in process listings
27 func ChrootExecWithStdin(logPath, mountPoint, command, stdin string) error {55 func ChrootExecWithStdin(logPath, mountPoint, command, stdin string) error {
A internal/system/network.go +30 -0
@@ -0,0 +1,30 @@
1+package system
2+
3+import (
4+ "fmt"
5+ "net/http"
6+ "time"
7+)
8+
9+const (
10+ NetworkCheckURL = "https://raw.githubusercontent.com"
11+ NetworkCheckTimeout = 5 * time.Second
12+)
13+
14+// CheckNetworkConnectivity verifies internet connectivity
15+// Returns nil if network is available, error otherwise
16+func CheckNetworkConnectivity() error {
17+ client := &http.Client{Timeout: NetworkCheckTimeout}
18+
19+ resp, err := client.Get(NetworkCheckURL)
20+ if err != nil {
21+ return fmt.Errorf("network connectivity check failed: %w", err)
22+ }
23+ defer resp.Body.Close()
24+
25+ if resp.StatusCode != http.StatusOK {
26+ return fmt.Errorf("network check returned HTTP %d", resp.StatusCode)
27+ }
28+
29+ return nil
30+}
@@ -0,0 +1,30 @@
1+package system
2+
3+import (
4+ "fmt"
5+ "net/http"
6+ "time"
7+)
8+
9+const (
10+ NetworkCheckURL = "https://raw.githubusercontent.com"
11+ NetworkCheckTimeout = 5 * time.Second
12+)
13+
14+// CheckNetworkConnectivity verifies internet connectivity
15+// Returns nil if network is available, error otherwise
16+func CheckNetworkConnectivity() error {
17+ client := &http.Client{Timeout: NetworkCheckTimeout}
18+
19+ resp, err := client.Get(NetworkCheckURL)
20+ if err != nil {
21+ return fmt.Errorf("network connectivity check failed: %w", err)
22+ }
23+ defer resp.Body.Close()
24+
25+ if resp.StatusCode != http.StatusOK {
26+ return fmt.Errorf("network check returned HTTP %d", resp.StatusCode)
27+ }
28+
29+ return nil
30+}
M internal/ui/model.go +42 -0
@@ -21,6 +21,7 @@ type ModelState int
2121
2222 const (
2323 StateShowLogo ModelState = iota
24+ StateNetworkCheck
2425 StatePreflightForm
2526 StateDiskForm
2627 StateOptionsForm
@@ -51,6 +52,8 @@ type Model struct {
5152 cpuInfo *system.CPUInfo
5253 installStartTime time.Time
5354 installEndTime time.Duration
55+ networkCheckDone bool
56+ networkErr error
5457 }
5558
5659 // NewModel creates a new installer model
@@ -103,6 +106,17 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
103106 case "enter":
104107 switch m.state {
105108 case StateShowLogo:
109+ m.logger.Info("Moving to network check")
110+ m.state = StateNetworkCheck
111+ return m, m.checkNetwork()
112+
113+ case StateNetworkCheck:
114+ // Handle retry if network check failed
115+ if m.networkErr != nil {
116+ m.logger.Info("Retrying network check")
117+ return m, m.checkNetwork()
118+ }
119+ // Network check passed, move to preflight form
106120 m.logger.Info("Moving to preflight form")
107121 m.state = StatePreflightForm
108122 m.currentForm = CreatePreflightForm(m.config, m.formBuilder, m.system)
@@ -145,6 +159,16 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
145159 }
146160 }
147161
162+ case networkCheckMsg:
163+ m.networkCheckDone = true
164+ m.networkErr = msg.err
165+ if msg.err != nil {
166+ m.logger.Warn("Network check failed", "error", msg.err)
167+ } else {
168+ m.logger.Info("Network check passed")
169+ }
170+ return m, nil
171+
148172 case phaseCompleteMsg:
149173 switch {
150174 case msg.err != nil:
@@ -220,6 +244,9 @@ func (m *Model) View() string {
220244 case StateShowLogo:
221245 return views.RenderWelcome(m)
222246
247+ case StateNetworkCheck:
248+ return views.RenderNetworkCheck(m)
249+
223250 case StatePreflightForm, StateDiskForm, StateOptionsForm, StateAMDPStatePrompt:
224251 return views.RenderForm(m)
225252
@@ -322,6 +349,8 @@ func (m *Model) CurrentForm() *huh.Form { return m.currentForm }
322349 func (m *Model) Spinner() spinner.Model { return m.spinner }
323350 func (m *Model) Output() *components.OutputViewer { return m.output }
324351 func (m *Model) RenderPhaseHeader() string { return m.renderPhaseHeader() }
352+func (m *Model) NetworkCheckDone() bool { return m.networkCheckDone }
353+func (m *Model) NetworkErr() error { return m.networkErr }
325354
326355 // executeNextPhase executes the next pending phase
327356 func (m *Model) executeNextPhase() tea.Cmd {
@@ -347,6 +376,19 @@ type phaseCompleteMsg struct {
347376 err error
348377 }
349378
379+// networkCheckMsg signals network check completion
380+type networkCheckMsg struct {
381+ err error
382+}
383+
384+// checkNetwork runs network connectivity check in background
385+func (m *Model) checkNetwork() tea.Cmd {
386+ return func() tea.Msg {
387+ err := system.CheckNetworkConnectivity()
388+ return networkCheckMsg{err: err}
389+ }
390+}
391+
350392 // renderPhaseHeader renders phase progress header
351393 func (m *Model) renderPhaseHeader() string {
352394 var stepNum, stepName string
@@ -21,6 +21,7 @@ type ModelState int
21 21
22 const (22 const (
23 StateShowLogo ModelState = iota23 StateShowLogo ModelState = iota
24+ StateNetworkCheck
24 StatePreflightForm25 StatePreflightForm
25 StateDiskForm26 StateDiskForm
26 StateOptionsForm27 StateOptionsForm
@@ -51,6 +52,8 @@ type Model struct {
51 cpuInfo *system.CPUInfo52 cpuInfo *system.CPUInfo
52 installStartTime time.Time53 installStartTime time.Time
53 installEndTime time.Duration54 installEndTime time.Duration
55+ networkCheckDone bool
56+ networkErr error
54 }57 }
55 58
56 // NewModel creates a new installer model59 // NewModel creates a new installer model
@@ -103,6 +106,17 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
103 case "enter":106 case "enter":
104 switch m.state {107 switch m.state {
105 case StateShowLogo:108 case StateShowLogo:
109+ m.logger.Info("Moving to network check")
110+ m.state = StateNetworkCheck
111+ return m, m.checkNetwork()
112+
113+ case StateNetworkCheck:
114+ // Handle retry if network check failed
115+ if m.networkErr != nil {
116+ m.logger.Info("Retrying network check")
117+ return m, m.checkNetwork()
118+ }
119+ // Network check passed, move to preflight form
106 m.logger.Info("Moving to preflight form")120 m.logger.Info("Moving to preflight form")
107 m.state = StatePreflightForm121 m.state = StatePreflightForm
108 m.currentForm = CreatePreflightForm(m.config, m.formBuilder, m.system)122 m.currentForm = CreatePreflightForm(m.config, m.formBuilder, m.system)
@@ -145,6 +159,16 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
145 }159 }
146 }160 }
147 161
162+ case networkCheckMsg:
163+ m.networkCheckDone = true
164+ m.networkErr = msg.err
165+ if msg.err != nil {
166+ m.logger.Warn("Network check failed", "error", msg.err)
167+ } else {
168+ m.logger.Info("Network check passed")
169+ }
170+ return m, nil
171+
148 case phaseCompleteMsg:172 case phaseCompleteMsg:
149 switch {173 switch {
150 case msg.err != nil:174 case msg.err != nil:
@@ -220,6 +244,9 @@ func (m *Model) View() string {
220 case StateShowLogo:244 case StateShowLogo:
221 return views.RenderWelcome(m)245 return views.RenderWelcome(m)
222 246
247+ case StateNetworkCheck:
248+ return views.RenderNetworkCheck(m)
249+
223 case StatePreflightForm, StateDiskForm, StateOptionsForm, StateAMDPStatePrompt:250 case StatePreflightForm, StateDiskForm, StateOptionsForm, StateAMDPStatePrompt:
224 return views.RenderForm(m)251 return views.RenderForm(m)
225 252
@@ -322,6 +349,8 @@ func (m *Model) CurrentForm() *huh.Form { return m.currentForm }
322 func (m *Model) Spinner() spinner.Model { return m.spinner }349 func (m *Model) Spinner() spinner.Model { return m.spinner }
323 func (m *Model) Output() *components.OutputViewer { return m.output }350 func (m *Model) Output() *components.OutputViewer { return m.output }
324 func (m *Model) RenderPhaseHeader() string { return m.renderPhaseHeader() }351 func (m *Model) RenderPhaseHeader() string { return m.renderPhaseHeader() }
352+func (m *Model) NetworkCheckDone() bool { return m.networkCheckDone }
353+func (m *Model) NetworkErr() error { return m.networkErr }
325 354
326 // executeNextPhase executes the next pending phase355 // executeNextPhase executes the next pending phase
327 func (m *Model) executeNextPhase() tea.Cmd {356 func (m *Model) executeNextPhase() tea.Cmd {
@@ -347,6 +376,19 @@ type phaseCompleteMsg struct {
347 err error376 err error
348 }377 }
349 378
379+// networkCheckMsg signals network check completion
380+type networkCheckMsg struct {
381+ err error
382+}
383+
384+// checkNetwork runs network connectivity check in background
385+func (m *Model) checkNetwork() tea.Cmd {
386+ return func() tea.Msg {
387+ err := system.CheckNetworkConnectivity()
388+ return networkCheckMsg{err: err}
389+ }
390+}
391+
350 // renderPhaseHeader renders phase progress header392 // renderPhaseHeader renders phase progress header
351 func (m *Model) renderPhaseHeader() string {393 func (m *Model) renderPhaseHeader() string {
352 var stepNum, stepName string394 var stepNum, stepName string
M internal/ui/model/model.go +2 -0
@@ -16,4 +16,6 @@ type UI interface {
1616 Spinner() spinner.Model
1717 Output() *components.OutputViewer
1818 RenderPhaseHeader() string
19+ NetworkCheckDone() bool
20+ NetworkErr() error
1921 }
@@ -16,4 +16,6 @@ type UI interface {
16 Spinner() spinner.Model16 Spinner() spinner.Model
17 Output() *components.OutputViewer17 Output() *components.OutputViewer
18 RenderPhaseHeader() string18 RenderPhaseHeader() string
19+ NetworkCheckDone() bool
20+ NetworkErr() error
19 }21 }
A internal/ui/views/network.go +34 -0
@@ -0,0 +1,34 @@
1+package views
2+
3+import (
4+ "fmt"
5+
6+ "github.com/bnema/archup/internal/ui/model"
7+ "github.com/bnema/archup/internal/ui/styles"
8+)
9+
10+// RenderNetworkCheck renders the network connectivity check screen
11+func RenderNetworkCheck(m model.UI) string {
12+ spinner := m.Spinner()
13+ spinnerView := spinner.View()
14+
15+ var content string
16+
17+ // If network check is still running
18+ if !m.NetworkCheckDone() {
19+ content = CenterText(spinnerView+" Checking network connectivity...", m.Width()) + "\n\n" +
20+ CenterText(styles.HelpStyle.Render("Please wait..."), m.Width())
21+ } else if m.NetworkErr() != nil {
22+ // Network check failed
23+ errorMsg := fmt.Sprintf("Network error: %v", m.NetworkErr())
24+ content = CenterText(styles.ErrorStyle.Render("✗ Network Check Failed"), m.Width()) + "\n\n" +
25+ CenterText(errorMsg, m.Width()) + "\n\n" +
26+ CenterText(styles.HelpStyle.Render("Press ENTER to retry or CTRL+C to exit"), m.Width())
27+ } else {
28+ // Network check passed
29+ content = CenterText(styles.SuccessStyle.Render("✓ Network Check Passed"), m.Width()) + "\n\n" +
30+ CenterText(styles.HelpStyle.Render("Press ENTER to continue"), m.Width())
31+ }
32+
33+ return styles.CenteredContainerStyle.Render(content)
34+}
@@ -0,0 +1,34 @@
1+package views
2+
3+import (
4+ "fmt"
5+
6+ "github.com/bnema/archup/internal/ui/model"
7+ "github.com/bnema/archup/internal/ui/styles"
8+)
9+
10+// RenderNetworkCheck renders the network connectivity check screen
11+func RenderNetworkCheck(m model.UI) string {
12+ spinner := m.Spinner()
13+ spinnerView := spinner.View()
14+
15+ var content string
16+
17+ // If network check is still running
18+ if !m.NetworkCheckDone() {
19+ content = CenterText(spinnerView+" Checking network connectivity...", m.Width()) + "\n\n" +
20+ CenterText(styles.HelpStyle.Render("Please wait..."), m.Width())
21+ } else if m.NetworkErr() != nil {
22+ // Network check failed
23+ errorMsg := fmt.Sprintf("Network error: %v", m.NetworkErr())
24+ content = CenterText(styles.ErrorStyle.Render("✗ Network Check Failed"), m.Width()) + "\n\n" +
25+ CenterText(errorMsg, m.Width()) + "\n\n" +
26+ CenterText(styles.HelpStyle.Render("Press ENTER to retry or CTRL+C to exit"), m.Width())
27+ } else {
28+ // Network check passed
29+ content = CenterText(styles.SuccessStyle.Render("✓ Network Check Passed"), m.Width()) + "\n\n" +
30+ CenterText(styles.HelpStyle.Render("Press ENTER to continue"), m.Width())
31+ }
32+
33+ return styles.CenteredContainerStyle.Render(content)
34+}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 0

    ↑↓ moveenter openesc close