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 }