diff --git a/cmd/dbc/install.go b/cmd/dbc/install.go index 82ab5cba..e56eb762 100644 --- a/cmd/dbc/install.go +++ b/cmd/dbc/install.go @@ -130,6 +130,8 @@ type progressiveInstallModel struct { state installState spinner spinner.Model + + width, height int } func (m progressiveInstallModel) Init() tea.Cmd { @@ -142,6 +144,31 @@ func (m progressiveInstallModel) Init() tea.Cmd { }) } +func (m progressiveInstallModel) FinalOutput() string { + if m.conflictingInfo.ID != "" && m.conflictingInfo.Version != nil { + if m.conflictingInfo.Version.Equal(m.DriverPackage.Version) { + return fmt.Sprintf("\nDriver %s %s already installed at %s\n", + m.conflictingInfo.ID, m.conflictingInfo.Version, filepath.SplitList(m.cfg.Location)[0]) + } + } + + var b strings.Builder + if m.state == stDone { + if m.conflictingInfo.ID != "" && m.conflictingInfo.Version != nil { + b.WriteString(fmt.Sprintf("\nRemoved conflicting driver: %s (version: %s)", + m.conflictingInfo.ID, m.conflictingInfo.Version)) + } + + b.WriteString(fmt.Sprintf("\nInstalled %s %s to %s\n", + m.Driver, m.DriverPackage.Version, filepath.SplitList(m.cfg.Location)[0])) + + if m.postInstallMessage != "" { + b.WriteString("\n" + postMsgStyle.Render(m.postInstallMessage) + "\n") + } + } + return b.String() +} + func (m progressiveInstallModel) searchForDriver(d dbc.Driver) tea.Cmd { return func() tea.Msg { pkg, err := d.GetPackage(m.VersionInput, config.PlatformTuple()) @@ -190,6 +217,8 @@ func (m progressiveInstallModel) startInstalling(downloaded *os.File) (tea.Model func (m progressiveInstallModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { + case tea.WindowSizeMsg: + m.width, m.height = msg.Width, msg.Height case spinner.TickMsg: var cmd tea.Cmd m.spinner, cmd = m.spinner.Update(msg) @@ -248,8 +277,7 @@ func (m progressiveInstallModel) View() string { if m.conflictingInfo.ID != "" && m.conflictingInfo.Version != nil { if m.conflictingInfo.Version.Equal(m.DriverPackage.Version) { - return fmt.Sprintf("\nDriver %s %s already installed at %s\n", - m.conflictingInfo.ID, m.conflictingInfo.Version, filepath.SplitList(m.cfg.Location)[0]) + return "" } } @@ -263,18 +291,5 @@ func (m progressiveInstallModel) View() string { b.WriteByte('\n') } - if m.state == stDone { - if m.conflictingInfo.ID != "" && m.conflictingInfo.Version != nil { - b.WriteString(fmt.Sprintf("\nRemoved conflicting driver: %s (version: %s)", - m.conflictingInfo.ID, m.conflictingInfo.Version)) - } - - b.WriteString(fmt.Sprintf("\nInstalled %s %s to %s\n", - m.Driver, m.DriverPackage.Version, filepath.SplitList(m.cfg.Location)[0])) - - if m.postInstallMessage != "" { - b.WriteString("\n" + postMsgStyle.Render(m.postInstallMessage) + "\n") - } - } return b.String() } diff --git a/cmd/dbc/install_test.go b/cmd/dbc/install_test.go index 2b63a979..c82091a8 100644 --- a/cmd/dbc/install_test.go +++ b/cmd/dbc/install_test.go @@ -16,8 +16,8 @@ func (suite *SubcommandTestSuite) TestInstall() { GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) out := suite.runCmd(m) - suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n"+ - "\r\nInstalled test-driver-1 1.1.0 to "+suite.tempdir+"\r\n", out) + suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n", + "\nInstalled test-driver-1 1.1.0 to "+suite.tempdir+"\n", out) if runtime.GOOS != "windows" { suite.FileExists(filepath.Join(suite.tempdir, "test-driver-1.toml")) } @@ -26,7 +26,7 @@ func (suite *SubcommandTestSuite) TestInstall() { func (suite *SubcommandTestSuite) TestInstallDriverNotFound() { m := InstallCmd{Driver: "foo", Level: config.ConfigEnv}. GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("Error: could not find driver: driver `foo` not found in driver index\r\n\r ", suite.runCmdErr(m)) + suite.validateOutput("Error: could not find driver: driver `foo` not found in driver index\r\n\r ", "", suite.runCmdErr(m)) } func (suite *SubcommandTestSuite) TestInstallUserFake() { @@ -85,8 +85,8 @@ func (suite *SubcommandTestSuite) TestInstallVenv() { m := InstallCmd{Driver: "test-driver-1"}. GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n"+ - "\r\nInstalled test-driver-1 1.1.0 to "+filepath.Join(suite.tempdir, "etc", "adbc", "drivers")+"\r\n", suite.runCmd(m)) + suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n", + "\nInstalled test-driver-1 1.1.0 to "+filepath.Join(suite.tempdir, "etc", "adbc", "drivers")+"\n", suite.runCmd(m)) } func (suite *SubcommandTestSuite) TestInstallCondaPrefix() { @@ -96,8 +96,8 @@ func (suite *SubcommandTestSuite) TestInstallCondaPrefix() { m := InstallCmd{Driver: "test-driver-1"}. GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n"+ - "\r\nInstalled test-driver-1 1.1.0 to "+filepath.Join(suite.tempdir, "etc", "adbc", "drivers")+"\r\n", suite.runCmd(m)) + suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n", + "\nInstalled test-driver-1 1.1.0 to "+filepath.Join(suite.tempdir, "etc", "adbc", "drivers")+"\n", suite.runCmd(m)) } func (suite *SubcommandTestSuite) TestInstallUserFakeExplicitLevelOverrides() { @@ -120,9 +120,9 @@ func (suite *SubcommandTestSuite) TestInstallUserFakeExplicitLevelOverrides() { func (suite *SubcommandTestSuite) TestInstallManifestOnlyDriver() { m := InstallCmd{Driver: "test-driver-manifest-only"}. GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n"+ - "\r\nInstalled test-driver-manifest-only 1.0.0 to "+suite.tempdir+"\r\n"+ - "\r\nMust have libtest_driver installed to load this driver\r\n", suite.runCmd(m)) + suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n", + "\nInstalled test-driver-manifest-only 1.0.0 to "+suite.tempdir+"\n"+ + "\nMust have libtest_driver installed to load this driver\n", suite.runCmd(m)) if runtime.GOOS != "windows" { suite.FileExists(filepath.Join(suite.tempdir, "test-driver-manifest-only.toml")) } @@ -149,6 +149,6 @@ func (suite *SubcommandTestSuite) TestInstallDriverNoSignature() { m = InstallCmd{Driver: "test-driver-no-sig", NoVerify: true}. GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n"+ - "\r\nInstalled test-driver-no-sig 1.0.0 to "+suite.tempdir+"\r\n", suite.runCmd(m)) + suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n", + "\nInstalled test-driver-no-sig 1.0.0 to "+suite.tempdir+"\n", suite.runCmd(m)) } diff --git a/cmd/dbc/main.go b/cmd/dbc/main.go index ccbe6fe2..a3e6d129 100644 --- a/cmd/dbc/main.go +++ b/cmd/dbc/main.go @@ -34,6 +34,10 @@ func errCmd(format string, a ...any) tea.Cmd { } } +type HasFinalOutput interface { + FinalOutput() string +} + type HasStatus interface { Status() int } @@ -83,6 +87,8 @@ func (m baseModel) Status() int { return m.status } +func (m baseModel) FinalOutput() string { return "" } + func (m baseModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: @@ -134,6 +140,10 @@ func main() { os.Exit(1) } + if fo, ok := m.(HasFinalOutput); ok { + fmt.Print(fo.FinalOutput()) + } + if h, ok := m.(HasStatus); ok { os.Exit(h.Status()) } diff --git a/cmd/dbc/search_test.go b/cmd/dbc/search_test.go index 1b880f7c..842f7d44 100644 --- a/cmd/dbc/search_test.go +++ b/cmd/dbc/search_test.go @@ -15,7 +15,7 @@ func (suite *SubcommandTestSuite) TestSearchCmd() { suite.validateOutput("• test-driver-1 - This is a test driver\r\n"+ "• test-driver-2 - This is another test driver\r\n"+ "• test-driver-manifest-only - This is manifest-only driver\r\n"+ - "• test-driver-no-sig - Driver manifest missing Files.signature entry\r\n\r ", suite.runCmd(m)) + "• test-driver-no-sig - Driver manifest missing Files.signature entry\r\n\r ", "", suite.runCmd(m)) } func (suite *SubcommandTestSuite) TestSearchCmdWithInstalled() { @@ -28,7 +28,7 @@ func (suite *SubcommandTestSuite) TestSearchCmdWithInstalled() { downloadPkg: downloadTestPkg}) suite.validateOutput("• test-driver-1 - This is a test driver [installed: env=>1.1.0]\r\n"+ "• test-driver-2 - This is another test driver\r\n• test-driver-manifest-only - This is manifest-only driver\r\n"+ - "• test-driver-no-sig - Driver manifest missing Files.signature entry\r\n\r ", suite.runCmd(m)) + "• test-driver-no-sig - Driver manifest missing Files.signature entry\r\n\r ", "", suite.runCmd(m)) } func (suite *SubcommandTestSuite) TestSearchCmdVerbose() { @@ -46,7 +46,7 @@ func (suite *SubcommandTestSuite) TestSearchCmdVerbose() { "Available Versions:\r\n ╰── 1.0.0\r\n"+ "• test-driver-no-sig\r\n Title: Test Driver No Signature\r\n "+ "Description: Driver manifest missing Files.signature entry\r\n License: Apache-2.0\r\n "+ - "Available Versions:\r\n ╰── 1.0.0\r\n\r ", suite.runCmd(m)) + "Available Versions:\r\n ╰── 1.0.0\r\n\r ", "", suite.runCmd(m)) } func (suite *SubcommandTestSuite) TestSearchCmdVerboseWithInstalled() { @@ -75,5 +75,5 @@ func (suite *SubcommandTestSuite) TestSearchCmdVerboseWithInstalled() { " Description: Driver manifest missing Files.signature entry\r\n"+ " License: Apache-2.0\r\n"+ " Available Versions:\r\n"+ - " ╰── 1.0.0\r\n\r ", suite.runCmd(m)) + " ╰── 1.0.0\r\n\r ", "", suite.runCmd(m)) } diff --git a/cmd/dbc/sync_test.go b/cmd/dbc/sync_test.go index 46be5613..fad61df3 100644 --- a/cmd/dbc/sync_test.go +++ b/cmd/dbc/sync_test.go @@ -101,16 +101,21 @@ func (suite *SubcommandTestSuite) runCmd(m tea.Model) string { m, err = p.Run() suite.Require().NoError(err) suite.Equal(0, m.(HasStatus).Status(), "The command exited with a non-zero status.") - return out.String() + + var extra string + if fo, ok := m.(HasFinalOutput); ok { + extra = fo.FinalOutput() + } + return out.String() + extra } -func (suite *SubcommandTestSuite) validateOutput(expected, actual string) { +func (suite *SubcommandTestSuite) validateOutput(expected, extra, actual string) { const ( terminalPrefix = "\x1b[?25l\x1b[?2004h" terminalSuffix = "\r\x1b[2K\r\x1b[?2004l\x1b[?25h\x1b[?1002l\x1b[?1003l\x1b[?1006l" ) - suite.Equal(terminalPrefix+expected+terminalSuffix, actual) + suite.Equal(terminalPrefix+expected+terminalSuffix+extra, actual) } func (suite *SubcommandTestSuite) TestSync() { @@ -124,14 +129,14 @@ func (suite *SubcommandTestSuite) TestSync() { Path: filepath.Join(suite.tempdir, "dbc.toml"), }.GetModelCustom( baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("✓ test-driver-1-1.1.0\r\n\rDone!\r\n", suite.runCmd(m)) + suite.validateOutput("✓ test-driver-1-1.1.0\r\n\rDone!\r\n", "", suite.runCmd(m)) suite.FileExists(filepath.Join(suite.tempdir, "test-driver-1.toml")) m = SyncCmd{ Path: filepath.Join(suite.tempdir, "dbc.toml"), }.GetModelCustom( baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("✓ test-driver-1-1.1.0 already installed\r\n\rDone!\r\n", suite.runCmd(m)) + suite.validateOutput("✓ test-driver-1-1.1.0 already installed\r\n\rDone!\r\n", "", suite.runCmd(m)) } func (suite *SubcommandTestSuite) TestSyncVirtualEnv() { @@ -150,14 +155,14 @@ func (suite *SubcommandTestSuite) TestSyncVirtualEnv() { Path: filepath.Join(suite.tempdir, "dbc.toml"), }.GetModelCustom( baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("✓ test-driver-1-1.1.0\r\n\rDone!\r\n", suite.runCmd(m)) + suite.validateOutput("✓ test-driver-1-1.1.0\r\n\rDone!\r\n", "", suite.runCmd(m)) suite.FileExists(filepath.Join(suite.tempdir, "etc", "adbc", "drivers", "test-driver-1.toml")) m = SyncCmd{ Path: filepath.Join(suite.tempdir, "dbc.toml"), }.GetModelCustom( baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("✓ test-driver-1-1.1.0 already installed\r\n\rDone!\r\n", suite.runCmd(m)) + suite.validateOutput("✓ test-driver-1-1.1.0 already installed\r\n\rDone!\r\n", "", suite.runCmd(m)) } func (suite *SubcommandTestSuite) TestSyncCondaPrefix() { @@ -176,14 +181,14 @@ func (suite *SubcommandTestSuite) TestSyncCondaPrefix() { Path: filepath.Join(suite.tempdir, "dbc.toml"), }.GetModelCustom( baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("✓ test-driver-1-1.1.0\r\n\rDone!\r\n", suite.runCmd(m)) + suite.validateOutput("✓ test-driver-1-1.1.0\r\n\rDone!\r\n", "", suite.runCmd(m)) suite.FileExists(filepath.Join(suite.tempdir, "etc", "adbc", "drivers", "test-driver-1.toml")) m = SyncCmd{ Path: filepath.Join(suite.tempdir, "dbc.toml"), }.GetModelCustom( baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("✓ test-driver-1-1.1.0 already installed\r\n\rDone!\r\n", suite.runCmd(m)) + suite.validateOutput("✓ test-driver-1-1.1.0 already installed\r\n\rDone!\r\n", "", suite.runCmd(m)) } func TestSubcommands(t *testing.T) { diff --git a/cmd/dbc/uninstall_test.go b/cmd/dbc/uninstall_test.go index 7b5f70b0..f04d093e 100644 --- a/cmd/dbc/uninstall_test.go +++ b/cmd/dbc/uninstall_test.go @@ -19,7 +19,7 @@ func (suite *SubcommandTestSuite) TestUninstallNotFound() { m := UninstallCmd{Driver: "notfound"}.GetModel() suite.validateOutput("Error: failed to find driver `notfound` in order to uninstall it: error opening manifest "+ - filepath.Join(suite.tempdir, "notfound.toml")+": open "+filepath.Join(suite.tempdir, "notfound.toml")+": no such file or directory\r\n\r ", suite.runCmdErr(m)) + filepath.Join(suite.tempdir, "notfound.toml")+": open "+filepath.Join(suite.tempdir, "notfound.toml")+": no such file or directory\r\n\r ", "", suite.runCmdErr(m)) } func (suite *SubcommandTestSuite) TestUninstallManifestOnly() { @@ -37,7 +37,7 @@ func (suite *SubcommandTestSuite) TestUninstallManifestOnly() { os.WriteFile(path.Join(suite.tempdir, "found.toml"), []byte(contents), 0644) m := UninstallCmd{Driver: "found", Level: config.ConfigEnv}.GetModel() - suite.validateOutput("Driver `found` uninstalled successfully!\r\n\r\n\r ", suite.runCmd(m)) + suite.validateOutput("Driver `found` uninstalled successfully!\r\n\r\n\r ", "", suite.runCmd(m)) } func (suite *SubcommandTestSuite) TestUninstallDriverAndManifest() { @@ -58,7 +58,7 @@ func (suite *SubcommandTestSuite) TestUninstallDriverAndManifest() { os.WriteFile(path.Join(pkgdir, "some.dll"), []byte("anything"), 0o644) m := UninstallCmd{Driver: "found", Level: config.ConfigEnv}.GetModel() - suite.validateOutput("Driver `found` uninstalled successfully!\r\n\r\n\r ", suite.runCmd(m)) + suite.validateOutput("Driver `found` uninstalled successfully!\r\n\r\n\r ", "", suite.runCmd(m)) } // Test what happens when a user installs a driver in multiple locations @@ -129,9 +129,9 @@ func (suite *SubcommandTestSuite) TestUninstallMultipleLocationsNonDefault() { func (suite *SubcommandTestSuite) TestUninstallManifestOnlyDriver() { m := InstallCmd{Driver: "test-driver-manifest-only"}. GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n"+ - "\r\nInstalled test-driver-manifest-only 1.0.0 to "+suite.tempdir+"\r\n"+ - "\r\nMust have libtest_driver installed to load this driver\r\n", suite.runCmd(m)) + suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n", + "\nInstalled test-driver-manifest-only 1.0.0 to "+suite.tempdir+"\n"+ + "\nMust have libtest_driver installed to load this driver\n", suite.runCmd(m)) if runtime.GOOS != "windows" { suite.FileExists(filepath.Join(suite.tempdir, "test-driver-manifest-only.toml")) } @@ -147,7 +147,7 @@ func (suite *SubcommandTestSuite) TestUninstallManifestOnlyDriver() { // Now uninstall and verify we clean up m = UninstallCmd{Driver: "test-driver-manifest-only"}. GetModelCustom(baseModel{getDriverList: getTestDriverList, downloadPkg: downloadTestPkg}) - suite.validateOutput("Driver `test-driver-manifest-only` uninstalled successfully!\r\n\r\n\r ", suite.runCmd(m)) + suite.validateOutput("Driver `test-driver-manifest-only` uninstalled successfully!\r\n\r\n\r ", "", suite.runCmd(m)) if runtime.GOOS != "windows" { suite.NoFileExists(filepath.Join(suite.tempdir, "test-driver-manifest-only.toml")) }