Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/progress bar #174

Merged
merged 26 commits into from
Oct 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8569801
wip: draft implementation of progress bar
reubenmiller Jan 24, 2022
b099138
Merge branch 'master' into feat/progress-bar
reubenmiller Jan 24, 2022
0072e3d
Merge branch 'master' into feat/progress-bar
reubenmiller May 9, 2022
201be6f
tidy go dependencies
reubenmiller May 9, 2022
c5c2efb
Merge remote-tracking branch 'origin/v2' into feat/progress-bar
reubenmiller Jul 17, 2022
cbc010b
fix invalid import
reubenmiller Jul 17, 2022
33ed2cd
Merge branch 'v2' into feat/progress-bar
reubenmiller Jul 25, 2022
44d14f6
Merge branch 'v2' into feat/progress-bar
reubenmiller Jul 25, 2022
b3d645d
revert binary update command
reubenmiller Jul 27, 2022
86c540d
Merge branch 'v2' into feat/progress-bar
reubenmiller Aug 17, 2022
676ac86
add download progress bar
reubenmiller Aug 27, 2022
62418e1
remove unnecessary changes and files
reubenmiller Aug 27, 2022
2342a8c
revert changes
reubenmiller Aug 27, 2022
10f8dba
support progress on event binaries uploads
reubenmiller Aug 27, 2022
cc686a5
use custom bar fillter
reubenmiller Aug 27, 2022
ea0a83a
fix progress bar when no files are present
reubenmiller Aug 27, 2022
5598720
fix typo
reubenmiller Aug 28, 2022
17ded4e
feat: c8y applications createHostedApplication - add tab completion t…
reubenmiller Aug 28, 2022
5677ba2
upgrade go-c8y version
reubenmiller Aug 28, 2022
c1cf8a7
wrap progress reader with a proxy
reubenmiller Aug 28, 2022
03db9a4
Merge branch 'v2' into feat/progress-bar
reubenmiller Sep 18, 2022
3af1305
wait for progress bar before printing to output
reubenmiller Sep 19, 2022
85036e7
support global noProgress flag
reubenmiller Sep 19, 2022
6d53ece
add NoProgress common flag in pwsh module
reubenmiller Sep 19, 2022
2128745
support progress for createHostedApplications
reubenmiller Sep 19, 2022
6fb1930
add progress support for software/firmware/configuration commands
reubenmiller Sep 30, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ test/c8y_test/debug.test
test/c8y_test/application.setup.properties
.cumulocity/
temp-example/
*.tmp
c8y.env
c8y.activitylog.*.json
c8y~
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ require (
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0
github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.3.0
github.com/reubenmiller/go-c8y v0.10.0-rc.6
github.com/reubenmiller/go-c8y v0.11.0-rc.2
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0
github.com/sergi/go-diff v1.2.0 // indirect
github.com/sethvargo/go-password v0.2.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/reubenmiller/go-c8y v0.10.0-rc.6 h1:bP5l2+gJZbTqY5FVTUOR/Z8urtZ47BuFVh+EeX8xqMo=
github.com/reubenmiller/go-c8y v0.10.0-rc.6/go.mod h1:aSU0AZdT/IWCn87wMveejGvwQE3FbnAkh5LEs/78xj8=
github.com/reubenmiller/go-c8y v0.11.0-rc.2 h1:d1FWuGGDYvPgcmdw51m8COYJc0xnDtN/8Xqie+KwRZw=
github.com/reubenmiller/go-c8y v0.11.0-rc.2/go.mod h1:aSU0AZdT/IWCn87wMveejGvwQE3FbnAkh5LEs/78xj8=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
Expand Down
234 changes: 234 additions & 0 deletions pkg/c8ybinary/c8ybinary.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
package c8ybinary

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"mime"
"net/http"
"os"
"path/filepath"

"github.com/reubenmiller/go-c8y-cli/v2/pkg/flags"
"github.com/reubenmiller/go-c8y/pkg/c8y"
"github.com/reubenmiller/go-c8y/pkg/c8y/binary"
"github.com/spf13/cobra"
"github.com/vbauerster/mpb/v6"
"github.com/vbauerster/mpb/v6/decor"
)

const BarFiller = "[━━ ]"

// const BarFiller = "[██-]"

