Skip to content

Commit

Permalink
WIP: adding more spinners for pkg verification and download
Browse files Browse the repository at this point in the history
  • Loading branch information
UncleGedd committed Mar 20, 2024
1 parent cfdbf69 commit 10655f2
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 47 deletions.
6 changes: 3 additions & 3 deletions src/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ var rootCmd = &cobra.Command{

// don't load log configs for the logs command
if cmd.Use != "logs" {
cliSetup()
cliSetup(cmd.Use)
}
},
Short: lang.RootCmdShort,
Expand Down Expand Up @@ -92,7 +92,7 @@ func init() {
rootCmd.PersistentFlags().BoolVar(&config.CommonOptions.NoTea, "no-tea", v.GetBool(V_NO_TEA), lang.RootCmdNoTea)
}

func cliSetup() {
func cliSetup(op string) {
match := map[string]message.LogLevel{
"warn": message.WarnLevel,
"info": message.InfoLevel,
Expand All @@ -113,7 +113,7 @@ func cliSetup() {
}

if !config.SkipLogFile && !config.ListTasks {
err := utils.ConfigureLogs()
err := utils.ConfigureLogs(op)
if err != nil {
message.Fatalf(err, "Error configuring logs")
}
Expand Down
10 changes: 1 addition & 9 deletions src/cmd/uds.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/defenseunicorns/uds-cli/src/config/lang"
"github.com/defenseunicorns/uds-cli/src/pkg/bundle"
"github.com/defenseunicorns/uds-cli/src/pkg/bundle/tui/deploy"
"github.com/defenseunicorns/uds-cli/src/pkg/utils"
zarfConfig "github.com/defenseunicorns/zarf/src/config"
"github.com/defenseunicorns/zarf/src/pkg/message"
zarfUtils "github.com/defenseunicorns/zarf/src/pkg/utils"
Expand Down Expand Up @@ -77,13 +76,6 @@ var deployCmd = &cobra.Command{
Short: lang.CmdBundleDeployShort,
Args: cobra.MaximumNArgs(1),
Run: func(_ *cobra.Command, args []string) {
// reconfigure logs for the deploy command so we can use BubbleTea
config.TeaEnabled = true
err := utils.ConfigureLogs()
if err != nil {
message.Fatalf(err, "Error configuring logs")
}

bundleCfg.DeployOpts.Source = chooseBundle(args)
configureZarf()

Expand All @@ -100,7 +92,7 @@ var deployCmd = &cobra.Command{

// pre-deploy validation
bundleYAML := ""
bundleYAML, err = bndlClient.PreDeployValidation()
bundleYAML, err := bndlClient.PreDeployValidation()
if err != nil {
return
}
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var versionCmd = &cobra.Command{
Aliases: []string{"v"},
PersistentPreRun: func(_ *cobra.Command, _ []string) {
config.SkipLogFile = true
cliSetup()
cliSetup("")
},
Short: lang.CmdVersionShort,
Long: lang.CmdVersionLong,
Expand Down
23 changes: 20 additions & 3 deletions src/pkg/bundle/tarball.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,9 +295,26 @@ func (tp *tarballBundleProvider) PublishBundle(bundle types.UDSBundle, remote *o
return err
}

_, err = oras.Copy(tp.ctx, store, ref, remote.Repo(), ref, copyOpts)
if err != nil {
return err
// copy bundle layers to remote with retries
maxRetries := 3
retries := 0

// reset retries if a desc was successful
copyOpts.PostCopy = func(_ context.Context, desc ocispec.Descriptor) error {
retries = 0
return nil
}

for {
_, err = oras.Copy(tp.ctx, store, ref, remote.Repo(), ref, copyOpts)
if err != nil && retries < maxRetries {
retries++
message.Debugf("Encountered err during publish: %s\nRetrying %d/%d", err, retries, maxRetries)
continue
} else if err != nil {
return err
}
break
}

// create or update, then push index.json
Expand Down
23 changes: 19 additions & 4 deletions src/pkg/bundle/tui/deploy/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ const (
totalComponents packageOp = "totalComponents"
totalPackages packageOp = "totalPackages"
complete packageOp = "complete"
verified packageOp = "verified"
verifying packageOp = "verifying"
downloading packageOp = "downloading"
)

var (
Expand All @@ -49,12 +50,16 @@ type bndlClientShim interface {
type pkgState struct {
name string
numComponents int
percLayersVerified float64
percLayersVerified int64
componentStatuses []bool
deploySpinner spinner.Model
complete bool
resetProgress bool
verifySpinner spinner.Model
percDownloaded int64
downloaded bool
verified bool
isRemote bool
}

type Model struct {
Expand Down Expand Up @@ -225,9 +230,19 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if totalPkgs, err := strconv.Atoi(strings.Split(msg, ":")[1]); err == nil {
m.totalPkgs = totalPkgs
}
case verified:
if perc, err := strconv.ParseFloat(strings.Split(msg, ":")[1], 64); err == nil {
case verifying:
if perc, err := strconv.ParseInt(strings.Split(msg, ":")[1], 10, 8); err == nil {
m.packages[m.pkgIdx].percLayersVerified = perc
if perc == 100 {
m.packages[m.pkgIdx].verified = true
}
}
case downloading:
if perc, err := strconv.ParseInt(strings.Split(msg, ":")[1], 10, 8); err == nil {
m.packages[m.pkgIdx].percDownloaded = perc
if perc == 100 {
m.packages[m.pkgIdx].downloaded = true
}
}
case complete:
m.packages[m.pkgIdx].complete = true
Expand Down
83 changes: 59 additions & 24 deletions src/pkg/bundle/tui/deploy/views.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ var (
)

func (m *Model) logView() string {
headerMsg := fmt.Sprintf("Package %s deploy logs", m.packages[m.pkgIdx].name)
headerMsg := fmt.Sprintf("%s %s", lightBlueText.Render(m.packages[m.pkgIdx].name), lightGrayText.Render("package logs"))
return lipgloss.NewStyle().Padding(0, 3).Render(
fmt.Sprintf("%s\n%s\n%s\n\n", m.logHeaderView(headerMsg), m.logViewport.View(), m.logFooterView()),
)
Expand Down Expand Up @@ -70,33 +70,71 @@ func (m *Model) deployView() string {
}

var text string
if p.percLayersVerified > 0 {
perc := lightGrayText.Render(fmt.Sprintf("%d%%", int32(p.percLayersVerified)))
text = lipgloss.NewStyle().
Align(lipgloss.Left).
Padding(0, 3).
Render(fmt.Sprintf("%s Verifying pkg %s (%s)", p.verifySpinner.View(), p.name, perc))
}
if p.numComponents != 0 {
// todo: sometimes this says it's deploying 0/0 components, fix this
text = lipgloss.NewStyle().
Align(lipgloss.Left).
Padding(0, 3).
Render(fmt.Sprintf("%s Package %s deploying (%d / %d components)", p.deploySpinner.View(), p.name, min(numComponentsSuccess+1, p.numComponents), p.numComponents))
}
if p.complete {
text = lipgloss.NewStyle().
Align(lipgloss.Left).
Padding(0, 3).
Render(fmt.Sprintf("✅ Package %s deployed", p.name))
}
// todo: check is pkg is remote....
//if p.isRemote {
text = genRemotePkgText(p, numComponentsSuccess)
//} else {
// text = genLocalPkgText(p, numComponentsSuccess)
//}

view = lipgloss.JoinVertical(lipgloss.Left, view, text+"\n")
}

return view
}

func genLocalPkgText(p pkgState, numComponentsSuccess int) string {
text := ""
if p.numComponents > 0 {
text = lipgloss.NewStyle().
Align(lipgloss.Left).
Padding(0, 3).
Render(fmt.Sprintf("%s Package %s deploying (%d / %d components)", p.deploySpinner.View(), p.name, min(numComponentsSuccess+1, p.numComponents), p.numComponents))
} else {
text = lipgloss.NewStyle().
Align(lipgloss.Left).
Padding(0, 3).
Render(fmt.Sprintf("%s Package %s deploying", p.deploySpinner.View(), p.name))
}
return text
}

func genRemotePkgText(p pkgState, numComponentsSuccess int) string {
text := ""
styledName := lightBlueText.Render(p.name)
if !p.verified {
perc := lightGrayText.Render(fmt.Sprintf("%d%%", p.percLayersVerified))
text = lipgloss.NewStyle().
Align(lipgloss.Left).
Padding(0, 3).
Render(fmt.Sprintf("%s Verifying %s package (%s)", p.verifySpinner.View(), styledName, perc))
} else if p.verified && !p.downloaded {
perc := lightGrayText.Render(fmt.Sprintf("%d%%", p.percDownloaded))
text = lipgloss.NewStyle().
Align(lipgloss.Left).
Padding(0, 3).
Render(fmt.Sprintf("%s Downloading %s package (%s)", p.deploySpinner.View(), styledName, perc))
} else if p.downloaded && p.verified && p.numComponents > 0 {
text = lipgloss.NewStyle().
Align(lipgloss.Left).
Padding(0, 3).
Render(fmt.Sprintf("%s Deploying %s package (%d / %d components)", p.deploySpinner.View(), styledName, min(numComponentsSuccess+1, p.numComponents), p.numComponents))
} else {
text = lipgloss.NewStyle().
Align(lipgloss.Left).
Padding(0, 3).
Render(fmt.Sprintf("%s Deploying %s package", p.deploySpinner.View(), styledName))
}

if p.complete {
text = lipgloss.NewStyle().
Align(lipgloss.Left).
Padding(0, 3).
Render(fmt.Sprintf("✅ Package %s deployed", p.name))
}
return text
}

func (m *Model) preDeployView() string {
paddingStyle := lipgloss.NewStyle().Padding(0, 3)
header := paddingStyle.Render("🎁 BUNDLE DEFINITION")
Expand All @@ -105,9 +143,6 @@ func (m *Model) preDeployView() string {
m.yamlViewport.SetContent(prettyYAML)

headerMsg := "Use mouse wheel to scroll"
//return lipgloss.NewStyle().Padding(0, 3).Render(
// fmt.Sprintf("%s\n%s\n%s\n\n", m.logHeaderView(headerMsg), m.logViewport.View(), m.logFooterView()),
//)

// Concatenate header, highlighted YAML, and prompt
return fmt.Sprintf("\n%s\n\n%s\n%s\n%s\n\n%s",
Expand Down
11 changes: 10 additions & 1 deletion src/pkg/sources/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ func (r *RemoteBundle) downloadPkgFromRemoteBundle() ([]ocispec.Descriptor, erro
layersToPull := []ocispec.Descriptor{pkgManifestDesc}
layersInBundle := []ocispec.Descriptor{pkgManifestDesc}
numLayersVerified := 0.0
downloadedBytes := int64(0)

for _, layer := range pkgManifest.Layers {
ok, err := r.Remote.Repo().Blobs().Exists(ctx, layer)
Expand All @@ -187,7 +188,7 @@ func (r *RemoteBundle) downloadPkgFromRemoteBundle() ([]ocispec.Descriptor, erro
numLayersVerified++
if ok {
percVerified := numLayersVerified / float64(len(pkgManifest.Layers)) * 100
deploy.Program.Send(fmt.Sprintf("verified:%v", percVerified))
deploy.Program.Send(fmt.Sprintf("verifying:%v", int64(percVerified)))
estimatedBytes += layer.Size
layersInBundle = append(layersInBundle, layer)
digest := layer.Digest.Encoded()
Expand Down Expand Up @@ -215,6 +216,14 @@ func (r *RemoteBundle) downloadPkgFromRemoteBundle() ([]ocispec.Descriptor, erro
copyOpts := utils.CreateCopyOpts(layersToPull, config.CommonOptions.OCIConcurrency)
doneSaving := make(chan error)
go zarfUtils.RenderProgressBarForLocalDirWrite(r.TmpDir, estimatedBytes, doneSaving, fmt.Sprintf("Pulling bundled Zarf pkg: %s", r.PkgName), fmt.Sprintf("Successfully pulled package: %s", r.PkgName))

copyOpts.PostCopy = func(_ context.Context, desc ocispec.Descriptor) error {
downloadedBytes += desc.Size
downloadedPerc := float64(downloadedBytes) / float64(estimatedBytes) * 100
deploy.Program.Send(fmt.Sprintf("downloading:%d", int64(downloadedPerc)))
return nil
}

_, err = oras.Copy(ctx, r.Remote.Repo(), r.Remote.Repo().Reference.String(), store, "", copyOpts)
doneSaving <- err
<-doneSaving
Expand Down
5 changes: 3 additions & 2 deletions src/pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func IsValidTarballPath(path string) bool {
}

// ConfigureLogs sets up the log file, log cache and output for the CLI
func ConfigureLogs() error {
func ConfigureLogs(op string) error {
writer, err := message.UseLogFile("")
logFile := writer
if err != nil {
Expand All @@ -82,7 +82,8 @@ func ConfigureLogs() error {
logWriter := io.MultiWriter(logFile, CacheLogFile)

// use Zarf pterm output if no-tea flag is set
if !config.TeaEnabled || config.CommonOptions.NoTea {
// todo: as more bundle ops use BubbleTea, need to also check them alongside 'deploy'
if !strings.Contains(op, "deploy") || config.CommonOptions.NoTea {
message.Notef("Saving log file to %s", location)
logWriter = io.MultiWriter(os.Stderr, CacheLogFile, logFile)
pterm.SetDefaultOutput(logWriter)
Expand Down

0 comments on commit 10655f2

Please sign in to comment.