Adding custom license functionality

* Refactoring code that unnecessarily declares a map before making it.
* Cleaning up gpl3 formatting to match other licenses.
* Adding functionality that allows specifying custom license header
  and text in cobra config.
* Using license header and text as templates so that they can use
  template variables (for custom and gpl3 licenses).
* Adding ability to specify no license.
* Adding custom license example to README.
This commit is contained in:
Ian Walter 2016-03-31 14:31:03 -04:00 committed by Steve Francia
parent 3dc021e8c7
commit d811f40c6a
5 changed files with 80 additions and 48 deletions

View file

@ -226,13 +226,27 @@ The cobra generator will be easier to use if you provide a simple configuration
file which will help you eliminate providing a bunch of repeated information in file which will help you eliminate providing a bunch of repeated information in
flags over and over. flags over and over.
an example ~/.cobra.yaml file: An example ~/.cobra.yaml file:
```yaml ```yaml
author: Steve Francia <spf@spf13.com> author: Steve Francia <spf@spf13.com>
license: MIT license: MIT
``` ```
You can specify no license by setting `license` to `none` or you can specify
a custom license:
```yaml
license:
header: This file is part of {{ .appName }}.
text: |
{{ .Copyright }}
This is my license. There are many like it, but this one is mine.
My license is my best friend. It is my life. I must master it as I must
master my life.
```
## Manually implementing Cobra ## Manually implementing Cobra
To manually implement cobra you need to create a bare main.go file and a RootCmd file. To manually implement cobra you need to create a bare main.go file and a RootCmd file.

View file

@ -319,6 +319,15 @@ func whichLicense() string {
// default to viper's setting // default to viper's setting
if viper.IsSet("license.header") || viper.IsSet("license.text") {
if custom, ok := Licenses["custom"]; ok {
custom.Header = viper.GetString("license.header")
custom.Text = viper.GetString("license.text")
Licenses["custom"] = custom
return "custom"
}
}
return matchLicense(viper.GetString("license")) return matchLicense(viper.GetString("license"))
} }

View file