func CreateBinaryWithProgress(ctx context.Context, client *c8y.Client, path string, filename string, properties interface{}, progress *mpb.Progress) (*c8y.Response, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}

values := map[string]io.Reader{
"file": file,
}

if properties != nil {
metadataBytes, err := json.Marshal(properties)
if err != nil {
return nil, fmt.Errorf("failed to convert binary properties to json. %w", err)
}
values["object"] = bytes.NewReader(metadataBytes)
}

return client.SendRequest(ctx, c8y.RequestOptions{
Method: "POST",
Accept: "application/json",
Path: path,
FormData: values,
PrepareRequest: func(r *http.Request) (*http.Request, error) {
if r.Body == nil || progress == nil {
return r, nil
}

bar, err := NewProgressBar(progress, filename)
if err != nil {
return nil, err
}
r.Body = bar.ProxyReader(r.Body)
return r, nil
},
})
}

func AddProgress(cmd *cobra.Command, fileFlag string, progress *mpb.Progress) func(r *http.Request) (*http.Request, error) {
return func(r *http.Request) (*http.Request, error) {
if r.Body == nil || progress == nil {
return r, nil
}
filename, err := cmd.Flags().GetString(fileFlag)
if err != nil {
// Don't return error here, as if the user does not provide a file, then ignore the progress
return r, nil
}

if filename == "" {
return r, nil
}

bar, err := NewProgressBar(progress, filename)
if err != nil {
return nil, err
}
r.Body = bar.ProxyReader(r.Body)

return r, nil
}
}

func CreateProxyReader(progress *mpb.Progress) func(response *http.Response) io.Reader {
return func(r *http.Response) io.Reader {
size := int64(r.ContentLength)
basename := "download"

_, params, err := mime.ParseMediaType(r.Header.Get("Content-Disposition"))
if err == nil {
if filename, ok := params["filename"]; ok {
basename = filename
}
}

bar := progress.Add(size,
mpb.NewBarFiller(BarFiller),
mpb.PrependDecorators(
decor.Name("elapsed", decor.WC{W: len("elapsed") + 1, C: decor.DidentRight}),
decor.Elapsed(decor.ET_STYLE_MMSS, decor.WC{W: 8, C: decor.DidentRight}),
decor.Name(basename, decor.WC{W: len(basename) + 1, C: decor.DidentRight}),
),
mpb.AppendDecorators(
decor.Percentage(decor.WC{W: 6, C: decor.DidentRight}),
decor.CountersKibiByte("% .2f / % .2f"),
),
)

proxyReader := c8y.NewProxyReader(bar.ProxyReader(r.Body))
r.Body = proxyReader
return proxyReader
}
}

func NewProgressBar(progress *mpb.Progress, filename string) (*mpb.Bar, error) {
if progress == nil {
return nil, nil
}

file, err := os.Stat(filename)

if err != nil {
return nil, err
}

size := int64(file.Size())
basename := filepath.Base(filename)

bar := progress.Add(size,
mpb.NewBarFiller(BarFiller),
mpb.PrependDecorators(
decor.Name("elapsed", decor.WC{W: len("elapsed") + 1, C: decor.DidentRight}),
decor.Elapsed(decor.ET_STYLE_MMSS, decor.WC{W: 8, C: decor.DidentRight}),
decor.Name(basename, decor.WC{W: len(basename) + 1, C: decor.DidentRight}),
),
mpb.AppendDecorators(
decor.Percentage(decor.WC{W: 6, C: decor.DidentRight}),
decor.CountersKibiByte("% .2f / % .2f"),
),
)

return bar, nil
}

func NewProxyReader(progress *mpb.Progress, r io.ReadCloser, filename string) (io.ReadCloser, error) {
if progress == nil {
return r, nil
}

file, err := os.Stat(filename)

if err != nil {
return nil, err
}

size := int64(file.Size())
basename := filepath.Base(filename)

bar := progress.Add(size,
mpb.NewBarFiller(BarFiller),
mpb.PrependDecorators(
decor.Name("elapsed", decor.WC{W: len("elapsed") + 1, C: decor.DidentRight}),
decor.Elapsed(decor.ET_STYLE_MMSS, decor.WC{W: 8, C: decor.DidentRight}),
decor.Name(basename, decor.WC{W: len(basename) + 1, C: decor.DidentRight}),
),
mpb.AppendDecorators(
decor.Percentage(decor.WC{W: 6, C: decor.DidentRight}),
decor.CountersKibiByte("% .2f / % .2f"),
),
)

return bar.ProxyReader(r), nil
}

