Make the cli colorful and informational (#4525)
This commit include a few things that improves the progresbars and other info messages are printed out during the CLI run.  --- #### Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [x] 🕐 Yes, but in a later PR - [ ] ⛔ No #### Type of change <!--- Please check the type of change your PR introduces: ---> - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Supportability/Tests - [ ] 💻 CI/Deployment - [ ] 🧹 Tech Debt/Cleanup #### Issue(s) <!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. --> * #<issue> #### Test Plan <!-- How will this be tested prior to merging.--> - [x] 💪 Manual - [ ] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
f2102e55f6
commit
b46f242bc4
@ -2,6 +2,7 @@ package backup
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -12,8 +13,10 @@ import (
|
|||||||
"github.com/alcionai/corso/src/cli/flags"
|
"github.com/alcionai/corso/src/cli/flags"
|
||||||
. "github.com/alcionai/corso/src/cli/print"
|
. "github.com/alcionai/corso/src/cli/print"
|
||||||
"github.com/alcionai/corso/src/cli/utils"
|
"github.com/alcionai/corso/src/cli/utils"
|
||||||
|
"github.com/alcionai/corso/src/internal/common/color"
|
||||||
"github.com/alcionai/corso/src/internal/common/idname"
|
"github.com/alcionai/corso/src/internal/common/idname"
|
||||||
"github.com/alcionai/corso/src/internal/data"
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
|
"github.com/alcionai/corso/src/internal/observe"
|
||||||
"github.com/alcionai/corso/src/pkg/backup"
|
"github.com/alcionai/corso/src/pkg/backup"
|
||||||
"github.com/alcionai/corso/src/pkg/backup/details"
|
"github.com/alcionai/corso/src/pkg/backup/details"
|
||||||
"github.com/alcionai/corso/src/pkg/control"
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
@ -187,8 +190,15 @@ func genericCreateCommand(
|
|||||||
|
|
||||||
bo, err := r.NewBackupWithLookup(ictx, discSel, ins)
|
bo, err := r.NewBackupWithLookup(ictx, discSel, ins)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, clues.WrapWC(ictx, err, owner))
|
cerr := clues.WrapWC(ictx, err, owner)
|
||||||
Errf(ictx, "%v\n", err)
|
errs = append(errs, cerr)
|
||||||
|
|
||||||
|
meta, err := json.Marshal(cerr.Core().Values)
|
||||||
|
if err != nil {
|
||||||
|
meta = []byte("Unable to marshal error metadata")
|
||||||
|
}
|
||||||
|
|
||||||
|
Errf(ictx, "%s\nMessage: %v\nMetadata:%s", "Unable to complete backup", err, meta)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -208,8 +218,15 @@ func genericCreateCommand(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = append(errs, clues.WrapWC(ictx, err, owner))
|
cerr := clues.WrapWC(ictx, err, owner)
|
||||||
Errf(ictx, "%v\n", err)
|
errs = append(errs, cerr)
|
||||||
|
|
||||||
|
meta, err := json.Marshal(cerr.Core().Values)
|
||||||
|
if err != nil {
|
||||||
|
meta = []byte("Unable to marshal error metadata")
|
||||||
|
}
|
||||||
|
|
||||||
|
Errf(ictx, "%s\nMessage: %v\nMetadata:%s", "Unable to complete backup", err, meta)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -217,10 +234,10 @@ func genericCreateCommand(
|
|||||||
bIDs = append(bIDs, string(bo.Results.BackupID))
|
bIDs = append(bIDs, string(bo.Results.BackupID))
|
||||||
|
|
||||||
if !DisplayJSONFormat() {
|
if !DisplayJSONFormat() {
|
||||||
Infof(ctx, "Done\n")
|
Infof(ctx, fmt.Sprintf("Backup complete %s %s", observe.Bullet, color.BlueOutput(bo.Results.BackupID)))
|
||||||
printBackupStats(ctx, r, string(bo.Results.BackupID))
|
printBackupStats(ctx, r, string(bo.Results.BackupID))
|
||||||
} else {
|
} else {
|
||||||
Infof(ctx, "Done - ID: %v\n", bo.Results.BackupID)
|
Infof(ctx, "Backup complete - ID: %v\n", bo.Results.BackupID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,10 +248,9 @@ func genericCreateCommand(
|
|||||||
|
|
||||||
if len(bups) > 0 {
|
if len(bups) > 0 {
|
||||||
Info(ctx, "Completed Backups:")
|
Info(ctx, "Completed Backups:")
|
||||||
|
backup.PrintAll(ctx, bups)
|
||||||
}
|
}
|
||||||
|
|
||||||
backup.PrintAll(ctx, bups)
|
|
||||||
|
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
sb := fmt.Sprintf("%d of %d backups failed:\n", len(errs), len(selectorSet))
|
sb := fmt.Sprintf("%d of %d backups failed:\n", len(errs), len(selectorSet))
|
||||||
|
|
||||||
|
|||||||
@ -73,7 +73,7 @@ func preRun(cc *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
func handleMailBoxFlag(ctx context.Context, c *cobra.Command, flagNames []string) {
|
func handleMailBoxFlag(ctx context.Context, c *cobra.Command, flagNames []string) {
|
||||||
if !slices.Contains(flagNames, "user") && !slices.Contains(flagNames, "mailbox") {
|
if !slices.Contains(flagNames, "user") && !slices.Contains(flagNames, "mailbox") {
|
||||||
print.Errf(ctx, "either --user or --mailbox flag is required")
|
print.Err(ctx, "either --user or --mailbox flag is required")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -107,7 +107,7 @@ func runExport(
|
|||||||
|
|
||||||
// It would be better to give a progressbar than a spinner, but we
|
// It would be better to give a progressbar than a spinner, but we
|
||||||
// have any way of knowing how many files are available as of now.
|
// have any way of knowing how many files are available as of now.
|
||||||
diskWriteComplete := observe.MessageWithCompletion(ctx, "Writing data to disk")
|
diskWriteComplete := observe.MessageWithCompletion(ctx, observe.ProgressCfg{}, "Writing data to disk")
|
||||||
|
|
||||||
err = export.ConsumeExportCollections(ctx, exportLocation, expColl, eo.Errors)
|
err = export.ConsumeExportCollections(ctx, exportLocation, expColl, eo.Errors)
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/tidwall/pretty"
|
"github.com/tidwall/pretty"
|
||||||
"github.com/tomlazar/table"
|
"github.com/tomlazar/table"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common/color"
|
||||||
"github.com/alcionai/corso/src/internal/observe"
|
"github.com/alcionai/corso/src/internal/observe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -83,16 +84,21 @@ func Only(ctx context.Context, e error) error {
|
|||||||
|
|
||||||
// Err prints the params to cobra's error writer (stdErr by default)
|
// Err prints the params to cobra's error writer (stdErr by default)
|
||||||
// if s is nil, prints nothing.
|
// if s is nil, prints nothing.
|
||||||
// Prepends the message with "Error: "
|
|
||||||
func Err(ctx context.Context, s ...any) {
|
func Err(ctx context.Context, s ...any) {
|
||||||
out(ctx, getRootCmd(ctx).ErrOrStderr(), s...)
|
cw := color.NewColorableWriter(color.Red, getRootCmd(ctx).ErrOrStderr())
|
||||||
|
|
||||||
|
s = append([]any{"Error:"}, s...)
|
||||||
|
|
||||||
|
out(ctx, cw, s...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errf prints the params to cobra's error writer (stdErr by default)
|
// Errf prints the params to cobra's error writer (stdErr by default)
|
||||||
// if s is nil, prints nothing.
|
// if s is nil, prints nothing.
|
||||||
// Prepends the message with "Error: "
|
// You should ideally be using SimpleError or OperationError.
|
||||||
func Errf(ctx context.Context, tmpl string, s ...any) {
|
func Errf(ctx context.Context, tmpl string, s ...any) {
|
||||||
outf(ctx, getRootCmd(ctx).ErrOrStderr(), "\nError: \n\t"+tmpl+"\n", s...)
|
cw := color.NewColorableWriter(color.Red, getRootCmd(ctx).ErrOrStderr())
|
||||||
|
tmpl = "Error: " + tmpl
|
||||||
|
outf(ctx, cw, tmpl, s...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Out prints the params to cobra's output writer (stdOut by default)
|
// Out prints the params to cobra's output writer (stdOut by default)
|
||||||
|
|||||||
@ -10,6 +10,7 @@ require (
|
|||||||
github.com/armon/go-metrics v0.4.1
|
github.com/armon/go-metrics v0.4.1
|
||||||
github.com/aws/aws-xray-sdk-go v1.8.3
|
github.com/aws/aws-xray-sdk-go v1.8.3
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1
|
github.com/cenkalti/backoff/v4 v4.2.1
|
||||||
|
github.com/fatih/color v1.15.0
|
||||||
github.com/golang-jwt/jwt/v5 v5.1.0
|
github.com/golang-jwt/jwt/v5 v5.1.0
|
||||||
github.com/google/uuid v1.4.0
|
github.com/google/uuid v1.4.0
|
||||||
github.com/h2non/gock v1.2.0
|
github.com/h2non/gock v1.2.0
|
||||||
@ -51,7 +52,6 @@ require (
|
|||||||
github.com/aws/aws-sdk-go v1.47.9 // indirect
|
github.com/aws/aws-sdk-go v1.47.9 // indirect
|
||||||
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/go-test/deep v1.1.0 // indirect
|
|
||||||
github.com/gofrs/flock v0.8.1 // indirect
|
github.com/gofrs/flock v0.8.1 // indirect
|
||||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
|
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
|
|||||||
@ -119,6 +119,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||||
|
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||||
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||||
|
|||||||
36
src/internal/common/color/color.go
Normal file
36
src/internal/common/color/color.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package color
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/fatih/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Red = color.FgRed
|
||||||
|
Blue = color.FgBlue
|
||||||
|
Magenta = color.FgMagenta
|
||||||
|
Cyan = color.FgCyan
|
||||||
|
Green = color.FgGreen
|
||||||
|
White = color.FgWhite
|
||||||
|
|
||||||
|
RedOutput = color.New(Red).SprintFunc()
|
||||||
|
BlueOutput = color.New(Blue).SprintFunc()
|
||||||
|
MagentaOutput = color.New(Magenta).SprintFunc()
|
||||||
|
CyanOutput = color.New(Cyan).SprintFunc()
|
||||||
|
GreenOutput = color.New(Green).SprintFunc()
|
||||||
|
GreyOutput = color.New(White).SprintFunc()
|
||||||
|
)
|
||||||
|
|
||||||
|
type colorableWriter struct {
|
||||||
|
color color.Attribute
|
||||||
|
writer io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewColorableWriter(clr color.Attribute, writer io.Writer) io.Writer {
|
||||||
|
return &colorableWriter{clr, writer}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cw *colorableWriter) Write(p []byte) (n int, err error) {
|
||||||
|
return color.New(cw.color).Fprint(cw.writer, string(p))
|
||||||
|
}
|
||||||
@ -651,6 +651,7 @@ func (w Wrapper) RepoMaintenance(
|
|||||||
if len(params.Owner) == 0 || (params.Owner != currentOwner && opts.Force) {
|
if len(params.Owner) == 0 || (params.Owner != currentOwner && opts.Force) {
|
||||||
observe.Message(
|
observe.Message(
|
||||||
ctx,
|
ctx,
|
||||||
|
observe.ProgressCfg{},
|
||||||
"updating maintenance user@host to ",
|
"updating maintenance user@host to ",
|
||||||
clues.Hide(currentOwner))
|
clues.Hide(currentOwner))
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package drive
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -18,7 +17,6 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/m365/collection/drive/metadata"
|
"github.com/alcionai/corso/src/internal/m365/collection/drive/metadata"
|
||||||
odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts"
|
odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts"
|
||||||
"github.com/alcionai/corso/src/internal/m365/support"
|
"github.com/alcionai/corso/src/internal/m365/support"
|
||||||
"github.com/alcionai/corso/src/internal/observe"
|
|
||||||
bupMD "github.com/alcionai/corso/src/pkg/backup/metadata"
|
bupMD "github.com/alcionai/corso/src/pkg/backup/metadata"
|
||||||
"github.com/alcionai/corso/src/pkg/control"
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
@ -283,11 +281,6 @@ func (c *Collections) Get(
|
|||||||
driveTombstones[driveID] = struct{}{}
|
driveTombstones[driveID] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
progressBar := observe.MessageWithCompletion(
|
|
||||||
ctx,
|
|
||||||
observe.Bulletf(path.FilesCategory.HumanString()))
|
|
||||||
defer close(progressBar)
|
|
||||||
|
|
||||||
// Enumerate drives for the specified resourceOwner
|
// Enumerate drives for the specified resourceOwner
|
||||||
pager := c.handler.NewDrivePager(c.protectedResource.ID(), nil)
|
pager := c.handler.NewDrivePager(c.protectedResource.ID(), nil)
|
||||||
|
|
||||||
@ -456,8 +449,6 @@ func (c *Collections) Get(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
observe.Message(ctx, fmt.Sprintf("Discovered %d items to backup", c.NumItems))
|
|
||||||
|
|
||||||
collections := []data.BackupCollection{}
|
collections := []data.BackupCollection{}
|
||||||
|
|
||||||
// add all the drives we found
|
// add all the drives we found
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package exchange
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
|
|
||||||
@ -42,6 +43,8 @@ func CreateCollections(
|
|||||||
ProtectedResource: bpc.ProtectedResource,
|
ProtectedResource: bpc.ProtectedResource,
|
||||||
TenantID: tenantID,
|
TenantID: tenantID,
|
||||||
}
|
}
|
||||||
|
collections map[string]data.BackupCollection
|
||||||
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
handler, ok := handlers[category]
|
handler, ok := handlers[category]
|
||||||
@ -49,9 +52,15 @@ func CreateCollections(
|
|||||||
return nil, clues.NewWC(ctx, "unsupported backup category type")
|
return nil, clues.NewWC(ctx, "unsupported backup category type")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pcfg := observe.ProgressCfg{
|
||||||
|
Indent: 1,
|
||||||
|
CompletionMessage: func() string { return fmt.Sprintf("(found %d folders)", len(collections)) },
|
||||||
|
}
|
||||||
foldersComplete := observe.MessageWithCompletion(
|
foldersComplete := observe.MessageWithCompletion(
|
||||||
ctx,
|
ctx,
|
||||||
observe.Bulletf("%s", qp.Category.HumanString()))
|
pcfg,
|
||||||
|
qp.Category.HumanString())
|
||||||
|
|
||||||
defer close(foldersComplete)
|
defer close(foldersComplete)
|
||||||
|
|
||||||
rootFolder, cc := handler.NewContainerCache(bpc.ProtectedResource.ID())
|
rootFolder, cc := handler.NewContainerCache(bpc.ProtectedResource.ID())
|
||||||
@ -60,7 +69,7 @@ func CreateCollections(
|
|||||||
return nil, clues.Wrap(err, "populating container cache")
|
return nil, clues.Wrap(err, "populating container cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
collections, err := populateCollections(
|
collections, err = populateCollections(
|
||||||
ctx,
|
ctx,
|
||||||
qp,
|
qp,
|
||||||
handler,
|
handler,
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package site
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
stdpath "path"
|
||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
|
|
||||||
@ -10,6 +12,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
||||||
betaAPI "github.com/alcionai/corso/src/internal/m365/service/sharepoint/api"
|
betaAPI "github.com/alcionai/corso/src/internal/m365/service/sharepoint/api"
|
||||||
"github.com/alcionai/corso/src/internal/m365/support"
|
"github.com/alcionai/corso/src/internal/m365/support"
|
||||||
|
"github.com/alcionai/corso/src/internal/observe"
|
||||||
"github.com/alcionai/corso/src/internal/operations/inject"
|
"github.com/alcionai/corso/src/internal/operations/inject"
|
||||||
"github.com/alcionai/corso/src/pkg/account"
|
"github.com/alcionai/corso/src/pkg/account"
|
||||||
"github.com/alcionai/corso/src/pkg/count"
|
"github.com/alcionai/corso/src/pkg/count"
|
||||||
@ -44,6 +47,18 @@ func CollectLibraries(
|
|||||||
bpc.Options)
|
bpc.Options)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
msg := fmt.Sprintf(
|
||||||
|
"%s (%s)",
|
||||||
|
path.LibrariesCategory.HumanString(),
|
||||||
|
stdpath.Base(bpc.ProtectedResource.Name()))
|
||||||
|
|
||||||
|
pcfg := observe.ProgressCfg{
|
||||||
|
Indent: 1,
|
||||||
|
CompletionMessage: func() string { return fmt.Sprintf("(found %d items)", colls.NumItems) },
|
||||||
|
}
|
||||||
|
progressBar := observe.MessageWithCompletion(ctx, pcfg, msg)
|
||||||
|
close(progressBar)
|
||||||
|
|
||||||
odcs, canUsePreviousBackup, err := colls.Get(ctx, bpc.MetadataCollections, ssmb, errs)
|
odcs, canUsePreviousBackup, err := colls.Get(ctx, bpc.MetadataCollections, ssmb, errs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, graph.Wrap(ctx, err, "getting library")
|
return nil, false, graph.Wrap(ctx, err, "getting library")
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package groups
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
"github.com/kopia/kopia/repo/manifest"
|
"github.com/kopia/kopia/repo/manifest"
|
||||||
@ -70,11 +71,6 @@ func ProduceBackupCollections(
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
progressBar := observe.MessageWithCompletion(
|
|
||||||
ctx,
|
|
||||||
observe.Bulletf("%s", scope.Category().PathType().HumanString()))
|
|
||||||
defer close(progressBar)
|
|
||||||
|
|
||||||
var dbcs []data.BackupCollection
|
var dbcs []data.BackupCollection
|
||||||
|
|
||||||
switch scope.Category().PathType() {
|
switch scope.Category().PathType() {
|
||||||
@ -134,15 +130,27 @@ func ProduceBackupCollections(
|
|||||||
|
|
||||||
dbcs = append(dbcs, cs...)
|
dbcs = append(dbcs, cs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
case path.ChannelMessagesCategory:
|
case path.ChannelMessagesCategory:
|
||||||
|
var (
|
||||||
|
cs []data.BackupCollection
|
||||||
|
canUsePreviousBackup bool
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
pcfg := observe.ProgressCfg{
|
||||||
|
Indent: 1,
|
||||||
|
// TODO(meain): Use number of messages and not channels
|
||||||
|
CompletionMessage: func() string { return fmt.Sprintf("(found %d channels)", len(cs)) },
|
||||||
|
}
|
||||||
|
progressBar := observe.MessageWithCompletion(ctx, pcfg, scope.Category().PathType().HumanString())
|
||||||
|
|
||||||
if !isTeam {
|
if !isTeam {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
bh := groups.NewChannelBackupHandler(bpc.ProtectedResource.ID(), ac.Channels())
|
bh := groups.NewChannelBackupHandler(bpc.ProtectedResource.ID(), ac.Channels())
|
||||||
|
|
||||||
cs, canUsePreviousBackup, err := groups.CreateCollections(
|
cs, canUsePreviousBackup, err = groups.CreateCollections(
|
||||||
ctx,
|
ctx,
|
||||||
bpc,
|
bpc,
|
||||||
bh,
|
bh,
|
||||||
@ -165,6 +173,8 @@ func ProduceBackupCollections(
|
|||||||
}
|
}
|
||||||
|
|
||||||
dbcs = append(dbcs, cs...)
|
dbcs = append(dbcs, cs...)
|
||||||
|
|
||||||
|
close(progressBar)
|
||||||
}
|
}
|
||||||
|
|
||||||
collections = append(collections, dbcs...)
|
collections = append(collections, dbcs...)
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package onedrive
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/data"
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
||||||
"github.com/alcionai/corso/src/internal/m365/support"
|
"github.com/alcionai/corso/src/internal/m365/support"
|
||||||
|
"github.com/alcionai/corso/src/internal/observe"
|
||||||
"github.com/alcionai/corso/src/internal/operations/inject"
|
"github.com/alcionai/corso/src/internal/operations/inject"
|
||||||
"github.com/alcionai/corso/src/internal/version"
|
"github.com/alcionai/corso/src/internal/version"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
@ -55,6 +57,14 @@ func ProduceBackupCollections(
|
|||||||
su,
|
su,
|
||||||
bpc.Options)
|
bpc.Options)
|
||||||
|
|
||||||
|
pcfg := observe.ProgressCfg{
|
||||||
|
Indent: 1,
|
||||||
|
CompletionMessage: func() string { return fmt.Sprintf("(found %d files)", nc.NumFiles) },
|
||||||
|
}
|
||||||
|
progressBar := observe.MessageWithCompletion(ctx, pcfg, path.FilesCategory.HumanString())
|
||||||
|
|
||||||
|
defer close(progressBar)
|
||||||
|
|
||||||
odcs, canUsePreviousBackup, err = nc.Get(ctx, bpc.MetadataCollections, ssmb, errs)
|
odcs, canUsePreviousBackup, err = nc.Get(ctx, bpc.MetadataCollections, ssmb, errs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
el.AddRecoverable(ctx, clues.Stack(err).Label(fault.LabelForceNoBackupCreation))
|
el.AddRecoverable(ctx, clues.Stack(err).Label(fault.LabelForceNoBackupCreation))
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
"github.com/alcionai/corso/src/internal/m365/collection/drive"
|
||||||
"github.com/alcionai/corso/src/internal/m365/collection/site"
|
"github.com/alcionai/corso/src/internal/m365/collection/site"
|
||||||
"github.com/alcionai/corso/src/internal/m365/support"
|
"github.com/alcionai/corso/src/internal/m365/support"
|
||||||
"github.com/alcionai/corso/src/internal/observe"
|
|
||||||
"github.com/alcionai/corso/src/internal/operations/inject"
|
"github.com/alcionai/corso/src/internal/operations/inject"
|
||||||
"github.com/alcionai/corso/src/pkg/account"
|
"github.com/alcionai/corso/src/pkg/account"
|
||||||
"github.com/alcionai/corso/src/pkg/count"
|
"github.com/alcionai/corso/src/pkg/count"
|
||||||
@ -52,11 +51,6 @@ func ProduceBackupCollections(
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
progressBar := observe.MessageWithCompletion(
|
|
||||||
ctx,
|
|
||||||
observe.Bulletf("%s", scope.Category().PathType().HumanString()))
|
|
||||||
defer close(progressBar)
|
|
||||||
|
|
||||||
var spcs []data.BackupCollection
|
var spcs []data.BackupCollection
|
||||||
|
|
||||||
switch scope.Category().PathType() {
|
switch scope.Category().PathType() {
|
||||||
|
|||||||
@ -15,13 +15,14 @@ import (
|
|||||||
"github.com/vbauerster/mpb/v8"
|
"github.com/vbauerster/mpb/v8"
|
||||||
"github.com/vbauerster/mpb/v8/decor"
|
"github.com/vbauerster/mpb/v8/decor"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common/color"
|
||||||
"github.com/alcionai/corso/src/pkg/logger"
|
"github.com/alcionai/corso/src/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
hideProgressBarsFN = "hide-progress"
|
hideProgressBarsFN = "hide-progress"
|
||||||
retainProgressBarsFN = "retain-progress"
|
retainProgressBarsFN = "retain-progress"
|
||||||
progressBarWidth = 32
|
progressBarWidth = 40
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -170,8 +171,15 @@ const (
|
|||||||
// Progress Updates
|
// Progress Updates
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
type ProgressCfg struct {
|
||||||
|
NewSection bool
|
||||||
|
SectionIdentifier any
|
||||||
|
Indent int
|
||||||
|
CompletionMessage func() string
|
||||||
|
}
|
||||||
|
|
||||||
// Message is used to display a progress message
|
// Message is used to display a progress message
|
||||||
func Message(ctx context.Context, msgs ...any) {
|
func Message(ctx context.Context, cfg ProgressCfg, msgs ...any) {
|
||||||
var (
|
var (
|
||||||
obs = getObserver(ctx)
|
obs = getObserver(ctx)
|
||||||
plainSl = make([]string, 0, len(msgs))
|
plainSl = make([]string, 0, len(msgs))
|
||||||
@ -186,23 +194,42 @@ func Message(ctx context.Context, msgs ...any) {
|
|||||||
plain := strings.Join(plainSl, " ")
|
plain := strings.Join(plainSl, " ")
|
||||||
loggable := strings.Join(loggableSl, " ")
|
loggable := strings.Join(loggableSl, " ")
|
||||||
|
|
||||||
|
if cfg.SectionIdentifier != nil {
|
||||||
|
plain = fmt.Sprintf(
|
||||||
|
"%s %s %s",
|
||||||
|
plain,
|
||||||
|
Bullet,
|
||||||
|
color.MagentaOutput(plainString(cfg.SectionIdentifier)))
|
||||||
|
loggable = fmt.Sprintf("%s - %v", loggable, cfg.SectionIdentifier)
|
||||||
|
}
|
||||||
|
|
||||||
logger.Ctx(ctx).Info(loggable)
|
logger.Ctx(ctx).Info(loggable)
|
||||||
|
|
||||||
if obs.hidden() {
|
if obs.hidden() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.NewSection {
|
||||||
|
// Empty bar to separate out section
|
||||||
|
obs.wg.Add(1)
|
||||||
|
empty := obs.mp.New(-1, mpb.NopStyle())
|
||||||
|
empty.SetTotal(-1, true)
|
||||||
|
waitAndCloseBar(ctx, empty, obs.wg, func() {})()
|
||||||
|
}
|
||||||
|
|
||||||
obs.wg.Add(1)
|
obs.wg.Add(1)
|
||||||
|
|
||||||
bar := obs.mp.New(
|
bar := obs.mp.New(
|
||||||
-1,
|
-1,
|
||||||
mpb.NopStyle(),
|
mpb.NopStyle(),
|
||||||
mpb.PrependDecorators(decor.Name(
|
mpb.PrependDecorators(
|
||||||
plain,
|
decor.Name("", decor.WC{W: cfg.Indent * 2}),
|
||||||
decor.WC{
|
decor.Name(
|
||||||
W: len(plain) + 1,
|
plain,
|
||||||
C: decor.DidentRight,
|
decor.WC{
|
||||||
})))
|
W: len(plain) + 1,
|
||||||
|
C: decor.DidentRight,
|
||||||
|
})))
|
||||||
|
|
||||||
// Complete the bar immediately
|
// Complete the bar immediately
|
||||||
bar.SetTotal(-1, true)
|
bar.SetTotal(-1, true)
|
||||||
@ -213,16 +240,38 @@ func Message(ctx context.Context, msgs ...any) {
|
|||||||
// that switches to "done" when the completion channel is signalled
|
// that switches to "done" when the completion channel is signalled
|
||||||
func MessageWithCompletion(
|
func MessageWithCompletion(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
msg any,
|
cfg ProgressCfg,
|
||||||
|
msgs ...any,
|
||||||
) chan<- struct{} {
|
) chan<- struct{} {
|
||||||
var (
|
var (
|
||||||
obs = getObserver(ctx)
|
obs = getObserver(ctx)
|
||||||
plain = plainString(msg)
|
log = logger.Ctx(ctx)
|
||||||
loggable = fmt.Sprintf("%v", msg)
|
plainSl = make([]string, 0, len(msgs))
|
||||||
log = logger.Ctx(ctx)
|
loggableSl = make([]string, 0, len(msgs))
|
||||||
ch = make(chan struct{}, 1)
|
ch = make(chan struct{}, 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for _, m := range msgs {
|
||||||
|
plainSl = append(plainSl, plainString(m))
|
||||||
|
loggableSl = append(loggableSl, fmt.Sprintf("%v", m))
|
||||||
|
}
|
||||||
|
|
||||||
|
plain := strings.Join(plainSl, " ")
|
||||||
|
loggable := strings.Join(loggableSl, " ")
|
||||||
|
|
||||||
|
if cfg.SectionIdentifier != nil {
|
||||||
|
plain = fmt.Sprintf(
|
||||||
|
"%s %s %s",
|
||||||
|
plain,
|
||||||
|
Bullet,
|
||||||
|
color.MagentaOutput(plainString(cfg.SectionIdentifier)))
|
||||||
|
loggable = fmt.Sprintf("%s - %v", loggable, cfg.SectionIdentifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Indent > 0 {
|
||||||
|
plain = color.CyanOutput(plain)
|
||||||
|
}
|
||||||
|
|
||||||
log.Info(loggable)
|
log.Info(loggable)
|
||||||
|
|
||||||
if obs.hidden() {
|
if obs.hidden() {
|
||||||
@ -230,17 +279,45 @@ func MessageWithCompletion(
|
|||||||
return ch
|
return ch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.NewSection {
|
||||||
|
// Empty bar to separate out section
|
||||||
|
obs.wg.Add(1)
|
||||||
|
empty := obs.mp.New(-1, mpb.NopStyle())
|
||||||
|
empty.SetTotal(-1, true)
|
||||||
|
waitAndCloseBar(ctx, empty, obs.wg, func() {})()
|
||||||
|
}
|
||||||
|
|
||||||
obs.wg.Add(1)
|
obs.wg.Add(1)
|
||||||
|
|
||||||
frames := []string{"∙∙∙", "●∙∙", "∙●∙", "∙∙●", "∙∙∙"}
|
frames := []string{"∙∙∙", "●∙∙", "∙●∙", "∙∙●", "∙∙∙"}
|
||||||
|
|
||||||
|
// https://github.com/vbauerster/mpb/issues/71
|
||||||
|
bfoc := mpb.BarFillerOnComplete(color.GreenOutput("done"))
|
||||||
|
if cfg.CompletionMessage != nil {
|
||||||
|
bfoc = mpb.BarFillerMiddleware(func(base mpb.BarFiller) mpb.BarFiller {
|
||||||
|
filler := func(w io.Writer, st decor.Statistics) error {
|
||||||
|
if st.Completed {
|
||||||
|
msg := fmt.Sprintf("%s %s", color.GreenOutput("done"), color.GreyOutput(cfg.CompletionMessage()))
|
||||||
|
_, err := io.WriteString(w, msg)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.Fill(w, st)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mpb.BarFillerFunc(filler)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
bar := obs.mp.New(
|
bar := obs.mp.New(
|
||||||
-1,
|
-1,
|
||||||
mpb.SpinnerStyle(frames...).PositionLeft(),
|
mpb.SpinnerStyle(frames...).PositionLeft(),
|
||||||
mpb.PrependDecorators(
|
mpb.PrependDecorators(
|
||||||
decor.Name(plain+":"),
|
decor.Name("", decor.WC{W: cfg.Indent * 2}),
|
||||||
|
decor.Name(plain, decor.WC{W: progressBarWidth - cfg.Indent*2, C: decor.DidentRight}),
|
||||||
decor.Elapsed(decor.ET_STYLE_GO, decor.WC{W: 8})),
|
decor.Elapsed(decor.ET_STYLE_GO, decor.WC{W: 8})),
|
||||||
mpb.BarFillerOnComplete("done"))
|
bfoc)
|
||||||
|
|
||||||
go listen(
|
go listen(
|
||||||
ctx,
|
ctx,
|
||||||
@ -520,7 +597,9 @@ func CollectionProgress(
|
|||||||
obs.wg.Add(1)
|
obs.wg.Add(1)
|
||||||
|
|
||||||
barOpts := []mpb.BarOption{
|
barOpts := []mpb.BarOption{
|
||||||
mpb.PrependDecorators(decor.Name(string(category))),
|
mpb.PrependDecorators(
|
||||||
|
decor.Name("", decor.WC{W: 2}),
|
||||||
|
decor.Name(color.CyanOutput(string(category)))),
|
||||||
mpb.AppendDecorators(
|
mpb.AppendDecorators(
|
||||||
decor.CurrentNoUnit("%d - ", decor.WCSyncSpace),
|
decor.CurrentNoUnit("%d - ", decor.WCSyncSpace),
|
||||||
decor.Name(plain)),
|
decor.Name(plain)),
|
||||||
|
|||||||
@ -127,6 +127,30 @@ func (suite *ObserveProgressUnitSuite) TestCollectionProgress_unblockOnChannelCl
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *ObserveProgressUnitSuite) TestObserve_section() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
|
ctx, flush := tester.NewContext(t)
|
||||||
|
defer flush()
|
||||||
|
|
||||||
|
recorder := strings.Builder{}
|
||||||
|
ctx = SeedObserver(ctx, &recorder, config{})
|
||||||
|
|
||||||
|
process := uuid.NewString()[:8]
|
||||||
|
target := uuid.NewString()[:8]
|
||||||
|
|
||||||
|
pcfg := ProgressCfg{
|
||||||
|
NewSection: true,
|
||||||
|
SectionIdentifier: target,
|
||||||
|
}
|
||||||
|
Message(ctx, pcfg, process)
|
||||||
|
|
||||||
|
Flush(ctx)
|
||||||
|
assert.NotEmpty(t, recorder)
|
||||||
|
assert.Contains(t, recorder.String(), process)
|
||||||
|
assert.Contains(t, recorder.String(), target)
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *ObserveProgressUnitSuite) TestObserve_message() {
|
func (suite *ObserveProgressUnitSuite) TestObserve_message() {
|
||||||
t := suite.T()
|
t := suite.T()
|
||||||
|
|
||||||
@ -138,7 +162,7 @@ func (suite *ObserveProgressUnitSuite) TestObserve_message() {
|
|||||||
|
|
||||||
message := uuid.NewString()[:8]
|
message := uuid.NewString()[:8]
|
||||||
|
|
||||||
Message(ctx, message)
|
Message(ctx, ProgressCfg{}, message)
|
||||||
Flush(ctx)
|
Flush(ctx)
|
||||||
assert.NotEmpty(t, recorder)
|
assert.NotEmpty(t, recorder)
|
||||||
assert.Contains(t, recorder.String(), message)
|
assert.Contains(t, recorder.String(), message)
|
||||||
@ -155,7 +179,7 @@ func (suite *ObserveProgressUnitSuite) TestObserve_progressWithChannelClosed() {
|
|||||||
|
|
||||||
message := uuid.NewString()[:8]
|
message := uuid.NewString()[:8]
|
||||||
|
|
||||||
ch := MessageWithCompletion(ctx, message)
|
ch := MessageWithCompletion(ctx, ProgressCfg{}, message)
|
||||||
|
|
||||||
// Close channel without completing
|
// Close channel without completing
|
||||||
close(ch)
|
close(ch)
|
||||||
@ -180,7 +204,7 @@ func (suite *ObserveProgressUnitSuite) TestObserve_progressWithContextCancelled(
|
|||||||
|
|
||||||
message := uuid.NewString()[:8]
|
message := uuid.NewString()[:8]
|
||||||
|
|
||||||
_ = MessageWithCompletion(ctx, message)
|
_ = MessageWithCompletion(ctx, ProgressCfg{}, message)
|
||||||
|
|
||||||
// cancel context
|
// cancel context
|
||||||
cancel()
|
cancel()
|
||||||
|
|||||||
@ -279,7 +279,11 @@ func (op *BackupOperation) Run(ctx context.Context) (err error) {
|
|||||||
// Execution
|
// Execution
|
||||||
// -----
|
// -----
|
||||||
|
|
||||||
observe.Message(ctx, "Backing Up", observe.Bullet, clues.Hide(op.ResourceOwner.Name()))
|
pcfg := observe.ProgressCfg{
|
||||||
|
NewSection: true,
|
||||||
|
SectionIdentifier: clues.Hide(op.ResourceOwner.Name()),
|
||||||
|
}
|
||||||
|
observe.Message(ctx, pcfg, "Backing Up")
|
||||||
|
|
||||||
deets, err := op.do(
|
deets, err := op.do(
|
||||||
ctx,
|
ctx,
|
||||||
@ -528,7 +532,7 @@ func produceBackupDataCollections(
|
|||||||
counter *count.Bus,
|
counter *count.Bus,
|
||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
) ([]data.BackupCollection, prefixmatcher.StringSetReader, bool, error) {
|
) ([]data.BackupCollection, prefixmatcher.StringSetReader, bool, error) {
|
||||||
progressBar := observe.MessageWithCompletion(ctx, "Discovering items to backup")
|
progressBar := observe.MessageWithCompletion(ctx, observe.ProgressCfg{}, "Discovering items to backup")
|
||||||
defer close(progressBar)
|
defer close(progressBar)
|
||||||
|
|
||||||
bpc := inject.BackupProducerConfig{
|
bpc := inject.BackupProducerConfig{
|
||||||
@ -565,7 +569,7 @@ func consumeBackupCollections(
|
|||||||
"collection_source", "operations",
|
"collection_source", "operations",
|
||||||
"snapshot_type", "item data")
|
"snapshot_type", "item data")
|
||||||
|
|
||||||
progressBar := observe.MessageWithCompletion(ctx, "Backing up data")
|
progressBar := observe.MessageWithCompletion(ctx, observe.ProgressCfg{}, "Backing up data")
|
||||||
defer close(progressBar)
|
defer close(progressBar)
|
||||||
|
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
|
|||||||
@ -223,7 +223,11 @@ func (op *ExportOperation) do(
|
|||||||
return nil, clues.Wrap(err, "getting backup and details")
|
return nil, clues.Wrap(err, "getting backup and details")
|
||||||
}
|
}
|
||||||
|
|
||||||
observe.Message(ctx, "Exporting", observe.Bullet, clues.Hide(bup.Selector.DiscreteOwner))
|
pcfg := observe.ProgressCfg{
|
||||||
|
NewSection: true,
|
||||||
|
SectionIdentifier: clues.Hide(bup.Selector.DiscreteOwner),
|
||||||
|
}
|
||||||
|
observe.Message(ctx, pcfg, "Exporting")
|
||||||
|
|
||||||
paths, err := formatDetailsForRestoration(ctx, bup.Version, op.Selectors, deets, op.ec, op.Errors)
|
paths, err := formatDetailsForRestoration(ctx, bup.Version, op.Selectors, deets, op.ec, op.Errors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -239,9 +243,12 @@ func (op *ExportOperation) do(
|
|||||||
"backup_snapshot_id", bup.SnapshotID,
|
"backup_snapshot_id", bup.SnapshotID,
|
||||||
"backup_version", bup.Version)
|
"backup_version", bup.Version)
|
||||||
|
|
||||||
observe.Message(ctx, fmt.Sprintf("Discovered %d items in backup %s to export", len(paths), op.BackupID))
|
observe.Message(
|
||||||
|
ctx,
|
||||||
|
observe.ProgressCfg{},
|
||||||
|
fmt.Sprintf("Discovered %d items in backup %s to export", len(paths), op.BackupID))
|
||||||
|
|
||||||
kopiaComplete := observe.MessageWithCompletion(ctx, "Enumerating items in repository")
|
kopiaComplete := observe.MessageWithCompletion(ctx, observe.ProgressCfg{}, "Enumerating items in repository")
|
||||||
defer close(kopiaComplete)
|
defer close(kopiaComplete)
|
||||||
|
|
||||||
dcs, err := op.kopia.ProduceRestoreCollections(ctx, bup.SnapshotID, paths, opStats.bytesRead, op.Errors)
|
dcs, err := op.kopia.ProduceRestoreCollections(ctx, bup.SnapshotID, paths, opStats.bytesRead, op.Errors)
|
||||||
@ -332,7 +339,7 @@ func produceExportCollections(
|
|||||||
exportStats *data.ExportStats,
|
exportStats *data.ExportStats,
|
||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
) ([]export.Collectioner, error) {
|
) ([]export.Collectioner, error) {
|
||||||
complete := observe.MessageWithCompletion(ctx, "Preparing export")
|
complete := observe.MessageWithCompletion(ctx, observe.ProgressCfg{}, "Preparing export")
|
||||||
defer func() {
|
defer func() {
|
||||||
complete <- struct{}{}
|
complete <- struct{}{}
|
||||||
close(complete)
|
close(complete)
|
||||||
|
|||||||
@ -250,7 +250,11 @@ func (op *RestoreOperation) do(
|
|||||||
return nil, clues.WrapWC(ctx, graph.ErrServiceNotEnabled, "service not enabled for restore")
|
return nil, clues.WrapWC(ctx, graph.ErrServiceNotEnabled, "service not enabled for restore")
|
||||||
}
|
}
|
||||||
|
|
||||||
observe.Message(ctx, "Restoring", observe.Bullet, clues.Hide(restoreToProtectedResource.Name()))
|
pcfg := observe.ProgressCfg{
|
||||||
|
NewSection: true,
|
||||||
|
SectionIdentifier: clues.Hide(restoreToProtectedResource.Name()),
|
||||||
|
}
|
||||||
|
observe.Message(ctx, pcfg, "Restoring")
|
||||||
|
|
||||||
paths, err := formatDetailsForRestoration(
|
paths, err := formatDetailsForRestoration(
|
||||||
ctx,
|
ctx,
|
||||||
@ -270,9 +274,16 @@ func (op *RestoreOperation) do(
|
|||||||
"backup_snapshot_id", bup.SnapshotID,
|
"backup_snapshot_id", bup.SnapshotID,
|
||||||
"backup_version", bup.Version)
|
"backup_version", bup.Version)
|
||||||
|
|
||||||
observe.Message(ctx, fmt.Sprintf("Discovered %d items in backup %s to restore", len(paths), op.BackupID))
|
if len(paths) == 0 {
|
||||||
|
return nil, clues.New("no items match the provided filters")
|
||||||
|
}
|
||||||
|
|
||||||
progressBar := observe.MessageWithCompletion(ctx, "Enumerating items in repository")
|
observe.Message(
|
||||||
|
ctx,
|
||||||
|
observe.ProgressCfg{},
|
||||||
|
fmt.Sprintf("Discovered %d items in backup %s to restore", len(paths), op.BackupID))
|
||||||
|
|
||||||
|
progressBar := observe.MessageWithCompletion(ctx, observe.ProgressCfg{}, "Enumerating items in repository")
|
||||||
defer close(progressBar)
|
defer close(progressBar)
|
||||||
|
|
||||||
dcs, err := op.kopia.ProduceRestoreCollections(
|
dcs, err := op.kopia.ProduceRestoreCollections(
|
||||||
@ -380,7 +391,7 @@ func consumeRestoreCollections(
|
|||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
ctr *count.Bus,
|
ctr *count.Bus,
|
||||||
) (*details.Details, error) {
|
) (*details.Details, error) {
|
||||||
progressBar := observe.MessageWithCompletion(ctx, "Restoring data")
|
progressBar := observe.MessageWithCompletion(ctx, observe.ProgressCfg{}, "Restoring data")
|
||||||
defer close(progressBar)
|
defer close(progressBar)
|
||||||
|
|
||||||
rcc := inject.RestoreConsumerConfig{
|
rcc := inject.RestoreConsumerConfig{
|
||||||
|
|||||||
@ -89,7 +89,7 @@ func connectToM365(
|
|||||||
return ctrl, nil
|
return ctrl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
progressBar := observe.MessageWithCompletion(ctx, "Connecting to M365")
|
progressBar := observe.MessageWithCompletion(ctx, observe.ProgressCfg{}, "Connecting to M365")
|
||||||
defer close(progressBar)
|
defer close(progressBar)
|
||||||
|
|
||||||
ctrl, err := m365.NewController(
|
ctrl, err := m365.NewController(
|
||||||
|
|||||||
@ -153,7 +153,7 @@ func (r *repository) Initialize(ctx context.Context, cfg InitConfig) (err error)
|
|||||||
return clues.Stack(err)
|
return clues.Stack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
observe.Message(ctx, "Initializing repository")
|
observe.Message(ctx, observe.ProgressCfg{}, "Initializing repository")
|
||||||
|
|
||||||
if err := r.setupKopia(ctx, cfg.RetentionOpts, true); err != nil {
|
if err := r.setupKopia(ctx, cfg.RetentionOpts, true); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -187,7 +187,8 @@ func (r *repository) Connect(ctx context.Context, cfg ConnConfig) (err error) {
|
|||||||
return clues.Stack(err)
|
return clues.Stack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
observe.Message(ctx, "Connecting to repository")
|
progressBar := observe.MessageWithCompletion(ctx, observe.ProgressCfg{}, "Connecting to repository")
|
||||||
|
defer close(progressBar)
|
||||||
|
|
||||||
if err := r.setupKopia(ctx, ctrlRepo.Retention{}, false); err != nil {
|
if err := r.setupKopia(ctx, ctrlRepo.Retention{}, false); err != nil {
|
||||||
return clues.Stack(err)
|
return clues.Stack(err)
|
||||||
@ -209,7 +210,7 @@ func (r *repository) UpdatePassword(ctx context.Context, password string) (err e
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
progressBar := observe.MessageWithCompletion(ctx, "Connecting to repository")
|
progressBar := observe.MessageWithCompletion(ctx, observe.ProgressCfg{}, "Connecting to repository")
|
||||||
defer close(progressBar)
|
defer close(progressBar)
|
||||||
|
|
||||||
repoNameHash, err := r.GenerateHashForRepositoryConfigFileName()
|
repoNameHash, err := r.GenerateHashForRepositoryConfigFileName()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user