Skip to content

Commit

Permalink
[feat] Allow "LicenseDir" field for non-enterprise usage (#214)
Browse files Browse the repository at this point in the history
Co-authored-by: Radek Simko <[email protected]>
  • Loading branch information
james0209 and radeksimko authored May 29, 2024
1 parent b439987 commit e082106
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 53 deletions.
65 changes: 46 additions & 19 deletions build/git_revision.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,21 @@ var (
discardLogger = log.New(io.Discard, "", 0)
)

const (
// dstLicenseFileName is the name of the license file to be copied to the destination directory
dstLicenseFileName = "LICENSE.txt"
)

// GitRevision installs a particular git revision by cloning
// the repository and building it per product BuildInstructions
type GitRevision struct {
Product product.Product
InstallDir string
Product product.Product
InstallDir string

// LicenseDir represents directory path where to install license files.
// If empty, license files will placed in the same directory as the binary.
LicenseDir string

Ref string
CloneTimeout time.Duration
BuildTimeout time.Duration
Expand Down Expand Up @@ -169,45 +179,62 @@ func (gr *GitRevision) Build(ctx context.Context) (string, error) {
installDir = tmpDir
gr.pathsToRemove = append(gr.pathsToRemove, installDir)
}
gr.log().Printf("install dir is %q", installDir)

// copy license file on best effort basis
dstLicensePath := filepath.Join(installDir, "LICENSE.txt")
srcLicensePath := filepath.Join(repoDir, "LICENSE.txt")
altSrcLicensePath := filepath.Join(repoDir, "LICENSE")
if _, err := os.Stat(srcLicensePath); err == nil {
err = gr.copyLicenseFile(srcLicensePath, dstLicensePath)
if err != nil {
return "", err
}
} else if _, err := os.Stat(altSrcLicensePath); err == nil {
err = gr.copyLicenseFile(altSrcLicensePath, dstLicensePath)
if err != nil {
return "", err
}
// default to installDir if LicenseDir is not set
licenseDir := gr.LicenseDir
if licenseDir == "" {
licenseDir = installDir
}
gr.log().Printf("attempting to copy license file to %q", licenseDir)
if err := gr.copyLicenseIfExists(repoDir, licenseDir); err != nil {
return "", err
}

gr.log().Printf("building %s (timeout: %s)", gr.Product.Name, buildTimeout)
defer gr.log().Printf("building of %s finished", gr.Product.Name)
return bi.Build.Build(buildCtx, repoDir, installDir, gr.Product.BinaryName())
}

func (gr *GitRevision) copyLicenseIfExists(repoDir string, dstDir string) error {
licenseFiles := []string{"LICENSE.txt", "LICENSE"}

for _, file := range licenseFiles {
srcPath := filepath.Join(repoDir, file)
if _, err := os.Stat(srcPath); err == nil {
gr.log().Printf("found license file at %q", srcPath)
dstPath := filepath.Join(dstDir, dstLicenseFileName)
if err := gr.copyLicenseFile(srcPath, dstPath); err != nil {
return fmt.Errorf("failed to copy license file from %q to %q: %w", srcPath, dstPath, err)
}
}
}

return nil
}

func (gr *GitRevision) copyLicenseFile(srcPath, dstPath string) error {
gr.log().Printf("copying license file from %q to %q", srcPath, dstPath)
src, err := os.Open(srcPath)
if err != nil {
return err
return fmt.Errorf("failed to open license file at %q: %w", srcPath, err)
}
defer src.Close()

dst, err := os.Create(dstPath)
if err != nil {
return err
return fmt.Errorf("failed to create license file at %q: %w", dstPath, err)
}
defer dst.Close()
n, err := io.Copy(dst, src)
if err != nil {
return err
return fmt.Errorf("failed to copy license file from %q to %q: %w", srcPath, dstPath, err)
}
gr.log().Printf("license file copied from %q to %q (%d bytes)",
srcPath, dstPath, n)
// Add the license file to the list of paths to remove after being successfully copied
gr.pathsToRemove = append(gr.pathsToRemove, dstPath)
return nil
}

Expand All @@ -216,7 +243,7 @@ func (gr *GitRevision) Remove(ctx context.Context) error {
for _, path := range gr.pathsToRemove {
err := os.RemoveAll(path)
if err != nil {
return err
return fmt.Errorf("failed to remove %q: %w", path, err)
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions build/git_revision_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ var (
func TestGitRevision_terraform(t *testing.T) {
testutil.EndToEndTest(t)

gr := &GitRevision{Product: product.Terraform}
tempDir := t.TempDir()

gr := &GitRevision{
Product: product.Terraform,
LicenseDir: tempDir,
}
gr.SetLogger(testutil.TestLogger())

ctx := context.Background()
Expand All @@ -35,7 +40,7 @@ func TestGitRevision_terraform(t *testing.T) {
t.Fatal(err)
}

licensePath := filepath.Join(filepath.Dir(execPath), "LICENSE.txt")
licensePath := filepath.Join(tempDir, dstLicenseFileName)
t.Cleanup(func() {
gr.Remove(ctx)
// check if license was deleted
Expand Down
8 changes: 7 additions & 1 deletion checkpoint/latest_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ type LatestVersion struct {
SkipChecksumVerification bool
InstallDir string

// LicenseDir represents directory path where to install license files.
// If empty, license files will placed in the same directory as the binary.
LicenseDir string

// ArmoredPublicKey is a public PGP key in ASCII/armor format to use
// instead of built-in pubkey to verify signature of downloaded checksums
ArmoredPublicKey string
Expand Down Expand Up @@ -126,7 +130,9 @@ func (lv *LatestVersion) Install(ctx context.Context) (string, error) {
if lv.ArmoredPublicKey != "" {
d.ArmoredPublicKey = lv.ArmoredPublicKey
}
up, err := d.DownloadAndUnpack(ctx, pv, dstDir, "")

licenseDir := lv.LicenseDir
up, err := d.DownloadAndUnpack(ctx, pv, dstDir, licenseDir)
if up != nil {
lv.pathsToRemove = append(lv.pathsToRemove, up.PathsToRemove...)
}
Expand Down
9 changes: 4 additions & 5 deletions installer_examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,10 @@ func ExampleInstaller_enterpriseVersion() {

execPath, err := i.Install(ctx, []src.Installable{
&releases.ExactVersion{
Product: product.Vault,
Version: v1_9,
Enterprise: &releases.EnterpriseOptions{ // specify that we want the enterprise version
LicenseDir: licenseDir, // where license files should be placed (required for enterprise versions)
},
Product: product.Vault,
Version: v1_9,
LicenseDir: licenseDir, // required for enterprise versions
Enterprise: &releases.EnterpriseOptions{}, // specify that we want the enterprise version
},
})
if err != nil {
Expand Down
7 changes: 3 additions & 4 deletions installer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"testing"

"github.com/hashicorp/go-version"
"github.com/hashicorp/hc-install"
install "github.com/hashicorp/hc-install"
"github.com/hashicorp/hc-install/fs"
"github.com/hashicorp/hc-install/internal/testutil"
"github.com/hashicorp/hc-install/product"
Expand Down Expand Up @@ -119,9 +119,8 @@ func TestInstaller_Install_enterprise(t *testing.T) {
Product: product.Vault,
Version: version.Must(version.NewVersion("1.9.8")),
InstallDir: tmpBinaryDir,
Enterprise: &releases.EnterpriseOptions{
LicenseDir: tmpLicenseDir,
},
LicenseDir: tmpLicenseDir,
Enterprise: &releases.EnterpriseOptions{},
},
})
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions internal/releasesjson/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion,

// Determine the appropriate destination file path
dstDir := binDir
// for license files, use binDir if licenseDir is not set
if isLicenseFile(f.Name) && licenseDir != "" {
dstDir = licenseDir
}
Expand Down
7 changes: 2 additions & 5 deletions releases/enterprise.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ package releases
import "fmt"

type EnterpriseOptions struct {
// LicenseDir represents directory path where to install license files (required)
LicenseDir string

// Meta represents optional version metadata (e.g. hsm, fips1402)
Meta string
}
Expand All @@ -25,12 +22,12 @@ func enterpriseVersionMetadata(eo *EnterpriseOptions) string {
return metadata
}

func validateEnterpriseOptions(eo *EnterpriseOptions) error {
func validateEnterpriseOptions(eo *EnterpriseOptions, licenseDir string) error {
if eo == nil {
return nil
}

if eo.LicenseDir == "" {
if licenseDir == "" {
return fmt.Errorf("LicenseDir must be provided when requesting enterprise versions")
}

Expand Down
11 changes: 6 additions & 5 deletions releases/exact_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ type ExactVersion struct {
InstallDir string
Timeout time.Duration

// LicenseDir represents directory path where to install license files
// (required for enterprise versions, optional for Community editions).
LicenseDir string

// Enterprise indicates installation of enterprise version (leave nil for Community editions)
Enterprise *EnterpriseOptions

Expand Down Expand Up @@ -72,7 +76,7 @@ func (ev *ExactVersion) Validate() error {
return fmt.Errorf("unknown version")
}

if err := validateEnterpriseOptions(ev.Enterprise); err != nil {
if err := validateEnterpriseOptions(ev.Enterprise, ev.LicenseDir); err != nil {
return err
}

Expand Down Expand Up @@ -131,10 +135,7 @@ func (ev *ExactVersion) Install(ctx context.Context) (string, error) {
d.BaseURL = ev.ApiBaseURL
}

licenseDir := ""
if ev.Enterprise != nil {
licenseDir = ev.Enterprise.LicenseDir
}
licenseDir := ev.LicenseDir
up, err := d.DownloadAndUnpack(ctx, pv, dstDir, licenseDir)
if up != nil {
ev.pathsToRemove = append(ev.pathsToRemove, up.PathsToRemove...)
Expand Down
11 changes: 6 additions & 5 deletions releases/latest_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ type LatestVersion struct {
Timeout time.Duration
IncludePrereleases bool

// LicenseDir represents directory path where to install license files
// (required for enterprise versions, optional for Community editions).
LicenseDir string

// Enterprise indicates installation of enterprise version (leave nil for Community editions)
Enterprise *EnterpriseOptions

Expand Down Expand Up @@ -68,7 +72,7 @@ func (lv *LatestVersion) Validate() error {
return fmt.Errorf("invalid binary name: %q", lv.Product.BinaryName())
}

if err := validateEnterpriseOptions(lv.Enterprise); err != nil {
if err := validateEnterpriseOptions(lv.Enterprise, lv.LicenseDir); err != nil {
return err
}

Expand Down Expand Up @@ -131,10 +135,7 @@ func (lv *LatestVersion) Install(ctx context.Context) (string, error) {
if lv.ApiBaseURL != "" {
d.BaseURL = lv.ApiBaseURL
}
licenseDir := ""
if lv.Enterprise != nil {
licenseDir = lv.Enterprise.LicenseDir
}
licenseDir := lv.LicenseDir
up, err := d.DownloadAndUnpack(ctx, versionToInstall, dstDir, licenseDir)
if up != nil {
lv.pathsToRemove = append(lv.pathsToRemove, up.PathsToRemove...)
Expand Down
11 changes: 6 additions & 5 deletions releases/versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ type Versions struct {
}

type InstallationOptions struct {
Timeout time.Duration
Dir string
Timeout time.Duration
Dir string
LicenseDir string

SkipChecksumVerification bool

Expand All @@ -46,7 +47,7 @@ func (v *Versions) List(ctx context.Context) ([]src.Source, error) {
return nil, fmt.Errorf("invalid product name: %q", v.Product.Name)
}

if err := validateEnterpriseOptions(v.Enterprise); err != nil {
if err := validateEnterpriseOptions(v.Enterprise, v.Install.LicenseDir); err != nil {
return nil, err
}

Expand Down Expand Up @@ -85,15 +86,15 @@ func (v *Versions) List(ctx context.Context) ([]src.Source, error) {
Version: pv.Version,
InstallDir: v.Install.Dir,
Timeout: v.Install.Timeout,
LicenseDir: v.Install.LicenseDir,

ArmoredPublicKey: v.Install.ArmoredPublicKey,
SkipChecksumVerification: v.Install.SkipChecksumVerification,
}

if v.Enterprise != nil {
ev.Enterprise = &EnterpriseOptions{
Meta: v.Enterprise.Meta,
LicenseDir: v.Enterprise.LicenseDir,
Meta: v.Enterprise.Meta,
}
}

Expand Down
6 changes: 4 additions & 2 deletions releases/versions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,12 @@ func TestVersions_List_enterprise(t *testing.T) {
versions := &Versions{
Product: product.Vault,
Constraints: cons,
Enterprise: &EnterpriseOptions{
Meta: "hsm",
Install: InstallationOptions{
LicenseDir: "/some/path",
},
Enterprise: &EnterpriseOptions{
Meta: "hsm",
},
}

ctx := context.Background()
Expand Down

0 comments on commit e082106

Please sign in to comment.