FIXED: TUI progess status and creating tar archive
This commit is contained in:
@ -374,7 +374,7 @@ func (e *Engine) BackupCluster(ctx context.Context) error {
|
|||||||
|
|
||||||
// Create archive
|
// Create archive
|
||||||
e.printf(" Creating compressed archive...\n")
|
e.printf(" Creating compressed archive...\n")
|
||||||
if err := e.createArchive(tempDir, outputFile); err != nil {
|
if err := e.createArchive(ctx, tempDir, outputFile); err != nil {
|
||||||
quietProgress.Fail(fmt.Sprintf("Failed to create archive: %v", err))
|
quietProgress.Fail(fmt.Sprintf("Failed to create archive: %v", err))
|
||||||
operation.Fail("Archive creation failed")
|
operation.Fail("Archive creation failed")
|
||||||
return fmt.Errorf("failed to create archive: %w", err)
|
return fmt.Errorf("failed to create archive: %w", err)
|
||||||
@ -672,7 +672,7 @@ func (e *Engine) backupGlobals(ctx context.Context, tempDir string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createArchive creates a compressed tar archive
|
// createArchive creates a compressed tar archive
|
||||||
func (e *Engine) createArchive(sourceDir, outputFile string) error {
|
func (e *Engine) createArchive(ctx context.Context, sourceDir, outputFile string) error {
|
||||||
// Use pigz for faster parallel compression if available, otherwise use standard gzip
|
// Use pigz for faster parallel compression if available, otherwise use standard gzip
|
||||||
compressCmd := "tar"
|
compressCmd := "tar"
|
||||||
compressArgs := []string{"-czf", outputFile, "-C", sourceDir, "."}
|
compressArgs := []string{"-czf", outputFile, "-C", sourceDir, "."}
|
||||||
@ -681,28 +681,46 @@ func (e *Engine) createArchive(sourceDir, outputFile string) error {
|
|||||||
if _, err := exec.LookPath("pigz"); err == nil {
|
if _, err := exec.LookPath("pigz"); err == nil {
|
||||||
// Use pigz with number of cores for parallel compression
|
// Use pigz with number of cores for parallel compression
|
||||||
compressArgs = []string{"-cf", "-", "-C", sourceDir, "."}
|
compressArgs = []string{"-cf", "-", "-C", sourceDir, "."}
|
||||||
cmd := exec.Command("tar", compressArgs...)
|
cmd := exec.CommandContext(ctx, "tar", compressArgs...)
|
||||||
|
|
||||||
// Pipe to pigz for parallel compression
|
// Create output file
|
||||||
pigzCmd := exec.Command("pigz", "-p", strconv.Itoa(e.cfg.Jobs), ">", outputFile)
|
outFile, err := os.Create(outputFile)
|
||||||
|
|
||||||
tarOut, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Fallback to regular tar
|
// Fallback to regular tar
|
||||||
goto regularTar
|
goto regularTar
|
||||||
}
|
}
|
||||||
pigzCmd.Stdin = tarOut
|
defer outFile.Close()
|
||||||
|
|
||||||
|
// Pipe to pigz for parallel compression
|
||||||
|
pigzCmd := exec.CommandContext(ctx, "pigz", "-p", strconv.Itoa(e.cfg.Jobs))
|
||||||
|
|
||||||
|
tarOut, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
outFile.Close()
|
||||||
|
// Fallback to regular tar
|
||||||
|
goto regularTar
|
||||||
|
}
|
||||||
|
pigzCmd.Stdin = tarOut
|
||||||
|
pigzCmd.Stdout = outFile
|
||||||
|
|
||||||
|
// Start both commands
|
||||||
if err := pigzCmd.Start(); err != nil {
|
if err := pigzCmd.Start(); err != nil {
|
||||||
|
outFile.Close()
|
||||||
goto regularTar
|
goto regularTar
|
||||||
}
|
}
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
|
pigzCmd.Process.Kill()
|
||||||
|
outFile.Close()
|
||||||
goto regularTar
|
goto regularTar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for tar to finish
|
||||||
if err := cmd.Wait(); err != nil {
|
if err := cmd.Wait(); err != nil {
|
||||||
|
pigzCmd.Process.Kill()
|
||||||
return fmt.Errorf("tar failed: %w", err)
|
return fmt.Errorf("tar failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for pigz to finish
|
||||||
if err := pigzCmd.Wait(); err != nil {
|
if err := pigzCmd.Wait(); err != nil {
|
||||||
return fmt.Errorf("pigz compression failed: %w", err)
|
return fmt.Errorf("pigz compression failed: %w", err)
|
||||||
}
|
}
|
||||||
@ -711,7 +729,7 @@ func (e *Engine) createArchive(sourceDir, outputFile string) error {
|
|||||||
|
|
||||||
regularTar:
|
regularTar:
|
||||||
// Standard tar with gzip (fallback)
|
// Standard tar with gzip (fallback)
|
||||||
cmd := exec.Command(compressCmd, compressArgs...)
|
cmd := exec.CommandContext(ctx, compressCmd, compressArgs...)
|
||||||
|
|
||||||
// Stream stderr to avoid memory issues
|
// Stream stderr to avoid memory issues
|
||||||
stderr, err := cmd.StderrPipe()
|
stderr, err := cmd.StderrPipe()
|
||||||
|
|||||||
@ -61,7 +61,18 @@ func (m BackupExecutionModel) Init() tea.Cmd {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
return executeBackupWithTUIProgress(m.config, m.logger, m.backupType, m.databaseName, m.ratio, reporter)
|
return tea.Batch(
|
||||||
|
executeBackupWithTUIProgress(m.config, m.logger, m.backupType, m.databaseName, m.ratio, reporter),
|
||||||
|
backupTickCmd(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type backupTickMsg time.Time
|
||||||
|
|
||||||
|
func backupTickCmd() tea.Cmd {
|
||||||
|
return tea.Tick(time.Millisecond*100, func(t time.Time) tea.Msg {
|
||||||
|
return backupTickMsg(t)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type backupProgressMsg struct {
|
type backupProgressMsg struct {
|
||||||
@ -142,6 +153,12 @@ func executeBackupWithTUIProgress(cfg *config.Config, log logger.Logger, backupT
|
|||||||
|
|
||||||
func (m BackupExecutionModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m BackupExecutionModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
|
case backupTickMsg:
|
||||||
|
if !m.done {
|
||||||
|
return m, backupTickCmd()
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
|
||||||
case backupProgressMsg:
|
case backupProgressMsg:
|
||||||
m.status = msg.status
|
m.status = msg.status
|
||||||
m.progress = msg.progress
|
m.progress = msg.progress
|
||||||
|
|||||||
@ -37,7 +37,18 @@ func NewStatusView(cfg *config.Config, log logger.Logger, parent tea.Model) Stat
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m StatusViewModel) Init() tea.Cmd {
|
func (m StatusViewModel) Init() tea.Cmd {
|
||||||
return fetchStatus(m.config, m.logger)
|
return tea.Batch(
|
||||||
|
fetchStatus(m.config, m.logger),
|
||||||
|
tickCmd(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type tickMsg time.Time
|
||||||
|
|
||||||
|
func tickCmd() tea.Cmd {
|
||||||
|
return tea.Tick(time.Millisecond*100, func(t time.Time) tea.Msg {
|
||||||
|
return tickMsg(t)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
type statusMsg struct {
|
type statusMsg struct {
|
||||||
@ -98,6 +109,12 @@ func fetchStatus(cfg *config.Config, log logger.Logger) tea.Cmd {
|
|||||||
|
|
||||||
func (m StatusViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
func (m StatusViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
|
case tickMsg:
|
||||||
|
if m.loading {
|
||||||
|
return m, tickCmd()
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
|
||||||
case statusMsg:
|
case statusMsg:
|
||||||
m.loading = false
|
m.loading = false
|
||||||
if msg.status != "" {
|
if msg.status != "" {
|
||||||
|
|||||||
Reference in New Issue
Block a user