Skip to content

Commit

Permalink
refactor the confirmation option
Browse files Browse the repository at this point in the history
Signed-off-by: Haoliang Yue <yuehaoliang@microsoft.com>
  • Loading branch information
yuehaoliang committed Sep 2, 2022
1 parent 1f60764 commit f4e876b
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,28 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package util
package option

import (
"fmt"
"strings"

"github.com/spf13/pflag"
)

func AskForComfirmation() (bool, error) {
// Confirmation option struct.
type Confirmation struct {
Confirmed bool
}

// ApplyFlags applies flags to a command flag set.
func (opts *Confirmation) ApplyFlags(fs *pflag.FlagSet) {
fs.BoolVarP(&opts.Confirmed, "yes", "y", false, "do not prompt for confirmation")
}

func (opts *Confirmation) AskForComfirmation(message string) (bool, error) {
fmt.Print(message)

var response string
_, err := fmt.Scanln(&response)
if err != nil {
Expand All @@ -33,7 +47,6 @@ func AskForComfirmation() (bool, error) {
case "n", "no":
return false, nil
default:
fmt.Println("please type (y)es or (n)o and then press enter")
return AskForComfirmation()
return opts.AskForComfirmation(message)
}
}
43 changes: 43 additions & 0 deletions cmd/oras/internal/option/descriptor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
Copyright The ORAS Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package option

import (
"encoding/json"
"fmt"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/spf13/pflag"
)

// Descriptor option struct.
type Descriptor struct {
OutputDescriptor bool
}

// ApplyFlags applies flags to a command flag set.
func (opts *Descriptor) ApplyFlags(fs *pflag.FlagSet) {
fs.BoolVarP(&opts.OutputDescriptor, "descriptor", "", false, "output the descriptor")
}

// Marshal returns the JSON encoding of descriptor.
func (opts *Descriptor) Marshal(desc ocispec.Descriptor) ([]byte, error) {
b, err := json.Marshal(desc)
if err != nil {
return nil, fmt.Errorf("failed to marshal descriptor: %w", err)
}
return b, err
}
51 changes: 51 additions & 0 deletions cmd/oras/internal/option/pretty.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
Copyright The ORAS Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package option

import (
"bytes"
"encoding/json"
"fmt"
"io"

"github.com/spf13/pflag"
)

// Pretty option struct.
type Pretty struct {
pretty bool
}

// ApplyFlags applies flags to a command flag set.
func (opts *Pretty) ApplyFlags(fs *pflag.FlagSet) {
fs.BoolVarP(&opts.pretty, "pretty", "", false, "output prettified content")
}

// Output outputs the prettified content if `--pretty` flag is used. Otherwise
// outputs the original content.
func (opts *Pretty) Output(w io.Writer, content []byte) error {
if opts.pretty {
buf := bytes.NewBuffer(nil)
if err := json.Indent(buf, content, "", " "); err != nil {
return fmt.Errorf("failed to prettify: %w", err)
}
buf.WriteByte('\n')
content = buf.Bytes()
}

_, err := w.Write(content)
return err
}
34 changes: 18 additions & 16 deletions cmd/oras/manifest/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,24 @@ limitations under the License.
package manifest

import (
"encoding/json"
"errors"
"fmt"
"os"

"github.com/spf13/cobra"
"oras.land/oras-go/v2/errdef"
ierrors "oras.land/oras/cmd/oras/internal/errors"
"oras.land/oras/cmd/oras/internal/option"
"oras.land/oras/cmd/oras/internal/util"
)

type deleteOptions struct {
option.Common
option.Confirmation
option.Descriptor
option.Pretty
option.Remote

confirmed bool
descriptor bool
targetRef string
targetRef string
}

func deleteCmd() *cobra.Command {
Expand All @@ -40,6 +40,7 @@ func deleteCmd() *cobra.Command {
Use: "delete name[:tag|@digest]",
Short: "[Preview] Delete a manifest from remote registry",
Long: `[Preview] Delete a manifest from remote registry
** This command is in preview and under development. **
Example - Delete a manifest tagged with 'latest' from repository 'locahost:5000/hello':
Expand All @@ -53,6 +54,9 @@ Example - Delete a manifest without TLS:
`,
Args: cobra.ExactArgs(1),
PreRunE: func(cmd *cobra.Command, args []string) error {
if opts.OutputDescriptor && !opts.Confirmed {
return errors.New("must have --yes to confirm the deletion if output the descriptor")
}
return opts.ReadPassword()
},
RunE: func(_ *cobra.Command, args []string) error {
Expand All @@ -61,8 +65,6 @@ Example - Delete a manifest without TLS:
},
}

cmd.Flags().BoolVarP(&opts.confirmed, "yes", "y", false, "do not prompt for confirmation")
cmd.Flags().BoolVarP(&opts.descriptor, "descriptor", "", false, "print the descriptor of the manifest")
option.ApplyFlags(&opts, cmd.Flags())
return cmd
}
Expand All @@ -87,9 +89,9 @@ func deleteManifest(opts deleteOptions) error {
return err
}

if !opts.confirmed {
fmt.Printf("Are you sure you want to delete the artifact '%v' and all manifests that refer to it? (y/n):", desc.Digest)
comfirmed, err := util.AskForComfirmation()
if !opts.Confirmed {
message := fmt.Sprintf("Are you sure you want to delete the artifact '%v' and all manifests that refer to it? (y/n):", desc.Digest)
comfirmed, err := opts.AskForComfirmation(message)
if err != nil {
return err
}
Expand All @@ -99,18 +101,18 @@ func deleteManifest(opts deleteOptions) error {
}

if err = repo.Delete(ctx, desc); err != nil {
return fmt.Errorf("failed to delete %s: %w", opts.targetRef, err)
return err
}

fmt.Println("Deleted", opts.targetRef)

if opts.descriptor {
descriptorByte, err := json.Marshal(desc)
if opts.OutputDescriptor {
bytes, err := opts.Marshal(desc)
if err != nil {
return err
}
fmt.Println(string(descriptorByte))
return opts.Output(os.Stdout, bytes)
}

fmt.Println("Deleted", opts.targetRef)

return nil
}

0 comments on commit f4e876b

Please sign in to comment.