Skip to content

Commit

Permalink
Make --output a global parameter, disable logging, fix bug
Browse files Browse the repository at this point in the history
This PR:
- Makes `-o` or `--output` a global parameter
- Disables logging completely when performing `-o json`, including
using verbosity `-v`
- Fixes a minor bug within some commands where `-o json` wasn't
detected corretly due to a local flag being used `outputFlag` rather
than `OutputFlag`
  • Loading branch information
cdrage committed Jul 29, 2019
1 parent 9276486 commit fb0fd8b
Show file tree
Hide file tree
Showing 14 changed files with 118 additions and 63 deletions.
59 changes: 47 additions & 12 deletions pkg/log/status.go
Expand Up @@ -112,14 +112,15 @@ func IsTerminal(w io.Writer) bool {
// there will be a loading spinner with this status
func (s *Status) Start(status string, debug bool) {
s.End(true)

// set new status
isTerm := IsTerminal(s.writer)
s.status = status

// If we are in debug mode, don't spin!
if !isTerm || debug {
fmt.Fprintf(s.writer, prefixSpacing+getSpacingString()+suffixSpacing+"%s ...\n", s.status)
} else {
} else if !IsJSON() {
s.spinner.SetPrefix(prefixSpacing)
s.spinner.SetSuffix(fmt.Sprintf(suffixSpacing+"%s", s.status))
s.spinner.Start()
Expand Down Expand Up @@ -154,68 +155,90 @@ func (s *Status) End(success bool) {
// Namef will output the name of the component / application / project in a *bolded* manner
func Namef(format string, a ...interface{}) {
bold := color.New(color.Bold).SprintFunc()
fmt.Fprintf(GetStdout(), "%s\n", bold(fmt.Sprintf(format, a...)))
if !IsJSON() {
fmt.Fprintf(GetStdout(), "%s\n", bold(fmt.Sprintf(format, a...)))
}
}

// Progressf will output in an appropriate "progress" manner
func Progressf(format string, a ...interface{}) {
fmt.Fprintf(GetStdout(), " %s%s\n", prefixSpacing, fmt.Sprintf(format, a...))
if !IsJSON() {
fmt.Fprintf(GetStdout(), " %s%s\n", prefixSpacing, fmt.Sprintf(format, a...))
}
}

// Success will output in an appropriate "success" manner
func Success(a ...interface{}) {
green := color.New(color.FgGreen).SprintFunc()
fmt.Fprintf(GetStdout(), "%s%s%s%s", prefixSpacing, green(getSuccessString()), suffixSpacing, fmt.Sprintln(a...))
if !IsJSON() {
fmt.Fprintf(GetStdout(), "%s%s%s%s", prefixSpacing, green(getSuccessString()), suffixSpacing, fmt.Sprintln(a...))
}
}

// Successf will output in an appropriate "progress" manner
func Successf(format string, a ...interface{}) {
green := color.New(color.FgGreen).SprintFunc()
fmt.Fprintf(GetStdout(), "%s%s%s%s\n", prefixSpacing, green(getSuccessString()), suffixSpacing, fmt.Sprintf(format, a...))
if !IsJSON() {
fmt.Fprintf(GetStdout(), "%s%s%s%s\n", prefixSpacing, green(getSuccessString()), suffixSpacing, fmt.Sprintf(format, a...))
}
}

// Warningf will output in an appropriate "progress" manner
func Warningf(format string, a ...interface{}) {
yellow := color.New(color.FgYellow).SprintFunc()
fmt.Fprintf(GetStderr(), " %s%s%s\n", yellow(getWarningString()), suffixSpacing, fmt.Sprintf(format, a...))
if !IsJSON() {
fmt.Fprintf(GetStderr(), " %s%s%s\n", yellow(getWarningString()), suffixSpacing, fmt.Sprintf(format, a...))
}
}

// Warning will output in an appropriate "progress" manner
func Warning(a ...interface{}) {
yellow := color.New(color.FgYellow).SprintFunc()
fmt.Fprintf(GetStderr(), "%s%s%s%s", prefixSpacing, yellow(getWarningString()), suffixSpacing, fmt.Sprintln(a...))
if !IsJSON() {
fmt.Fprintf(GetStderr(), "%s%s%s%s", prefixSpacing, yellow(getWarningString()), suffixSpacing, fmt.Sprintln(a...))
}
}

// Errorf will output in an appropriate "progress" manner
func Errorf(format string, a ...interface{}) {
red := color.New(color.FgRed).SprintFunc()
fmt.Fprintf(GetStderr(), " %s%s%s\n", red(getErrString()), suffixSpacing, fmt.Sprintf(format, a...))
if !IsJSON() {
fmt.Fprintf(GetStderr(), " %s%s%s\n", red(getErrString()), suffixSpacing, fmt.Sprintf(format, a...))
}
}

// Error will output in an appropriate "progress" manner
func Error(a ...interface{}) {
red := color.New(color.FgRed).SprintFunc()
fmt.Fprintf(GetStderr(), "%s%s%s%s", prefixSpacing, red(getErrString()), suffixSpacing, fmt.Sprintln(a...))
if !IsJSON() {
fmt.Fprintf(GetStderr(), "%s%s%s%s", prefixSpacing, red(getErrString()), suffixSpacing, fmt.Sprintln(a...))
}
}

// Info will simply print out information on a new (bolded) line
// this is intended as information *after* something has been deployed
func Info(a ...interface{}) {
bold := color.New(color.Bold).SprintFunc()
fmt.Fprintf(GetStdout(), "%s", bold(fmt.Sprintln(a...)))
if !IsJSON() {
fmt.Fprintf(GetStdout(), "%s", bold(fmt.Sprintln(a...)))
}
}

// Infof will simply print out information on a new (bolded) line
// this is intended as information *after* something has been deployed
func Infof(format string, a ...interface{}) {
bold := color.New(color.Bold).SprintFunc()
fmt.Fprintf(GetStdout(), "%s\n", bold(fmt.Sprintf(format, a...)))
if !IsJSON() {
fmt.Fprintf(GetStdout(), "%s\n", bold(fmt.Sprintf(format, a...)))
}
}

// Askf will print out information, but in an "Ask" way (without newline)
func Askf(format string, a ...interface{}) {
bold := color.New(color.Bold).SprintFunc()
fmt.Fprintf(GetStdout(), "%s", bold(fmt.Sprintf(format, a...)))
if !IsJSON() {
fmt.Fprintf(GetStdout(), "%s", bold(fmt.Sprintf(format, a...)))
}
}

// Spinner creates a spinner, sets the prefix then returns it.
Expand Down Expand Up @@ -244,6 +267,18 @@ func SpinnerNoSpin(status string) *Status {
return s
}

// IsJSON returns true if we are in machine output mode..
// under NO circumstances should we output any logging.. as we are only outputting json
func IsJSON() bool {

flag := pflag.Lookup("o")
if flag != nil && flag.Changed {
return strings.Contains(pflag.Lookup("o").Value.String(), "json")
}

return false
}

// IsDebug returns true if we are debugging (-v is set to anything but 0)
func IsDebug() bool {

Expand Down
3 changes: 1 addition & 2 deletions pkg/odo/cli/application/delete.go
Expand Up @@ -64,7 +64,7 @@ func (o *DeleteOptions) Validate() (err error) {

// Run contains the logic for the odo command
func (o *DeleteOptions) Run() (err error) {
if o.OutputFlag == "json" {
if log.IsJSON() {
err = application.Delete(o.Client, o.appName)
if err != nil {
return err
Expand Down Expand Up @@ -105,7 +105,6 @@ func NewCmdDelete(name, fullName string) *cobra.Command {
}

command.Flags().BoolVarP(&o.force, "force", "f", false, "Delete application without prompting")
genericclioptions.AddOutputFlag(command)

project.AddProjectFlag(command)
completion.RegisterCommandHandler(command, completion.AppCompletionHandler)
Expand Down
4 changes: 2 additions & 2 deletions pkg/odo/cli/application/describe.go
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/openshift/odo/pkg/application"
"github.com/openshift/odo/pkg/component"
"github.com/openshift/odo/pkg/log"
"github.com/openshift/odo/pkg/odo/cli/project"
"github.com/openshift/odo/pkg/odo/genericclioptions"
"github.com/openshift/odo/pkg/odo/util"
Expand Down Expand Up @@ -62,7 +63,7 @@ func (o *DescribeOptions) Validate() (err error) {

// Run contains the logic for the odo command
func (o *DescribeOptions) Run() (err error) {
if o.outputFormat == "json" {
if log.IsJSON() {
appDef := application.GetMachineReadableFormat(o.Client, o.appName, o.Project)
out, err := json.Marshal(appDef)
if err != nil {
Expand Down Expand Up @@ -121,7 +122,6 @@ func NewCmdDescribe(name, fullName string) *cobra.Command {
},
}

command.Flags().StringVarP(&o.outputFormat, "output", "o", "", "output in json format")
completion.RegisterCommandHandler(command, completion.AppCompletionHandler)
project.AddProjectFlag(command)
return command
Expand Down
5 changes: 2 additions & 3 deletions pkg/odo/cli/application/list.go
Expand Up @@ -60,7 +60,7 @@ func (o *ListOptions) Run() (err error) {

if len(apps) > 0 {

if o.outputFormat == "json" {
if log.IsJSON() {
var appList []application.App
for _, app := range apps {
appDef := application.GetMachineReadableFormat(o.Client, app, o.Project)
Expand Down Expand Up @@ -90,7 +90,7 @@ func (o *ListOptions) Run() (err error) {
return tabWriter.Flush()
}
} else {
if o.outputFormat == "json" {
if log.IsJSON() {
out, err := json.Marshal(application.GetMachineReadableFormatForList([]application.App{}))
if err != nil {
return err
Expand Down Expand Up @@ -118,7 +118,6 @@ func NewCmdList(name, fullName string) *cobra.Command {
},
}

command.Flags().StringVarP(&o.outputFormat, "output", "o", "", "output in json format")
project.AddProjectFlag(command)
return command
}
6 changes: 6 additions & 0 deletions pkg/odo/cli/cli.go
Expand Up @@ -89,6 +89,12 @@ func NewCmdOdo(name, fullName string) *cobra.Command {

rootCmd.PersistentFlags().Bool(genericclioptions.SkipConnectionCheckFlagName, false, "Skip cluster check")

// Add the machine readable output flag to all commands
// We use "flag" in order to make this accessible throughtout ALL of odo, rather than the
// above traditional "persistentflags" usage that does not make it a pointer within the 'pflag'
// package
flag.CommandLine.String("o", "json", "Specify output format, supported format: json")

// Here we add the necessary "logging" flags.. However, we choose to hide some of these from the user
// as they are not necessarily needed and more for advanced debugging
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
Expand Down
9 changes: 4 additions & 5 deletions pkg/odo/cli/component/describe.go
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/openshift/odo/pkg/config"
"github.com/openshift/odo/pkg/log"
"github.com/openshift/odo/pkg/odo/genericclioptions"

"github.com/openshift/odo/pkg/component"
Expand All @@ -28,14 +29,13 @@ var describeExample = ktemplates.Examples(` # Describe nodejs component,
// DescribeOptions is a dummy container to attach complete, validate and run pattern
type DescribeOptions struct {
localConfigInfo *config.LocalConfigInfo
outputFlag string
componentContext string
*ComponentOptions
}

// NewDescribeOptions returns new instance of ListOptions
func NewDescribeOptions() *DescribeOptions {
return &DescribeOptions{nil, "", "", &ComponentOptions{}}
return &DescribeOptions{nil, "", &ComponentOptions{}}
}

// Complete completes describe args
Expand All @@ -59,7 +59,7 @@ func (do *DescribeOptions) Validate() (err error) {
return fmt.Errorf("component %s not pushed to the OpenShift cluster, use `odo push` to deploy the component", do.componentName)
}

return odoutil.CheckOutputFlag(do.outputFlag)
return nil
}

// Run has the logic to perform the required actions as part of command
Expand All @@ -68,7 +68,7 @@ func (do *DescribeOptions) Run() (err error) {
if err != nil {
return err
}
if do.outputFlag == "json" {
if log.IsJSON() {
componentDesc.Spec.Ports = do.localConfigInfo.GetPorts()
out, err := json.Marshal(componentDesc)
if err != nil {
Expand Down Expand Up @@ -102,7 +102,6 @@ func NewCmdDescribe(name, fullName string) *cobra.Command {
describeCmd.Annotations = map[string]string{"command": "component"}
describeCmd.SetUsageTemplate(odoutil.CmdUsageTemplate)
completion.RegisterCommandHandler(describeCmd, completion.ComponentNameCompletionHandler)
describeCmd.Flags().StringVarP(&do.outputFlag, "output", "o", "", "output in json format")
// Adding --context flag
genericclioptions.AddContextFlag(describeCmd, &do.componentContext)

Expand Down
9 changes: 4 additions & 5 deletions pkg/odo/cli/component/list.go
Expand Up @@ -32,7 +32,6 @@ var listExample = ktemplates.Examples(` # List all components in the applicatio

// ListOptions is a dummy container to attach complete, validate and run pattern
type ListOptions struct {
outputFlag string
pathFlag string
allFlag bool
componentContext string
Expand All @@ -56,17 +55,18 @@ func (lo *ListOptions) Validate() (err error) {
return odoutil.ThrowContextError()
}

return odoutil.CheckOutputFlag(lo.outputFlag)
return nil
}

// Run has the logic to perform the required actions as part of command
func (lo *ListOptions) Run() (err error) {

if len(lo.pathFlag) != 0 {
components, err := component.ListIfPathGiven(lo.Context.Client, filepath.SplitList(lo.pathFlag))
if err != nil {
return err
}
if lo.outputFlag == "json" {
if log.IsJSON() {
out, err := json.Marshal(components)
if err != nil {
return err
Expand Down Expand Up @@ -112,7 +112,7 @@ func (lo *ListOptions) Run() (err error) {
}
glog.V(4).Infof("the components are %+v", components)

if lo.outputFlag == "json" {
if log.IsJSON() {

out, err := json.Marshal(components)
if err != nil {
Expand Down Expand Up @@ -152,7 +152,6 @@ func NewCmdList(name, fullName string) *cobra.Command {
// Add a defined annotation in order to appear in the help menu
componentListCmd.Annotations = map[string]string{"command": "component"}
genericclioptions.AddContextFlag(componentListCmd, &o.componentContext)
componentListCmd.Flags().StringVarP(&o.outputFlag, "output", "o", "", "output in json format")
componentListCmd.Flags().StringVar(&o.pathFlag, "path", "", "path")
componentListCmd.Flags().BoolVar(&o.allFlag, "all", false, "lists all components")
//Adding `--project` flag
Expand Down
4 changes: 2 additions & 2 deletions pkg/odo/cli/project/list.go
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"text/tabwriter"

"github.com/openshift/odo/pkg/log"
"github.com/openshift/odo/pkg/odo/genericclioptions"
"github.com/openshift/odo/pkg/project"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -51,7 +52,7 @@ func (plo *ProjectListOptions) Run() (err error) {
if err != nil {
return err
}
if plo.OutputFlag == "json" {
if log.IsJSON() {
out, err := json.Marshal(projects)
if err != nil {
return err
Expand Down Expand Up @@ -89,6 +90,5 @@ func NewCmdProjectList(name, fullName string) *cobra.Command {
genericclioptions.GenericRun(o, cmd, args)
},
}
genericclioptions.AddOutputFlag(projectListCmd)
return projectListCmd
}
20 changes: 9 additions & 11 deletions pkg/odo/cli/storage/create.go
@@ -1,7 +1,9 @@
package storage

import (
"encoding/json"
"fmt"

"github.com/openshift/odo/pkg/config"
"github.com/openshift/odo/pkg/log"
"github.com/openshift/odo/pkg/odo/genericclioptions"
Expand Down Expand Up @@ -58,10 +60,6 @@ func (o *StorageCreateOptions) Complete(name string, cmd *cobra.Command, args []

// Validate validates the StorageCreateOptions based on completed values
func (o *StorageCreateOptions) Validate() (err error) {
// check the machine readable format
if !util.CheckOutputFlag(o.OutputFlag) {
return fmt.Errorf("given output format %s is not supported", o.OutputFlag)
}
// validate storage path
return o.localConfig.ValidateStorage(o.storageName, o.storagePath)
}
Expand All @@ -74,12 +72,13 @@ func (o *StorageCreateOptions) Run() (err error) {
}

storageResultMachineReadable := storage.GetMachineReadableFormat(storageResult.Name, storageResult.Size, storageResult.Path)
out, err := util.MachineOutput(o.OutputFlag, storageResultMachineReadable)
if err != nil {
return err
}
if out != "" {
fmt.Println(out)

if log.IsJSON() {
out, err := json.Marshal(storageResultMachineReadable)
if err != nil {
return err
}
fmt.Println(string(out))
} else {
log.Successf("Added storage %v to %v", o.storageName, o.localConfig.GetName())
}
Expand Down Expand Up @@ -109,7 +108,6 @@ func NewCmdStorageCreate(name, fullName string) *cobra.Command {
appCmd.AddApplicationFlag(storageCreateCmd)
componentCmd.AddComponentFlag(storageCreateCmd)

genericclioptions.AddOutputFlag(storageCreateCmd)
genericclioptions.AddContextFlag(storageCreateCmd, &o.componentContext)
completion.RegisterCommandFlagHandler(storageCreateCmd, "context", completion.FileCompletionHandler)

Expand Down

0 comments on commit fb0fd8b

Please sign in to comment.