github.com/joey-fossa/fossa-cli@v0.7.34-0.20190708193710-569f1e8679f0/config/keys.go (about)

     1  package config
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"path/filepath"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/apex/log"
    11  	"github.com/mattn/go-isatty"
    12  
    13  	"github.com/fossas/fossa-cli/cmd/fossa/flags"
    14  	"github.com/fossas/fossa-cli/module"
    15  	"github.com/fossas/fossa-cli/pkg"
    16  )
    17  
    18  /**** Mock configuration values ****/
    19  var (
    20  	MockBranch string
    21  )
    22  
    23  /**** Global configuration keys ****/
    24  
    25  var (
    26  	filename string
    27  )
    28  
    29  func Version() int {
    30  	return file.GetVersion()
    31  }
    32  
    33  // Interactive is true if the user desires interactive output.
    34  func Interactive() bool {
    35  	return isatty.IsTerminal(os.Stderr.Fd()) && !BoolFlag(flags.NoAnsi)
    36  }
    37  
    38  // Debug is true if the user has requested debug-level logging.
    39  func Debug() bool {
    40  	return BoolFlag(flags.Debug)
    41  }
    42  
    43  // Filepath is the configuration file path.
    44  func Filepath() string {
    45  	return filename
    46  }
    47  
    48  /**** API configuration keys ****/
    49  
    50  // APIKey is user's FOSSA API key.
    51  func APIKey() string {
    52  	return TryStrings(file.APIKey(), os.Getenv("FOSSA_API_KEY"))
    53  }
    54  
    55  // Endpoint is the desired FOSSA backend endpoint.
    56  func Endpoint() string {
    57  	return TryStrings(StringFlag(flags.Endpoint), file.Server(), "https://app.fossa.com")
    58  }
    59  
    60  /**** Project configuration keys ****/
    61  
    62  func Title() string {
    63  	dir, _ := os.Getwd()
    64  	return TryStrings(StringFlag(flags.Title), file.Title(), Project(), filepath.Base(dir))
    65  }
    66  
    67  func Fetcher() string {
    68  	return TryStrings(StringFlag(flags.Fetcher), file.Fetcher(), "custom")
    69  }
    70  
    71  func Project() string {
    72  	inferred := ""
    73  	if repo != nil {
    74  		inferred = repo.Project()
    75  	}
    76  	return TryStrings(StringFlag(flags.Project), file.Project(), inferred)
    77  }
    78  
    79  func Revision() string {
    80  	inferred := ""
    81  	if repo != nil {
    82  		inferred = repo.Head().RevisionID
    83  	}
    84  	return TryStrings(StringFlag(flags.Revision), file.Revision(), inferred)
    85  }
    86  
    87  func Branch() string {
    88  	inferred := ""
    89  	if repo != nil {
    90  		inferred = repo.Head().Branch
    91  	}
    92  	return TryStrings(MockBranch, StringFlag(flags.Branch), file.Branch(), inferred, "master")
    93  }
    94  
    95  func ProjectURL() string {
    96  	return TryStrings(StringFlag(flags.ProjectURL), file.ProjectURL(), "")
    97  }
    98  
    99  func JIRAProjectKey() string {
   100  	return TryStrings(StringFlag(flags.JIRAProjectKey), file.JIRAProjectKey(), "")
   101  }
   102  
   103  func Link() string {
   104  	return TryStrings(StringFlag(flags.Link), file.Link(), "")
   105  }
   106  
   107  func Team() string {
   108  	return TryStrings(StringFlag(flags.Team), file.Team(), "")
   109  }
   110  
   111  /**** Analysis configuration keys ****/
   112  
   113  func Options() (map[string]interface{}, error) {
   114  	opts := ctx.StringSlice(flags.Option)
   115  	opts = append(opts, ctx.GlobalStringSlice(flags.Option)...)
   116  
   117  	options := make(map[string]interface{})
   118  	for _, option := range opts {
   119  		sections := strings.Split(option, ":")
   120  		key := sections[0]
   121  		value := strings.Join(sections[1:], ":")
   122  		log.WithFields(log.Fields{
   123  			"sections": sections,
   124  			"key":      key,
   125  			"value":    value,
   126  		}).Debug("parsing options")
   127  		// Attempt to parse as boolean.
   128  		if value == "true" {
   129  			options[key] = true
   130  			continue
   131  		} else if value == "false" {
   132  			options[key] = false
   133  			continue
   134  		} else if i, err := strconv.Atoi(value); err == nil {
   135  			// Attempt to parse as number.
   136  			options[key] = i
   137  		} else {
   138  			// Treat as a string.
   139  			options[key] = value
   140  		}
   141  	}
   142  
   143  	return options, nil
   144  }
   145  
   146  func Modules() ([]module.Module, error) {
   147  	args := ctx.Args()
   148  	log.WithFields(log.Fields{"args": args}).Debug("parsing modules")
   149  
   150  	var modules []module.Module
   151  
   152  	// If arguments are present, prefer arguments over the configuration file.
   153  	if args.Present() {
   154  		// Validate arguments.
   155  		if ctx.NArg() != 1 {
   156  			return nil, errors.New("must specify exactly 1 module")
   157  		}
   158  
   159  		// Parse module.
   160  		arg := args.First()
   161  		sections := strings.Split(arg, ":")
   162  		typename := sections[0]
   163  		name := strings.Join(sections[1:], ":")
   164  		mtype, err := pkg.ParseType(typename)
   165  		if err != nil {
   166  			return nil, err
   167  		}
   168  
   169  		// Note that these parsed modules do not have any options set yet.
   170  		m := module.Module{
   171  			Name:        name,
   172  			Type:        mtype,
   173  			BuildTarget: name,
   174  		}
   175  
   176  		log.WithField("module", m).Debug("parsed module")
   177  		modules = append(modules, m)
   178  	} else {
   179  		// Otherwise, get the modules from the configuration file.
   180  		modules = file.Modules()
   181  		if len(modules) == 0 {
   182  			return modules, errors.New("No modules provided")
   183  		}
   184  	}
   185  
   186  	// Parse options set via the command line.
   187  	options, err := Options()
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	log.WithFields(log.Fields{"options": options}).Debug("parsing options")
   192  
   193  	// Set options passed via the command line on all modules. For modules where
   194  	// this conflicts with a configuration file option, prefer the command line
   195  	// option.
   196  	for i, m := range modules {
   197  		if m.Options == nil {
   198  			modules[i].Options = make(map[string]interface{})
   199  		}
   200  
   201  		// We iterate over and copy the command-line options instead of setting the
   202  		// module options equal to avoid _unsetting_ module options that were set
   203  		// within the configuration file.
   204  		for key, val := range options {
   205  			modules[i].Options[key] = val
   206  		}
   207  	}
   208  
   209  	return modules, nil
   210  }