cmd/wfnconvert/options.go (188 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. // // 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 main import ( "errors" "flag" "fmt" "strconv" "strings" "github.com/facebookincubator/nvdtools/wfn" ) type intFields []int // Set is part of flag.Value interface func (f *intFields) Set(s string) error { if f == nil { return errors.New("Set called on nil reciever") } for _, t := range strings.Split(s, ",") { i, err := strconv.Atoi(t) if err != nil { return fmt.Errorf("failed to parse fields from %q: %v", s, err) } if i <= 0 { return fmt.Errorf("illegal CSV index %d: %q", i, s) } *f = append(*f, i-1) } return nil } // String is part of flag.Value interface func (f *intFields) String() string { if f == nil { return "" } var sb strings.Builder for i, n := range *f { if i != 0 { sb.WriteByte(',') } fmt.Fprintf(&sb, "%d", n+1) } return sb.String() } type strFields map[string]bool // Set is part of flag.Value interface func (f *strFields) Set(s string) error { if *f == nil { *f = make(strFields) } for _, s := range strings.Split(s, ",") { (*f)[s] = true } return nil } // String is part of flag.Value interface func (f *strFields) String() string { if f == nil { return "" } var sb strings.Builder i := 0 for k := range *f { if i != 0 { sb.WriteByte(',') } sb.WriteString(k) i++ } return sb.String() } type options struct { outBinding string attributes strFields invertAttributes bool any2na, na2any bool csvFields intFields csvComma string } func (o *options) addFlags() { flag.StringVar(&o.outBinding, "b", "fstr", "ouput bindings, one of\n"+ "'uri'\te.g. cpe:/a:foo:bar:1.1)\n"+ "'fstr'\te.g. cpe:2.3:a:foo:bar:1.1:*:*:*:*:*:*:*)\n"+ "'str'\te.g. "+`wfn:[part="a",vendor="foo",product="bar", version="1\.1"])`+"\n") flag.Var(&o.attributes, "attr", "comma-separated list of WFN attributes to manipulate; CPE 2.3 defines following attributes:\n"+ "part, vendor, product, version, update, edition, language, sw_edition, target_sw, target_hw, other\n"+ "additionally a special value 'all' is accepted") flag.BoolVar(&o.invertAttributes, "v", false, "invert attributes: process attributes not matched by -v flag") flag.BoolVar(&o.any2na, "any2na", false, "assign logical value N/A to all attributes with logical value ANY") flag.BoolVar(&o.na2any, "na2any", false, "assign logical value ANY to all attributes with logical value N/A") flag.Var(&o.csvFields, "csv", "comma-separated list of fields to read CPEs from, starting at 1;\n"+ "assumes input as CSV, fields not specified in the list are passed unchanged") flag.StringVar(&o.csvComma, "d", ",", "if csv flag is set, sets the CSV delimiter, otherwise this flag is ignored") } func (o *options) validate() error { if err := validateAttrNames(o.attributes); err != nil { return err } if o.any2na && o.na2any { return fmt.Errorf("-any2na and -na2any flags are mutually exclusive") } switch o.outBinding { case "uri", "fstr", "str": break default: return fmt.Errorf("-b: invalid value %q", o.outBinding) } return nil } func (o *options) shouldProcess(name string) bool { do := o.attributes["all"] || o.attributes[name] if o.invertAttributes { return !do } return do } func (o *options) processAttributes(attr *wfn.Attributes, f func(*string) error) error { if o.shouldProcess("part") { if err := f(&attr.Part); err != nil { return err } } if o.shouldProcess("vendor") { if err := f(&attr.Vendor); err != nil { return err } } if o.shouldProcess("product") { if err := f(&attr.Product); err != nil { return err } } if o.shouldProcess("version") { if err := f(&attr.Version); err != nil { return err } } if o.shouldProcess("update") { if err := f(&attr.Update); err != nil { return err } } if o.shouldProcess("edition") { if err := f(&attr.Edition); err != nil { return err } } if o.shouldProcess("sw_edition") { if err := f(&attr.SWEdition); err != nil { return err } } if o.shouldProcess("target_sw") { if err := f(&attr.TargetSW); err != nil { return err } } if o.shouldProcess("target_hw") { if err := f(&attr.TargetHW); err != nil { return err } } if o.shouldProcess("other") { if err := f(&attr.Other); err != nil { return err } } if o.shouldProcess("language") { if err := f(&attr.Language); err != nil { return err } } return nil } func validateAttrNames(names strFields) error { valid := map[string]bool{ "part": true, "vendor": true, "product": true, "version": true, "update": true, "edition": true, "language": true, "sw_edition": true, "target_sw": true, "target_hw": true, "other": true, } for n := range names { if n != "all" && !valid[n] { return fmt.Errorf("bad attribute name: %q", n) } } return nil }