| 
									
										
										
										
											2021-09-12 16:15:40 +02:00
										 |  |  | package backup | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"sort" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/archiver" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/restic" | 
					
						
							| 
									
										
										
										
											2021-09-12 16:15:40 +02:00
										 |  |  | 	"github.com/restic/restic/internal/ui" | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 	"github.com/restic/restic/internal/ui/termstatus" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-12 16:15:40 +02:00
										 |  |  | // TextProgress reports progress for the `backup` command. | 
					
						
							|  |  |  | type TextProgress struct { | 
					
						
							|  |  |  | 	*ui.Message | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 12:52:00 -07:00
										 |  |  | 	term *termstatus.Terminal | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-18 13:07:53 +02:00
										 |  |  | // assert that Backup implements the ProgressPrinter interface | 
					
						
							| 
									
										
										
										
											2021-09-12 16:15:40 +02:00
										 |  |  | var _ ProgressPrinter = &TextProgress{} | 
					
						
							| 
									
										
										
										
											2021-08-18 13:07:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-12 16:15:40 +02:00
										 |  |  | // NewTextProgress returns a new backup progress reporter. | 
					
						
							|  |  |  | func NewTextProgress(term *termstatus.Terminal, verbosity uint) *TextProgress { | 
					
						
							|  |  |  | 	return &TextProgress{ | 
					
						
							| 
									
										
										
										
											2022-12-28 21:55:02 +01:00
										 |  |  | 		Message: ui.NewMessage(term, verbosity), | 
					
						
							|  |  |  | 		term:    term, | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-12 16:15:40 +02:00
										 |  |  | // Update updates the status lines. | 
					
						
							|  |  |  | func (b *TextProgress) Update(total, processed Counter, errors uint, currentFiles map[string]struct{}, start time.Time, secs uint64) { | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 	var status string | 
					
						
							|  |  |  | 	if total.Files == 0 && total.Dirs == 0 { | 
					
						
							|  |  |  | 		// no total count available yet | 
					
						
							|  |  |  | 		status = fmt.Sprintf("[%s] %v files, %s, %d errors", | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 			ui.FormatDuration(time.Since(start)), | 
					
						
							|  |  |  | 			processed.Files, ui.FormatBytes(processed.Bytes), errors, | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 		) | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2018-05-06 20:20:10 +02:00
										 |  |  | 		var eta, percent string | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-29 14:40:49 +02:00
										 |  |  | 		if secs > 0 && processed.Bytes < total.Bytes { | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 			eta = fmt.Sprintf(" ETA %s", ui.FormatSeconds(secs)) | 
					
						
							|  |  |  | 			percent = ui.FormatPercent(processed.Bytes, total.Bytes) | 
					
						
							| 
									
										
										
										
											2018-05-06 20:20:10 +02:00
										 |  |  | 			percent += "  " | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// include totals | 
					
						
							| 
									
										
										
										
											2018-05-06 20:20:10 +02:00
										 |  |  | 		status = fmt.Sprintf("[%s] %s%v files %s, total %v files %v, %d errors%s", | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 			ui.FormatDuration(time.Since(start)), | 
					
						
							| 
									
										
										
										
											2018-05-06 20:20:10 +02:00
										 |  |  | 			percent, | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 			processed.Files, | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 			ui.FormatBytes(processed.Bytes), | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 			total.Files, | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 			ui.FormatBytes(total.Bytes), | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 			errors, | 
					
						
							|  |  |  | 			eta, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lines := make([]string, 0, len(currentFiles)+1) | 
					
						
							|  |  |  | 	for filename := range currentFiles { | 
					
						
							|  |  |  | 		lines = append(lines, filename) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-30 23:20:32 +03:00
										 |  |  | 	sort.Strings(lines) | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 	lines = append([]string{status}, lines...) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b.term.SetStatus(lines) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ScannerError is the error callback function for the scanner, it prints the | 
					
						
							|  |  |  | // error in verbose mode and returns nil. | 
					
						
							| 
									
										
										
										
											2023-05-18 19:27:38 +02:00
										 |  |  | func (b *TextProgress) ScannerError(_ string, err error) error { | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 	b.V("scan: %v\n", err) | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Error is the error callback function for the archiver, it prints the error and returns nil. | 
					
						
							| 
									
										
										
										
											2023-05-18 19:27:38 +02:00
										 |  |  | func (b *TextProgress) Error(_ string, err error) error { | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 	b.E("error: %v\n", err) | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-10 23:34:37 -06:00
										 |  |  | // CompleteItem is the status callback function for the archiver when a | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | // file/dir has been saved successfully. | 
					
						
							| 
									
										
										
										
											2023-05-18 19:29:50 +02:00
										 |  |  | func (b *TextProgress) CompleteItem(messageType, item string, s archiver.ItemStats, d time.Duration) { | 
					
						
							| 
									
										
										
										
											2023-02-11 14:51:58 +01:00
										 |  |  | 	item = termstatus.Quote(item) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 12:52:00 -07:00
										 |  |  | 	switch messageType { | 
					
						
							|  |  |  | 	case "dir new": | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 		b.VV("new       %v, saved in %.3fs (%v added, %v stored, %v metadata)", | 
					
						
							|  |  |  | 			item, d.Seconds(), ui.FormatBytes(s.DataSize), | 
					
						
							|  |  |  | 			ui.FormatBytes(s.DataSizeInRepo), ui.FormatBytes(s.TreeSizeInRepo)) | 
					
						
							| 
									
										
										
										
											2021-01-26 12:52:00 -07:00
										 |  |  | 	case "dir unchanged": | 
					
						
							|  |  |  | 		b.VV("unchanged %v", item) | 
					
						
							|  |  |  | 	case "dir modified": | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 		b.VV("modified  %v, saved in %.3fs (%v added, %v stored, %v metadata)", | 
					
						
							|  |  |  | 			item, d.Seconds(), ui.FormatBytes(s.DataSize), | 
					
						
							|  |  |  | 			ui.FormatBytes(s.DataSizeInRepo), ui.FormatBytes(s.TreeSizeInRepo)) | 
					
						
							| 
									
										
										
										
											2021-01-26 12:52:00 -07:00
										 |  |  | 	case "file new": | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 		b.VV("new       %v, saved in %.3fs (%v added)", item, | 
					
						
							|  |  |  | 			d.Seconds(), ui.FormatBytes(s.DataSize)) | 
					
						
							| 
									
										
										
										
											2021-01-26 12:52:00 -07:00
										 |  |  | 	case "file unchanged": | 
					
						
							|  |  |  | 		b.VV("unchanged %v", item) | 
					
						
							|  |  |  | 	case "file modified": | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 		b.VV("modified  %v, saved in %.3fs (%v added, %v stored)", item, | 
					
						
							|  |  |  | 			d.Seconds(), ui.FormatBytes(s.DataSize), ui.FormatBytes(s.DataSizeInRepo)) | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ReportTotal sets the total stats up to now | 
					
						
							| 
									
										
										
										
											2023-05-18 19:29:50 +02:00
										 |  |  | func (b *TextProgress) ReportTotal(start time.Time, s archiver.ScanStats) { | 
					
						
							| 
									
										
										
										
											2021-08-18 01:25:34 +02:00
										 |  |  | 	b.V("scan finished in %.3fs: %v files, %s", | 
					
						
							|  |  |  | 		time.Since(start).Seconds(), | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 		s.Files, ui.FormatBytes(s.Bytes), | 
					
						
							| 
									
										
										
										
											2021-08-18 01:25:34 +02:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 12:52:00 -07:00
										 |  |  | // Reset status | 
					
						
							| 
									
										
										
										
											2021-09-12 16:15:40 +02:00
										 |  |  | func (b *TextProgress) Reset() { | 
					
						
							| 
									
										
										
										
											2021-01-26 12:52:00 -07:00
										 |  |  | 	if b.term.CanUpdateStatus() { | 
					
						
							|  |  |  | 		b.term.SetStatus([]string{""}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-04-29 15:01:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 12:52:00 -07:00
										 |  |  | // Finish prints the finishing messages. | 
					
						
							| 
									
										
										
										
											2024-02-22 22:14:48 +01:00
										 |  |  | func (b *TextProgress) Finish(_ restic.ID, start time.Time, summary *archiver.Summary, dryRun bool) { | 
					
						
							| 
									
										
										
										
											2018-05-01 22:02:48 +02:00
										 |  |  | 	b.P("\n") | 
					
						
							| 
									
										
										
										
											2021-01-26 12:52:00 -07:00
										 |  |  | 	b.P("Files:       %5d new, %5d changed, %5d unmodified\n", summary.Files.New, summary.Files.Changed, summary.Files.Unchanged) | 
					
						
							|  |  |  | 	b.P("Dirs:        %5d new, %5d changed, %5d unmodified\n", summary.Dirs.New, summary.Dirs.Changed, summary.Dirs.Unchanged) | 
					
						
							|  |  |  | 	b.V("Data Blobs:  %5d new\n", summary.ItemStats.DataBlobs) | 
					
						
							|  |  |  | 	b.V("Tree Blobs:  %5d new\n", summary.ItemStats.TreeBlobs) | 
					
						
							| 
									
										
											  
											
												backup: add --dry-run/-n flag to show what would happen.
This can be used to check how large a backup is or validate exclusions.
It does not actually write any data to the underlying backend. This is
implemented as a simple overlay backend that accepts writes without
forwarding them, passes through reads, and generally does the minimal
necessary to pretend that progress is actually happening.
Fixes #1542
Example usage:
$ restic -vv --dry-run . | grep add
new       /changelog/unreleased/issue-1542, saved in 0.000s (350 B added)
modified  /cmd/restic/cmd_backup.go, saved in 0.000s (16.543 KiB added)
modified  /cmd/restic/global.go, saved in 0.000s (0 B added)
new       /internal/backend/dry/dry_backend_test.go, saved in 0.000s (3.866 KiB added)
new       /internal/backend/dry/dry_backend.go, saved in 0.000s (3.744 KiB added)
modified  /internal/backend/test/tests.go, saved in 0.000s (0 B added)
modified  /internal/repository/repository.go, saved in 0.000s (20.707 KiB added)
modified  /internal/ui/backup.go, saved in 0.000s (9.110 KiB added)
modified  /internal/ui/jsonstatus/status.go, saved in 0.001s (11.055 KiB added)
modified  /restic, saved in 0.131s (25.542 MiB added)
Would add to the repo: 25.892 MiB
											
										 
											2019-06-12 20:39:13 -07:00
										 |  |  | 	verb := "Added" | 
					
						
							| 
									
										
										
										
											2021-08-18 13:03:08 +02:00
										 |  |  | 	if dryRun { | 
					
						
							| 
									
										
											  
											
												backup: add --dry-run/-n flag to show what would happen.
This can be used to check how large a backup is or validate exclusions.
It does not actually write any data to the underlying backend. This is
implemented as a simple overlay backend that accepts writes without
forwarding them, passes through reads, and generally does the minimal
necessary to pretend that progress is actually happening.
Fixes #1542
Example usage:
$ restic -vv --dry-run . | grep add
new       /changelog/unreleased/issue-1542, saved in 0.000s (350 B added)
modified  /cmd/restic/cmd_backup.go, saved in 0.000s (16.543 KiB added)
modified  /cmd/restic/global.go, saved in 0.000s (0 B added)
new       /internal/backend/dry/dry_backend_test.go, saved in 0.000s (3.866 KiB added)
new       /internal/backend/dry/dry_backend.go, saved in 0.000s (3.744 KiB added)
modified  /internal/backend/test/tests.go, saved in 0.000s (0 B added)
modified  /internal/repository/repository.go, saved in 0.000s (20.707 KiB added)
modified  /internal/ui/backup.go, saved in 0.000s (9.110 KiB added)
modified  /internal/ui/jsonstatus/status.go, saved in 0.001s (11.055 KiB added)
modified  /restic, saved in 0.131s (25.542 MiB added)
Would add to the repo: 25.892 MiB
											
										 
											2019-06-12 20:39:13 -07:00
										 |  |  | 		verb = "Would add" | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 	b.P("%s to the repository: %-5s (%-5s stored)\n", verb, | 
					
						
							|  |  |  | 		ui.FormatBytes(summary.ItemStats.DataSize+summary.ItemStats.TreeSize), | 
					
						
							|  |  |  | 		ui.FormatBytes(summary.ItemStats.DataSizeInRepo+summary.ItemStats.TreeSizeInRepo)) | 
					
						
							| 
									
										
										
										
											2018-05-01 22:02:48 +02:00
										 |  |  | 	b.P("\n") | 
					
						
							|  |  |  | 	b.P("processed %v files, %v in %s", | 
					
						
							| 
									
										
										
										
											2021-01-26 12:52:00 -07:00
										 |  |  | 		summary.Files.New+summary.Files.Changed+summary.Files.Unchanged, | 
					
						
							| 
									
										
										
										
											2022-10-21 17:34:14 +02:00
										 |  |  | 		ui.FormatBytes(summary.ProcessedBytes), | 
					
						
							|  |  |  | 		ui.FormatDuration(time.Since(start)), | 
					
						
							| 
									
										
										
										
											2018-05-01 22:02:48 +02:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2018-04-22 11:57:20 +02:00
										 |  |  | } |