// WithBinaryUploadURL uploads an inventory binary and returns the URL to it
func WithBinaryUploadURL(client *c8y.Client, progress *mpb.Progress, opts ...string) flags.GetOption {
return func(cmd *cobra.Command, inputIterators *flags.RequestInputIterators) (string, interface{}, error) {
src, dst, _ := flags.UnpackGetterOptions("%s", opts...)

if !cmd.Flags().Changed(src) {
return "", "", nil
}

filename, err := cmd.Flags().GetString(src)
if err != nil {
return dst, filename, err
}

// binary properties
file, err := os.Open(filename)
if err != nil {
return "", nil, err
}

defer file.Close()

bar, err := NewProgressBar(progress, filename)

if err != nil {
return "", nil, err
}

binaryFile, err := binary.NewBinaryFile(
binary.WithReader(file),
binary.WithFileProperties(filename),
binary.WithGlobal(),
)
if err != nil {
return "", nil, err
}

mo, _, err := client.Inventory.CreateBinary(context.Background(), binaryFile, func(r *http.Request) (*http.Request, error) {
if bar != nil {
r.Body = bar.ProxyReader(r.Body)
}
return r, nil
})

if progress != nil {
progress.Wait()
}

if err != nil {
return "", nil, err
}

return dst, mo.Self, err
}
}
5 changes: 5 additions & 0 deletions pkg/cmd/api/api.manual.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/MakeNowJust/heredoc/v2"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/c8ybinary"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/cmd/subcommand"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/cmderrors"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/cmdutil"
Expand Down Expand Up @@ -278,8 +279,12 @@ func (n *CmdAPI) RunE(cmd *cobra.Command, args []string) error {
req.Body = body
}

req.PrepareRequest = c8ybinary.AddProgress(cmd, "file", cfg.GetProgressBar(n.factory.IOStreams.ErrOut, n.factory.IOStreams.IsStderrTTY()))
// get file info
// form data
// BUG: Format data needs to be lazily loaded via the iterator so it can be re-read
// for each request
//
formData := make(map[string]io.Reader)
err = flags.WithFormDataOptions(
cmd,
Expand Down
18 changes: 10 additions & 8 deletions pkg/cmd/applications/createbinary/createBinary.auto.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import (
"strings"

"github.com/MakeNowJust/heredoc/v2"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/c8ybinary"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/c8yfetcher"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/cmd/subcommand"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/cmdutil"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/completion"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/flags"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/logger"
"github.com/reubenmiller/go-c8y-cli/v2/pkg/zipUtilities"
Expand Down Expand Up @@ -94,6 +96,11 @@ func NewCmdCreateHostedApplication(f *cmdutil.Factory) *CmdCreateHostedApplicati
cmd.Flags().BoolVar(&ccmd.skipActivation, "skipActivation", false, "Don't activate to the application after it has been created and uploaded")
cmd.Flags().BoolVar(&ccmd.skipUpload, "skipUpload", false, "Don't uploaded the web app binary. Only the application placeholder will be created")

completion.WithOptions(
cmd,
completion.WithValidateSet("availability", "MARKET", "PRIVATE"),
)

flags.WithOptions(
cmd,
flags.WithData(),
Expand Down Expand Up @@ -297,7 +304,16 @@ func (n *CmdCreateHostedApplication) RunE(cmd *cobra.Command, args []string) err
}

log.Infof("uploading binary [app=%s]", application.ID)
resp, err := client.Application.CreateBinary(context.Background(), zipfile, application.ID)
progress := n.factory.IOStreams.ProgressIndicator()
resp, err := c8ybinary.CreateBinaryWithProgress(
context.Background(),
client,
"/application/applications/"+application.ID+"/binaries",
zipfile,
nil,
progress,
)
n.factory.IOStreams.WaitForProgressIndicator()

if err != nil {
// handle error
Expand Down
18 changes: 10 additions & 8 deletions pkg/cmd/binaries/create/create.auto.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading