add vendor
This commit is contained in:
1
vendor/github.com/hashicorp/hc-install/.go-version
generated
vendored
Normal file
1
vendor/github.com/hashicorp/hc-install/.go-version
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
1.17.3
|
29
vendor/github.com/hashicorp/hc-install/.goreleaser.yml
generated
vendored
Normal file
29
vendor/github.com/hashicorp/hc-install/.goreleaser.yml
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
project_name: tfinstall
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
main: ./cmd/hcinstall/main.go
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
id: "tfinstall"
|
||||
binary: tfinstall
|
||||
flags:
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}'
|
||||
goos:
|
||||
- linux
|
||||
- darwin
|
||||
- windows
|
||||
goarch:
|
||||
- amd64
|
||||
- arm
|
||||
- arm64
|
||||
archives:
|
||||
- files: []
|
||||
format: zip
|
||||
name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}'
|
||||
checksum:
|
||||
name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS'
|
||||
algorithm: sha256
|
||||
changelog:
|
||||
skip: true
|
373
vendor/github.com/hashicorp/hc-install/LICENSE
generated
vendored
Normal file
373
vendor/github.com/hashicorp/hc-install/LICENSE
generated
vendored
Normal file
@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
133
vendor/github.com/hashicorp/hc-install/README.md
generated
vendored
Normal file
133
vendor/github.com/hashicorp/hc-install/README.md
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
# hc-install
|
||||
|
||||
An **experimental** Go module for downloading or locating HashiCorp binaries, verifying signatures and checksums, and asserting version constraints.
|
||||
|
||||
This module is a successor to tfinstall, available in pre-1.0 versions of [terraform-exec](https://github.com/hashicorp/terraform-exec). Current users of tfinstall are advised to move to hc-install before upgrading terraform-exec to v1.0.0.
|
||||
|
||||
## hc-install is not a package manager
|
||||
|
||||
This library is intended for use within Go programs or automated environments (such as CIs)
|
||||
which have some business downloading or otherwise locating HashiCorp binaries.
|
||||
|
||||
The included command-line utility, `hc-install`, is a convenient way of using
|
||||
the library in ad-hoc or CI shell scripting outside of Go.
|
||||
|
||||
`hc-install` does **not**:
|
||||
|
||||
- Determine suitable installation path based on target system. e.g. in `/usr/bin` or `/usr/local/bin` on Unix based system.
|
||||
- Deal with execution of installed binaries (via service files or otherwise).
|
||||
- Upgrade existing binaries on your system.
|
||||
- Add nor link downloaded binaries to your `$PATH`.
|
||||
|
||||
## API
|
||||
|
||||
The `Installer` offers a few high-level methods:
|
||||
|
||||
- `Ensure(context.Context, []src.Source)` to find, install, or build a product version
|
||||
- `Install(context.Context, []src.Installable)` to install a product version
|
||||
|
||||
### Sources
|
||||
|
||||
The `Installer` methods accept number of different `Source` types.
|
||||
Each comes with different trade-offs described below.
|
||||
|
||||
- `fs.{AnyVersion,ExactVersion}` - Finds a binary in `$PATH` (or additional paths)
|
||||
- **Pros:**
|
||||
- This is most convenient when you already have the product installed on your system
|
||||
which you already manage.
|
||||
- **Cons:**
|
||||
- Only relies on a single version, expects _you_ to manage the installation
|
||||
- _Not recommended_ for any environment where product installation is not controlled or managed by you (e.g. default GitHub Actions image managed by GitHub)
|
||||
- `releases.{LatestVersion,ExactVersion}` - Downloads, verifies & installs any known product from `releases.hashicorp.com`
|
||||
- **Pros:**
|
||||
- Fast and reliable way of obtaining any pre-built version of any product
|
||||
- **Cons:**
|
||||
- Installation may consume some bandwith, disk space and a little time
|
||||
- Potentially less stable builds (see `checkpoint` below)
|
||||
- `checkpoint.{LatestVersion}` - Downloads, verifies & installs any known product available in HashiCorp Checkpoint
|
||||
- **Pros:**
|
||||
- Checkpoint typically contains only product versions considered stable
|
||||
- **Cons:**
|
||||
- Installation may consume some bandwith, disk space and a little time
|
||||
- Currently doesn't allow installation of a old versions (see `releases` above)
|
||||
- `build.{GitRevision}` - Clones raw source code and builds the product from it
|
||||
- **Pros:**
|
||||
- Useful for catching bugs and incompatibilities as early as possible (prior to product release).
|
||||
- **Cons:**
|
||||
- Building from scratch can consume significant amount of time & resources (CPU, memory, bandwith, disk space)
|
||||
- There are no guarantees that build instructions will always be up-to-date
|
||||
- There's increased likelihood of build containing bugs prior to release
|
||||
- Any CI builds relying on this are likely to be fragile
|
||||
|
||||
## Example Usage
|
||||
|
||||
### Install single version
|
||||
|
||||
```go
|
||||
TODO
|
||||
```
|
||||
|
||||
### Find or install single version
|
||||
|
||||
```go
|
||||
i := NewInstaller()
|
||||
|
||||
v0_14_0 := version.Must(version.NewVersion("0.14.0"))
|
||||
|
||||
execPath, err := i.Ensure(context.Background(), []src.Source{
|
||||
&fs.ExactVersion{
|
||||
Product: product.Terraform,
|
||||
Version: v0_14_0,
|
||||
},
|
||||
&releases.ExactVersion{
|
||||
Product: product.Terraform,
|
||||
Version: v0_14_0,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
// process err
|
||||
}
|
||||
|
||||
// run any tests
|
||||
|
||||
defer i.Remove()
|
||||
```
|
||||
|
||||
### Install multiple versions
|
||||
|
||||
```go
|
||||
TODO
|
||||
```
|
||||
|
||||
### Install and build multiple versions
|
||||
|
||||
```go
|
||||
i := NewInstaller()
|
||||
|
||||
vc, _ := version.NewConstraint(">= 0.12")
|
||||
rv := &releases.Versions{
|
||||
Product: product.Terraform,
|
||||
Constraints: vc,
|
||||
}
|
||||
|
||||
versions, err := rv.List(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
versions = append(versions, &build.GitRevision{Ref: "HEAD"})
|
||||
|
||||
for _, installableVersion := range versions {
|
||||
execPath, err := i.Ensure(context.Background(), []src.Source{
|
||||
installableVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Do some testing here
|
||||
_ = execPath
|
||||
|
||||
// clean up
|
||||
os.Remove(execPath)
|
||||
}
|
||||
```
|
154
vendor/github.com/hashicorp/hc-install/checkpoint/latest_version.go
generated
vendored
Normal file
154
vendor/github.com/hashicorp/hc-install/checkpoint/latest_version.go
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
package checkpoint
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
checkpoint "github.com/hashicorp/go-checkpoint"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/hc-install/internal/pubkey"
|
||||
rjson "github.com/hashicorp/hc-install/internal/releasesjson"
|
||||
isrc "github.com/hashicorp/hc-install/internal/src"
|
||||
"github.com/hashicorp/hc-install/internal/validators"
|
||||
"github.com/hashicorp/hc-install/product"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultTimeout = 30 * time.Second
|
||||
discardLogger = log.New(ioutil.Discard, "", 0)
|
||||
)
|
||||
|
||||
// LatestVersion installs the latest version known to Checkpoint
|
||||
// to OS temp directory, or to InstallDir (if not empty)
|
||||
type LatestVersion struct {
|
||||
Product product.Product
|
||||
Timeout time.Duration
|
||||
SkipChecksumVerification bool
|
||||
InstallDir 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
|
||||
|
||||
logger *log.Logger
|
||||
pathsToRemove []string
|
||||
}
|
||||
|
||||
func (*LatestVersion) IsSourceImpl() isrc.InstallSrcSigil {
|
||||
return isrc.InstallSrcSigil{}
|
||||
}
|
||||
|
||||
func (lv *LatestVersion) SetLogger(logger *log.Logger) {
|
||||
lv.logger = logger
|
||||
}
|
||||
|
||||
func (lv *LatestVersion) log() *log.Logger {
|
||||
if lv.logger == nil {
|
||||
return discardLogger
|
||||
}
|
||||
return lv.logger
|
||||
}
|
||||
|
||||
func (lv *LatestVersion) Validate() error {
|
||||
if !validators.IsProductNameValid(lv.Product.Name) {
|
||||
return fmt.Errorf("invalid product name: %q", lv.Product.Name)
|
||||
}
|
||||
if !validators.IsBinaryNameValid(lv.Product.BinaryName()) {
|
||||
return fmt.Errorf("invalid binary name: %q", lv.Product.BinaryName())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lv *LatestVersion) Install(ctx context.Context) (string, error) {
|
||||
timeout := defaultTimeout
|
||||
if lv.Timeout > 0 {
|
||||
timeout = lv.Timeout
|
||||
}
|
||||
ctx, cancelFunc := context.WithTimeout(ctx, timeout)
|
||||
defer cancelFunc()
|
||||
|
||||
// TODO: Introduce CheckWithContext to allow for cancellation
|
||||
resp, err := checkpoint.Check(&checkpoint.CheckParams{
|
||||
Product: lv.Product.Name,
|
||||
OS: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
Force: true,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
latestVersion, err := version.NewVersion(resp.CurrentVersion)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if lv.pathsToRemove == nil {
|
||||
lv.pathsToRemove = make([]string, 0)
|
||||
}
|
||||
|
||||
dstDir := lv.InstallDir
|
||||
if dstDir == "" {
|
||||
var err error
|
||||
dirName := fmt.Sprintf("%s_*", lv.Product.Name)
|
||||
dstDir, err = ioutil.TempDir("", dirName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
lv.pathsToRemove = append(lv.pathsToRemove, dstDir)
|
||||
lv.log().Printf("created new temp dir at %s", dstDir)
|
||||
}
|
||||
lv.log().Printf("will install into dir at %s", dstDir)
|
||||
|
||||
rels := rjson.NewReleases()
|
||||
rels.SetLogger(lv.log())
|
||||
pv, err := rels.GetProductVersion(ctx, lv.Product.Name, latestVersion)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
d := &rjson.Downloader{
|
||||
Logger: lv.log(),
|
||||
VerifyChecksum: !lv.SkipChecksumVerification,
|
||||
ArmoredPublicKey: pubkey.DefaultPublicKey,
|
||||
BaseURL: rels.BaseURL,
|
||||
}
|
||||
if lv.ArmoredPublicKey != "" {
|
||||
d.ArmoredPublicKey = lv.ArmoredPublicKey
|
||||
}
|
||||
err = d.DownloadAndUnpack(ctx, pv, dstDir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
execPath := filepath.Join(dstDir, lv.Product.BinaryName())
|
||||
|
||||
lv.pathsToRemove = append(lv.pathsToRemove, execPath)
|
||||
|
||||
lv.log().Printf("changing perms of %s", execPath)
|
||||
err = os.Chmod(execPath, 0o700)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return execPath, nil
|
||||
}
|
||||
|
||||
func (lv *LatestVersion) Remove(ctx context.Context) error {
|
||||
if lv.pathsToRemove != nil {
|
||||
for _, path := range lv.pathsToRemove {
|
||||
err := os.RemoveAll(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
18
vendor/github.com/hashicorp/hc-install/errors/errors.go
generated
vendored
Normal file
18
vendor/github.com/hashicorp/hc-install/errors/errors.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package errors
|
||||
|
||||
type skippableErr struct {
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e skippableErr) Error() string {
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
func SkippableErr(err error) skippableErr {
|
||||
return skippableErr{Err: err}
|
||||
}
|
||||
|
||||
func IsErrorSkippable(err error) bool {
|
||||
_, ok := err.(skippableErr)
|
||||
return ok
|
||||
}
|
95
vendor/github.com/hashicorp/hc-install/fs/any_version.go
generated
vendored
Normal file
95
vendor/github.com/hashicorp/hc-install/fs/any_version.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/hc-install/errors"
|
||||
"github.com/hashicorp/hc-install/internal/src"
|
||||
"github.com/hashicorp/hc-install/internal/validators"
|
||||
"github.com/hashicorp/hc-install/product"
|
||||
)
|
||||
|
||||
// AnyVersion finds an executable binary of any version
|
||||
// either defined by ExactBinPath, or as part of Product.
|
||||
//
|
||||
// When ExactBinPath is used, the source is skipped when
|
||||
// the binary is not found or accessible/executable.
|
||||
//
|
||||
// When Product is used, binary name is looked up within system $PATH
|
||||
// and any declared ExtraPaths (which are *appended* to
|
||||
// any directories in $PATH). Source is skipped if no binary
|
||||
// is found or accessible/executable.
|
||||
type AnyVersion struct {
|
||||
// Product represents the product (its binary name to look up),
|
||||
// conflicts with ExactBinPath
|
||||
Product *product.Product
|
||||
|
||||
// ExtraPaths represents additional dir paths to be appended to
|
||||
// the default system $PATH, conflicts with ExactBinPath
|
||||
ExtraPaths []string
|
||||
|
||||
// ExactBinPath represents exact path to the binary,
|
||||
// conflicts with Product and ExtraPaths
|
||||
ExactBinPath string
|
||||
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (*AnyVersion) IsSourceImpl() src.InstallSrcSigil {
|
||||
return src.InstallSrcSigil{}
|
||||
}
|
||||
|
||||
func (av *AnyVersion) Validate() error {
|
||||
if av.ExactBinPath == "" && av.Product == nil {
|
||||
return fmt.Errorf("must use either ExactBinPath or Product + ExtraPaths")
|
||||
}
|
||||
if av.ExactBinPath != "" && (av.Product != nil || len(av.ExtraPaths) > 0) {
|
||||
return fmt.Errorf("use either ExactBinPath or Product + ExtraPaths, not both")
|
||||
}
|
||||
if av.ExactBinPath != "" && !filepath.IsAbs(av.ExactBinPath) {
|
||||
return fmt.Errorf("expected ExactBinPath (%q) to be an absolute path", av.ExactBinPath)
|
||||
}
|
||||
if av.Product != nil && !validators.IsBinaryNameValid(av.Product.BinaryName()) {
|
||||
return fmt.Errorf("invalid binary name: %q", av.Product.BinaryName())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (av *AnyVersion) SetLogger(logger *log.Logger) {
|
||||
av.logger = logger
|
||||
}
|
||||
|
||||
func (av *AnyVersion) log() *log.Logger {
|
||||
if av.logger == nil {
|
||||
return discardLogger
|
||||
}
|
||||
return av.logger
|
||||
}
|
||||
|
||||
func (av *AnyVersion) Find(ctx context.Context) (string, error) {
|
||||
if av.ExactBinPath != "" {
|
||||
err := checkExecutable(av.ExactBinPath)
|
||||
if err != nil {
|
||||
return "", errors.SkippableErr(err)
|
||||
}
|
||||
|
||||
return av.ExactBinPath, nil
|
||||
}
|
||||
|
||||
execPath, err := findFile(lookupDirs(av.ExtraPaths), av.Product.BinaryName(), checkExecutable)
|
||||
if err != nil {
|
||||
return "", errors.SkippableErr(err)
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(execPath) {
|
||||
var err error
|
||||
execPath, err = filepath.Abs(execPath)
|
||||
if err != nil {
|
||||
return "", errors.SkippableErr(err)
|
||||
}
|
||||
}
|
||||
return execPath, nil
|
||||
}
|
95
vendor/github.com/hashicorp/hc-install/fs/exact_version.go
generated
vendored
Normal file
95
vendor/github.com/hashicorp/hc-install/fs/exact_version.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/hc-install/errors"
|
||||
"github.com/hashicorp/hc-install/internal/src"
|
||||
"github.com/hashicorp/hc-install/internal/validators"
|
||||
"github.com/hashicorp/hc-install/product"
|
||||
)
|
||||
|
||||
// ExactVersion finds the first executable binary of the product name
|
||||
// which matches the Version within system $PATH and any declared ExtraPaths
|
||||
// (which are *appended* to any directories in $PATH)
|
||||
type ExactVersion struct {
|
||||
Product product.Product
|
||||
Version *version.Version
|
||||
ExtraPaths []string
|
||||
Timeout time.Duration
|
||||
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (*ExactVersion) IsSourceImpl() src.InstallSrcSigil {
|
||||
return src.InstallSrcSigil{}
|
||||
}
|
||||
|
||||
func (ev *ExactVersion) SetLogger(logger *log.Logger) {
|
||||
ev.logger = logger
|
||||
}
|
||||
|
||||
func (ev *ExactVersion) log() *log.Logger {
|
||||
if ev.logger == nil {
|
||||
return discardLogger
|
||||
}
|
||||
return ev.logger
|
||||
}
|
||||
|
||||
func (ev *ExactVersion) Validate() error {
|
||||
if !validators.IsBinaryNameValid(ev.Product.BinaryName()) {
|
||||
return fmt.Errorf("invalid binary name: %q", ev.Product.BinaryName())
|
||||
}
|
||||
if ev.Version == nil {
|
||||
return fmt.Errorf("undeclared version")
|
||||
}
|
||||
if ev.Product.GetVersion == nil {
|
||||
return fmt.Errorf("undeclared version getter")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ev *ExactVersion) Find(ctx context.Context) (string, error) {
|
||||
timeout := defaultTimeout
|
||||
if ev.Timeout > 0 {
|
||||
timeout = ev.Timeout
|
||||
}
|
||||
ctx, cancelFunc := context.WithTimeout(ctx, timeout)
|
||||
defer cancelFunc()
|
||||
|
||||
execPath, err := findFile(lookupDirs(ev.ExtraPaths), ev.Product.BinaryName(), func(file string) error {
|
||||
err := checkExecutable(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v, err := ev.Product.GetVersion(ctx, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !ev.Version.Equal(v) {
|
||||
return fmt.Errorf("version (%s) doesn't match %s", v, ev.Version)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", errors.SkippableErr(err)
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(execPath) {
|
||||
var err error
|
||||
execPath, err = filepath.Abs(execPath)
|
||||
if err != nil {
|
||||
return "", errors.SkippableErr(err)
|
||||
}
|
||||
}
|
||||
|
||||
return execPath, nil
|
||||
}
|
14
vendor/github.com/hashicorp/hc-install/fs/fs.go
generated
vendored
Normal file
14
vendor/github.com/hashicorp/hc-install/fs/fs.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultTimeout = 10 * time.Second
|
||||
discardLogger = log.New(ioutil.Discard, "", 0)
|
||||
)
|
||||
|
||||
type fileCheckFunc func(path string) error
|
45
vendor/github.com/hashicorp/hc-install/fs/fs_unix.go
generated
vendored
Normal file
45
vendor/github.com/hashicorp/hc-install/fs/fs_unix.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func lookupDirs(extraDirs []string) []string {
|
||||
pathVar := os.Getenv("PATH")
|
||||
dirs := filepath.SplitList(pathVar)
|
||||
for _, ep := range extraDirs {
|
||||
dirs = append(dirs, ep)
|
||||
}
|
||||
return dirs
|
||||
}
|
||||
|
||||
func findFile(dirs []string, file string, f fileCheckFunc) (string, error) {
|
||||
for _, dir := range dirs {
|
||||
if dir == "" {
|
||||
// Unix shell semantics: path element "" means "."
|
||||
dir = "."
|
||||
}
|
||||
path := filepath.Join(dir, file)
|
||||
if err := f(path); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("%s: %w", file, exec.ErrNotFound)
|
||||
}
|
||||
|
||||
func checkExecutable(file string) error {
|
||||
d, err := os.Stat(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if m := d.Mode(); !m.IsDir() && m&0111 != 0 {
|
||||
return nil
|
||||
}
|
||||
return os.ErrPermission
|
||||
}
|
81
vendor/github.com/hashicorp/hc-install/fs/fs_windows.go
generated
vendored
Normal file
81
vendor/github.com/hashicorp/hc-install/fs/fs_windows.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func lookupDirs(extraDirs []string) []string {
|
||||
pathVar := os.Getenv("path")
|
||||
dirs := filepath.SplitList(pathVar)
|
||||
for _, ep := range extraDirs {
|
||||
dirs = append(dirs, ep)
|
||||
}
|
||||
return dirs
|
||||
}
|
||||
|
||||
func findFile(dirs []string, file string, f fileCheckFunc) (string, error) {
|
||||
for _, dir := range dirs {
|
||||
path := filepath.Join(dir, file)
|
||||
if err := f(path); err == nil {
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("%s: %w", file, exec.ErrNotFound)
|
||||
}
|
||||
|
||||
func checkExecutable(file string) error {
|
||||
var exts []string
|
||||
x := os.Getenv(`PATHEXT`)
|
||||
if x != "" {
|
||||
for _, e := range strings.Split(strings.ToLower(x), `;`) {
|
||||
if e == "" {
|
||||
continue
|
||||
}
|
||||
if e[0] != '.' {
|
||||
e = "." + e
|
||||
}
|
||||
exts = append(exts, e)
|
||||
}
|
||||
} else {
|
||||
exts = []string{".com", ".exe", ".bat", ".cmd"}
|
||||
}
|
||||
|
||||
if len(exts) == 0 {
|
||||
return chkStat(file)
|
||||
}
|
||||
if hasExt(file) {
|
||||
if chkStat(file) == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
for _, e := range exts {
|
||||
if f := file + e; chkStat(f) == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fs.ErrNotExist
|
||||
}
|
||||
|
||||
func chkStat(file string) error {
|
||||
d, err := os.Stat(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return fs.ErrPermission
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasExt(file string) bool {
|
||||
i := strings.LastIndex(file, ".")
|
||||
if i < 0 {
|
||||
return false
|
||||
}
|
||||
return strings.LastIndexAny(file, `:\/`) < i
|
||||
}
|
154
vendor/github.com/hashicorp/hc-install/installer.go
generated
vendored
Normal file
154
vendor/github.com/hashicorp/hc-install/installer.go
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
package install
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/hc-install/errors"
|
||||
"github.com/hashicorp/hc-install/src"
|
||||
)
|
||||
|
||||
type Installer struct {
|
||||
logger *log.Logger
|
||||
|
||||
removableSources []src.Removable
|
||||
}
|
||||
|
||||
type RemoveFunc func(ctx context.Context) error
|
||||
|
||||
func NewInstaller() *Installer {
|
||||
discardLogger := log.New(ioutil.Discard, "", 0)
|
||||
return &Installer{
|
||||
logger: discardLogger,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Installer) SetLogger(logger *log.Logger) {
|
||||
i.logger = logger
|
||||
}
|
||||
|
||||
func (i *Installer) Ensure(ctx context.Context, sources []src.Source) (string, error) {
|
||||
var errs *multierror.Error
|
||||
|
||||
for _, source := range sources {
|
||||
if srcWithLogger, ok := source.(src.LoggerSettable); ok {
|
||||
srcWithLogger.SetLogger(i.logger)
|
||||
}
|
||||
|
||||
if srcValidatable, ok := source.(src.Validatable); ok {
|
||||
err := srcValidatable.Validate()
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if errs.ErrorOrNil() != nil {
|
||||
return "", errs
|
||||
}
|
||||
|
||||
i.removableSources = make([]src.Removable, 0)
|
||||
|
||||
for _, source := range sources {
|
||||
if s, ok := source.(src.Removable); ok {
|
||||
i.removableSources = append(i.removableSources, s)
|
||||
}
|
||||
|
||||
switch s := source.(type) {
|
||||
case src.Findable:
|
||||
execPath, err := s.Find(ctx)
|
||||
if err != nil {
|
||||
if errors.IsErrorSkippable(err) {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
return execPath, nil
|
||||
case src.Installable:
|
||||
execPath, err := s.Install(ctx)
|
||||
if err != nil {
|
||||
if errors.IsErrorSkippable(err) {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
return execPath, nil
|
||||
case src.Buildable:
|
||||
execPath, err := s.Build(ctx)
|
||||
if err != nil {
|
||||
if errors.IsErrorSkippable(err) {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
return execPath, nil
|
||||
default:
|
||||
return "", fmt.Errorf("unknown source: %T", s)
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unable to find, install, or build from %d sources: %s",
|
||||
len(sources), errs.ErrorOrNil())
|
||||
}
|
||||
|
||||
func (i *Installer) Install(ctx context.Context, sources []src.Installable) (string, error) {
|
||||
var errs *multierror.Error
|
||||
|
||||
i.removableSources = make([]src.Removable, 0)
|
||||
|
||||
for _, source := range sources {
|
||||
if srcWithLogger, ok := source.(src.LoggerSettable); ok {
|
||||
srcWithLogger.SetLogger(i.logger)
|
||||
}
|
||||
|
||||
if srcValidatable, ok := source.(src.Validatable); ok {
|
||||
err := srcValidatable.Validate()
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if s, ok := source.(src.Removable); ok {
|
||||
i.removableSources = append(i.removableSources, s)
|
||||
}
|
||||
|
||||
execPath, err := source.Install(ctx)
|
||||
if err != nil {
|
||||
if errors.IsErrorSkippable(err) {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
return execPath, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unable install from %d sources: %s",
|
||||
len(sources), errs.ErrorOrNil())
|
||||
}
|
||||
|
||||
func (i *Installer) Remove(ctx context.Context) error {
|
||||
var errs *multierror.Error
|
||||
|
||||
if i.removableSources != nil {
|
||||
for _, rs := range i.removableSources {
|
||||
err := rs.Remove(ctx)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errs.ErrorOrNil()
|
||||
}
|
37
vendor/github.com/hashicorp/hc-install/internal/build/get_go_version.go
generated
vendored
Normal file
37
vendor/github.com/hashicorp/hc-install/internal/build/get_go_version.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
)
|
||||
|
||||
// GetGoVersion obtains version of locally installed Go via "go version"
|
||||
func GetGoVersion(ctx context.Context) (*version.Version, error) {
|
||||
cmd := exec.CommandContext(ctx, "go", "version")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to build: %w\n%s", err, out)
|
||||
}
|
||||
|
||||
output := strings.TrimSpace(string(out))
|
||||
|
||||
// e.g. "go version go1.15"
|
||||
re := regexp.MustCompile(`^go version go([0-9.]+)\s+`)
|
||||
matches := re.FindStringSubmatch(output)
|
||||
if len(matches) != 2 {
|
||||
return nil, fmt.Errorf("unexpected go version output: %q", output)
|
||||
}
|
||||
|
||||
rawGoVersion := matches[1]
|
||||
v, err := version.NewVersion(rawGoVersion)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unexpected go version output: %w", err)
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
123
vendor/github.com/hashicorp/hc-install/internal/build/go_build.go
generated
vendored
Normal file
123
vendor/github.com/hashicorp/hc-install/internal/build/go_build.go
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
)
|
||||
|
||||
var discardLogger = log.New(ioutil.Discard, "", 0)
|
||||
|
||||
// GoBuild represents a Go builder (to run "go build")
|
||||
type GoBuild struct {
|
||||
Version *version.Version
|
||||
DetectVendoring bool
|
||||
|
||||
pathToRemove string
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (gb *GoBuild) SetLogger(logger *log.Logger) {
|
||||
gb.logger = logger
|
||||
}
|
||||
|
||||
func (gb *GoBuild) log() *log.Logger {
|
||||
if gb.logger == nil {
|
||||
return discardLogger
|
||||
}
|
||||
return gb.logger
|
||||
}
|
||||
|
||||
// Build runs "go build" within a given repo to produce binaryName in targetDir
|
||||
func (gb *GoBuild) Build(ctx context.Context, repoDir, targetDir, binaryName string) (string, error) {
|
||||
goCmd, cleanupFunc, err := gb.ensureRequiredGoVersion(ctx, repoDir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer cleanupFunc(ctx)
|
||||
|
||||
goArgs := []string{"build", "-o", filepath.Join(targetDir, binaryName)}
|
||||
|
||||
if gb.DetectVendoring {
|
||||
vendorDir := filepath.Join(repoDir, "vendor")
|
||||
if fi, err := os.Stat(vendorDir); err == nil && fi.IsDir() {
|
||||
goArgs = append(goArgs, "-mod", "vendor")
|
||||
}
|
||||
}
|
||||
|
||||
gb.log().Printf("executing %s %q in %q", goCmd, goArgs, repoDir)
|
||||
cmd := exec.CommandContext(ctx, goCmd, goArgs...)
|
||||
cmd.Dir = repoDir
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to build: %w\n%s", err, out)
|
||||
}
|
||||
|
||||
binPath := filepath.Join(targetDir, binaryName)
|
||||
|
||||
gb.pathToRemove = binPath
|
||||
|
||||
return binPath, nil
|
||||
}
|
||||
|
||||
func (gb *GoBuild) Remove(ctx context.Context) error {
|
||||
return os.RemoveAll(gb.pathToRemove)
|
||||
}
|
||||
|
||||
func (gb *GoBuild) ensureRequiredGoVersion(ctx context.Context, repoDir string) (string, CleanupFunc, error) {
|
||||
cmdName := "go"
|
||||
noopCleanupFunc := func(context.Context) {}
|
||||
|
||||
if gb.Version != nil {
|
||||
goVersion, err := GetGoVersion(ctx)
|
||||
if err != nil {
|
||||
return cmdName, noopCleanupFunc, err
|
||||
}
|
||||
|
||||
if !goVersion.GreaterThanOrEqual(gb.Version) {
|
||||
// found incompatible version, try downloading the desired one
|
||||
return gb.installGoVersion(ctx, gb.Version)
|
||||
}
|
||||
}
|
||||
|
||||
if requiredVersion, ok := guessRequiredGoVersion(repoDir); ok {
|
||||
goVersion, err := GetGoVersion(ctx)
|
||||
if err != nil {
|
||||
return cmdName, noopCleanupFunc, err
|
||||
}
|
||||
|
||||
if !goVersion.GreaterThanOrEqual(requiredVersion) {
|
||||
// found incompatible version, try downloading the desired one
|
||||
return gb.installGoVersion(ctx, requiredVersion)
|
||||
}
|
||||
}
|
||||
|
||||
return cmdName, noopCleanupFunc, nil
|
||||
}
|
||||
|
||||
// CleanupFunc represents a function to be called once Go is no longer needed
|
||||
// e.g. to remove any version installed temporarily per requirements
|
||||
type CleanupFunc func(context.Context)
|
||||
|
||||
func guessRequiredGoVersion(repoDir string) (*version.Version, bool) {
|
||||
goEnvFile := filepath.Join(repoDir, ".go-version")
|
||||
if fi, err := os.Stat(goEnvFile); err == nil && !fi.IsDir() {
|
||||
b, err := ioutil.ReadFile(goEnvFile)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
requiredVersion, err := version.NewVersion(string(bytes.TrimSpace(b)))
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return requiredVersion, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
28
vendor/github.com/hashicorp/hc-install/internal/build/go_is_installed.go
generated
vendored
Normal file
28
vendor/github.com/hashicorp/hc-install/internal/build/go_is_installed.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
)
|
||||
|
||||
// GoIsInstalled represents a checker of whether Go is installed locally
|
||||
type GoIsInstalled struct {
|
||||
RequiredVersion version.Constraints
|
||||
}
|
||||
|
||||
// Check checks whether any Go version is installed locally
|
||||
func (gii *GoIsInstalled) Check(ctx context.Context) error {
|
||||
goVersion, err := GetGoVersion(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if gii.RequiredVersion != nil && !gii.RequiredVersion.Check(goVersion) {
|
||||
return fmt.Errorf("go %s required (%s available)",
|
||||
gii.RequiredVersion, goVersion)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
53
vendor/github.com/hashicorp/hc-install/internal/build/install_go_version.go
generated
vendored
Normal file
53
vendor/github.com/hashicorp/hc-install/internal/build/install_go_version.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
)
|
||||
|
||||
// installGoVersion installs given version of Go using Go
|
||||
// according to https://golang.org/doc/manage-install
|
||||
func (gb *GoBuild) installGoVersion(ctx context.Context, v *version.Version) (string, CleanupFunc, error) {
|
||||
// trim 0 patch versions as that's how Go does it :shrug:
|
||||
shortVersion := strings.TrimSuffix(v.String(), ".0")
|
||||
|
||||
pkgURL := fmt.Sprintf("golang.org/dl/go%s", shortVersion)
|
||||
|
||||
gb.log().Printf("go getting %q", pkgURL)
|
||||
cmd := exec.CommandContext(ctx, "go", "get", pkgURL)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("unable to install Go %s: %w\n%s", v, err, out)
|
||||
}
|
||||
|
||||
cmdName := fmt.Sprintf("go%s", shortVersion)
|
||||
|
||||
gb.log().Printf("downloading go %q", shortVersion)
|
||||
cmd = exec.CommandContext(ctx, cmdName, "download")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("unable to download Go %s: %w\n%s", v, err, out)
|
||||
}
|
||||
gb.log().Printf("download of go %q finished", shortVersion)
|
||||
|
||||
cleanupFunc := func(ctx context.Context) {
|
||||
cmd = exec.CommandContext(ctx, cmdName, "env", "GOROOT")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rootPath := strings.TrimSpace(string(out))
|
||||
|
||||
// run some extra checks before deleting, just to be sure
|
||||
if rootPath != "" && strings.HasSuffix(rootPath, v.String()) {
|
||||
os.RemoveAll(rootPath)
|
||||
}
|
||||
}
|
||||
|
||||
return cmdName, cleanupFunc, nil
|
||||
}
|
37
vendor/github.com/hashicorp/hc-install/internal/httpclient/httpclient.go
generated
vendored
Normal file
37
vendor/github.com/hashicorp/hc-install/internal/httpclient/httpclient.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/go-cleanhttp"
|
||||
"github.com/hashicorp/hc-install/internal/version"
|
||||
)
|
||||
|
||||
// NewHTTPClient provides a pre-configured http.Client
|
||||
// e.g. with relevant User-Agent header
|
||||
func NewHTTPClient() *http.Client {
|
||||
client := cleanhttp.DefaultClient()
|
||||
|
||||
userAgent := fmt.Sprintf("hc-install/%s", version.ModuleVersion())
|
||||
|
||||
cli := cleanhttp.DefaultPooledClient()
|
||||
cli.Transport = &userAgentRoundTripper{
|
||||
userAgent: userAgent,
|
||||
inner: cli.Transport,
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
type userAgentRoundTripper struct {
|
||||
inner http.RoundTripper
|
||||
userAgent string
|
||||
}
|
||||
|
||||
func (rt *userAgentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if _, ok := req.Header["User-Agent"]; !ok {
|
||||
req.Header.Set("User-Agent", rt.userAgent)
|
||||
}
|
||||
return rt.inner.RoundTrip(req)
|
||||
}
|
127
vendor/github.com/hashicorp/hc-install/internal/pubkey/pubkey.go
generated
vendored
Normal file
127
vendor/github.com/hashicorp/hc-install/internal/pubkey/pubkey.go
generated
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
package pubkey
|
||||
|
||||
const (
|
||||
// See https://www.hashicorp.com/security
|
||||
DefaultPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
ZF5q4h4I33PSGDdSvGXn9UMY5Isjpg==
|
||||
=7pIB
|
||||
-----END PGP PUBLIC KEY BLOCK-----`
|
||||
)
|
203
vendor/github.com/hashicorp/hc-install/internal/releasesjson/checksum_downloader.go
generated
vendored
Normal file
203
vendor/github.com/hashicorp/hc-install/internal/releasesjson/checksum_downloader.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
package releasesjson
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/hc-install/internal/httpclient"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
)
|
||||
|
||||
type ChecksumDownloader struct {
|
||||
ProductVersion *ProductVersion
|
||||
Logger *log.Logger
|
||||
ArmoredPublicKey string
|
||||
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
type ChecksumFileMap map[string]HashSum
|
||||
|
||||
type HashSum []byte
|
||||
|
||||
func (hs HashSum) Size() int {
|
||||
return len(hs)
|
||||
}
|
||||
|
||||
func (hs HashSum) String() string {
|
||||
return hex.EncodeToString(hs)
|
||||
}
|
||||
|
||||
func HashSumFromHexDigest(hexDigest string) (HashSum, error) {
|
||||
sumBytes, err := hex.DecodeString(hexDigest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return HashSum(sumBytes), nil
|
||||
}
|
||||
|
||||
func (cd *ChecksumDownloader) DownloadAndVerifyChecksums() (ChecksumFileMap, error) {
|
||||
sigFilename, err := cd.findSigFilename(cd.ProductVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := httpclient.NewHTTPClient()
|
||||
sigURL := fmt.Sprintf("%s/%s/%s/%s", cd.BaseURL,
|
||||
url.PathEscape(cd.ProductVersion.Name),
|
||||
url.PathEscape(cd.ProductVersion.RawVersion),
|
||||
url.PathEscape(sigFilename))
|
||||
cd.Logger.Printf("downloading signature from %s", sigURL)
|
||||
sigResp, err := client.Get(sigURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if sigResp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("failed to download signature from %q: %s", sigURL, sigResp.Status)
|
||||
}
|
||||
|
||||
defer sigResp.Body.Close()
|
||||
|
||||
shasumsURL := fmt.Sprintf("%s/%s/%s/%s", cd.BaseURL,
|
||||
url.PathEscape(cd.ProductVersion.Name),
|
||||
url.PathEscape(cd.ProductVersion.RawVersion),
|
||||
url.PathEscape(cd.ProductVersion.SHASUMS))
|
||||
cd.Logger.Printf("downloading checksums from %s", shasumsURL)
|
||||
sumsResp, err := client.Get(shasumsURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if sumsResp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("failed to download checksums from %q: %s", shasumsURL, sumsResp.Status)
|
||||
}
|
||||
|
||||
defer sumsResp.Body.Close()
|
||||
|
||||
var shaSums strings.Builder
|
||||
sumsReader := io.TeeReader(sumsResp.Body, &shaSums)
|
||||
|
||||
err = cd.verifySumsSignature(sumsReader, sigResp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return fileMapFromChecksums(shaSums)
|
||||
}
|
||||
|
||||
func fileMapFromChecksums(checksums strings.Builder) (ChecksumFileMap, error) {
|
||||
csMap := make(ChecksumFileMap, 0)
|
||||
|
||||
lines := strings.Split(checksums.String(), "\n")
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(line)
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("unexpected checksum line format: %q", line)
|
||||
}
|
||||
|
||||
h, err := HashSumFromHexDigest(parts[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if h.Size() != sha256.Size {
|
||||
return nil, fmt.Errorf("unexpected sha256 format (len: %d, expected: %d)",
|
||||
h.Size(), sha256.Size)
|
||||
}
|
||||
|
||||
csMap[parts[1]] = h
|
||||
}
|
||||
return csMap, nil
|
||||
}
|
||||
|
||||
func compareChecksum(logger *log.Logger, r io.Reader, verifiedHashSum HashSum) error {
|
||||
h := sha256.New()
|
||||
_, err := io.Copy(h, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
calculatedSum := h.Sum(nil)
|
||||
if !bytes.Equal(calculatedSum, verifiedHashSum) {
|
||||
return fmt.Errorf("checksum mismatch (expected %q, calculated %q)",
|
||||
verifiedHashSum,
|
||||
hex.EncodeToString(calculatedSum))
|
||||
}
|
||||
|
||||
logger.Printf("checksum matches: %q", hex.EncodeToString(calculatedSum))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cd *ChecksumDownloader) verifySumsSignature(checksums, signature io.Reader) error {
|
||||
el, err := cd.keyEntityList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = openpgp.CheckDetachedSignature(el, checksums, signature)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to verify checksums signature: %w", err)
|
||||
}
|
||||
|
||||
cd.Logger.Printf("checksum signature is valid")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cd *ChecksumDownloader) findSigFilename(pv *ProductVersion) (string, error) {
|
||||
sigFiles := pv.SHASUMSSigs
|
||||
if len(sigFiles) == 0 {
|
||||
sigFiles = []string{pv.SHASUMSSig}
|
||||
}
|
||||
|
||||
keyIds, err := cd.pubKeyIds()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, filename := range sigFiles {
|
||||
for _, keyID := range keyIds {
|
||||
if strings.HasSuffix(filename, fmt.Sprintf("_SHA256SUMS.%s.sig", keyID)) {
|
||||
return filename, nil
|
||||
}
|
||||
}
|
||||
if strings.HasSuffix(filename, "_SHA256SUMS.sig") {
|
||||
return filename, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("no suitable sig file found")
|
||||
}
|
||||
|
||||
func (cd *ChecksumDownloader) pubKeyIds() ([]string, error) {
|
||||
entityList, err := cd.keyEntityList()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fingerprints := make([]string, 0)
|
||||
for _, entity := range entityList {
|
||||
fingerprints = append(fingerprints, entity.PrimaryKey.KeyIdShortString())
|
||||
}
|
||||
|
||||
return fingerprints, nil
|
||||
}
|
||||
|
||||
func (cd *ChecksumDownloader) keyEntityList() (openpgp.EntityList, error) {
|
||||
if cd.ArmoredPublicKey == "" {
|
||||
return nil, fmt.Errorf("no public key provided")
|
||||
}
|
||||
return openpgp.ReadArmoredKeyRing(strings.NewReader(cd.ArmoredPublicKey))
|
||||
}
|
182
vendor/github.com/hashicorp/hc-install/internal/releasesjson/downloader.go
generated
vendored
Normal file
182
vendor/github.com/hashicorp/hc-install/internal/releasesjson/downloader.go
generated
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
package releasesjson
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/hashicorp/hc-install/internal/httpclient"
|
||||
)
|
||||
|
||||
type Downloader struct {
|
||||
Logger *log.Logger
|
||||
VerifyChecksum bool
|
||||
ArmoredPublicKey string
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, dstDir string) error {
|
||||
if len(pv.Builds) == 0 {
|
||||
return fmt.Errorf("no builds found for %s %s", pv.Name, pv.Version)
|
||||
}
|
||||
|
||||
pb, ok := pv.Builds.FilterBuild(runtime.GOOS, runtime.GOARCH, "zip")
|
||||
if !ok {
|
||||
return fmt.Errorf("no ZIP archive found for %s %s %s/%s",
|
||||
pv.Name, pv.Version, runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
var verifiedChecksum HashSum
|
||||
if d.VerifyChecksum {
|
||||
v := &ChecksumDownloader{
|
||||
BaseURL: d.BaseURL,
|
||||
ProductVersion: pv,
|
||||
Logger: d.Logger,
|
||||
ArmoredPublicKey: d.ArmoredPublicKey,
|
||||
}
|
||||
verifiedChecksums, err := v.DownloadAndVerifyChecksums()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var ok bool
|
||||
verifiedChecksum, ok = verifiedChecksums[pb.Filename]
|
||||
if !ok {
|
||||
return fmt.Errorf("no checksum found for %q", pb.Filename)
|
||||
}
|
||||
}
|
||||
|
||||
client := httpclient.NewHTTPClient()
|
||||
|
||||
archiveURL := pb.URL
|
||||
if d.BaseURL != "" {
|
||||
// ensure that absolute download links from mocked responses
|
||||
// are still pointing to the mock server if one is set
|
||||
baseURL, err := url.Parse(d.BaseURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
u, err := url.Parse(archiveURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
u.Scheme = baseURL.Scheme
|
||||
u.Host = baseURL.Host
|
||||
archiveURL = u.String()
|
||||
}
|
||||
|
||||
d.Logger.Printf("downloading archive from %s", archiveURL)
|
||||
resp, err := client.Get(archiveURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("failed to download ZIP archive from %q: %s", archiveURL, resp.Status)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
var pkgReader io.Reader
|
||||
pkgReader = resp.Body
|
||||
|
||||
contentType := resp.Header.Get("content-type")
|
||||
if !contentTypeIsZip(contentType) {
|
||||
return fmt.Errorf("unexpected content-type: %s (expected any of %q)",
|
||||
contentType, zipMimeTypes)
|
||||
}
|
||||
|
||||
if d.VerifyChecksum {
|
||||
d.Logger.Printf("calculating checksum of %q", pb.Filename)
|
||||
// provide extra reader to calculate & compare checksum
|
||||
var buf bytes.Buffer
|
||||
r := io.TeeReader(resp.Body, &buf)
|
||||
pkgReader = &buf
|
||||
|
||||
err := compareChecksum(d.Logger, r, verifiedChecksum)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
pkgFile, err := ioutil.TempFile("", pb.Filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer pkgFile.Close()
|
||||
|
||||
d.Logger.Printf("copying downloaded file to %s", pkgFile.Name())
|
||||
bytesCopied, err := io.Copy(pkgFile, pkgReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Logger.Printf("copied %d bytes to %s", bytesCopied, pkgFile.Name())
|
||||
|
||||
expectedSize := 0
|
||||
if length := resp.Header.Get("content-length"); length != "" {
|
||||
var err error
|
||||
expectedSize, err = strconv.Atoi(length)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if expectedSize != 0 && bytesCopied != int64(expectedSize) {
|
||||
return fmt.Errorf("unexpected size (downloaded: %d, expected: %d)",
|
||||
bytesCopied, expectedSize)
|
||||
}
|
||||
|
||||
r, err := zip.OpenReader(pkgFile.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
for _, f := range r.File {
|
||||
srcFile, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Logger.Printf("unpacking %s to %s", f.Name, dstDir)
|
||||
dstPath := filepath.Join(dstDir, f.Name)
|
||||
dstFile, err := os.Create(dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(dstFile, srcFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srcFile.Close()
|
||||
dstFile.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The production release site uses consistent single mime type
|
||||
// but mime types are platform-dependent
|
||||
// and we may use different OS under test
|
||||
var zipMimeTypes = []string{
|
||||
"application/x-zip-compressed", // Windows
|
||||
"application/zip", // Unix
|
||||
}
|
||||
|
||||
func contentTypeIsZip(contentType string) bool {
|
||||
for _, mt := range zipMimeTypes {
|
||||
if mt == contentType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
41
vendor/github.com/hashicorp/hc-install/internal/releasesjson/product_version.go
generated
vendored
Normal file
41
vendor/github.com/hashicorp/hc-install/internal/releasesjson/product_version.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
package releasesjson
|
||||
|
||||
import "github.com/hashicorp/go-version"
|
||||
|
||||
// ProductVersion is a wrapper around a particular product version like
|
||||
// "consul 0.5.1". A ProductVersion may have one or more builds.
|
||||
type ProductVersion struct {
|
||||
Name string `json:"name"`
|
||||
RawVersion string `json:"version"`
|
||||
Version *version.Version `json:"-"`
|
||||
SHASUMS string `json:"shasums,omitempty"`
|
||||
SHASUMSSig string `json:"shasums_signature,omitempty"`
|
||||
SHASUMSSigs []string `json:"shasums_signatures,omitempty"`
|
||||
Builds ProductBuilds `json:"builds"`
|
||||
}
|
||||
|
||||
type ProductVersionsMap map[string]*ProductVersion
|
||||
|
||||
type ProductVersions []*ProductVersion
|
||||
|
||||
func (pv ProductVersions) Len() int {
|
||||
return len(pv)
|
||||
}
|
||||
|
||||
func (pv ProductVersions) Less(i, j int) bool {
|
||||
return pv[i].Version.LessThan(pv[j].Version)
|
||||
}
|
||||
|
||||
func (pv ProductVersions) Swap(i, j int) {
|
||||
pv[i], pv[j] = pv[j], pv[i]
|
||||
}
|
||||
|
||||
func (pvm ProductVersionsMap) AsSlice() ProductVersions {
|
||||
versions := make(ProductVersions, 0)
|
||||
|
||||
for _, pVersion := range pvm {
|
||||
versions = append(versions, pVersion)
|
||||
}
|
||||
|
||||
return versions
|
||||
}
|
177
vendor/github.com/hashicorp/hc-install/internal/releasesjson/releases.go
generated
vendored
Normal file
177
vendor/github.com/hashicorp/hc-install/internal/releasesjson/releases.go
generated
vendored
Normal file
@ -0,0 +1,177 @@
|
||||
package releasesjson
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/hc-install/internal/httpclient"
|
||||
)
|
||||
|
||||
const defaultBaseURL = "https://releases.hashicorp.com"
|
||||
|
||||
// Product is a top-level product like "Consul" or "Nomad". A Product may have
|
||||
// one or more versions.
|
||||
type Product struct {
|
||||
Name string `json:"name"`
|
||||
Versions ProductVersionsMap `json:"versions"`
|
||||
}
|
||||
|
||||
type ProductBuilds []*ProductBuild
|
||||
|
||||
func (pbs ProductBuilds) FilterBuild(os string, arch string, suffix string) (*ProductBuild, bool) {
|
||||
for _, pb := range pbs {
|
||||
if pb.OS == os && pb.Arch == arch && strings.HasSuffix(pb.Filename, suffix) {
|
||||
return pb, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// ProductBuild is an OS/arch-specific representation of a product. This is the
|
||||
// actual file that a user would download, like "consul_0.5.1_linux_amd64".
|
||||
type ProductBuild struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
OS string `json:"os"`
|
||||
Arch string `json:"arch"`
|
||||
Filename string `json:"filename"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
type Releases struct {
|
||||
logger *log.Logger
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
func NewReleases() *Releases {
|
||||
return &Releases{
|
||||
logger: log.New(ioutil.Discard, "", 0),
|
||||
BaseURL: defaultBaseURL,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Releases) SetLogger(logger *log.Logger) {
|
||||
r.logger = logger
|
||||
}
|
||||
|
||||
func (r *Releases) ListProductVersions(ctx context.Context, productName string) (ProductVersionsMap, error) {
|
||||
client := httpclient.NewHTTPClient()
|
||||
|
||||
productIndexURL := fmt.Sprintf("%s/%s/index.json",
|
||||
r.BaseURL,
|
||||
url.PathEscape(productName))
|
||||
r.logger.Printf("requesting versions from %s", productIndexURL)
|
||||
|
||||
resp, err := client.Get(productIndexURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("failed to obtain product versions from %q: %s ",
|
||||
productIndexURL, resp.Status)
|
||||
}
|
||||
|
||||
contentType := resp.Header.Get("content-type")
|
||||
if contentType != "application/json" {
|
||||
return nil, fmt.Errorf("unexpected Content-Type: %q", contentType)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
r.logger.Printf("received %s", resp.Status)
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p := Product{}
|
||||
err = json.Unmarshal(body, &p)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: failed to unmarshal: %q",
|
||||
err, string(body))
|
||||
}
|
||||
|
||||
for rawVersion := range p.Versions {
|
||||
v, err := version.NewVersion(rawVersion)
|
||||
if err != nil {
|
||||
// remove unparseable version
|
||||
delete(p.Versions, rawVersion)
|
||||
continue
|
||||
}
|
||||
|
||||
if ok, _ := versionIsSupported(v); !ok {
|
||||
// Remove (currently unsupported) enterprise
|
||||
// version and any other "custom" build
|
||||
delete(p.Versions, rawVersion)
|
||||
continue
|
||||
}
|
||||
|
||||
p.Versions[rawVersion].Version = v
|
||||
}
|
||||
|
||||
return p.Versions, nil
|
||||
}
|
||||
|
||||
func (r *Releases) GetProductVersion(ctx context.Context, product string, version *version.Version) (*ProductVersion, error) {
|
||||
if ok, err := versionIsSupported(version); !ok {
|
||||
return nil, fmt.Errorf("%s: %w", product, err)
|
||||
}
|
||||
|
||||
client := httpclient.NewHTTPClient()
|
||||
|
||||
indexURL := fmt.Sprintf("%s/%s/%s/index.json",
|
||||
r.BaseURL,
|
||||
url.PathEscape(product),
|
||||
url.PathEscape(version.String()))
|
||||
r.logger.Printf("requesting version from %s", indexURL)
|
||||
|
||||
resp, err := client.Get(indexURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return nil, fmt.Errorf("failed to obtain product version from %q: %s ",
|
||||
indexURL, resp.Status)
|
||||
}
|
||||
|
||||
contentType := resp.Header.Get("content-type")
|
||||
if contentType != "application/json" {
|
||||
return nil, fmt.Errorf("unexpected Content-Type: %q", contentType)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
r.logger.Printf("received %s", resp.Status)
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pv := &ProductVersion{}
|
||||
err = json.Unmarshal(body, pv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: failed to unmarshal response: %q",
|
||||
err, string(body))
|
||||
}
|
||||
|
||||
return pv, nil
|
||||
}
|
||||
|
||||
func versionIsSupported(v *version.Version) (bool, error) {
|
||||
isSupported := v.Metadata() == ""
|
||||
if !isSupported {
|
||||
return false, fmt.Errorf("cannot obtain %s (enterprise versions are not supported)",
|
||||
v.String())
|
||||
}
|
||||
return true, nil
|
||||
}
|
3
vendor/github.com/hashicorp/hc-install/internal/src/src.go
generated
vendored
Normal file
3
vendor/github.com/hashicorp/hc-install/internal/src/src.go
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package src
|
||||
|
||||
type InstallSrcSigil struct{}
|
18
vendor/github.com/hashicorp/hc-install/internal/validators/validators.go
generated
vendored
Normal file
18
vendor/github.com/hashicorp/hc-install/internal/validators/validators.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package validators
|
||||
|
||||
import "regexp"
|
||||
|
||||
var (
|
||||
productNameRe = regexp.MustCompile(`^[a-z0-9-]+$`)
|
||||
binaryNameRe = regexp.MustCompile(`^[a-zA-Z0-9-_.]+$`)
|
||||
)
|
||||
|
||||
// IsProductNameValid provides early user-facing validation of a product name
|
||||
func IsProductNameValid(productName string) bool {
|
||||
return productNameRe.MatchString(productName)
|
||||
}
|
||||
|
||||
// IsBinaryNameValid provides early user-facing validation of binary name
|
||||
func IsBinaryNameValid(binaryName string) bool {
|
||||
return binaryNameRe.MatchString(binaryName)
|
||||
}
|
9
vendor/github.com/hashicorp/hc-install/internal/version/version.go
generated
vendored
Normal file
9
vendor/github.com/hashicorp/hc-install/internal/version/version.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
package version
|
||||
|
||||
const version = "0.1.0"
|
||||
|
||||
// ModuleVersion returns the current version of the github.com/hashicorp/hc-install Go module.
|
||||
// This is a function to allow for future possible enhancement using debug.BuildInfo.
|
||||
func ModuleVersion() string {
|
||||
return version
|
||||
}
|
57
vendor/github.com/hashicorp/hc-install/product/consul.go
generated
vendored
Normal file
57
vendor/github.com/hashicorp/hc-install/product/consul.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/hc-install/internal/build"
|
||||
)
|
||||
|
||||
var consulVersionOutputRe = regexp.MustCompile(`Consul ` + simpleVersionRe)
|
||||
|
||||
var (
|
||||
v1_16 = version.Must(version.NewVersion("1.16"))
|
||||
// TODO: version.MustConstraint() ?
|
||||
v1_16c, _ = version.NewConstraint("1.16")
|
||||
)
|
||||
|
||||
var Consul = Product{
|
||||
Name: "consul",
|
||||
BinaryName: func() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return "consul.exe"
|
||||
}
|
||||
return "consul"
|
||||
},
|
||||
GetVersion: func(ctx context.Context, path string) (*version.Version, error) {
|
||||
cmd := exec.CommandContext(ctx, path, "version")
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stdout := strings.TrimSpace(string(out))
|
||||
|
||||
submatches := consulVersionOutputRe.FindStringSubmatch(stdout)
|
||||
if len(submatches) != 2 {
|
||||
return nil, fmt.Errorf("unexpected number of version matches %d for %s", len(submatches), stdout)
|
||||
}
|
||||
v, err := version.NewVersion(submatches[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse version %q: %w", submatches[1], err)
|
||||
}
|
||||
|
||||
return v, err
|
||||
},
|
||||
BuildInstructions: &BuildInstructions{
|
||||
GitRepoURL: "https://github.com/hashicorp/consul.git",
|
||||
PreCloneCheck: &build.GoIsInstalled{},
|
||||
Build: &build.GoBuild{Version: v1_16},
|
||||
},
|
||||
}
|
60
vendor/github.com/hashicorp/hc-install/product/product.go
generated
vendored
Normal file
60
vendor/github.com/hashicorp/hc-install/product/product.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
)
|
||||
|
||||
type Product struct {
|
||||
// Name which identifies the product
|
||||
// on releases.hashicorp.com and in Checkpoint
|
||||
Name string
|
||||
|
||||
// BinaryName represents name of the unpacked binary to be executed or built
|
||||
BinaryName BinaryNameFunc
|
||||
|
||||
// GetVersion represents how to obtain the version of the product
|
||||
// reflecting any output or CLI flag differences
|
||||
GetVersion func(ctx context.Context, execPath string) (*version.Version, error)
|
||||
|
||||
// BuildInstructions represents how to build the product "from scratch"
|
||||
BuildInstructions *BuildInstructions
|
||||
}
|
||||
|
||||
type BinaryNameFunc func() string
|
||||
|
||||
type BuildInstructions struct {
|
||||
GitRepoURL string
|
||||
|
||||
// CloneTimeout overrides default timeout
|
||||
// for cloning the repository
|
||||
CloneTimeout time.Duration
|
||||
|
||||
// PreCloneCheck represents any checks to run
|
||||
// prior to building, such as verifying build
|
||||
// dependencies (e.g. whether Go is installed)
|
||||
PreCloneCheck Checker
|
||||
|
||||
// PreCloneCheckTimeout overrides default timeout
|
||||
// for the PreCloneCheck
|
||||
PreCloneCheckTimeout time.Duration
|
||||
|
||||
// Build represents how to build the product
|
||||
// after checking out the source code
|
||||
Build Builder
|
||||
|
||||
// BuildTimeout overrides default timeout
|
||||
// for the Builder
|
||||
BuildTimeout time.Duration
|
||||
}
|
||||
|
||||
type Checker interface {
|
||||
Check(ctx context.Context) error
|
||||
}
|
||||
|
||||
type Builder interface {
|
||||
Build(ctx context.Context, repoDir, targetDir, binaryName string) (string, error)
|
||||
Remove(ctx context.Context) error
|
||||
}
|
55
vendor/github.com/hashicorp/hc-install/product/terraform.go
generated
vendored
Normal file
55
vendor/github.com/hashicorp/hc-install/product/terraform.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/hc-install/internal/build"
|
||||
)
|
||||
|
||||
var (
|
||||
simpleVersionRe = `v?(?P<version>[0-9]+(?:\.[0-9]+)*(?:-[A-Za-z0-9\.]+)?)`
|
||||
|
||||
terraformVersionOutputRe = regexp.MustCompile(`Terraform ` + simpleVersionRe)
|
||||
)
|
||||
|
||||
var Terraform = Product{
|
||||
Name: "terraform",
|
||||
BinaryName: func() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return "terraform.exe"
|
||||
}
|
||||
return "terraform"
|
||||
},
|
||||
GetVersion: func(ctx context.Context, path string) (*version.Version, error) {
|
||||
cmd := exec.CommandContext(ctx, path, "version")
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stdout := strings.TrimSpace(string(out))
|
||||
|
||||
submatches := terraformVersionOutputRe.FindStringSubmatch(stdout)
|
||||
if len(submatches) != 2 {
|
||||
return nil, fmt.Errorf("unexpected number of version matches %d for %s", len(submatches), stdout)
|
||||
}
|
||||
v, err := version.NewVersion(submatches[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse version %q: %w", submatches[1], err)
|
||||
}
|
||||
|
||||
return v, err
|
||||
},
|
||||
BuildInstructions: &BuildInstructions{
|
||||
GitRepoURL: "https://github.com/hashicorp/terraform.git",
|
||||
PreCloneCheck: &build.GoIsInstalled{},
|
||||
Build: &build.GoBuild{DetectVendoring: true},
|
||||
},
|
||||
}
|
147
vendor/github.com/hashicorp/hc-install/releases/exact_version.go
generated
vendored
Normal file
147
vendor/github.com/hashicorp/hc-install/releases/exact_version.go
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
||||
package releases
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/hc-install/internal/pubkey"
|
||||
rjson "github.com/hashicorp/hc-install/internal/releasesjson"
|
||||
isrc "github.com/hashicorp/hc-install/internal/src"
|
||||
"github.com/hashicorp/hc-install/internal/validators"
|
||||
"github.com/hashicorp/hc-install/product"
|
||||
)
|
||||
|
||||
// ExactVersion installs the given Version of product
|
||||
// to OS temp directory, or to InstallDir (if not empty)
|
||||
type ExactVersion struct {
|
||||
Product product.Product
|
||||
Version *version.Version
|
||||
InstallDir string
|
||||
Timeout time.Duration
|
||||
|
||||
SkipChecksumVerification bool
|
||||
|
||||
// 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
|
||||
|
||||
apiBaseURL string
|
||||
logger *log.Logger
|
||||
pathsToRemove []string
|
||||
}
|
||||
|
||||
func (*ExactVersion) IsSourceImpl() isrc.InstallSrcSigil {
|
||||
return isrc.InstallSrcSigil{}
|
||||
}
|
||||
|
||||
func (ev *ExactVersion) SetLogger(logger *log.Logger) {
|
||||
ev.logger = logger
|
||||
}
|
||||
|
||||
func (ev *ExactVersion) log() *log.Logger {
|
||||
if ev.logger == nil {
|
||||
return discardLogger
|
||||
}
|
||||
return ev.logger
|
||||
}
|
||||
|
||||
func (ev *ExactVersion) Validate() error {
|
||||
if !validators.IsProductNameValid(ev.Product.Name) {
|
||||
return fmt.Errorf("invalid product name: %q", ev.Product.Name)
|
||||
}
|
||||
|
||||
if !validators.IsBinaryNameValid(ev.Product.BinaryName()) {
|
||||
return fmt.Errorf("invalid binary name: %q", ev.Product.BinaryName())
|
||||
}
|
||||
|
||||
if ev.Version == nil {
|
||||
return fmt.Errorf("unknown version")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ev *ExactVersion) Install(ctx context.Context) (string, error) {
|
||||
timeout := defaultInstallTimeout
|
||||
if ev.Timeout > 0 {
|
||||
timeout = ev.Timeout
|
||||
}
|
||||
ctx, cancelFunc := context.WithTimeout(ctx, timeout)
|
||||
defer cancelFunc()
|
||||
|
||||
if ev.pathsToRemove == nil {
|
||||
ev.pathsToRemove = make([]string, 0)
|
||||
}
|
||||
|
||||
dstDir := ev.InstallDir
|
||||
if dstDir == "" {
|
||||
var err error
|
||||
dirName := fmt.Sprintf("%s_*", ev.Product.Name)
|
||||
dstDir, err = ioutil.TempDir("", dirName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ev.pathsToRemove = append(ev.pathsToRemove, dstDir)
|
||||
ev.log().Printf("created new temp dir at %s", dstDir)
|
||||
}
|
||||
ev.log().Printf("will install into dir at %s", dstDir)
|
||||
|
||||
rels := rjson.NewReleases()
|
||||
if ev.apiBaseURL != "" {
|
||||
rels.BaseURL = ev.apiBaseURL
|
||||
}
|
||||
rels.SetLogger(ev.log())
|
||||
pv, err := rels.GetProductVersion(ctx, ev.Product.Name, ev.Version)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
d := &rjson.Downloader{
|
||||
Logger: ev.log(),
|
||||
VerifyChecksum: !ev.SkipChecksumVerification,
|
||||
ArmoredPublicKey: pubkey.DefaultPublicKey,
|
||||
BaseURL: rels.BaseURL,
|
||||
}
|
||||
if ev.ArmoredPublicKey != "" {
|
||||
d.ArmoredPublicKey = ev.ArmoredPublicKey
|
||||
}
|
||||
if ev.apiBaseURL != "" {
|
||||
d.BaseURL = ev.apiBaseURL
|
||||
}
|
||||
|
||||
err = d.DownloadAndUnpack(ctx, pv, dstDir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
execPath := filepath.Join(dstDir, ev.Product.BinaryName())
|
||||
|
||||
ev.pathsToRemove = append(ev.pathsToRemove, execPath)
|
||||
|
||||
ev.log().Printf("changing perms of %s", execPath)
|
||||
err = os.Chmod(execPath, 0o700)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return execPath, nil
|
||||
}
|
||||
|
||||
func (ev *ExactVersion) Remove(ctx context.Context) error {
|
||||
if ev.pathsToRemove != nil {
|
||||
for _, path := range ev.pathsToRemove {
|
||||
err := os.RemoveAll(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
171
vendor/github.com/hashicorp/hc-install/releases/latest_version.go
generated
vendored
Normal file
171
vendor/github.com/hashicorp/hc-install/releases/latest_version.go
generated
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
package releases
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/hc-install/internal/pubkey"
|
||||
rjson "github.com/hashicorp/hc-install/internal/releasesjson"
|
||||
isrc "github.com/hashicorp/hc-install/internal/src"
|
||||
"github.com/hashicorp/hc-install/internal/validators"
|
||||
"github.com/hashicorp/hc-install/product"
|
||||
)
|
||||
|
||||
type LatestVersion struct {
|
||||
Product product.Product
|
||||
Constraints version.Constraints
|
||||
InstallDir string
|
||||
Timeout time.Duration
|
||||
IncludePrereleases bool
|
||||
|
||||
SkipChecksumVerification bool
|
||||
|
||||
// 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
|
||||
|
||||
apiBaseURL string
|
||||
logger *log.Logger
|
||||
pathsToRemove []string
|
||||
}
|
||||
|
||||
func (*LatestVersion) IsSourceImpl() isrc.InstallSrcSigil {
|
||||
return isrc.InstallSrcSigil{}
|
||||
}
|
||||
|
||||
func (lv *LatestVersion) SetLogger(logger *log.Logger) {
|
||||
lv.logger = logger
|
||||
}
|
||||
|
||||
func (lv *LatestVersion) log() *log.Logger {
|
||||
if lv.logger == nil {
|
||||
return discardLogger
|
||||
}
|
||||
return lv.logger
|
||||
}
|
||||
|
||||
func (lv *LatestVersion) Validate() error {
|
||||
if !validators.IsProductNameValid(lv.Product.Name) {
|
||||
return fmt.Errorf("invalid product name: %q", lv.Product.Name)
|
||||
}
|
||||
|
||||
if !validators.IsBinaryNameValid(lv.Product.BinaryName()) {
|
||||
return fmt.Errorf("invalid binary name: %q", lv.Product.BinaryName())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lv *LatestVersion) Install(ctx context.Context) (string, error) {
|
||||
timeout := defaultInstallTimeout
|
||||
if lv.Timeout > 0 {
|
||||
timeout = lv.Timeout
|
||||
}
|
||||
ctx, cancelFunc := context.WithTimeout(ctx, timeout)
|
||||
defer cancelFunc()
|
||||
|
||||
if lv.pathsToRemove == nil {
|
||||
lv.pathsToRemove = make([]string, 0)
|
||||
}
|
||||
|
||||
dstDir := lv.InstallDir
|
||||
if dstDir == "" {
|
||||
var err error
|
||||
dirName := fmt.Sprintf("%s_*", lv.Product.Name)
|
||||
dstDir, err = ioutil.TempDir("", dirName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
lv.pathsToRemove = append(lv.pathsToRemove, dstDir)
|
||||
lv.log().Printf("created new temp dir at %s", dstDir)
|
||||
}
|
||||
lv.log().Printf("will install into dir at %s", dstDir)
|
||||
|
||||
rels := rjson.NewReleases()
|
||||
if lv.apiBaseURL != "" {
|
||||
rels.BaseURL = lv.apiBaseURL
|
||||
}
|
||||
rels.SetLogger(lv.log())
|
||||
versions, err := rels.ListProductVersions(ctx, lv.Product.Name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(versions) == 0 {
|
||||
return "", fmt.Errorf("no versions found for %q", lv.Product.Name)
|
||||
}
|
||||
|
||||
versionToInstall, ok := lv.findLatestMatchingVersion(versions, lv.Constraints)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("no matching version found for %q", lv.Constraints)
|
||||
}
|
||||
|
||||
d := &rjson.Downloader{
|
||||
Logger: lv.log(),
|
||||
VerifyChecksum: !lv.SkipChecksumVerification,
|
||||
ArmoredPublicKey: pubkey.DefaultPublicKey,
|
||||
BaseURL: rels.BaseURL,
|
||||
}
|
||||
if lv.ArmoredPublicKey != "" {
|
||||
d.ArmoredPublicKey = lv.ArmoredPublicKey
|
||||
}
|
||||
if lv.apiBaseURL != "" {
|
||||
d.BaseURL = lv.apiBaseURL
|
||||
}
|
||||
err = d.DownloadAndUnpack(ctx, versionToInstall, dstDir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
execPath := filepath.Join(dstDir, lv.Product.BinaryName())
|
||||
|
||||
lv.pathsToRemove = append(lv.pathsToRemove, execPath)
|
||||
|
||||
lv.log().Printf("changing perms of %s", execPath)
|
||||
err = os.Chmod(execPath, 0o700)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return execPath, nil
|
||||
}
|
||||
|
||||
func (lv *LatestVersion) Remove(ctx context.Context) error {
|
||||
if lv.pathsToRemove != nil {
|
||||
for _, path := range lv.pathsToRemove {
|
||||
err := os.RemoveAll(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (lv *LatestVersion) findLatestMatchingVersion(pvs rjson.ProductVersionsMap, vc version.Constraints) (*rjson.ProductVersion, bool) {
|
||||
versions := make(version.Collection, 0)
|
||||
for _, pv := range pvs.AsSlice() {
|
||||
if !lv.IncludePrereleases && pv.Version.Prerelease() != "" {
|
||||
// skip prereleases if desired
|
||||
continue
|
||||
}
|
||||
|
||||
versions = append(versions, pv.Version)
|
||||
}
|
||||
|
||||
if len(versions) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
sort.Stable(versions)
|
||||
latestVersion := versions[len(versions)-1]
|
||||
|
||||
return pvs[latestVersion.Original()], true
|
||||
}
|
13
vendor/github.com/hashicorp/hc-install/releases/releases.go
generated
vendored
Normal file
13
vendor/github.com/hashicorp/hc-install/releases/releases.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
package releases
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultInstallTimeout = 30 * time.Second
|
||||
defaultListTimeout = 10 * time.Second
|
||||
discardLogger = log.New(ioutil.Discard, "", 0)
|
||||
)
|
82
vendor/github.com/hashicorp/hc-install/releases/versions.go
generated
vendored
Normal file
82
vendor/github.com/hashicorp/hc-install/releases/versions.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
package releases
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
rjson "github.com/hashicorp/hc-install/internal/releasesjson"
|
||||
"github.com/hashicorp/hc-install/internal/validators"
|
||||
"github.com/hashicorp/hc-install/product"
|
||||
"github.com/hashicorp/hc-install/src"
|
||||
)
|
||||
|
||||
// Versions allows listing all versions of a product
|
||||
// which match Constraints
|
||||
type Versions struct {
|
||||
Product product.Product
|
||||
Constraints version.Constraints
|
||||
|
||||
ListTimeout time.Duration
|
||||
|
||||
// Install represents configuration for installation of any listed version
|
||||
Install InstallationOptions
|
||||
}
|
||||
|
||||
type InstallationOptions struct {
|
||||
Timeout time.Duration
|
||||
Dir string
|
||||
|
||||
SkipChecksumVerification bool
|
||||
|
||||
// ArmoredPublicKey is a public PGP key in ASCII/armor format to use
|
||||
// instead of built-in pubkey to verify signature of downloaded checksums
|
||||
// during installation
|
||||
ArmoredPublicKey string
|
||||
}
|
||||
|
||||
func (v *Versions) List(ctx context.Context) ([]src.Source, error) {
|
||||
if !validators.IsProductNameValid(v.Product.Name) {
|
||||
return nil, fmt.Errorf("invalid product name: %q", v.Product.Name)
|
||||
}
|
||||
|
||||
timeout := defaultListTimeout
|
||||
if v.ListTimeout > 0 {
|
||||
timeout = v.ListTimeout
|
||||
}
|
||||
ctx, cancelFunc := context.WithTimeout(ctx, timeout)
|
||||
defer cancelFunc()
|
||||
|
||||
r := rjson.NewReleases()
|
||||
pvs, err := r.ListProductVersions(ctx, v.Product.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
versions := pvs.AsSlice()
|
||||
sort.Stable(versions)
|
||||
|
||||
installables := make([]src.Source, 0)
|
||||
for _, pv := range versions {
|
||||
if !v.Constraints.Check(pv.Version) {
|
||||
// skip version which doesn't match constraint
|
||||
continue
|
||||
}
|
||||
|
||||
ev := &ExactVersion{
|
||||
Product: v.Product,
|
||||
Version: pv.Version,
|
||||
InstallDir: v.Install.Dir,
|
||||
Timeout: v.Install.Timeout,
|
||||
|
||||
ArmoredPublicKey: v.Install.ArmoredPublicKey,
|
||||
SkipChecksumVerification: v.Install.SkipChecksumVerification,
|
||||
}
|
||||
|
||||
installables = append(installables, ev)
|
||||
}
|
||||
|
||||
return installables, nil
|
||||
}
|
42
vendor/github.com/hashicorp/hc-install/src/src.go
generated
vendored
Normal file
42
vendor/github.com/hashicorp/hc-install/src/src.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
package src
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
isrc "github.com/hashicorp/hc-install/internal/src"
|
||||
)
|
||||
|
||||
// Source represents an installer, finder, or builder
|
||||
type Source interface {
|
||||
IsSourceImpl() isrc.InstallSrcSigil
|
||||
}
|
||||
|
||||
type Installable interface {
|
||||
Source
|
||||
Install(ctx context.Context) (string, error)
|
||||
}
|
||||
|
||||
type Findable interface {
|
||||
Source
|
||||
Find(ctx context.Context) (string, error)
|
||||
}
|
||||
|
||||
type Buildable interface {
|
||||
Source
|
||||
Build(ctx context.Context) (string, error)
|
||||
}
|
||||
|
||||
type Validatable interface {
|
||||
Source
|
||||
Validate() error
|
||||
}
|
||||
|
||||
type Removable interface {
|
||||
Source
|
||||
Remove(ctx context.Context) error
|
||||
}
|
||||
|
||||
type LoggerSettable interface {
|
||||
SetLogger(logger *log.Logger)
|
||||
}
|
Reference in New Issue
Block a user