Fix: Ctrl+C now works in TUI, improve database creation with peer auth support

This commit is contained in:
2025-11-07 10:35:24 +00:00
parent d2fa4025db
commit 98fa594f59
4 changed files with 40 additions and 23 deletions

BIN
dbbackup

Binary file not shown.

Binary file not shown.

View File

@ -410,30 +410,44 @@ func (e *Engine) restoreGlobals(ctx context.Context, globalsFile string) error {
// ensureDatabaseExists checks if a database exists and creates it if not // ensureDatabaseExists checks if a database exists and creates it if not
func (e *Engine) ensureDatabaseExists(ctx context.Context, dbName string) error { func (e *Engine) ensureDatabaseExists(ctx context.Context, dbName string) error {
// Check if database exists using psql // Build psql command with authentication
checkCmd := exec.CommandContext(ctx, "psql", buildPsqlCmd := func(ctx context.Context, database, query string) *exec.Cmd {
"-h", e.cfg.Host, args := []string{
"-p", fmt.Sprintf("%d", e.cfg.Port), "-h", e.cfg.Host,
"-U", e.cfg.User, "-p", fmt.Sprintf("%d", e.cfg.Port),
"-d", "postgres", // Connect to default postgres database "-U", e.cfg.User,
"-tAc", "-d", database,
fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", dbName), "-tAc", query,
) }
checkCmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", e.cfg.Password))
cmd := exec.CommandContext(ctx, "psql", args...)
// Set PGPASSWORD only if password is provided
if e.cfg.Password != "" {
cmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", e.cfg.Password))
}
return cmd
}
// Check if database exists
checkCmd := buildPsqlCmd(ctx, "postgres", fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", dbName))
output, err := checkCmd.CombinedOutput() output, err := checkCmd.CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("failed to check database existence: %w", err) e.log.Warn("Database existence check failed", "name", dbName, "error", err, "output", string(output))
// Continue anyway - maybe we can create it
} }
// If database exists, we're done // If database exists, we're done
if strings.TrimSpace(string(output)) == "1" { if strings.TrimSpace(string(output)) == "1" {
e.log.Info(fmt.Sprintf("Database '%s' already exists", dbName)) e.log.Info("Database already exists", "name", dbName)
return nil return nil
} }
// Database doesn't exist, create it // Database doesn't exist, create it
e.log.Info(fmt.Sprintf("Creating database '%s'", dbName)) e.log.Info("Creating database", "name", dbName)
createCmd := exec.CommandContext(ctx, "psql", createCmd := exec.CommandContext(ctx, "psql",
"-h", e.cfg.Host, "-h", e.cfg.Host,
"-p", fmt.Sprintf("%d", e.cfg.Port), "-p", fmt.Sprintf("%d", e.cfg.Port),
@ -441,14 +455,20 @@ func (e *Engine) ensureDatabaseExists(ctx context.Context, dbName string) error
"-d", "postgres", "-d", "postgres",
"-c", fmt.Sprintf("CREATE DATABASE \"%s\"", dbName), "-c", fmt.Sprintf("CREATE DATABASE \"%s\"", dbName),
) )
createCmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", e.cfg.Password))
// Set PGPASSWORD only if password is provided
if e.cfg.Password != "" {
createCmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", e.cfg.Password))
}
output, err = createCmd.CombinedOutput() output, err = createCmd.CombinedOutput()
if err != nil { if err != nil {
return fmt.Errorf("failed to create database '%s': %w\nOutput: %s", dbName, err, string(output)) // Log the error but don't fail - pg_restore might handle it
e.log.Warn("Database creation failed", "name", dbName, "error", err, "output", string(output))
return fmt.Errorf("failed to create database '%s': %w", dbName, err)
} }
e.log.Info(fmt.Sprintf("Successfully created database '%s'", dbName)) e.log.Info("Successfully created database", "name", dbName)
return nil return nil
} }

View File

@ -176,14 +176,11 @@ func (m RestoreExecutionModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case tea.KeyMsg: case tea.KeyMsg:
switch msg.String() { switch msg.String() {
case "ctrl+c": case "ctrl+c", "q":
if !m.done { // Always allow quitting
m.status = "Cancelling..." return m.parent, tea.Quit
// In real implementation, would cancel context
}
return m, nil
case "enter", " ", "q", "esc": case "enter", " ", "esc":
if m.done { if m.done {
return m.parent, nil return m.parent, nil
} }