@ -14,6 +14,7 @@
package cmd package cmd
import ( import (
"bytes"
"fmt" "fmt"
"os" "os"
"strings" "strings"
@ -87,29 +88,33 @@ func initializePath(path string) {
} }
func createLicenseFile() { func createLicenseFile() {
lic := getLicense() data := make(map[string]interface{})
template := lic.Text
var data map[string]interface{}
data = make(map[string]interface{})
// Try to remove the email address, if any // Try to remove the email address, if any
data["copyright"] = strings.Split(copyrightLine(), " <")[0] data["copyright"] = strings.Split(copyrightLine(), " <")[0]
err := writeTemplateToFile(ProjectPath(), "LICENSE", template, data) data["appName"] = projectName()
_ = err
// if err != nil { // Get license and generate the template from text and data.
// er(err) lic := getLicense()
// } r, _ := templateToReader(lic.Text, data)
buf := new(bytes.Buffer)
buf.ReadFrom(r)
if template := buf.String(); template != "" {
err := writeTemplateToFile(ProjectPath(), "LICENSE", template, data)
_ = err
// if err != nil {
// er(err)
// }
}
} }
func createMainFile() { func createMainFile() {
lic := getLicense() lic := getLicense()
template := `{{ comment .copyright }} template := `{{ comment .copyright }}
{{ comment .license }} {{if .license}}{{ comment .license }}
{{end}}
package main package main
import "{{ .importpath }}" import "{{ .importpath }}"
@ -118,11 +123,17 @@ func main() {
cmd.Execute() cmd.Execute()
} }
` `
var data map[string]interface{} data := make(map[string]interface{})
data = make(map[string]interface{})
data["copyright"] = copyrightLine() data["copyright"] = copyrightLine()
data["license"] = lic.Header data["appName"] = projectName()
// Generate license template from header and data.
r, _ := templateToReader(lic.Header, data)
buf := new(bytes.Buffer)
buf.ReadFrom(r)
data["license"] = buf.String()
data["importpath"] = guessImportPath() + "/" + guessCmdDir() data["importpath"] = guessImportPath() + "/" + guessCmdDir()
err := writeTemplateToFile(ProjectPath(), "main.go", template, data) err := writeTemplateToFile(ProjectPath(), "main.go", template, data)
@ -136,8 +147,8 @@ func createRootCmdFile() {
lic := getLicense() lic := getLicense()
template := `{{ comment .copyright }} template := `{{ comment .copyright }}
{{ comment .license }} {{if .license}}{{ comment .license }}
{{end}}
package cmd package cmd
import ( import (
@ -206,12 +217,17 @@ func initConfig() {
} }
{{ end }}` {{ end }}`
var data map[string]interface{} data := make(map[string]interface{})
data = make(map[string]interface{})
data["copyright"] = copyrightLine() data["copyright"] = copyrightLine()
data["license"] = lic.Header
data["appName"] = projectName() data["appName"] = projectName()
// Generate license template from header and data.
r, _ := templateToReader(lic.Header, data)
buf := new(bytes.Buffer)
buf.ReadFrom(r)
data["license"] = buf.String()
data["viper"] = viper.GetBool("useViper") data["viper"] = viper.GetBool("useViper")
err := writeTemplateToFile(ProjectPath()+string(os.PathSeparator)+guessCmdDir(), "root.go", template, data) err := writeTemplateToFile(ProjectPath()+string(os.PathSeparator)+guessCmdDir(), "root.go", template, data)

View file

@ -46,6 +46,12 @@ func matchLicense(in string) string {
func init() { func init() {
Licenses = make(map[string]License) Licenses = make(map[string]License)
// Allows a user to not use a license.
Licenses["none"] = License{"None", []string{"none", "false"}, "", ""}
// Allows a user to use config for a custom license.
Licenses["custom"] = License{"Custom", []string{}, "", ""}
Licenses["apache"] = License{ Licenses["apache"] = License{
Name: "Apache 2.0", Name: "Apache 2.0",
PossibleMatches: []string{"apache", "apache20", "apache 2.0", "apache2.0", "apache-2.0"}, PossibleMatches: []string{"apache", "apache20", "apache 2.0", "apache2.0", "apache-2.0"},
@ -727,22 +733,21 @@ POSSIBILITY OF SUCH DAMAGES.
Licenses["gpl3"] = License{ Licenses["gpl3"] = License{
Name: "GNU General Public License 3.0", Name: "GNU General Public License 3.0",
PossibleMatches: []string{"gpl3", "gpl", "gnu gpl3", "gnu gpl"}, PossibleMatches: []string{"gpl3", "gpl", "gnu gpl3", "gnu gpl"},
Header: `{{ .copyright }} Header: `
This file is part of {{ .appName }}.
This file is part of {{ .appName }}. {{ .appName }} is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
{{ .appName }} is free software: you can redistribute it and/or modify {{ .appName }} is distributed in the hope that it will be useful,
it under the terms of the GNU Lesser General Public License as published by but WITHOUT ANY WARRANTY; without even the implied warranty of
the Free Software Foundation, either version 3 of the License, or MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
(at your option) any later version. GNU Lesser General Public License for more details.
{{ .appName }} is distributed in the hope that it will be useful, You should have received a copy of the GNU Lesser General Public License
but WITHOUT ANY WARRANTY; without even the implied warranty of along with {{ .appName }}. If not, see <http://www.gnu.org/licenses/>.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with {{ .appName }}. If not, see <http://www.gnu.org/licenses/>.
`, `,
Text: ` GNU GENERAL PUBLIC LICENSE Text: ` GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007

View file

@ -46,25 +46,13 @@ func init() {
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory, e.g. github.com/spf13/") RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory, e.g. github.com/spf13/")
RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution")
RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `license` in config)")
RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration")
viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author"))
viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase")) viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase"))
viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper")) viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper"))
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>") viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
viper.SetDefault("license", "apache") viper.SetDefault("license", "apache")
viper.SetDefault("licenseText", `
// 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.
`)
} }
// Read in config file and ENV variables if set. // Read in config file and ENV variables if set.