diff --git a/.gitignore b/.gitignore index c9ef3ade3..a1cacf463 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ profile.out /dist *.test tests/__snapshot__ +/licenses diff --git a/Justfile b/Justfile index b7c5ff808..971668f9e 100644 --- a/Justfile +++ b/Justfile @@ -14,11 +14,11 @@ _default: # --- Build --- # Build the vcluster binary -build-snapshot: +build-snapshot: gen-license-report TELEMETRY_PRIVATE_KEY="" goreleaser build --snapshot --clean --single-target # Build the vcluster release binary in snapshot mode -release-snapshot: +release-snapshot: gen-license-report TELEMETRY_PRIVATE_KEY="" goreleaser release --snapshot --clean # --- Code quality --- @@ -136,3 +136,17 @@ generate-compatibility: validate-compat-matrix: go run hack/compat-matrix/main.go validate docs/pages/deploying-vclusters/compat-matrix.mdx + +gen-license-report: + rm -rf ./licenses + (cd ./cmd/vclusterctl/cmd/credits/licenses && find . -type d -exec rm -rf "{}" \;) || true + + go-licenses save --save_path=./licenses --ignore github.com/loft-sh --ignore modernc.org/mathutil --ignore github.com/mattn/go-localereader $(go work edit -json | jq -c -r '[.Use[].DiskPath] | map_values(. + "/...")[]') || exit 0 + + mkdir -p ./licenses/github.com/mattn/go-localereader + cd ./licenses/github.com/mattn/go-localereader && curl -O https://raw.githubusercontent.com/mattn/go-localereader/master/LICENSE + + mkdir -p ./licenses/modernc.org/mathutil + cd ./licenses/modernc.org/mathutil && curl -O https://gitlab.com/cznic/mathutil/-/raw/master/LICENSE?ref_type=heads + + cp -r ./licenses ./cmd/vclusterctl/cmd/credits diff --git a/cmd/vclusterctl/cmd/credits/credits.go b/cmd/vclusterctl/cmd/credits/credits.go new file mode 100644 index 000000000..d620f838c --- /dev/null +++ b/cmd/vclusterctl/cmd/credits/credits.go @@ -0,0 +1,72 @@ +package credits + +import ( + "embed" + "errors" + "fmt" + "io/fs" + "os" + "path" + "strings" + + "github.com/loft-sh/log" + "github.com/spf13/cobra" +) + +//go:embed licenses +var licenses embed.FS + +func NewCreditsCmd() *cobra.Command { + creditsCmd := &cobra.Command{ + Use: "credits [OUTDIR]", + Args: cobra.ExactArgs(1), + Short: "Saves the OSS credits", + Long: "Saves licenses, copyright notices and source code, as required by a Go package's dependencies, to a directory.", + RunE: func(_ *cobra.Command, args []string) error { + outDir := args[0] + if outDir == "" { + return errors.New("please specify the out directory") + } + + logger := log.GetInstance() + + if err := fs.WalkDir(licenses, "licenses", func(filePath string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + if !d.IsDir() { + contents, err := licenses.ReadFile(filePath) + if err != nil { + return fmt.Errorf("failed to read file %s: %w", filePath, err) + } + + outPath := path.Join(outDir, strings.TrimPrefix(filePath, "licenses/")) + + dir := path.Dir(outPath) + + if _, err := os.Stat(dir); os.IsNotExist(err) { + if err := os.MkdirAll(dir, 0700); err != nil { + return fmt.Errorf("failed to create directory %s: %w", dir, err) + } + } + + if err := os.WriteFile(outPath, contents, 0644); err != nil { + return fmt.Errorf("failed to write file %s: %w", outPath, err) + } + } + + return nil + }); err != nil { + return fmt.Errorf("failed to walk through licenses: %w", err) + } + + outPath := path.Clean(outDir) + logger.Info("Wrote credits to " + outPath) + + return nil + }, + } + + return creditsCmd +} diff --git a/cmd/vclusterctl/cmd/credits/licenses/.gitignore b/cmd/vclusterctl/cmd/credits/licenses/.gitignore new file mode 100644 index 000000000..7feff33a8 --- /dev/null +++ b/cmd/vclusterctl/cmd/credits/licenses/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!readme.txt diff --git a/cmd/vclusterctl/cmd/credits/licenses/readme.txt b/cmd/vclusterctl/cmd/credits/licenses/readme.txt new file mode 100644 index 000000000..a6ef34a02 --- /dev/null +++ b/cmd/vclusterctl/cmd/credits/licenses/readme.txt @@ -0,0 +1 @@ +These are the licenses, copyright notices and source code used, as required by a Go package's dependencies licenses. diff --git a/cmd/vclusterctl/cmd/root.go b/cmd/vclusterctl/cmd/root.go index b04dfecb8..babba9257 100644 --- a/cmd/vclusterctl/cmd/root.go +++ b/cmd/vclusterctl/cmd/root.go @@ -7,6 +7,7 @@ import ( "github.com/loft-sh/log" "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/convert" + "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/credits" "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/get" cmdpro "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/platform" cmdtelemetry "github.com/loft-sh/vcluster/cmd/vclusterctl/cmd/telemetry" @@ -132,6 +133,7 @@ func BuildRoot(log log.Logger) (*cobra.Command, error) { return nil, fmt.Errorf("failed to create activate command: %w", err) } rootCmd.AddCommand(importCmd) + rootCmd.AddCommand(credits.NewCreditsCmd()) // add completion command err = rootCmd.RegisterFlagCompletionFunc("namespace", newNamespaceCompletionFunc(rootCmd.Context())) diff --git a/go.mod b/go.mod index 3454a1671..0c5dad549 100644 --- a/go.mod +++ b/go.mod @@ -123,7 +123,7 @@ require ( github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/evanphx/json-patch v5.8.1+incompatible // indirect + github.com/evanphx/json-patch v5.8.1+incompatible github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect