github.com/glimps-jbo/go-licenses@v0.0.0-20230908151000-e06d3c113277/check.go (about)

     1  // Copyright 2019 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"fmt"
    21  	"os"
    22  	"strings"
    23  
    24  	"github.com/glimps-jbo/go-licenses/licenses"
    25  	"github.com/spf13/cobra"
    26  	"golang.org/x/text/cases"
    27  	"golang.org/x/text/language"
    28  )
    29  
    30  var (
    31  	checkHelp = "Checks whether licenses for a package are not allowed."
    32  	checkCmd  = &cobra.Command{
    33  		Use:   "check <package> [package...]",
    34  		Short: checkHelp,
    35  		Long:  checkHelp + packageHelp,
    36  		Args:  cobra.MinimumNArgs(1),
    37  		RunE:  checkMain,
    38  	}
    39  
    40  	allowedLicenses []string
    41  	disallowedTypes []string
    42  )
    43  
    44  func init() {
    45  	checkCmd.Flags().StringSliceVar(&allowedLicenses, "allowed_licenses", []string{}, "list of allowed license names, can't be used in combination with disallowed_types")
    46  	checkCmd.Flags().StringSliceVar(&disallowedTypes, "disallowed_types", []string{}, "list of disallowed license types, can't be used in combination with allowed_licenses (default: forbidden, unknown)")
    47  
    48  	rootCmd.AddCommand(checkCmd)
    49  }
    50  
    51  func checkMain(_ *cobra.Command, args []string) error {
    52  	var disallowedLicenseTypes []licenses.Type
    53  
    54  	allowedLicenseNames := getAllowedLicenseNames()
    55  	disallowedLicenseTypes = getDisallowedLicenseTypes()
    56  
    57  	hasLicenseNames := len(allowedLicenseNames) > 0
    58  	hasLicenseType := len(disallowedLicenseTypes) > 0
    59  
    60  	if hasLicenseNames && hasLicenseType {
    61  		return errors.New("allowed_licenses && disallowed_types can't be used at the same time")
    62  	}
    63  
    64  	if !hasLicenseNames && !hasLicenseType {
    65  		// fallback to original behaviour to avoid breaking changes
    66  		disallowedLicenseTypes = []licenses.Type{licenses.Forbidden, licenses.Unknown}
    67  		hasLicenseType = true
    68  	}
    69  
    70  	classifier, err := licenses.NewClassifier()
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	libs, err := licenses.Libraries(context.Background(), classifier, includeTests, ignore, args...)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	// indicate that a forbidden license was found
    81  	found := false
    82  
    83  	for _, lib := range libs {
    84  		if lib.LicenseFile == "" {
    85  			fmt.Fprintf(os.Stderr, "Did not find license for library '%v'.\n", lib)
    86  			found = true
    87  			continue
    88  		}
    89  
    90  		for _, license := range lib.Licenses {
    91  			if hasLicenseNames && !isAllowedLicenseName(license.Name, allowedLicenseNames) {
    92  				fmt.Fprintf(os.Stderr, "Not allowed license '%s' found for library '%v'.\n", license.Name, lib)
    93  				found = true
    94  			} else if hasLicenseType && isDisallowedLicenseType(license.Type, disallowedLicenseTypes) {
    95  				fmt.Fprintf(
    96  					os.Stderr,
    97  					"License '%s' of not allowed license type '%s' found for library '%v'.\n",
    98  					license.Name,
    99  					cases.Title(language.English).String(license.Type.String()),
   100  					lib)
   101  				found = true
   102  			}
   103  		}
   104  	}
   105  
   106  	if found {
   107  		os.Exit(1)
   108  	}
   109  
   110  	return nil
   111  }
   112  
   113  func getDisallowedLicenseTypes() []licenses.Type {
   114  	if len(disallowedTypes) == 0 {
   115  		return []licenses.Type{}
   116  	}
   117  
   118  	excludedLicenseTypes := make([]licenses.Type, 0)
   119  
   120  	for _, v := range disallowedTypes {
   121  		switch strings.TrimSpace(strings.ToLower(v)) {
   122  		case "forbidden":
   123  			excludedLicenseTypes = append(excludedLicenseTypes, licenses.Forbidden)
   124  		case "notice":
   125  			excludedLicenseTypes = append(excludedLicenseTypes, licenses.Notice)
   126  		case "permissive":
   127  			excludedLicenseTypes = append(excludedLicenseTypes, licenses.Permissive)
   128  		case "reciprocal":
   129  			excludedLicenseTypes = append(excludedLicenseTypes, licenses.Reciprocal)
   130  		case "restricted":
   131  			excludedLicenseTypes = append(excludedLicenseTypes, licenses.Restricted)
   132  		case "unencumbered":
   133  			excludedLicenseTypes = append(excludedLicenseTypes, licenses.Unencumbered)
   134  		case "unknown":
   135  			excludedLicenseTypes = append(excludedLicenseTypes, licenses.Unknown)
   136  		default:
   137  			fmt.Fprintf(
   138  				os.Stderr,
   139  				"Unknown license type '%s' provided.\n"+
   140  					"Allowed types: forbidden, notice, permissive, reciprocal, restricted, unencumbered, unknown\n",
   141  				v)
   142  		}
   143  	}
   144  
   145  	return excludedLicenseTypes
   146  }
   147  
   148  func isDisallowedLicenseType(licenseType licenses.Type, excludedLicenseTypes []licenses.Type) bool {
   149  	for _, excluded := range excludedLicenseTypes {
   150  		if excluded == licenseType {
   151  			return true
   152  		}
   153  	}
   154  
   155  	return false
   156  }
   157  
   158  func getAllowedLicenseNames() []string {
   159  	if len(allowedLicenses) == 0 {
   160  		return []string{}
   161  	}
   162  
   163  	var allowed []string
   164  
   165  	for _, licenseName := range allowedLicenses {
   166  		allowed = append(allowed, strings.TrimSpace(licenseName))
   167  	}
   168  
   169  	return allowed
   170  }
   171  
   172  func isAllowedLicenseName(licenseName string, allowedLicenseNames []string) bool {
   173  	for _, allowed := range allowedLicenseNames {
   174  		if allowed == licenseName {
   175  			return true
   176  		}
   177  	}
   178  
   179  	return false
   180  }