mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-13 10:00:56 +00:00
manually add dependency on go-getter
This commit is contained in:
363
vendor/github.com/hashicorp/go-cleanhttp/LICENSE
generated
vendored
Normal file
363
vendor/github.com/hashicorp/go-cleanhttp/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,363 @@
|
||||
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.
|
||||
|
||||
30
vendor/github.com/hashicorp/go-cleanhttp/README.md
generated
vendored
Normal file
30
vendor/github.com/hashicorp/go-cleanhttp/README.md
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# cleanhttp
|
||||
|
||||
Functions for accessing "clean" Go http.Client values
|
||||
|
||||
-------------
|
||||
|
||||
The Go standard library contains a default `http.Client` called
|
||||
`http.DefaultClient`. It is a common idiom in Go code to start with
|
||||
`http.DefaultClient` and tweak it as necessary, and in fact, this is
|
||||
encouraged; from the `http` package documentation:
|
||||
|
||||
> The Client's Transport typically has internal state (cached TCP connections),
|
||||
so Clients should be reused instead of created as needed. Clients are safe for
|
||||
concurrent use by multiple goroutines.
|
||||
|
||||
Unfortunately, this is a shared value, and it is not uncommon for libraries to
|
||||
assume that they are free to modify it at will. With enough dependencies, it
|
||||
can be very easy to encounter strange problems and race conditions due to
|
||||
manipulation of this shared value across libraries and goroutines (clients are
|
||||
safe for concurrent use, but writing values to the client struct itself is not
|
||||
protected).
|
||||
|
||||
Making things worse is the fact that a bare `http.Client` will use a default
|
||||
`http.Transport` called `http.DefaultTransport`, which is another global value
|
||||
that behaves the same way. So it is not simply enough to replace
|
||||
`http.DefaultClient` with `&http.Client{}`.
|
||||
|
||||
This repository provides some simple functions to get a "clean" `http.Client`
|
||||
-- one that uses the same default values as the Go standard library, but
|
||||
returns a client that does not share any state with other clients.
|
||||
57
vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
generated
vendored
Normal file
57
vendor/github.com/hashicorp/go-cleanhttp/cleanhttp.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package cleanhttp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DefaultTransport returns a new http.Transport with similar default values to
|
||||
// http.DefaultTransport, but with idle connections and keepalives disabled.
|
||||
func DefaultTransport() *http.Transport {
|
||||
transport := DefaultPooledTransport()
|
||||
transport.DisableKeepAlives = true
|
||||
transport.MaxIdleConnsPerHost = -1
|
||||
return transport
|
||||
}
|
||||
|
||||
// DefaultPooledTransport returns a new http.Transport with similar default
|
||||
// values to http.DefaultTransport. Do not use this for transient transports as
|
||||
// it can leak file descriptors over time. Only use this for transports that
|
||||
// will be re-used for the same host(s).
|
||||
func DefaultPooledTransport() *http.Transport {
|
||||
transport := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}).DialContext,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1,
|
||||
}
|
||||
return transport
|
||||
}
|
||||
|
||||
// DefaultClient returns a new http.Client with similar default values to
|
||||
// http.Client, but with a non-shared Transport, idle connections disabled, and
|
||||
// keepalives disabled.
|
||||
func DefaultClient() *http.Client {
|
||||
return &http.Client{
|
||||
Transport: DefaultTransport(),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultPooledClient returns a new http.Client with similar default values to
|
||||
// http.Client, but with a shared Transport. Do not use this function for
|
||||
// transient clients as it can leak file descriptors over time. Only use this
|
||||
// for clients that will be re-used for the same host(s).
|
||||
func DefaultPooledClient() *http.Client {
|
||||
return &http.Client{
|
||||
Transport: DefaultPooledTransport(),
|
||||
}
|
||||
}
|
||||
20
vendor/github.com/hashicorp/go-cleanhttp/doc.go
generated
vendored
Normal file
20
vendor/github.com/hashicorp/go-cleanhttp/doc.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Package cleanhttp offers convenience utilities for acquiring "clean"
|
||||
// http.Transport and http.Client structs.
|
||||
//
|
||||
// Values set on http.DefaultClient and http.DefaultTransport affect all
|
||||
// callers. This can have detrimental effects, esepcially in TLS contexts,
|
||||
// where client or root certificates set to talk to multiple endpoints can end
|
||||
// up displacing each other, leading to hard-to-debug issues. This package
|
||||
// provides non-shared http.Client and http.Transport structs to ensure that
|
||||
// the configuration will not be overwritten by other parts of the application
|
||||
// or dependencies.
|
||||
//
|
||||
// The DefaultClient and DefaultTransport functions disable idle connections
|
||||
// and keepalives. Without ensuring that idle connections are closed before
|
||||
// garbage collection, short-term clients/transports can leak file descriptors,
|
||||
// eventually leading to "too many open files" errors. If you will be
|
||||
// connecting to the same hosts repeatedly from the same client, you can use
|
||||
// DefaultPooledClient to receive a client that has connection pooling
|
||||
// semantics similar to http.DefaultClient.
|
||||
//
|
||||
package cleanhttp
|
||||
43
vendor/github.com/hashicorp/go-cleanhttp/handlers.go
generated
vendored
Normal file
43
vendor/github.com/hashicorp/go-cleanhttp/handlers.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package cleanhttp
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// HandlerInput provides input options to cleanhttp's handlers
|
||||
type HandlerInput struct {
|
||||
ErrStatus int
|
||||
}
|
||||
|
||||
// PrintablePathCheckHandler is a middleware that ensures the request path
|
||||
// contains only printable runes.
|
||||
func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler {
|
||||
// Nil-check on input to make it optional
|
||||
if input == nil {
|
||||
input = &HandlerInput{
|
||||
ErrStatus: http.StatusBadRequest,
|
||||
}
|
||||
}
|
||||
|
||||
// Default to http.StatusBadRequest on error
|
||||
if input.ErrStatus == 0 {
|
||||
input.ErrStatus = http.StatusBadRequest
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Check URL path for non-printable characters
|
||||
idx := strings.IndexFunc(r.URL.Path, func(c rune) bool {
|
||||
return !unicode.IsPrint(c)
|
||||
})
|
||||
|
||||
if idx != -1 {
|
||||
w.WriteHeader(input.ErrStatus)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
})
|
||||
}
|
||||
72
vendor/github.com/hashicorp/go-cleanhttp/handlers_test.go
generated
vendored
Normal file
72
vendor/github.com/hashicorp/go-cleanhttp/handlers_test.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
package cleanhttp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPrintablePathCheckHandler(t *testing.T) {
|
||||
getTestHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "Hello, client")
|
||||
})
|
||||
|
||||
cases := map[string]struct {
|
||||
path string
|
||||
expectCode int
|
||||
input *HandlerInput
|
||||
}{
|
||||
"valid nil input": {
|
||||
path: "/valid",
|
||||
expectCode: http.StatusOK,
|
||||
input: nil,
|
||||
},
|
||||
|
||||
"valid empty error status": {
|
||||
path: "/valid",
|
||||
expectCode: http.StatusOK,
|
||||
input: &HandlerInput{},
|
||||
},
|
||||
|
||||
"invalid newline": {
|
||||
path: "/invalid\n",
|
||||
expectCode: http.StatusBadRequest,
|
||||
},
|
||||
|
||||
"invalid carriage return": {
|
||||
path: "/invalid\r",
|
||||
expectCode: http.StatusBadRequest,
|
||||
},
|
||||
|
||||
"invalid null": {
|
||||
path: "/invalid\x00",
|
||||
expectCode: http.StatusBadRequest,
|
||||
},
|
||||
|
||||
"invalid alternate status": {
|
||||
path: "/invalid\n",
|
||||
expectCode: http.StatusInternalServerError,
|
||||
input: &HandlerInput{
|
||||
ErrStatus: http.StatusInternalServerError,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// Create test HTTP server
|
||||
ts := httptest.NewServer(PrintablePathCheckHandler(getTestHandler, tc.input))
|
||||
defer ts.Close()
|
||||
|
||||
res, err := http.Get(ts.URL + tc.path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if tc.expectCode != res.StatusCode {
|
||||
t.Fatalf("expected %d, got :%d", tc.expectCode, res.StatusCode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
23
vendor/github.com/hashicorp/go-getter/.travis.yml
generated
vendored
Normal file
23
vendor/github.com/hashicorp/go-getter/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
sudo: false
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:git-core/ppa'
|
||||
packages:
|
||||
- git
|
||||
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- master
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: master
|
||||
354
vendor/github.com/hashicorp/go-getter/LICENSE
generated
vendored
Normal file
354
vendor/github.com/hashicorp/go-getter/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
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.
|
||||
|
||||
301
vendor/github.com/hashicorp/go-getter/README.md
generated
vendored
Normal file
301
vendor/github.com/hashicorp/go-getter/README.md
generated
vendored
Normal file
@@ -0,0 +1,301 @@
|
||||
# go-getter
|
||||
|
||||
[][travis]
|
||||
[][appveyor]
|
||||
[][godocs]
|
||||
|
||||
[travis]: http://travis-ci.org/hashicorp/go-getter
|
||||
[godocs]: http://godoc.org/github.com/hashicorp/go-getter
|
||||
[appveyor]: https://ci.appveyor.com/project/hashicorp/go-getter/branch/master
|
||||
|
||||
go-getter is a library for Go (golang) for downloading files or directories
|
||||
from various sources using a URL as the primary form of input.
|
||||
|
||||
The power of this library is being flexible in being able to download
|
||||
from a number of different sources (file paths, Git, HTTP, Mercurial, etc.)
|
||||
using a single string as input. This removes the burden of knowing how to
|
||||
download from a variety of sources from the implementer.
|
||||
|
||||
The concept of a _detector_ automatically turns invalid URLs into proper
|
||||
URLs. For example: "github.com/hashicorp/go-getter" would turn into a
|
||||
Git URL. Or "./foo" would turn into a file URL. These are extensible.
|
||||
|
||||
This library is used by [Terraform](https://terraform.io) for
|
||||
downloading modules and [Nomad](https://nomadproject.io) for downloading
|
||||
binaries.
|
||||
|
||||
## Installation and Usage
|
||||
|
||||
Package documentation can be found on
|
||||
[GoDoc](http://godoc.org/github.com/hashicorp/go-getter).
|
||||
|
||||
Installation can be done with a normal `go get`:
|
||||
|
||||
```
|
||||
$ go get github.com/hashicorp/go-getter
|
||||
```
|
||||
|
||||
go-getter also has a command you can use to test URL strings:
|
||||
|
||||
```
|
||||
$ go install github.com/hashicorp/go-getter/cmd/go-getter
|
||||
...
|
||||
|
||||
$ go-getter github.com/foo/bar ./foo
|
||||
...
|
||||
```
|
||||
|
||||
The command is useful for verifying URL structures.
|
||||
|
||||
## URL Format
|
||||
|
||||
go-getter uses a single string URL as input to download from a variety of
|
||||
protocols. go-getter has various "tricks" with this URL to do certain things.
|
||||
This section documents the URL format.
|
||||
|
||||
### Supported Protocols and Detectors
|
||||
|
||||
**Protocols** are used to download files/directories using a specific
|
||||
mechanism. Example protocols are Git and HTTP.
|
||||
|
||||
**Detectors** are used to transform a valid or invalid URL into another
|
||||
URL if it matches a certain pattern. Example: "github.com/user/repo" is
|
||||
automatically transformed into a fully valid Git URL. This allows go-getter
|
||||
to be very user friendly.
|
||||
|
||||
go-getter out of the box supports the following protocols. Additional protocols
|
||||
can be augmented at runtime by implementing the `Getter` interface.
|
||||
|
||||
* Local files
|
||||
* Git
|
||||
* Mercurial
|
||||
* HTTP
|
||||
* Amazon S3
|
||||
|
||||
In addition to the above protocols, go-getter has what are called "detectors."
|
||||
These take a URL and attempt to automatically choose the best protocol for
|
||||
it, which might involve even changing the protocol. The following detection
|
||||
is built-in by default:
|
||||
|
||||
* File paths such as "./foo" are automatically changed to absolute
|
||||
file URLs.
|
||||
* GitHub URLs, such as "github.com/mitchellh/vagrant" are automatically
|
||||
changed to Git protocol over HTTP.
|
||||
* BitBucket URLs, such as "bitbucket.org/mitchellh/vagrant" are automatically
|
||||
changed to a Git or mercurial protocol using the BitBucket API.
|
||||
|
||||
### Forced Protocol
|
||||
|
||||
In some cases, the protocol to use is ambiguous depending on the source
|
||||
URL. For example, "http://github.com/mitchellh/vagrant.git" could reference
|
||||
an HTTP URL or a Git URL. Forced protocol syntax is used to disambiguate this
|
||||
URL.
|
||||
|
||||
Forced protocol can be done by prefixing the URL with the protocol followed
|
||||
by double colons. For example: `git::http://github.com/mitchellh/vagrant.git`
|
||||
would download the given HTTP URL using the Git protocol.
|
||||
|
||||
Forced protocols will also override any detectors.
|
||||
|
||||
In the absense of a forced protocol, detectors may be run on the URL, transforming
|
||||
the protocol anyways. The above example would've used the Git protocol either
|
||||
way since the Git detector would've detected it was a GitHub URL.
|
||||
|
||||
### Protocol-Specific Options
|
||||
|
||||
Each protocol can support protocol-specific options to configure that
|
||||
protocol. For example, the `git` protocol supports specifying a `ref`
|
||||
query parameter that tells it what ref to checkout for that Git
|
||||
repository.
|
||||
|
||||
The options are specified as query parameters on the URL (or URL-like string)
|
||||
given to go-getter. Using the Git example above, the URL below is a valid
|
||||
input to go-getter:
|
||||
|
||||
github.com/hashicorp/go-getter?ref=abcd1234
|
||||
|
||||
The protocol-specific options are documented below the URL format
|
||||
section. But because they are part of the URL, we point it out here so
|
||||
you know they exist.
|
||||
|
||||
### Subdirectories
|
||||
|
||||
If you want to download only a specific subdirectory from a downloaded
|
||||
directory, you can specify a subdirectory after a double-slash `//`.
|
||||
go-getter will first download the URL specified _before_ the double-slash
|
||||
(as if you didn't specify a double-slash), but will then copy the
|
||||
path after the double slash into the target directory.
|
||||
|
||||
For example, if you're downloading this GitHub repository, but you only
|
||||
want to download the `test-fixtures` directory, you can do the following:
|
||||
|
||||
```
|
||||
https://github.com/hashicorp/go-getter.git//test-fixtures
|
||||
```
|
||||
|
||||
If you downloaded this to the `/tmp` directory, then the file
|
||||
`/tmp/archive.gz` would exist. Notice that this file is in the `test-fixtures`
|
||||
directory in this repository, but because we specified a subdirectory,
|
||||
go-getter automatically copied only that directory contents.
|
||||
|
||||
Subdirectory paths may contain may also use filesystem glob patterns.
|
||||
The path must match _exactly one_ entry or go-getter will return an error.
|
||||
This is useful if you're not sure the exact directory name but it follows
|
||||
a predictable naming structure.
|
||||
|
||||
For example, the following URL would also work:
|
||||
|
||||
```
|
||||
https://github.com/hashicorp/go-getter.git//test-*
|
||||
```
|
||||
|
||||
### Checksumming
|
||||
|
||||
For file downloads of any protocol, go-getter can automatically verify
|
||||
a checksum for you. Note that checksumming only works for downloading files,
|
||||
not directories, but checksumming will work for any protocol.
|
||||
|
||||
To checksum a file, append a `checksum` query parameter to the URL.
|
||||
The paramter value should be in the format of `type:value`, where
|
||||
type is "md5", "sha1", "sha256", or "sha512". The "value" should be
|
||||
the actual checksum value. go-getter will parse out this query parameter
|
||||
automatically and use it to verify the checksum. An example URL
|
||||
is shown below:
|
||||
|
||||
```
|
||||
./foo.txt?checksum=md5:b7d96c89d09d9e204f5fedc4d5d55b21
|
||||
```
|
||||
|
||||
The checksum query parameter is never sent to the backend protocol
|
||||
implementation. It is used at a higher level by go-getter itself.
|
||||
|
||||
### Unarchiving
|
||||
|
||||
go-getter will automatically unarchive files into a file or directory
|
||||
based on the extension of the file being requested (over any protocol).
|
||||
This works for both file and directory downloads.
|
||||
|
||||
go-getter looks for an `archive` query parameter to specify the format of
|
||||
the archive. If this isn't specified, go-getter will use the extension of
|
||||
the path to see if it appears archived. Unarchiving can be explicitly
|
||||
disabled by setting the `archive` query parameter to `false`.
|
||||
|
||||
The following archive formats are supported:
|
||||
|
||||
* `tar.gz` and `tgz`
|
||||
* `tar.bz2` and `tbz2`
|
||||
* `tar.xz` and `txz`
|
||||
* `zip`
|
||||
* `gz`
|
||||
* `bz2`
|
||||
* `xz`
|
||||
|
||||
For example, an example URL is shown below:
|
||||
|
||||
```
|
||||
./foo.zip
|
||||
```
|
||||
|
||||
This will automatically be inferred to be a ZIP file and will be extracted.
|
||||
You can also be explicit about the archive type:
|
||||
|
||||
```
|
||||
./some/other/path?archive=zip
|
||||
```
|
||||
|
||||
And finally, you can disable archiving completely:
|
||||
|
||||
```
|
||||
./some/path?archive=false
|
||||
```
|
||||
|
||||
You can combine unarchiving with the other features of go-getter such
|
||||
as checksumming. The special `archive` query parameter will be removed
|
||||
from the URL before going to the final protocol downloader.
|
||||
|
||||
## Protocol-Specific Options
|
||||
|
||||
This section documents the protocol-specific options that can be specified
|
||||
for go-getter. These options should be appended to the input as normal query
|
||||
parameters. Depending on the usage of go-getter, applications may provide
|
||||
alternate ways of inputting options. For example, [Nomad](https://www.nomadproject.io)
|
||||
provides a nice options block for specifying options rather than in the URL.
|
||||
|
||||
## General (All Protocols)
|
||||
|
||||
The options below are available to all protocols:
|
||||
|
||||
* `archive` - The archive format to use to unarchive this file, or "" (empty
|
||||
string) to disable unarchiving. For more details, see the complete section
|
||||
on archive support above.
|
||||
|
||||
* `checksum` - Checksum to verify the downloaded file or archive. See
|
||||
the entire section on checksumming above for format and more details.
|
||||
|
||||
* `filename` - When in file download mode, allows specifying the name of the
|
||||
downloaded file on disk. Has no effect in directory mode.
|
||||
|
||||
### Local Files (`file`)
|
||||
|
||||
None
|
||||
|
||||
### Git (`git`)
|
||||
|
||||
* `ref` - The Git ref to checkout. This is a ref, so it can point to
|
||||
a commit SHA, a branch name, etc. If it is a named ref such as a branch
|
||||
name, go-getter will update it to the latest on each get.
|
||||
|
||||
* `sshkey` - An SSH private key to use during clones. The provided key must
|
||||
be a base64-encoded string. For example, to generate a suitable `sshkey`
|
||||
from a private key file on disk, you would run `base64 -w0 <file>`.
|
||||
|
||||
**Note**: Git 2.3+ is required to use this feature.
|
||||
|
||||
### Mercurial (`hg`)
|
||||
|
||||
* `rev` - The Mercurial revision to checkout.
|
||||
|
||||
### HTTP (`http`)
|
||||
|
||||
#### Basic Authentication
|
||||
|
||||
To use HTTP basic authentication with go-getter, simply prepend `username:password@` to the
|
||||
hostname in the URL such as `https://Aladdin:OpenSesame@www.example.com/index.html`. All special
|
||||
characters, including the username and password, must be URL encoded.
|
||||
|
||||
### S3 (`s3`)
|
||||
|
||||
S3 takes various access configurations in the URL. Note that it will also
|
||||
read these from standard AWS environment variables if they're set. S3 compliant servers like Minio
|
||||
are also supported. If the query parameters are present, these take priority.
|
||||
|
||||
* `aws_access_key_id` - AWS access key.
|
||||
* `aws_access_key_secret` - AWS access key secret.
|
||||
* `aws_access_token` - AWS access token if this is being used.
|
||||
|
||||
#### Using IAM Instance Profiles with S3
|
||||
|
||||
If you use go-getter and want to use an EC2 IAM Instance Profile to avoid
|
||||
using credentials, then just omit these and the profile, if available will
|
||||
be used automatically.
|
||||
|
||||
### Using S3 with Minio
|
||||
If you use go-gitter for Minio support, you must consider the following:
|
||||
|
||||
* `aws_access_key_id` (required) - Minio access key.
|
||||
* `aws_access_key_secret` (required) - Minio access key secret.
|
||||
* `region` (optional - defaults to us-east-1) - Region identifier to use.
|
||||
* `version` (optional - defaults to Minio default) - Configuration file format.
|
||||
|
||||
#### S3 Bucket Examples
|
||||
|
||||
S3 has several addressing schemes used to reference your bucket. These are
|
||||
listed here: http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html#access-bucket-intro
|
||||
|
||||
Some examples for these addressing schemes:
|
||||
- s3::https://s3.amazonaws.com/bucket/foo
|
||||
- s3::https://s3-eu-west-1.amazonaws.com/bucket/foo
|
||||
- bucket.s3.amazonaws.com/foo
|
||||
- bucket.s3-eu-west-1.amazonaws.com/foo/bar
|
||||
- "s3::http://127.0.0.1:9000/test-bucket/hello.txt?aws_access_key_id=KEYID&aws_access_key_secret=SECRETKEY®ion=us-east-2"
|
||||
|
||||
16
vendor/github.com/hashicorp/go-getter/appveyor.yml
generated
vendored
Normal file
16
vendor/github.com/hashicorp/go-getter/appveyor.yml
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
version: "build-{branch}-{build}"
|
||||
image: Visual Studio 2017
|
||||
clone_folder: c:\gopath\github.com\hashicorp\go-getter
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
install:
|
||||
- cmd: >-
|
||||
echo %Path%
|
||||
|
||||
go version
|
||||
|
||||
go env
|
||||
|
||||
go get -d -v -t ./...
|
||||
build_script:
|
||||
- cmd: go test -v ./...
|
||||
350
vendor/github.com/hashicorp/go-getter/client.go
generated
vendored
Normal file
350
vendor/github.com/hashicorp/go-getter/client.go
generated
vendored
Normal file
@@ -0,0 +1,350 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
urlhelper "github.com/hashicorp/go-getter/helper/url"
|
||||
"github.com/hashicorp/go-safetemp"
|
||||
)
|
||||
|
||||
// Client is a client for downloading things.
|
||||
//
|
||||
// Top-level functions such as Get are shortcuts for interacting with a client.
|
||||
// Using a client directly allows more fine-grained control over how downloading
|
||||
// is done, as well as customizing the protocols supported.
|
||||
type Client struct {
|
||||
// Src is the source URL to get.
|
||||
//
|
||||
// Dst is the path to save the downloaded thing as. If Dir is set to
|
||||
// true, then this should be a directory. If the directory doesn't exist,
|
||||
// it will be created for you.
|
||||
//
|
||||
// Pwd is the working directory for detection. If this isn't set, some
|
||||
// detection may fail. Client will not default pwd to the current
|
||||
// working directory for security reasons.
|
||||
Src string
|
||||
Dst string
|
||||
Pwd string
|
||||
|
||||
// Mode is the method of download the client will use. See ClientMode
|
||||
// for documentation.
|
||||
Mode ClientMode
|
||||
|
||||
// Detectors is the list of detectors that are tried on the source.
|
||||
// If this is nil, then the default Detectors will be used.
|
||||
Detectors []Detector
|
||||
|
||||
// Decompressors is the map of decompressors supported by this client.
|
||||
// If this is nil, then the default value is the Decompressors global.
|
||||
Decompressors map[string]Decompressor
|
||||
|
||||
// Getters is the map of protocols supported by this client. If this
|
||||
// is nil, then the default Getters variable will be used.
|
||||
Getters map[string]Getter
|
||||
|
||||
// Dir, if true, tells the Client it is downloading a directory (versus
|
||||
// a single file). This distinction is necessary since filenames and
|
||||
// directory names follow the same format so disambiguating is impossible
|
||||
// without knowing ahead of time.
|
||||
//
|
||||
// WARNING: deprecated. If Mode is set, that will take precedence.
|
||||
Dir bool
|
||||
}
|
||||
|
||||
// Get downloads the configured source to the destination.
|
||||
func (c *Client) Get() error {
|
||||
// Store this locally since there are cases we swap this
|
||||
mode := c.Mode
|
||||
if mode == ClientModeInvalid {
|
||||
if c.Dir {
|
||||
mode = ClientModeDir
|
||||
} else {
|
||||
mode = ClientModeFile
|
||||
}
|
||||
}
|
||||
|
||||
// Default decompressor value
|
||||
decompressors := c.Decompressors
|
||||
if decompressors == nil {
|
||||
decompressors = Decompressors
|
||||
}
|
||||
|
||||
// Detect the URL. This is safe if it is already detected.
|
||||
detectors := c.Detectors
|
||||
if detectors == nil {
|
||||
detectors = Detectors
|
||||
}
|
||||
src, err := Detect(c.Src, c.Pwd, detectors)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Determine if we have a forced protocol, i.e. "git::http://..."
|
||||
force, src := getForcedGetter(src)
|
||||
|
||||
// If there is a subdir component, then we download the root separately
|
||||
// and then copy over the proper subdir.
|
||||
var realDst string
|
||||
dst := c.Dst
|
||||
src, subDir := SourceDirSubdir(src)
|
||||
if subDir != "" {
|
||||
td, tdcloser, err := safetemp.Dir("", "getter")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tdcloser.Close()
|
||||
|
||||
realDst = dst
|
||||
dst = td
|
||||
}
|
||||
|
||||
u, err := urlhelper.Parse(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if force == "" {
|
||||
force = u.Scheme
|
||||
}
|
||||
|
||||
getters := c.Getters
|
||||
if getters == nil {
|
||||
getters = Getters
|
||||
}
|
||||
|
||||
g, ok := getters[force]
|
||||
if !ok {
|
||||
return fmt.Errorf(
|
||||
"download not supported for scheme '%s'", force)
|
||||
}
|
||||
|
||||
// We have magic query parameters that we use to signal different features
|
||||
q := u.Query()
|
||||
|
||||
// Determine if we have an archive type
|
||||
archiveV := q.Get("archive")
|
||||
if archiveV != "" {
|
||||
// Delete the paramter since it is a magic parameter we don't
|
||||
// want to pass on to the Getter
|
||||
q.Del("archive")
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
// If we can parse the value as a bool and it is false, then
|
||||
// set the archive to "-" which should never map to a decompressor
|
||||
if b, err := strconv.ParseBool(archiveV); err == nil && !b {
|
||||
archiveV = "-"
|
||||
}
|
||||
}
|
||||
if archiveV == "" {
|
||||
// We don't appear to... but is it part of the filename?
|
||||
matchingLen := 0
|
||||
for k, _ := range decompressors {
|
||||
if strings.HasSuffix(u.Path, "."+k) && len(k) > matchingLen {
|
||||
archiveV = k
|
||||
matchingLen = len(k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a decompressor, then we need to change the destination
|
||||
// to download to a temporary path. We unarchive this into the final,
|
||||
// real path.
|
||||
var decompressDst string
|
||||
var decompressDir bool
|
||||
decompressor := decompressors[archiveV]
|
||||
if decompressor != nil {
|
||||
// Create a temporary directory to store our archive. We delete
|
||||
// this at the end of everything.
|
||||
td, err := ioutil.TempDir("", "getter")
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error creating temporary directory for archive: %s", err)
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
|
||||
// Swap the download directory to be our temporary path and
|
||||
// store the old values.
|
||||
decompressDst = dst
|
||||
decompressDir = mode != ClientModeFile
|
||||
dst = filepath.Join(td, "archive")
|
||||
mode = ClientModeFile
|
||||
}
|
||||
|
||||
// Determine if we have a checksum
|
||||
var checksumHash hash.Hash
|
||||
var checksumValue []byte
|
||||
if v := q.Get("checksum"); v != "" {
|
||||
// Delete the query parameter if we have it.
|
||||
q.Del("checksum")
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
// Determine the checksum hash type
|
||||
checksumType := ""
|
||||
idx := strings.Index(v, ":")
|
||||
if idx > -1 {
|
||||
checksumType = v[:idx]
|
||||
}
|
||||
switch checksumType {
|
||||
case "md5":
|
||||
checksumHash = md5.New()
|
||||
case "sha1":
|
||||
checksumHash = sha1.New()
|
||||
case "sha256":
|
||||
checksumHash = sha256.New()
|
||||
case "sha512":
|
||||
checksumHash = sha512.New()
|
||||
default:
|
||||
return fmt.Errorf(
|
||||
"unsupported checksum type: %s", checksumType)
|
||||
}
|
||||
|
||||
// Get the remainder of the value and parse it into bytes
|
||||
b, err := hex.DecodeString(v[idx+1:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid checksum: %s", err)
|
||||
}
|
||||
|
||||
// Set our value
|
||||
checksumValue = b
|
||||
}
|
||||
|
||||
if mode == ClientModeAny {
|
||||
// Ask the getter which client mode to use
|
||||
mode, err = g.ClientMode(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Destination is the base name of the URL path in "any" mode when
|
||||
// a file source is detected.
|
||||
if mode == ClientModeFile {
|
||||
filename := filepath.Base(u.Path)
|
||||
|
||||
// Determine if we have a custom file name
|
||||
if v := q.Get("filename"); v != "" {
|
||||
// Delete the query parameter if we have it.
|
||||
q.Del("filename")
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
filename = v
|
||||
}
|
||||
|
||||
dst = filepath.Join(dst, filename)
|
||||
}
|
||||
}
|
||||
|
||||
// If we're not downloading a directory, then just download the file
|
||||
// and return.
|
||||
if mode == ClientModeFile {
|
||||
err := g.GetFile(dst, u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if checksumHash != nil {
|
||||
if err := checksum(dst, checksumHash, checksumValue); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if decompressor != nil {
|
||||
// We have a decompressor, so decompress the current destination
|
||||
// into the final destination with the proper mode.
|
||||
err := decompressor.Decompress(decompressDst, dst, decompressDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Swap the information back
|
||||
dst = decompressDst
|
||||
if decompressDir {
|
||||
mode = ClientModeAny
|
||||
} else {
|
||||
mode = ClientModeFile
|
||||
}
|
||||
}
|
||||
|
||||
// We check the dir value again because it can be switched back
|
||||
// if we were unarchiving. If we're still only Get-ing a file, then
|
||||
// we're done.
|
||||
if mode == ClientModeFile {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// If we're at this point we're either downloading a directory or we've
|
||||
// downloaded and unarchived a directory and we're just checking subdir.
|
||||
// In the case we have a decompressor we don't Get because it was Get
|
||||
// above.
|
||||
if decompressor == nil {
|
||||
// If we're getting a directory, then this is an error. You cannot
|
||||
// checksum a directory. TODO: test
|
||||
if checksumHash != nil {
|
||||
return fmt.Errorf(
|
||||
"checksum cannot be specified for directory download")
|
||||
}
|
||||
|
||||
// We're downloading a directory, which might require a bit more work
|
||||
// if we're specifying a subdir.
|
||||
err := g.Get(dst, u)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error downloading '%s': %s", src, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a subdir, copy that over
|
||||
if subDir != "" {
|
||||
if err := os.RemoveAll(realDst); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(realDst, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Process any globs
|
||||
subDir, err := SubdirGlob(dst, subDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return copyDir(realDst, subDir, false)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// checksum is a simple method to compute the checksum of a source file
|
||||
// and compare it to the given expected value.
|
||||
func checksum(source string, h hash.Hash, v []byte) error {
|
||||
f, err := os.Open(source)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to open file for checksum: %s", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return fmt.Errorf("Failed to hash: %s", err)
|
||||
}
|
||||
|
||||
if actual := h.Sum(nil); !bytes.Equal(actual, v) {
|
||||
return fmt.Errorf(
|
||||
"Checksums did not match.\nExpected: %s\nGot: %s",
|
||||
hex.EncodeToString(v),
|
||||
hex.EncodeToString(actual))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
24
vendor/github.com/hashicorp/go-getter/client_mode.go
generated
vendored
Normal file
24
vendor/github.com/hashicorp/go-getter/client_mode.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package getter
|
||||
|
||||
// ClientMode is the mode that the client operates in.
|
||||
type ClientMode uint
|
||||
|
||||
const (
|
||||
ClientModeInvalid ClientMode = iota
|
||||
|
||||
// ClientModeAny downloads anything it can. In this mode, dst must
|
||||
// be a directory. If src is a file, it is saved into the directory
|
||||
// with the basename of the URL. If src is a directory or archive,
|
||||
// it is unpacked directly into dst.
|
||||
ClientModeAny
|
||||
|
||||
// ClientModeFile downloads a single file. In this mode, dst must
|
||||
// be a file path (doesn't have to exist). src must point to a single
|
||||
// file. It is saved as dst.
|
||||
ClientModeFile
|
||||
|
||||
// ClientModeDir downloads a directory. In this mode, dst must be
|
||||
// a directory path (doesn't have to exist). src must point to an
|
||||
// archive or directory (such as in s3).
|
||||
ClientModeDir
|
||||
)
|
||||
78
vendor/github.com/hashicorp/go-getter/copy_dir.go
generated
vendored
Normal file
78
vendor/github.com/hashicorp/go-getter/copy_dir.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// copyDir copies the src directory contents into dst. Both directories
|
||||
// should already exist.
|
||||
//
|
||||
// If ignoreDot is set to true, then dot-prefixed files/folders are ignored.
|
||||
func copyDir(dst string, src string, ignoreDot bool) error {
|
||||
src, err := filepath.EvalSymlinks(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
walkFn := func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if path == src {
|
||||
return nil
|
||||
}
|
||||
|
||||
if ignoreDot && strings.HasPrefix(filepath.Base(path), ".") {
|
||||
// Skip any dot files
|
||||
if info.IsDir() {
|
||||
return filepath.SkipDir
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// The "path" has the src prefixed to it. We need to join our
|
||||
// destination with the path without the src on it.
|
||||
dstPath := filepath.Join(dst, path[len(src):])
|
||||
|
||||
// If we have a directory, make that subdirectory, then continue
|
||||
// the walk.
|
||||
if info.IsDir() {
|
||||
if path == filepath.Join(src, dst) {
|
||||
// dst is in src; don't walk it.
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(dstPath, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// If we have a file, copy the contents.
|
||||
srcF, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcF.Close()
|
||||
|
||||
dstF, err := os.Create(dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstF.Close()
|
||||
|
||||
if _, err := io.Copy(dstF, srcF); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Chmod it
|
||||
return os.Chmod(dstPath, info.Mode())
|
||||
}
|
||||
|
||||
return filepath.Walk(src, walkFn)
|
||||
}
|
||||
58
vendor/github.com/hashicorp/go-getter/decompress.go
generated
vendored
Normal file
58
vendor/github.com/hashicorp/go-getter/decompress.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Decompressor defines the interface that must be implemented to add
|
||||
// support for decompressing a type.
|
||||
//
|
||||
// Important: if you're implementing a decompressor, please use the
|
||||
// containsDotDot helper in this file to ensure that files can't be
|
||||
// decompressed outside of the specified directory.
|
||||
type Decompressor interface {
|
||||
// Decompress should decompress src to dst. dir specifies whether dst
|
||||
// is a directory or single file. src is guaranteed to be a single file
|
||||
// that exists. dst is not guaranteed to exist already.
|
||||
Decompress(dst, src string, dir bool) error
|
||||
}
|
||||
|
||||
// Decompressors is the mapping of extension to the Decompressor implementation
|
||||
// that will decompress that extension/type.
|
||||
var Decompressors map[string]Decompressor
|
||||
|
||||
func init() {
|
||||
tbzDecompressor := new(TarBzip2Decompressor)
|
||||
tgzDecompressor := new(TarGzipDecompressor)
|
||||
txzDecompressor := new(TarXzDecompressor)
|
||||
|
||||
Decompressors = map[string]Decompressor{
|
||||
"bz2": new(Bzip2Decompressor),
|
||||
"gz": new(GzipDecompressor),
|
||||
"xz": new(XzDecompressor),
|
||||
"tar.bz2": tbzDecompressor,
|
||||
"tar.gz": tgzDecompressor,
|
||||
"tar.xz": txzDecompressor,
|
||||
"tbz2": tbzDecompressor,
|
||||
"tgz": tgzDecompressor,
|
||||
"txz": txzDecompressor,
|
||||
"zip": new(ZipDecompressor),
|
||||
}
|
||||
}
|
||||
|
||||
// containsDotDot checks if the filepath value v contains a ".." entry.
|
||||
// This will check filepath components by splitting along / or \. This
|
||||
// function is copied directly from the Go net/http implementation.
|
||||
func containsDotDot(v string) bool {
|
||||
if !strings.Contains(v, "..") {
|
||||
return false
|
||||
}
|
||||
for _, ent := range strings.FieldsFunc(v, isSlashRune) {
|
||||
if ent == ".." {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isSlashRune(r rune) bool { return r == '/' || r == '\\' }
|
||||
45
vendor/github.com/hashicorp/go-getter/decompress_bzip2.go
generated
vendored
Normal file
45
vendor/github.com/hashicorp/go-getter/decompress_bzip2.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"compress/bzip2"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Bzip2Decompressor is an implementation of Decompressor that can
|
||||
// decompress bz2 files.
|
||||
type Bzip2Decompressor struct{}
|
||||
|
||||
func (d *Bzip2Decompressor) Decompress(dst, src string, dir bool) error {
|
||||
// Directory isn't supported at all
|
||||
if dir {
|
||||
return fmt.Errorf("bzip2-compressed files can only unarchive to a single file")
|
||||
}
|
||||
|
||||
// If we're going into a directory we should make that first
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// File first
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Bzip2 compression is second
|
||||
bzipR := bzip2.NewReader(f)
|
||||
|
||||
// Copy it out
|
||||
dstF, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstF.Close()
|
||||
|
||||
_, err = io.Copy(dstF, bzipR)
|
||||
return err
|
||||
}
|
||||
34
vendor/github.com/hashicorp/go-getter/decompress_bzip2_test.go
generated
vendored
Normal file
34
vendor/github.com/hashicorp/go-getter/decompress_bzip2_test.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBzip2Decompressor(t *testing.T) {
|
||||
cases := []TestDecompressCase{
|
||||
{
|
||||
"single.bz2",
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
"d3b07384d113edec49eaa6238ad5ff00",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"single.bz2",
|
||||
true,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
cases[i].Input = filepath.Join("./test-fixtures", "decompress-bz2", tc.Input)
|
||||
}
|
||||
|
||||
TestDecompressor(t, new(Bzip2Decompressor), cases)
|
||||
}
|
||||
49
vendor/github.com/hashicorp/go-getter/decompress_gzip.go
generated
vendored
Normal file
49
vendor/github.com/hashicorp/go-getter/decompress_gzip.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// GzipDecompressor is an implementation of Decompressor that can
|
||||
// decompress gzip files.
|
||||
type GzipDecompressor struct{}
|
||||
|
||||
func (d *GzipDecompressor) Decompress(dst, src string, dir bool) error {
|
||||
// Directory isn't supported at all
|
||||
if dir {
|
||||
return fmt.Errorf("gzip-compressed files can only unarchive to a single file")
|
||||
}
|
||||
|
||||
// If we're going into a directory we should make that first
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// File first
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// gzip compression is second
|
||||
gzipR, err := gzip.NewReader(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer gzipR.Close()
|
||||
|
||||
// Copy it out
|
||||
dstF, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstF.Close()
|
||||
|
||||
_, err = io.Copy(dstF, gzipR)
|
||||
return err
|
||||
}
|
||||
34
vendor/github.com/hashicorp/go-getter/decompress_gzip_test.go
generated
vendored
Normal file
34
vendor/github.com/hashicorp/go-getter/decompress_gzip_test.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGzipDecompressor(t *testing.T) {
|
||||
cases := []TestDecompressCase{
|
||||
{
|
||||
"single.gz",
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
"d3b07384d113edec49eaa6238ad5ff00",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"single.gz",
|
||||
true,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
cases[i].Input = filepath.Join("./test-fixtures", "decompress-gz", tc.Input)
|
||||
}
|
||||
|
||||
TestDecompressor(t, new(GzipDecompressor), cases)
|
||||
}
|
||||
160
vendor/github.com/hashicorp/go-getter/decompress_tar.go
generated
vendored
Normal file
160
vendor/github.com/hashicorp/go-getter/decompress_tar.go
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// untar is a shared helper for untarring an archive. The reader should provide
|
||||
// an uncompressed view of the tar archive.
|
||||
func untar(input io.Reader, dst, src string, dir bool) error {
|
||||
tarR := tar.NewReader(input)
|
||||
done := false
|
||||
dirHdrs := []*tar.Header{}
|
||||
now := time.Now()
|
||||
for {
|
||||
hdr, err := tarR.Next()
|
||||
if err == io.EOF {
|
||||
if !done {
|
||||
// Empty archive
|
||||
return fmt.Errorf("empty archive: %s", src)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if hdr.Typeflag == tar.TypeXGlobalHeader || hdr.Typeflag == tar.TypeXHeader {
|
||||
// don't unpack extended headers as files
|
||||
continue
|
||||
}
|
||||
|
||||
path := dst
|
||||
if dir {
|
||||
// Disallow parent traversal
|
||||
if containsDotDot(hdr.Name) {
|
||||
return fmt.Errorf("entry contains '..': %s", hdr.Name)
|
||||
}
|
||||
|
||||
path = filepath.Join(path, hdr.Name)
|
||||
}
|
||||
|
||||
if hdr.FileInfo().IsDir() {
|
||||
if !dir {
|
||||
return fmt.Errorf("expected a single file: %s", src)
|
||||
}
|
||||
|
||||
// A directory, just make the directory and continue unarchiving...
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Record the directory information so that we may set its attributes
|
||||
// after all files have been extracted
|
||||
dirHdrs = append(dirHdrs, hdr)
|
||||
|
||||
continue
|
||||
} else {
|
||||
// There is no ordering guarantee that a file in a directory is
|
||||
// listed before the directory
|
||||
dstPath := filepath.Dir(path)
|
||||
|
||||
// Check that the directory exists, otherwise create it
|
||||
if _, err := os.Stat(dstPath); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(dstPath, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We have a file. If we already decoded, then it is an error
|
||||
if !dir && done {
|
||||
return fmt.Errorf("expected a single file, got multiple: %s", src)
|
||||
}
|
||||
|
||||
// Mark that we're done so future in single file mode errors
|
||||
done = true
|
||||
|
||||
// Open the file for writing
|
||||
dstF, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(dstF, tarR)
|
||||
dstF.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Chmod the file
|
||||
if err := os.Chmod(path, hdr.FileInfo().Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the access and modification time if valid, otherwise default to current time
|
||||
aTime := now
|
||||
mTime := now
|
||||
if hdr.AccessTime.Unix() > 0 {
|
||||
aTime = hdr.AccessTime
|
||||
}
|
||||
if hdr.ModTime.Unix() > 0 {
|
||||
mTime = hdr.ModTime
|
||||
}
|
||||
if err := os.Chtimes(path, aTime, mTime); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Perform a final pass over extracted directories to update metadata
|
||||
for _, dirHdr := range dirHdrs {
|
||||
path := filepath.Join(dst, dirHdr.Name)
|
||||
// Chmod the directory since they might be created before we know the mode flags
|
||||
if err := os.Chmod(path, dirHdr.FileInfo().Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
// Set the mtime/atime attributes since they would have been changed during extraction
|
||||
aTime := now
|
||||
mTime := now
|
||||
if dirHdr.AccessTime.Unix() > 0 {
|
||||
aTime = dirHdr.AccessTime
|
||||
}
|
||||
if dirHdr.ModTime.Unix() > 0 {
|
||||
mTime = dirHdr.ModTime
|
||||
}
|
||||
if err := os.Chtimes(path, aTime, mTime); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// tarDecompressor is an implementation of Decompressor that can
|
||||
// unpack tar files.
|
||||
type tarDecompressor struct{}
|
||||
|
||||
func (d *tarDecompressor) Decompress(dst, src string, dir bool) error {
|
||||
// If we're going into a directory we should make that first
|
||||
mkdir := dst
|
||||
if !dir {
|
||||
mkdir = filepath.Dir(dst)
|
||||
}
|
||||
if err := os.MkdirAll(mkdir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// File first
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return untar(f, dst, src, dir)
|
||||
}
|
||||
43
vendor/github.com/hashicorp/go-getter/decompress_tar_test.go
generated
vendored
Normal file
43
vendor/github.com/hashicorp/go-getter/decompress_tar_test.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestTar(t *testing.T) {
|
||||
mtime := time.Unix(0, 0)
|
||||
cases := []TestDecompressCase{
|
||||
{
|
||||
"extended_header.tar",
|
||||
true,
|
||||
false,
|
||||
[]string{"directory/", "directory/a", "directory/b"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"implied_dir.tar",
|
||||
true,
|
||||
false,
|
||||
[]string{"directory/", "directory/sub/", "directory/sub/a", "directory/sub/b"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"unix_time_0.tar",
|
||||
true,
|
||||
false,
|
||||
[]string{"directory/", "directory/sub/", "directory/sub/a", "directory/sub/b"},
|
||||
"",
|
||||
&mtime,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
cases[i].Input = filepath.Join("./test-fixtures", "decompress-tar", tc.Input)
|
||||
}
|
||||
|
||||
TestDecompressor(t, new(tarDecompressor), cases)
|
||||
}
|
||||
33
vendor/github.com/hashicorp/go-getter/decompress_tbz2.go
generated
vendored
Normal file
33
vendor/github.com/hashicorp/go-getter/decompress_tbz2.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"compress/bzip2"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// TarBzip2Decompressor is an implementation of Decompressor that can
|
||||
// decompress tar.bz2 files.
|
||||
type TarBzip2Decompressor struct{}
|
||||
|
||||
func (d *TarBzip2Decompressor) Decompress(dst, src string, dir bool) error {
|
||||
// If we're going into a directory we should make that first
|
||||
mkdir := dst
|
||||
if !dir {
|
||||
mkdir = filepath.Dir(dst)
|
||||
}
|
||||
if err := os.MkdirAll(mkdir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// File first
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Bzip2 compression is second
|
||||
bzipR := bzip2.NewReader(f)
|
||||
return untar(bzipR, dst, src, dir)
|
||||
}
|
||||
73
vendor/github.com/hashicorp/go-getter/decompress_tbz2_test.go
generated
vendored
Normal file
73
vendor/github.com/hashicorp/go-getter/decompress_tbz2_test.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTarBzip2Decompressor(t *testing.T) {
|
||||
orderingPaths := []string{"workers/", "workers/mq/", "workers/mq/__init__.py"}
|
||||
|
||||
cases := []TestDecompressCase{
|
||||
{
|
||||
"empty.tar.bz2",
|
||||
false,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"single.tar.bz2",
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
"d3b07384d113edec49eaa6238ad5ff00",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"single.tar.bz2",
|
||||
true,
|
||||
false,
|
||||
[]string{"file"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"multiple.tar.bz2",
|
||||
true,
|
||||
false,
|
||||
[]string{"file1", "file2"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"multiple.tar.bz2",
|
||||
false,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
// Tests when the file is listed before the parent folder
|
||||
{
|
||||
"ordering.tar.bz2",
|
||||
true,
|
||||
false,
|
||||
orderingPaths,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
cases[i].Input = filepath.Join("./test-fixtures", "decompress-tbz2", tc.Input)
|
||||
}
|
||||
|
||||
TestDecompressor(t, new(TarBzip2Decompressor), cases)
|
||||
}
|
||||
169
vendor/github.com/hashicorp/go-getter/decompress_testing.go
generated
vendored
Normal file
169
vendor/github.com/hashicorp/go-getter/decompress_testing.go
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/go-testing-interface"
|
||||
)
|
||||
|
||||
// TestDecompressCase is a single test case for testing decompressors
|
||||
type TestDecompressCase struct {
|
||||
Input string // Input is the complete path to the input file
|
||||
Dir bool // Dir is whether or not we're testing directory mode
|
||||
Err bool // Err is whether we expect an error or not
|
||||
DirList []string // DirList is the list of files for Dir mode
|
||||
FileMD5 string // FileMD5 is the expected MD5 for a single file
|
||||
Mtime *time.Time // Mtime is the optionally expected mtime for a single file (or all files if in Dir mode)
|
||||
}
|
||||
|
||||
// TestDecompressor is a helper function for testing generic decompressors.
|
||||
func TestDecompressor(t testing.T, d Decompressor, cases []TestDecompressCase) {
|
||||
for _, tc := range cases {
|
||||
t.Logf("Testing: %s", tc.Input)
|
||||
|
||||
// Temporary dir to store stuff
|
||||
td, err := ioutil.TempDir("", "getter")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Destination is always joining result so that we have a new path
|
||||
dst := filepath.Join(td, "subdir", "result")
|
||||
|
||||
// We use a function so defers work
|
||||
func() {
|
||||
defer os.RemoveAll(td)
|
||||
|
||||
// Decompress
|
||||
err := d.Decompress(dst, tc.Input, tc.Dir)
|
||||
if (err != nil) != tc.Err {
|
||||
t.Fatalf("err %s: %s", tc.Input, err)
|
||||
}
|
||||
if tc.Err {
|
||||
return
|
||||
}
|
||||
|
||||
// If it isn't a directory, then check for a single file
|
||||
if !tc.Dir {
|
||||
fi, err := os.Stat(dst)
|
||||
if err != nil {
|
||||
t.Fatalf("err %s: %s", tc.Input, err)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
t.Fatalf("err %s: expected file, got directory", tc.Input)
|
||||
}
|
||||
if tc.FileMD5 != "" {
|
||||
actual := testMD5(t, dst)
|
||||
expected := tc.FileMD5
|
||||
if actual != expected {
|
||||
t.Fatalf("err %s: expected MD5 %s, got %s", tc.Input, expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
if tc.Mtime != nil {
|
||||
actual := fi.ModTime()
|
||||
if tc.Mtime.Unix() > 0 {
|
||||
expected := *tc.Mtime
|
||||
if actual != expected {
|
||||
t.Fatalf("err %s: expected mtime '%s' for %s, got '%s'", tc.Input, expected.String(), dst, actual.String())
|
||||
}
|
||||
} else if actual.Unix() <= 0 {
|
||||
t.Fatalf("err %s: expected mtime to be > 0, got '%s'", actual.String())
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Convert expected for windows
|
||||
expected := tc.DirList
|
||||
if runtime.GOOS == "windows" {
|
||||
for i, v := range expected {
|
||||
expected[i] = strings.Replace(v, "/", "\\", -1)
|
||||
}
|
||||
}
|
||||
|
||||
// Directory, check for the correct contents
|
||||
actual := testListDir(t, dst)
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("bad %s\n\n%#v\n\n%#v", tc.Input, actual, expected)
|
||||
}
|
||||
// Check for correct atime/mtime
|
||||
for _, dir := range actual {
|
||||
path := filepath.Join(dst, dir)
|
||||
if tc.Mtime != nil {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
actual := fi.ModTime()
|
||||
if tc.Mtime.Unix() > 0 {
|
||||
expected := *tc.Mtime
|
||||
if actual != expected {
|
||||
t.Fatalf("err %s: expected mtime '%s' for %s, got '%s'", tc.Input, expected.String(), path, actual.String())
|
||||
}
|
||||
} else if actual.Unix() < 0 {
|
||||
t.Fatalf("err %s: expected mtime to be > 0, got '%s'", actual.String())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func testListDir(t testing.T, path string) []string {
|
||||
var result []string
|
||||
err := filepath.Walk(path, func(sub string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sub = strings.TrimPrefix(sub, path)
|
||||
if sub == "" {
|
||||
return nil
|
||||
}
|
||||
sub = sub[1:] // Trim the leading path sep.
|
||||
|
||||
// If it is a dir, add trailing sep
|
||||
if info.IsDir() {
|
||||
sub += string(os.PathSeparator)
|
||||
}
|
||||
|
||||
result = append(result, sub)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
sort.Strings(result)
|
||||
return result
|
||||
}
|
||||
|
||||
func testMD5(t testing.T, path string) string {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
h := md5.New()
|
||||
_, err = io.Copy(h, f)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
result := h.Sum(nil)
|
||||
return hex.EncodeToString(result)
|
||||
}
|
||||
39
vendor/github.com/hashicorp/go-getter/decompress_tgz.go
generated
vendored
Normal file
39
vendor/github.com/hashicorp/go-getter/decompress_tgz.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// TarGzipDecompressor is an implementation of Decompressor that can
|
||||
// decompress tar.gzip files.
|
||||
type TarGzipDecompressor struct{}
|
||||
|
||||
func (d *TarGzipDecompressor) Decompress(dst, src string, dir bool) error {
|
||||
// If we're going into a directory we should make that first
|
||||
mkdir := dst
|
||||
if !dir {
|
||||
mkdir = filepath.Dir(dst)
|
||||
}
|
||||
if err := os.MkdirAll(mkdir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// File first
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Gzip compression is second
|
||||
gzipR, err := gzip.NewReader(f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error opening a gzip reader for %s: %s", src, err)
|
||||
}
|
||||
defer gzipR.Close()
|
||||
|
||||
return untar(gzipR, dst, src, dir)
|
||||
}
|
||||
95
vendor/github.com/hashicorp/go-getter/decompress_tgz_test.go
generated
vendored
Normal file
95
vendor/github.com/hashicorp/go-getter/decompress_tgz_test.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTarGzipDecompressor(t *testing.T) {
|
||||
|
||||
multiplePaths := []string{"dir/", "dir/test2", "test1"}
|
||||
orderingPaths := []string{"workers/", "workers/mq/", "workers/mq/__init__.py"}
|
||||
|
||||
cases := []TestDecompressCase{
|
||||
{
|
||||
"empty.tar.gz",
|
||||
false,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"single.tar.gz",
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
"d3b07384d113edec49eaa6238ad5ff00",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"single.tar.gz",
|
||||
true,
|
||||
false,
|
||||
[]string{"file"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"multiple.tar.gz",
|
||||
true,
|
||||
false,
|
||||
[]string{"file1", "file2"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"multiple.tar.gz",
|
||||
false,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"multiple_dir.tar.gz",
|
||||
true,
|
||||
false,
|
||||
multiplePaths,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
// Tests when the file is listed before the parent folder
|
||||
{
|
||||
"ordering.tar.gz",
|
||||
true,
|
||||
false,
|
||||
orderingPaths,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
// Tests that a tar.gz can't contain references with "..".
|
||||
// GNU `tar` also disallows this.
|
||||
{
|
||||
"outside_parent.tar.gz",
|
||||
true,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
cases[i].Input = filepath.Join("./test-fixtures", "decompress-tgz", tc.Input)
|
||||
}
|
||||
|
||||
TestDecompressor(t, new(TarGzipDecompressor), cases)
|
||||
}
|
||||
39
vendor/github.com/hashicorp/go-getter/decompress_txz.go
generated
vendored
Normal file
39
vendor/github.com/hashicorp/go-getter/decompress_txz.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ulikunitz/xz"
|
||||
)
|
||||
|
||||
// TarXzDecompressor is an implementation of Decompressor that can
|
||||
// decompress tar.xz files.
|
||||
type TarXzDecompressor struct{}
|
||||
|
||||
func (d *TarXzDecompressor) Decompress(dst, src string, dir bool) error {
|
||||
// If we're going into a directory we should make that first
|
||||
mkdir := dst
|
||||
if !dir {
|
||||
mkdir = filepath.Dir(dst)
|
||||
}
|
||||
if err := os.MkdirAll(mkdir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// File first
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// xz compression is second
|
||||
txzR, err := xz.NewReader(f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error opening an xz reader for %s: %s", src, err)
|
||||
}
|
||||
|
||||
return untar(txzR, dst, src, dir)
|
||||
}
|
||||
84
vendor/github.com/hashicorp/go-getter/decompress_txz_test.go
generated
vendored
Normal file
84
vendor/github.com/hashicorp/go-getter/decompress_txz_test.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTarXzDecompressor(t *testing.T) {
|
||||
|
||||
multiplePaths := []string{"dir/", "dir/test2", "test1"}
|
||||
orderingPaths := []string{"workers/", "workers/mq/", "workers/mq/__init__.py"}
|
||||
|
||||
cases := []TestDecompressCase{
|
||||
{
|
||||
"empty.tar.xz",
|
||||
false,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"single.tar.xz",
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
"d3b07384d113edec49eaa6238ad5ff00",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"single.tar.xz",
|
||||
true,
|
||||
false,
|
||||
[]string{"file"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"multiple.tar.xz",
|
||||
true,
|
||||
false,
|
||||
[]string{"file1", "file2"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"multiple.tar.xz",
|
||||
false,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"multiple_dir.tar.xz",
|
||||
true,
|
||||
false,
|
||||
multiplePaths,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
// Tests when the file is listed before the parent folder
|
||||
{
|
||||
"ordering.tar.xz",
|
||||
true,
|
||||
false,
|
||||
orderingPaths,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
cases[i].Input = filepath.Join("./test-fixtures", "decompress-txz", tc.Input)
|
||||
}
|
||||
|
||||
TestDecompressor(t, new(TarXzDecompressor), cases)
|
||||
}
|
||||
49
vendor/github.com/hashicorp/go-getter/decompress_xz.go
generated
vendored
Normal file
49
vendor/github.com/hashicorp/go-getter/decompress_xz.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ulikunitz/xz"
|
||||
)
|
||||
|
||||
// XzDecompressor is an implementation of Decompressor that can
|
||||
// decompress xz files.
|
||||
type XzDecompressor struct{}
|
||||
|
||||
func (d *XzDecompressor) Decompress(dst, src string, dir bool) error {
|
||||
// Directory isn't supported at all
|
||||
if dir {
|
||||
return fmt.Errorf("xz-compressed files can only unarchive to a single file")
|
||||
}
|
||||
|
||||
// If we're going into a directory we should make that first
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// File first
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// xz compression is second
|
||||
xzR, err := xz.NewReader(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy it out
|
||||
dstF, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstF.Close()
|
||||
|
||||
_, err = io.Copy(dstF, xzR)
|
||||
return err
|
||||
}
|
||||
34
vendor/github.com/hashicorp/go-getter/decompress_xz_test.go
generated
vendored
Normal file
34
vendor/github.com/hashicorp/go-getter/decompress_xz_test.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestXzDecompressor(t *testing.T) {
|
||||
cases := []TestDecompressCase{
|
||||
{
|
||||
"single.xz",
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
"d3b07384d113edec49eaa6238ad5ff00",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"single.xz",
|
||||
true,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
cases[i].Input = filepath.Join("./test-fixtures", "decompress-xz", tc.Input)
|
||||
}
|
||||
|
||||
TestDecompressor(t, new(XzDecompressor), cases)
|
||||
}
|
||||
101
vendor/github.com/hashicorp/go-getter/decompress_zip.go
generated
vendored
Normal file
101
vendor/github.com/hashicorp/go-getter/decompress_zip.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// ZipDecompressor is an implementation of Decompressor that can
|
||||
// decompress tar.gzip files.
|
||||
type ZipDecompressor struct{}
|
||||
|
||||
func (d *ZipDecompressor) Decompress(dst, src string, dir bool) error {
|
||||
// If we're going into a directory we should make that first
|
||||
mkdir := dst
|
||||
if !dir {
|
||||
mkdir = filepath.Dir(dst)
|
||||
}
|
||||
if err := os.MkdirAll(mkdir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Open the zip
|
||||
zipR, err := zip.OpenReader(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer zipR.Close()
|
||||
|
||||
// Check the zip integrity
|
||||
if len(zipR.File) == 0 {
|
||||
// Empty archive
|
||||
return fmt.Errorf("empty archive: %s", src)
|
||||
}
|
||||
if !dir && len(zipR.File) > 1 {
|
||||
return fmt.Errorf("expected a single file: %s", src)
|
||||
}
|
||||
|
||||
// Go through and unarchive
|
||||
for _, f := range zipR.File {
|
||||
path := dst
|
||||
if dir {
|
||||
// Disallow parent traversal
|
||||
if containsDotDot(f.Name) {
|
||||
return fmt.Errorf("entry contains '..': %s", f.Name)
|
||||
}
|
||||
|
||||
path = filepath.Join(path, f.Name)
|
||||
}
|
||||
|
||||
if f.FileInfo().IsDir() {
|
||||
if !dir {
|
||||
return fmt.Errorf("expected a single file: %s", src)
|
||||
}
|
||||
|
||||
// A directory, just make the directory and continue unarchiving...
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Create the enclosing directories if we must. ZIP files aren't
|
||||
// required to contain entries for just the directories so this
|
||||
// can happen.
|
||||
if dir {
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Open the file for reading
|
||||
srcF, err := f.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Open the file for writing
|
||||
dstF, err := os.Create(path)
|
||||
if err != nil {
|
||||
srcF.Close()
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(dstF, srcF)
|
||||
srcF.Close()
|
||||
dstF.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Chmod the file
|
||||
if err := os.Chmod(path, f.Mode()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
98
vendor/github.com/hashicorp/go-getter/decompress_zip_test.go
generated
vendored
Normal file
98
vendor/github.com/hashicorp/go-getter/decompress_zip_test.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestZipDecompressor(t *testing.T) {
|
||||
cases := []TestDecompressCase{
|
||||
{
|
||||
"empty.zip",
|
||||
false,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"single.zip",
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
"d3b07384d113edec49eaa6238ad5ff00",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"single.zip",
|
||||
true,
|
||||
false,
|
||||
[]string{"file"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"multiple.zip",
|
||||
true,
|
||||
false,
|
||||
[]string{"file1", "file2"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"multiple.zip",
|
||||
false,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"subdir.zip",
|
||||
true,
|
||||
false,
|
||||
[]string{"file1", "subdir/", "subdir/child"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"subdir_empty.zip",
|
||||
true,
|
||||
false,
|
||||
[]string{"file1", "subdir/"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
{
|
||||
"subdir_missing_dir.zip",
|
||||
true,
|
||||
false,
|
||||
[]string{"file1", "subdir/", "subdir/child"},
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
|
||||
// Tests that a zip can't contain references with "..".
|
||||
{
|
||||
"outside_parent.zip",
|
||||
true,
|
||||
true,
|
||||
nil,
|
||||
"",
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
cases[i].Input = filepath.Join("./test-fixtures", "decompress-zip", tc.Input)
|
||||
}
|
||||
|
||||
TestDecompressor(t, new(ZipDecompressor), cases)
|
||||
}
|
||||
103
vendor/github.com/hashicorp/go-getter/detect.go
generated
vendored
Normal file
103
vendor/github.com/hashicorp/go-getter/detect.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/go-getter/helper/url"
|
||||
)
|
||||
|
||||
// Detector defines the interface that an invalid URL or a URL with a blank
|
||||
// scheme is passed through in order to determine if its shorthand for
|
||||
// something else well-known.
|
||||
type Detector interface {
|
||||
// Detect will detect whether the string matches a known pattern to
|
||||
// turn it into a proper URL.
|
||||
Detect(string, string) (string, bool, error)
|
||||
}
|
||||
|
||||
// Detectors is the list of detectors that are tried on an invalid URL.
|
||||
// This is also the order they're tried (index 0 is first).
|
||||
var Detectors []Detector
|
||||
|
||||
func init() {
|
||||
Detectors = []Detector{
|
||||
new(GitHubDetector),
|
||||
new(BitBucketDetector),
|
||||
new(S3Detector),
|
||||
new(FileDetector),
|
||||
}
|
||||
}
|
||||
|
||||
// Detect turns a source string into another source string if it is
|
||||
// detected to be of a known pattern.
|
||||
//
|
||||
// The third parameter should be the list of detectors to use in the
|
||||
// order to try them. If you don't want to configure this, just use
|
||||
// the global Detectors variable.
|
||||
//
|
||||
// This is safe to be called with an already valid source string: Detect
|
||||
// will just return it.
|
||||
func Detect(src string, pwd string, ds []Detector) (string, error) {
|
||||
getForce, getSrc := getForcedGetter(src)
|
||||
|
||||
// Separate out the subdir if there is one, we don't pass that to detect
|
||||
getSrc, subDir := SourceDirSubdir(getSrc)
|
||||
|
||||
u, err := url.Parse(getSrc)
|
||||
if err == nil && u.Scheme != "" {
|
||||
// Valid URL
|
||||
return src, nil
|
||||
}
|
||||
|
||||
for _, d := range ds {
|
||||
result, ok, err := d.Detect(getSrc, pwd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var detectForce string
|
||||
detectForce, result = getForcedGetter(result)
|
||||
result, detectSubdir := SourceDirSubdir(result)
|
||||
|
||||
// If we have a subdir from the detection, then prepend it to our
|
||||
// requested subdir.
|
||||
if detectSubdir != "" {
|
||||
if subDir != "" {
|
||||
subDir = filepath.Join(detectSubdir, subDir)
|
||||
} else {
|
||||
subDir = detectSubdir
|
||||
}
|
||||
}
|
||||
|
||||
if subDir != "" {
|
||||
u, err := url.Parse(result)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error parsing URL: %s", err)
|
||||
}
|
||||
u.Path += "//" + subDir
|
||||
|
||||
// a subdir may contain wildcards, but in order to support them we
|
||||
// have to ensure the path isn't escaped.
|
||||
u.RawPath = u.Path
|
||||
|
||||
result = u.String()
|
||||
}
|
||||
|
||||
// Preserve the forced getter if it exists. We try to use the
|
||||
// original set force first, followed by any force set by the
|
||||
// detector.
|
||||
if getForce != "" {
|
||||
result = fmt.Sprintf("%s::%s", getForce, result)
|
||||
} else if detectForce != "" {
|
||||
result = fmt.Sprintf("%s::%s", detectForce, result)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("invalid source string: %s", src)
|
||||
}
|
||||
66
vendor/github.com/hashicorp/go-getter/detect_bitbucket.go
generated
vendored
Normal file
66
vendor/github.com/hashicorp/go-getter/detect_bitbucket.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BitBucketDetector implements Detector to detect BitBucket URLs and turn
|
||||
// them into URLs that the Git or Hg Getter can understand.
|
||||
type BitBucketDetector struct{}
|
||||
|
||||
func (d *BitBucketDetector) Detect(src, _ string) (string, bool, error) {
|
||||
if len(src) == 0 {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(src, "bitbucket.org/") {
|
||||
return d.detectHTTP(src)
|
||||
}
|
||||
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
func (d *BitBucketDetector) detectHTTP(src string) (string, bool, error) {
|
||||
u, err := url.Parse("https://" + src)
|
||||
if err != nil {
|
||||
return "", true, fmt.Errorf("error parsing BitBucket URL: %s", err)
|
||||
}
|
||||
|
||||
// We need to get info on this BitBucket repository to determine whether
|
||||
// it is Git or Hg.
|
||||
var info struct {
|
||||
SCM string `json:"scm"`
|
||||
}
|
||||
infoUrl := "https://api.bitbucket.org/1.0/repositories" + u.Path
|
||||
resp, err := http.Get(infoUrl)
|
||||
if err != nil {
|
||||
return "", true, fmt.Errorf("error looking up BitBucket URL: %s", err)
|
||||
}
|
||||
if resp.StatusCode == 403 {
|
||||
// A private repo
|
||||
return "", true, fmt.Errorf(
|
||||
"shorthand BitBucket URL can't be used for private repos, " +
|
||||
"please use a full URL")
|
||||
}
|
||||
dec := json.NewDecoder(resp.Body)
|
||||
if err := dec.Decode(&info); err != nil {
|
||||
return "", true, fmt.Errorf("error looking up BitBucket URL: %s", err)
|
||||
}
|
||||
|
||||
switch info.SCM {
|
||||
case "git":
|
||||
if !strings.HasSuffix(u.Path, ".git") {
|
||||
u.Path += ".git"
|
||||
}
|
||||
|
||||
return "git::" + u.String(), true, nil
|
||||
case "hg":
|
||||
return "hg::" + u.String(), true, nil
|
||||
default:
|
||||
return "", true, fmt.Errorf("unknown BitBucket SCM type: %s", info.SCM)
|
||||
}
|
||||
}
|
||||
67
vendor/github.com/hashicorp/go-getter/detect_bitbucket_test.go
generated
vendored
Normal file
67
vendor/github.com/hashicorp/go-getter/detect_bitbucket_test.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const testBBUrl = "https://bitbucket.org/hashicorp/tf-test-git"
|
||||
|
||||
func TestBitBucketDetector(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if _, err := http.Get(testBBUrl); err != nil {
|
||||
t.Log("internet may not be working, skipping BB tests")
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
Input string
|
||||
Output string
|
||||
}{
|
||||
// HTTP
|
||||
{
|
||||
"bitbucket.org/hashicorp/tf-test-git",
|
||||
"git::https://bitbucket.org/hashicorp/tf-test-git.git",
|
||||
},
|
||||
{
|
||||
"bitbucket.org/hashicorp/tf-test-git.git",
|
||||
"git::https://bitbucket.org/hashicorp/tf-test-git.git",
|
||||
},
|
||||
{
|
||||
"bitbucket.org/hashicorp/tf-test-hg",
|
||||
"hg::https://bitbucket.org/hashicorp/tf-test-hg",
|
||||
},
|
||||
}
|
||||
|
||||
pwd := "/pwd"
|
||||
f := new(BitBucketDetector)
|
||||
for i, tc := range cases {
|
||||
var err error
|
||||
for i := 0; i < 3; i++ {
|
||||
var output string
|
||||
var ok bool
|
||||
output, ok, err = f.Detect(tc.Input, pwd)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "invalid character") {
|
||||
continue
|
||||
}
|
||||
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatal("not ok")
|
||||
}
|
||||
|
||||
if output != tc.Output {
|
||||
t.Fatalf("%d: bad: %#v", i, output)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
if i >= 3 {
|
||||
t.Fatalf("failure from bitbucket: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
67
vendor/github.com/hashicorp/go-getter/detect_file.go
generated
vendored
Normal file
67
vendor/github.com/hashicorp/go-getter/detect_file.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// FileDetector implements Detector to detect file paths.
|
||||
type FileDetector struct{}
|
||||
|
||||
func (d *FileDetector) Detect(src, pwd string) (string, bool, error) {
|
||||
if len(src) == 0 {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(src) {
|
||||
if pwd == "" {
|
||||
return "", true, fmt.Errorf(
|
||||
"relative paths require a module with a pwd")
|
||||
}
|
||||
|
||||
// Stat the pwd to determine if its a symbolic link. If it is,
|
||||
// then the pwd becomes the original directory. Otherwise,
|
||||
// `filepath.Join` below does some weird stuff.
|
||||
//
|
||||
// We just ignore if the pwd doesn't exist. That error will be
|
||||
// caught later when we try to use the URL.
|
||||
if fi, err := os.Lstat(pwd); !os.IsNotExist(err) {
|
||||
if err != nil {
|
||||
return "", true, err
|
||||
}
|
||||
if fi.Mode()&os.ModeSymlink != 0 {
|
||||
pwd, err = filepath.EvalSymlinks(pwd)
|
||||
if err != nil {
|
||||
return "", true, err
|
||||
}
|
||||
|
||||
// The symlink itself might be a relative path, so we have to
|
||||
// resolve this to have a correctly rooted URL.
|
||||
pwd, err = filepath.Abs(pwd)
|
||||
if err != nil {
|
||||
return "", true, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
src = filepath.Join(pwd, src)
|
||||
}
|
||||
|
||||
return fmtFileURL(src), true, nil
|
||||
}
|
||||
|
||||
func fmtFileURL(path string) string {
|
||||
if runtime.GOOS == "windows" {
|
||||
// Make sure we're using "/" on Windows. URLs are "/"-based.
|
||||
path = filepath.ToSlash(path)
|
||||
return fmt.Sprintf("file://%s", path)
|
||||
}
|
||||
|
||||
// Make sure that we don't start with "/" since we add that below.
|
||||
if path[0] == '/' {
|
||||
path = path[1:]
|
||||
}
|
||||
return fmt.Sprintf("file:///%s", path)
|
||||
}
|
||||
118
vendor/github.com/hashicorp/go-getter/detect_file_test.go
generated
vendored
Normal file
118
vendor/github.com/hashicorp/go-getter/detect_file_test.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type fileTest struct {
|
||||
in, pwd, out string
|
||||
err bool
|
||||
}
|
||||
|
||||
var fileTests = []fileTest{
|
||||
{"./foo", "/pwd", "file:///pwd/foo", false},
|
||||
{"./foo?foo=bar", "/pwd", "file:///pwd/foo?foo=bar", false},
|
||||
{"foo", "/pwd", "file:///pwd/foo", false},
|
||||
}
|
||||
|
||||
var unixFileTests = []fileTest{
|
||||
{"./foo", "test-fixtures/detect-file-symlink-pwd/syml/pwd",
|
||||
"test-fixtures/detect-file-symlink-pwd/real/foo", false},
|
||||
|
||||
{"/foo", "/pwd", "file:///foo", false},
|
||||
{"/foo?bar=baz", "/pwd", "file:///foo?bar=baz", false},
|
||||
}
|
||||
|
||||
var winFileTests = []fileTest{
|
||||
{"/foo", "/pwd", "file:///pwd/foo", false},
|
||||
{`C:\`, `/pwd`, `file://C:/`, false},
|
||||
{`C:\?bar=baz`, `/pwd`, `file://C:/?bar=baz`, false},
|
||||
}
|
||||
|
||||
func TestFileDetector(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
fileTests = append(fileTests, winFileTests...)
|
||||
} else {
|
||||
fileTests = append(fileTests, unixFileTests...)
|
||||
}
|
||||
|
||||
// Get the pwd
|
||||
pwdRoot, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
pwdRoot, err = filepath.Abs(pwdRoot)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
f := new(FileDetector)
|
||||
for i, tc := range fileTests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
pwd := tc.pwd
|
||||
if !filepath.IsAbs(pwd) {
|
||||
pwd = filepath.Join(pwdRoot, pwd)
|
||||
}
|
||||
|
||||
out, ok, err := f.Detect(tc.in, pwd)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatal("not ok")
|
||||
}
|
||||
|
||||
expected := tc.out
|
||||
if !strings.HasPrefix(expected, "file://") {
|
||||
expected = "file://" + filepath.Join(pwdRoot, expected)
|
||||
}
|
||||
|
||||
if out != expected {
|
||||
t.Fatalf("input: %q\npwd: %q\nexpected: %q\nbad output: %#v",
|
||||
tc.in, pwd, expected, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var noPwdFileTests = []fileTest{
|
||||
{in: "./foo", pwd: "", out: "", err: true},
|
||||
{in: "foo", pwd: "", out: "", err: true},
|
||||
}
|
||||
|
||||
var noPwdUnixFileTests = []fileTest{
|
||||
{in: "/foo", pwd: "", out: "file:///foo", err: false},
|
||||
}
|
||||
|
||||
var noPwdWinFileTests = []fileTest{
|
||||
{in: "/foo", pwd: "", out: "", err: true},
|
||||
{in: `C:\`, pwd: ``, out: `file://C:/`, err: false},
|
||||
}
|
||||
|
||||
func TestFileDetector_noPwd(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
noPwdFileTests = append(noPwdFileTests, noPwdWinFileTests...)
|
||||
} else {
|
||||
noPwdFileTests = append(noPwdFileTests, noPwdUnixFileTests...)
|
||||
}
|
||||
|
||||
f := new(FileDetector)
|
||||
for i, tc := range noPwdFileTests {
|
||||
out, ok, err := f.Detect(tc.in, tc.pwd)
|
||||
if err != nil != tc.err {
|
||||
t.Fatalf("%d: err: %s", i, err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatal("not ok")
|
||||
}
|
||||
|
||||
if out != tc.out {
|
||||
t.Fatalf("%d: bad: %#v", i, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
70
vendor/github.com/hashicorp/go-getter/detect_file_unix_test.go
generated
vendored
Normal file
70
vendor/github.com/hashicorp/go-getter/detect_file_unix_test.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
// +build test unix
|
||||
|
||||
package getter
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// If a relative symlink is passed in as the pwd to Detect, the resulting URL
|
||||
// can have an invalid path.
|
||||
func TestFileDetector_relativeSymlink(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "go-getter")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
// We may have a symlinked tmp dir,
|
||||
// e.g. OSX uses /var -> /private/var
|
||||
tmpDir, err = filepath.EvalSymlinks(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = os.Mkdir(filepath.Join(tmpDir, "realPWD"), 0755)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
subdir := filepath.Join(tmpDir, "subdir")
|
||||
err = os.Mkdir(subdir, 0755)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
prevDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Chdir(prevDir)
|
||||
|
||||
err = os.Chdir(subdir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = os.Symlink("../realPWD", "linkedPWD")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// if detech doesn't fully resolve the pwd symlink, the output will be the
|
||||
// invalid path: "file:///../modules/foo"
|
||||
f := new(FileDetector)
|
||||
out, ok, err := f.Detect("../modules/foo", "./linkedPWD")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatal("not ok")
|
||||
}
|
||||
if out != "file://"+filepath.Join(tmpDir, "modules/foo") {
|
||||
t.Logf("expected: %v", "file://"+filepath.Join(tmpDir, "modules/foo"))
|
||||
t.Fatalf("bad: %v", out)
|
||||
}
|
||||
}
|
||||
73
vendor/github.com/hashicorp/go-getter/detect_github.go
generated
vendored
Normal file
73
vendor/github.com/hashicorp/go-getter/detect_github.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GitHubDetector implements Detector to detect GitHub URLs and turn
|
||||
// them into URLs that the Git Getter can understand.
|
||||
type GitHubDetector struct{}
|
||||
|
||||
func (d *GitHubDetector) Detect(src, _ string) (string, bool, error) {
|
||||
if len(src) == 0 {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
if strings.HasPrefix(src, "github.com/") {
|
||||
return d.detectHTTP(src)
|
||||
} else if strings.HasPrefix(src, "git@github.com:") {
|
||||
return d.detectSSH(src)
|
||||
}
|
||||
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
func (d *GitHubDetector) detectHTTP(src string) (string, bool, error) {
|
||||
parts := strings.Split(src, "/")
|
||||
if len(parts) < 3 {
|
||||
return "", false, fmt.Errorf(
|
||||
"GitHub URLs should be github.com/username/repo")
|
||||
}
|
||||
|
||||
urlStr := fmt.Sprintf("https://%s", strings.Join(parts[:3], "/"))
|
||||
url, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return "", true, fmt.Errorf("error parsing GitHub URL: %s", err)
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(url.Path, ".git") {
|
||||
url.Path += ".git"
|
||||
}
|
||||
|
||||
if len(parts) > 3 {
|
||||
url.Path += "//" + strings.Join(parts[3:], "/")
|
||||
}
|
||||
|
||||
return "git::" + url.String(), true, nil
|
||||
}
|
||||
|
||||
func (d *GitHubDetector) detectSSH(src string) (string, bool, error) {
|
||||
idx := strings.Index(src, ":")
|
||||
qidx := strings.Index(src, "?")
|
||||
if qidx == -1 {
|
||||
qidx = len(src)
|
||||
}
|
||||
|
||||
var u url.URL
|
||||
u.Scheme = "ssh"
|
||||
u.User = url.User("git")
|
||||
u.Host = "github.com"
|
||||
u.Path = src[idx+1 : qidx]
|
||||
if qidx < len(src) {
|
||||
q, err := url.ParseQuery(src[qidx+1:])
|
||||
if err != nil {
|
||||
return "", true, fmt.Errorf("error parsing GitHub SSH URL: %s", err)
|
||||
}
|
||||
|
||||
u.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
return "git::" + u.String(), true, nil
|
||||
}
|
||||
55
vendor/github.com/hashicorp/go-getter/detect_github_test.go
generated
vendored
Normal file
55
vendor/github.com/hashicorp/go-getter/detect_github_test.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGitHubDetector(t *testing.T) {
|
||||
cases := []struct {
|
||||
Input string
|
||||
Output string
|
||||
}{
|
||||
// HTTP
|
||||
{"github.com/hashicorp/foo", "git::https://github.com/hashicorp/foo.git"},
|
||||
{"github.com/hashicorp/foo.git", "git::https://github.com/hashicorp/foo.git"},
|
||||
{
|
||||
"github.com/hashicorp/foo/bar",
|
||||
"git::https://github.com/hashicorp/foo.git//bar",
|
||||
},
|
||||
{
|
||||
"github.com/hashicorp/foo?foo=bar",
|
||||
"git::https://github.com/hashicorp/foo.git?foo=bar",
|
||||
},
|
||||
{
|
||||
"github.com/hashicorp/foo.git?foo=bar",
|
||||
"git::https://github.com/hashicorp/foo.git?foo=bar",
|
||||
},
|
||||
|
||||
// SSH
|
||||
{"git@github.com:hashicorp/foo.git", "git::ssh://git@github.com/hashicorp/foo.git"},
|
||||
{
|
||||
"git@github.com:hashicorp/foo.git//bar",
|
||||
"git::ssh://git@github.com/hashicorp/foo.git//bar",
|
||||
},
|
||||
{
|
||||
"git@github.com:hashicorp/foo.git?foo=bar",
|
||||
"git::ssh://git@github.com/hashicorp/foo.git?foo=bar",
|
||||
},
|
||||
}
|
||||
|
||||
pwd := "/pwd"
|
||||
f := new(GitHubDetector)
|
||||
for i, tc := range cases {
|
||||
output, ok, err := f.Detect(tc.Input, pwd)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatal("not ok")
|
||||
}
|
||||
|
||||
if output != tc.Output {
|
||||
t.Fatalf("%d: bad: %#v", i, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
61
vendor/github.com/hashicorp/go-getter/detect_s3.go
generated
vendored
Normal file
61
vendor/github.com/hashicorp/go-getter/detect_s3.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// S3Detector implements Detector to detect S3 URLs and turn
|
||||
// them into URLs that the S3 getter can understand.
|
||||
type S3Detector struct{}
|
||||
|
||||
func (d *S3Detector) Detect(src, _ string) (string, bool, error) {
|
||||
if len(src) == 0 {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
if strings.Contains(src, ".amazonaws.com/") {
|
||||
return d.detectHTTP(src)
|
||||
}
|
||||
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
func (d *S3Detector) detectHTTP(src string) (string, bool, error) {
|
||||
parts := strings.Split(src, "/")
|
||||
if len(parts) < 2 {
|
||||
return "", false, fmt.Errorf(
|
||||
"URL is not a valid S3 URL")
|
||||
}
|
||||
|
||||
hostParts := strings.Split(parts[0], ".")
|
||||
if len(hostParts) == 3 {
|
||||
return d.detectPathStyle(hostParts[0], parts[1:])
|
||||
} else if len(hostParts) == 4 {
|
||||
return d.detectVhostStyle(hostParts[1], hostParts[0], parts[1:])
|
||||
} else {
|
||||
return "", false, fmt.Errorf(
|
||||
"URL is not a valid S3 URL")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *S3Detector) detectPathStyle(region string, parts []string) (string, bool, error) {
|
||||
urlStr := fmt.Sprintf("https://%s.amazonaws.com/%s", region, strings.Join(parts, "/"))
|
||||
url, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return "", false, fmt.Errorf("error parsing S3 URL: %s", err)
|
||||
}
|
||||
|
||||
return "s3::" + url.String(), true, nil
|
||||
}
|
||||
|
||||
func (d *S3Detector) detectVhostStyle(region, bucket string, parts []string) (string, bool, error) {
|
||||
urlStr := fmt.Sprintf("https://%s.amazonaws.com/%s/%s", region, bucket, strings.Join(parts, "/"))
|
||||
url, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return "", false, fmt.Errorf("error parsing S3 URL: %s", err)
|
||||
}
|
||||
|
||||
return "s3::" + url.String(), true, nil
|
||||
}
|
||||
84
vendor/github.com/hashicorp/go-getter/detect_s3_test.go
generated
vendored
Normal file
84
vendor/github.com/hashicorp/go-getter/detect_s3_test.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestS3Detector(t *testing.T) {
|
||||
cases := []struct {
|
||||
Input string
|
||||
Output string
|
||||
}{
|
||||
// Virtual hosted style
|
||||
{
|
||||
"bucket.s3.amazonaws.com/foo",
|
||||
"s3::https://s3.amazonaws.com/bucket/foo",
|
||||
},
|
||||
{
|
||||
"bucket.s3.amazonaws.com/foo/bar",
|
||||
"s3::https://s3.amazonaws.com/bucket/foo/bar",
|
||||
},
|
||||
{
|
||||
"bucket.s3.amazonaws.com/foo/bar.baz",
|
||||
"s3::https://s3.amazonaws.com/bucket/foo/bar.baz",
|
||||
},
|
||||
{
|
||||
"bucket.s3-eu-west-1.amazonaws.com/foo",
|
||||
"s3::https://s3-eu-west-1.amazonaws.com/bucket/foo",
|
||||
},
|
||||
{
|
||||
"bucket.s3-eu-west-1.amazonaws.com/foo/bar",
|
||||
"s3::https://s3-eu-west-1.amazonaws.com/bucket/foo/bar",
|
||||
},
|
||||
{
|
||||
"bucket.s3-eu-west-1.amazonaws.com/foo/bar.baz",
|
||||
"s3::https://s3-eu-west-1.amazonaws.com/bucket/foo/bar.baz",
|
||||
},
|
||||
// Path style
|
||||
{
|
||||
"s3.amazonaws.com/bucket/foo",
|
||||
"s3::https://s3.amazonaws.com/bucket/foo",
|
||||
},
|
||||
{
|
||||
"s3.amazonaws.com/bucket/foo/bar",
|
||||
"s3::https://s3.amazonaws.com/bucket/foo/bar",
|
||||
},
|
||||
{
|
||||
"s3.amazonaws.com/bucket/foo/bar.baz",
|
||||
"s3::https://s3.amazonaws.com/bucket/foo/bar.baz",
|
||||
},
|
||||
{
|
||||
"s3-eu-west-1.amazonaws.com/bucket/foo",
|
||||
"s3::https://s3-eu-west-1.amazonaws.com/bucket/foo",
|
||||
},
|
||||
{
|
||||
"s3-eu-west-1.amazonaws.com/bucket/foo/bar",
|
||||
"s3::https://s3-eu-west-1.amazonaws.com/bucket/foo/bar",
|
||||
},
|
||||
{
|
||||
"s3-eu-west-1.amazonaws.com/bucket/foo/bar.baz",
|
||||
"s3::https://s3-eu-west-1.amazonaws.com/bucket/foo/bar.baz",
|
||||
},
|
||||
// Misc tests
|
||||
{
|
||||
"s3-eu-west-1.amazonaws.com/bucket/foo/bar.baz?version=1234",
|
||||
"s3::https://s3-eu-west-1.amazonaws.com/bucket/foo/bar.baz?version=1234",
|
||||
},
|
||||
}
|
||||
|
||||
pwd := "/pwd"
|
||||
f := new(S3Detector)
|
||||
for i, tc := range cases {
|
||||
output, ok, err := f.Detect(tc.Input, pwd)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatal("not ok")
|
||||
}
|
||||
|
||||
if output != tc.Output {
|
||||
t.Fatalf("%d: bad: %#v", i, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
57
vendor/github.com/hashicorp/go-getter/detect_test.go
generated
vendored
Normal file
57
vendor/github.com/hashicorp/go-getter/detect_test.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDetect(t *testing.T) {
|
||||
cases := []struct {
|
||||
Input string
|
||||
Pwd string
|
||||
Output string
|
||||
Err bool
|
||||
}{
|
||||
{"./foo", "/foo", "file:///foo/foo", false},
|
||||
{"git::./foo", "/foo", "git::file:///foo/foo", false},
|
||||
{
|
||||
"git::github.com/hashicorp/foo",
|
||||
"",
|
||||
"git::https://github.com/hashicorp/foo.git",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"./foo//bar",
|
||||
"/foo",
|
||||
"file:///foo/foo//bar",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"git::github.com/hashicorp/foo//bar",
|
||||
"",
|
||||
"git::https://github.com/hashicorp/foo.git//bar",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"git::https://github.com/hashicorp/consul.git",
|
||||
"",
|
||||
"git::https://github.com/hashicorp/consul.git",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"./foo/archive//*",
|
||||
"/bar",
|
||||
"file:///bar/foo/archive//*",
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
output, err := Detect(tc.Input, tc.Pwd, Detectors)
|
||||
if err != nil != tc.Err {
|
||||
t.Fatalf("%d: bad err: %s", i, err)
|
||||
}
|
||||
if output != tc.Output {
|
||||
t.Fatalf("%d: bad output: %s\nexpected: %s", i, output, tc.Output)
|
||||
}
|
||||
}
|
||||
}
|
||||
65
vendor/github.com/hashicorp/go-getter/folder_storage.go
generated
vendored
Normal file
65
vendor/github.com/hashicorp/go-getter/folder_storage.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// FolderStorage is an implementation of the Storage interface that manages
|
||||
// modules on the disk.
|
||||
type FolderStorage struct {
|
||||
// StorageDir is the directory where the modules will be stored.
|
||||
StorageDir string
|
||||
}
|
||||
|
||||
// Dir implements Storage.Dir
|
||||
func (s *FolderStorage) Dir(key string) (d string, e bool, err error) {
|
||||
d = s.dir(key)
|
||||
_, err = os.Stat(d)
|
||||
if err == nil {
|
||||
// Directory exists
|
||||
e = true
|
||||
return
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
// Directory doesn't exist
|
||||
d = ""
|
||||
e = false
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
|
||||
// An error
|
||||
d = ""
|
||||
e = false
|
||||
return
|
||||
}
|
||||
|
||||
// Get implements Storage.Get
|
||||
func (s *FolderStorage) Get(key string, source string, update bool) error {
|
||||
dir := s.dir(key)
|
||||
if !update {
|
||||
if _, err := os.Stat(dir); err == nil {
|
||||
// If the directory already exists, then we're done since
|
||||
// we're not updating.
|
||||
return nil
|
||||
} else if !os.IsNotExist(err) {
|
||||
// If the error we got wasn't a file-not-exist error, then
|
||||
// something went wrong and we should report it.
|
||||
return fmt.Errorf("Error reading module directory: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Get the source. This always forces an update.
|
||||
return Get(dir, source)
|
||||
}
|
||||
|
||||
// dir returns the directory name internally that we'll use to map to
|
||||
// internally.
|
||||
func (s *FolderStorage) dir(key string) string {
|
||||
sum := md5.Sum([]byte(key))
|
||||
return filepath.Join(s.StorageDir, hex.EncodeToString(sum[:]))
|
||||
}
|
||||
48
vendor/github.com/hashicorp/go-getter/folder_storage_test.go
generated
vendored
Normal file
48
vendor/github.com/hashicorp/go-getter/folder_storage_test.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFolderStorage_impl(t *testing.T) {
|
||||
var _ Storage = new(FolderStorage)
|
||||
}
|
||||
|
||||
func TestFolderStorage(t *testing.T) {
|
||||
s := &FolderStorage{StorageDir: tempDir(t)}
|
||||
|
||||
module := testModule("basic")
|
||||
|
||||
// A module shouldn't exist at first...
|
||||
_, ok, err := s.Dir(module)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if ok {
|
||||
t.Fatal("should not exist")
|
||||
}
|
||||
|
||||
key := "foo"
|
||||
|
||||
// We can get it
|
||||
err = s.Get(key, module, false)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Now the module exists
|
||||
dir, ok, err := s.Dir(key)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatal("should exist")
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dir, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
146
vendor/github.com/hashicorp/go-getter/get.go
generated
vendored
Normal file
146
vendor/github.com/hashicorp/go-getter/get.go
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
// getter is a package for downloading files or directories from a variety of
|
||||
// protocols.
|
||||
//
|
||||
// getter is unique in its ability to download both directories and files.
|
||||
// It also detects certain source strings to be protocol-specific URLs. For
|
||||
// example, "github.com/hashicorp/go-getter" would turn into a Git URL and
|
||||
// use the Git protocol.
|
||||
//
|
||||
// Protocols and detectors are extensible.
|
||||
//
|
||||
// To get started, see Client.
|
||||
package getter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"syscall"
|
||||
|
||||
cleanhttp "github.com/hashicorp/go-cleanhttp"
|
||||
)
|
||||
|
||||
// Getter defines the interface that schemes must implement to download
|
||||
// things.
|
||||
type Getter interface {
|
||||
// Get downloads the given URL into the given directory. This always
|
||||
// assumes that we're updating and gets the latest version that it can.
|
||||
//
|
||||
// The directory may already exist (if we're updating). If it is in a
|
||||
// format that isn't understood, an error should be returned. Get shouldn't
|
||||
// simply nuke the directory.
|
||||
Get(string, *url.URL) error
|
||||
|
||||
// GetFile downloads the give URL into the given path. The URL must
|
||||
// reference a single file. If possible, the Getter should check if
|
||||
// the remote end contains the same file and no-op this operation.
|
||||
GetFile(string, *url.URL) error
|
||||
|
||||
// ClientMode returns the mode based on the given URL. This is used to
|
||||
// allow clients to let the getters decide which mode to use.
|
||||
ClientMode(*url.URL) (ClientMode, error)
|
||||
}
|
||||
|
||||
// Getters is the mapping of scheme to the Getter implementation that will
|
||||
// be used to get a dependency.
|
||||
var Getters map[string]Getter
|
||||
|
||||
// forcedRegexp is the regular expression that finds forced getters. This
|
||||
// syntax is schema::url, example: git::https://foo.com
|
||||
var forcedRegexp = regexp.MustCompile(`^([A-Za-z0-9]+)::(.+)$`)
|
||||
|
||||
// httpClient is the default client to be used by HttpGetters.
|
||||
var httpClient = cleanhttp.DefaultClient()
|
||||
|
||||
func init() {
|
||||
httpGetter := &HttpGetter{
|
||||
Netrc: true,
|
||||
}
|
||||
|
||||
Getters = map[string]Getter{
|
||||
"file": new(FileGetter),
|
||||
"git": new(GitGetter),
|
||||
"hg": new(HgGetter),
|
||||
"s3": new(S3Getter),
|
||||
"http": httpGetter,
|
||||
"https": httpGetter,
|
||||
}
|
||||
}
|
||||
|
||||
// Get downloads the directory specified by src into the folder specified by
|
||||
// dst. If dst already exists, Get will attempt to update it.
|
||||
//
|
||||
// src is a URL, whereas dst is always just a file path to a folder. This
|
||||
// folder doesn't need to exist. It will be created if it doesn't exist.
|
||||
func Get(dst, src string) error {
|
||||
return (&Client{
|
||||
Src: src,
|
||||
Dst: dst,
|
||||
Dir: true,
|
||||
Getters: Getters,
|
||||
}).Get()
|
||||
}
|
||||
|
||||
// GetAny downloads a URL into the given destination. Unlike Get or
|
||||
// GetFile, both directories and files are supported.
|
||||
//
|
||||
// dst must be a directory. If src is a file, it will be downloaded
|
||||
// into dst with the basename of the URL. If src is a directory or
|
||||
// archive, it will be unpacked directly into dst.
|
||||
func GetAny(dst, src string) error {
|
||||
return (&Client{
|
||||
Src: src,
|
||||
Dst: dst,
|
||||
Mode: ClientModeAny,
|
||||
Getters: Getters,
|
||||
}).Get()
|
||||
}
|
||||
|
||||
// GetFile downloads the file specified by src into the path specified by
|
||||
// dst.
|
||||
func GetFile(dst, src string) error {
|
||||
return (&Client{
|
||||
Src: src,
|
||||
Dst: dst,
|
||||
Dir: false,
|
||||
Getters: Getters,
|
||||
}).Get()
|
||||
}
|
||||
|
||||
// getRunCommand is a helper that will run a command and capture the output
|
||||
// in the case an error happens.
|
||||
func getRunCommand(cmd *exec.Cmd) error {
|
||||
var buf bytes.Buffer
|
||||
cmd.Stdout = &buf
|
||||
cmd.Stderr = &buf
|
||||
err := cmd.Run()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
// The program has exited with an exit code != 0
|
||||
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||
return fmt.Errorf(
|
||||
"%s exited with %d: %s",
|
||||
cmd.Path,
|
||||
status.ExitStatus(),
|
||||
buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("error running %s: %s", cmd.Path, buf.String())
|
||||
}
|
||||
|
||||
// getForcedGetter takes a source and returns the tuple of the forced
|
||||
// getter and the raw URL (without the force syntax).
|
||||
func getForcedGetter(src string) (string, string) {
|
||||
var forced string
|
||||
if ms := forcedRegexp.FindStringSubmatch(src); ms != nil {
|
||||
forced = ms[1]
|
||||
src = ms[2]
|
||||
}
|
||||
|
||||
return forced, src
|
||||
}
|
||||
32
vendor/github.com/hashicorp/go-getter/get_file.go
generated
vendored
Normal file
32
vendor/github.com/hashicorp/go-getter/get_file.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
)
|
||||
|
||||
// FileGetter is a Getter implementation that will download a module from
|
||||
// a file scheme.
|
||||
type FileGetter struct {
|
||||
// Copy, if set to true, will copy data instead of using a symlink
|
||||
Copy bool
|
||||
}
|
||||
|
||||
func (g *FileGetter) ClientMode(u *url.URL) (ClientMode, error) {
|
||||
path := u.Path
|
||||
if u.RawPath != "" {
|
||||
path = u.RawPath
|
||||
}
|
||||
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Check if the source is a directory.
|
||||
if fi.IsDir() {
|
||||
return ClientModeDir, nil
|
||||
}
|
||||
|
||||
return ClientModeFile, nil
|
||||
}
|
||||
202
vendor/github.com/hashicorp/go-getter/get_file_test.go
generated
vendored
Normal file
202
vendor/github.com/hashicorp/go-getter/get_file_test.go
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFileGetter_impl(t *testing.T) {
|
||||
var _ Getter = new(FileGetter)
|
||||
}
|
||||
|
||||
func TestFileGetter(t *testing.T) {
|
||||
g := new(FileGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
// With a dir that doesn't exist
|
||||
if err := g.Get(dst, testModuleURL("basic")); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the destination folder is a symlink
|
||||
fi, err := os.Lstat(dst)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if fi.Mode()&os.ModeSymlink == 0 {
|
||||
t.Fatal("destination is not a symlink")
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileGetter_sourceFile(t *testing.T) {
|
||||
g := new(FileGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
// With a source URL that is a path to a file
|
||||
u := testModuleURL("basic")
|
||||
u.Path += "/main.tf"
|
||||
if err := g.Get(dst, u); err == nil {
|
||||
t.Fatal("should error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileGetter_sourceNoExist(t *testing.T) {
|
||||
g := new(FileGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
// With a source URL that doesn't exist
|
||||
u := testModuleURL("basic")
|
||||
u.Path += "/main"
|
||||
if err := g.Get(dst, u); err == nil {
|
||||
t.Fatal("should error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileGetter_dir(t *testing.T) {
|
||||
g := new(FileGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
if err := os.MkdirAll(dst, 0755); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// With a dir that exists that isn't a symlink
|
||||
if err := g.Get(dst, testModuleURL("basic")); err == nil {
|
||||
t.Fatal("should error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileGetter_dirSymlink(t *testing.T) {
|
||||
g := new(FileGetter)
|
||||
dst := tempDir(t)
|
||||
dst2 := tempDir(t)
|
||||
|
||||
// Make parents
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if err := os.MkdirAll(dst2, 0755); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Make a symlink
|
||||
if err := os.Symlink(dst2, dst); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// With a dir that exists that isn't a symlink
|
||||
if err := g.Get(dst, testModuleURL("basic")); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileGetter_GetFile(t *testing.T) {
|
||||
g := new(FileGetter)
|
||||
dst := tempFile(t)
|
||||
|
||||
// With a dir that doesn't exist
|
||||
if err := g.GetFile(dst, testModuleURL("basic-file/foo.txt")); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the destination folder is a symlink
|
||||
fi, err := os.Lstat(dst)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if fi.Mode()&os.ModeSymlink == 0 {
|
||||
t.Fatal("destination is not a symlink")
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
assertContents(t, dst, "Hello\n")
|
||||
}
|
||||
|
||||
func TestFileGetter_GetFile_Copy(t *testing.T) {
|
||||
g := new(FileGetter)
|
||||
g.Copy = true
|
||||
|
||||
dst := tempFile(t)
|
||||
|
||||
// With a dir that doesn't exist
|
||||
if err := g.GetFile(dst, testModuleURL("basic-file/foo.txt")); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the destination folder is a symlink
|
||||
fi, err := os.Lstat(dst)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if fi.Mode()&os.ModeSymlink != 0 {
|
||||
t.Fatal("destination is a symlink")
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
assertContents(t, dst, "Hello\n")
|
||||
}
|
||||
|
||||
// https://github.com/hashicorp/terraform/issues/8418
|
||||
func TestFileGetter_percent2F(t *testing.T) {
|
||||
g := new(FileGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
// With a dir that doesn't exist
|
||||
if err := g.Get(dst, testModuleURL("basic%2Ftest")); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileGetter_ClientMode_notexist(t *testing.T) {
|
||||
g := new(FileGetter)
|
||||
|
||||
u := testURL("nonexistent")
|
||||
if _, err := g.ClientMode(u); err == nil {
|
||||
t.Fatal("expect source file error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileGetter_ClientMode_file(t *testing.T) {
|
||||
g := new(FileGetter)
|
||||
|
||||
// Check the client mode when pointed at a file.
|
||||
mode, err := g.ClientMode(testModuleURL("basic-file/foo.txt"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if mode != ClientModeFile {
|
||||
t.Fatal("expect ClientModeFile")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileGetter_ClientMode_dir(t *testing.T) {
|
||||
g := new(FileGetter)
|
||||
|
||||
// Check the client mode when pointed at a directory.
|
||||
mode, err := g.ClientMode(testModuleURL("basic"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if mode != ClientModeDir {
|
||||
t.Fatal("expect ClientModeDir")
|
||||
}
|
||||
}
|
||||
103
vendor/github.com/hashicorp/go-getter/get_file_unix.go
generated
vendored
Normal file
103
vendor/github.com/hashicorp/go-getter/get_file_unix.go
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
// +build !windows
|
||||
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func (g *FileGetter) Get(dst string, u *url.URL) error {
|
||||
path := u.Path
|
||||
if u.RawPath != "" {
|
||||
path = u.RawPath
|
||||
}
|
||||
|
||||
// The source path must exist and be a directory to be usable.
|
||||
if fi, err := os.Stat(path); err != nil {
|
||||
return fmt.Errorf("source path error: %s", err)
|
||||
} else if !fi.IsDir() {
|
||||
return fmt.Errorf("source path must be a directory")
|
||||
}
|
||||
|
||||
fi, err := os.Lstat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the destination already exists, it must be a symlink
|
||||
if err == nil {
|
||||
mode := fi.Mode()
|
||||
if mode&os.ModeSymlink == 0 {
|
||||
return fmt.Errorf("destination exists and is not a symlink")
|
||||
}
|
||||
|
||||
// Remove the destination
|
||||
if err := os.Remove(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.Symlink(path, dst)
|
||||
}
|
||||
|
||||
func (g *FileGetter) GetFile(dst string, u *url.URL) error {
|
||||
path := u.Path
|
||||
if u.RawPath != "" {
|
||||
path = u.RawPath
|
||||
}
|
||||
|
||||
// The source path must exist and be a file to be usable.
|
||||
if fi, err := os.Stat(path); err != nil {
|
||||
return fmt.Errorf("source path error: %s", err)
|
||||
} else if fi.IsDir() {
|
||||
return fmt.Errorf("source path must be a file")
|
||||
}
|
||||
|
||||
_, err := os.Lstat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the destination already exists, it must be a symlink
|
||||
if err == nil {
|
||||
// Remove the destination
|
||||
if err := os.Remove(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we're not copying, just symlink and we're done
|
||||
if !g.Copy {
|
||||
return os.Symlink(path, dst)
|
||||
}
|
||||
|
||||
// Copy
|
||||
srcF, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcF.Close()
|
||||
|
||||
dstF, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstF.Close()
|
||||
|
||||
_, err = io.Copy(dstF, srcF)
|
||||
return err
|
||||
}
|
||||
120
vendor/github.com/hashicorp/go-getter/get_file_windows.go
generated
vendored
Normal file
120
vendor/github.com/hashicorp/go-getter/get_file_windows.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
// +build windows
|
||||
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (g *FileGetter) Get(dst string, u *url.URL) error {
|
||||
path := u.Path
|
||||
if u.RawPath != "" {
|
||||
path = u.RawPath
|
||||
}
|
||||
|
||||
// The source path must exist and be a directory to be usable.
|
||||
if fi, err := os.Stat(path); err != nil {
|
||||
return fmt.Errorf("source path error: %s", err)
|
||||
} else if !fi.IsDir() {
|
||||
return fmt.Errorf("source path must be a directory")
|
||||
}
|
||||
|
||||
fi, err := os.Lstat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the destination already exists, it must be a symlink
|
||||
if err == nil {
|
||||
mode := fi.Mode()
|
||||
if mode&os.ModeSymlink == 0 {
|
||||
return fmt.Errorf("destination exists and is not a symlink")
|
||||
}
|
||||
|
||||
// Remove the destination
|
||||
if err := os.Remove(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sourcePath := toBackslash(path)
|
||||
|
||||
// Use mklink to create a junction point
|
||||
output, err := exec.Command("cmd", "/c", "mklink", "/J", dst, sourcePath).CombinedOutput()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to run mklink %v %v: %v %q", dst, sourcePath, err, output)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *FileGetter) GetFile(dst string, u *url.URL) error {
|
||||
path := u.Path
|
||||
if u.RawPath != "" {
|
||||
path = u.RawPath
|
||||
}
|
||||
|
||||
// The source path must exist and be a directory to be usable.
|
||||
if fi, err := os.Stat(path); err != nil {
|
||||
return fmt.Errorf("source path error: %s", err)
|
||||
} else if fi.IsDir() {
|
||||
return fmt.Errorf("source path must be a file")
|
||||
}
|
||||
|
||||
_, err := os.Lstat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the destination already exists, it must be a symlink
|
||||
if err == nil {
|
||||
// Remove the destination
|
||||
if err := os.Remove(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we're not copying, just symlink and we're done
|
||||
if !g.Copy {
|
||||
return os.Symlink(path, dst)
|
||||
}
|
||||
|
||||
// Copy
|
||||
srcF, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcF.Close()
|
||||
|
||||
dstF, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstF.Close()
|
||||
|
||||
_, err = io.Copy(dstF, srcF)
|
||||
return err
|
||||
}
|
||||
|
||||
// toBackslash returns the result of replacing each slash character
|
||||
// in path with a backslash ('\') character. Multiple separators are
|
||||
// replaced by multiple backslashes.
|
||||
func toBackslash(path string) string {
|
||||
return strings.Replace(path, "/", "\\", -1)
|
||||
}
|
||||
241
vendor/github.com/hashicorp/go-getter/get_git.go
generated
vendored
Normal file
241
vendor/github.com/hashicorp/go-getter/get_git.go
generated
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
urlhelper "github.com/hashicorp/go-getter/helper/url"
|
||||
"github.com/hashicorp/go-safetemp"
|
||||
"github.com/hashicorp/go-version"
|
||||
)
|
||||
|
||||
// GitGetter is a Getter implementation that will download a module from
|
||||
// a git repository.
|
||||
type GitGetter struct{}
|
||||
|
||||
func (g *GitGetter) ClientMode(_ *url.URL) (ClientMode, error) {
|
||||
return ClientModeDir, nil
|
||||
}
|
||||
|
||||
func (g *GitGetter) Get(dst string, u *url.URL) error {
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
return fmt.Errorf("git must be available and on the PATH")
|
||||
}
|
||||
|
||||
// Extract some query parameters we use
|
||||
var ref, sshKey string
|
||||
q := u.Query()
|
||||
if len(q) > 0 {
|
||||
ref = q.Get("ref")
|
||||
q.Del("ref")
|
||||
|
||||
sshKey = q.Get("sshkey")
|
||||
q.Del("sshkey")
|
||||
|
||||
// Copy the URL
|
||||
var newU url.URL = *u
|
||||
u = &newU
|
||||
u.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
var sshKeyFile string
|
||||
if sshKey != "" {
|
||||
// Check that the git version is sufficiently new.
|
||||
if err := checkGitVersion("2.3"); err != nil {
|
||||
return fmt.Errorf("Error using ssh key: %v", err)
|
||||
}
|
||||
|
||||
// We have an SSH key - decode it.
|
||||
raw, err := base64.StdEncoding.DecodeString(sshKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a temp file for the key and ensure it is removed.
|
||||
fh, err := ioutil.TempFile("", "go-getter")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sshKeyFile = fh.Name()
|
||||
defer os.Remove(sshKeyFile)
|
||||
|
||||
// Set the permissions prior to writing the key material.
|
||||
if err := os.Chmod(sshKeyFile, 0600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write the raw key into the temp file.
|
||||
_, err = fh.Write(raw)
|
||||
fh.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Clone or update the repository
|
||||
_, err := os.Stat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
err = g.update(dst, sshKeyFile, ref)
|
||||
} else {
|
||||
err = g.clone(dst, sshKeyFile, u)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Next: check out the proper tag/branch if it is specified, and checkout
|
||||
if ref != "" {
|
||||
if err := g.checkout(dst, ref); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Lastly, download any/all submodules.
|
||||
return g.fetchSubmodules(dst, sshKeyFile)
|
||||
}
|
||||
|
||||
// GetFile for Git doesn't support updating at this time. It will download
|
||||
// the file every time.
|
||||
func (g *GitGetter) GetFile(dst string, u *url.URL) error {
|
||||
td, tdcloser, err := safetemp.Dir("", "getter")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tdcloser.Close()
|
||||
|
||||
// Get the filename, and strip the filename from the URL so we can
|
||||
// just get the repository directly.
|
||||
filename := filepath.Base(u.Path)
|
||||
u.Path = filepath.Dir(u.Path)
|
||||
|
||||
// Get the full repository
|
||||
if err := g.Get(td, u); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy the single file
|
||||
u, err = urlhelper.Parse(fmtFileURL(filepath.Join(td, filename)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fg := &FileGetter{Copy: true}
|
||||
return fg.GetFile(dst, u)
|
||||
}
|
||||
|
||||
func (g *GitGetter) checkout(dst string, ref string) error {
|
||||
cmd := exec.Command("git", "checkout", ref)
|
||||
cmd.Dir = dst
|
||||
return getRunCommand(cmd)
|
||||
}
|
||||
|
||||
func (g *GitGetter) clone(dst, sshKeyFile string, u *url.URL) error {
|
||||
cmd := exec.Command("git", "clone", u.String(), dst)
|
||||
setupGitEnv(cmd, sshKeyFile)
|
||||
return getRunCommand(cmd)
|
||||
}
|
||||
|
||||
func (g *GitGetter) update(dst, sshKeyFile, ref string) error {
|
||||
// Determine if we're a branch. If we're NOT a branch, then we just
|
||||
// switch to master prior to checking out
|
||||
cmd := exec.Command("git", "show-ref", "-q", "--verify", "refs/heads/"+ref)
|
||||
cmd.Dir = dst
|
||||
|
||||
if getRunCommand(cmd) != nil {
|
||||
// Not a branch, switch to master. This will also catch non-existent
|
||||
// branches, in which case we want to switch to master and then
|
||||
// checkout the proper branch later.
|
||||
ref = "master"
|
||||
}
|
||||
|
||||
// We have to be on a branch to pull
|
||||
if err := g.checkout(dst, ref); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd = exec.Command("git", "pull", "--ff-only")
|
||||
cmd.Dir = dst
|
||||
setupGitEnv(cmd, sshKeyFile)
|
||||
return getRunCommand(cmd)
|
||||
}
|
||||
|
||||
// fetchSubmodules downloads any configured submodules recursively.
|
||||
func (g *GitGetter) fetchSubmodules(dst, sshKeyFile string) error {
|
||||
cmd := exec.Command("git", "submodule", "update", "--init", "--recursive")
|
||||
cmd.Dir = dst
|
||||
setupGitEnv(cmd, sshKeyFile)
|
||||
return getRunCommand(cmd)
|
||||
}
|
||||
|
||||
// setupGitEnv sets up the environment for the given command. This is used to
|
||||
// pass configuration data to git and ssh and enables advanced cloning methods.
|
||||
func setupGitEnv(cmd *exec.Cmd, sshKeyFile string) {
|
||||
const gitSSHCommand = "GIT_SSH_COMMAND="
|
||||
var sshCmd []string
|
||||
|
||||
// If we have an existing GIT_SSH_COMMAND, we need to append our options.
|
||||
// We will also remove our old entry to make sure the behavior is the same
|
||||
// with versions of Go < 1.9.
|
||||
env := os.Environ()
|
||||
for i, v := range env {
|
||||
if strings.HasPrefix(v, gitSSHCommand) {
|
||||
sshCmd = []string{v}
|
||||
|
||||
env[i], env[len(env)-1] = env[len(env)-1], env[i]
|
||||
env = env[:len(env)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(sshCmd) == 0 {
|
||||
sshCmd = []string{gitSSHCommand + "ssh"}
|
||||
}
|
||||
|
||||
if sshKeyFile != "" {
|
||||
// We have an SSH key temp file configured, tell ssh about this.
|
||||
sshCmd = append(sshCmd, "-i", sshKeyFile)
|
||||
}
|
||||
|
||||
env = append(env, strings.Join(sshCmd, " "))
|
||||
cmd.Env = env
|
||||
}
|
||||
|
||||
// checkGitVersion is used to check the version of git installed on the system
|
||||
// against a known minimum version. Returns an error if the installed version
|
||||
// is older than the given minimum.
|
||||
func checkGitVersion(min string) error {
|
||||
want, err := version.NewVersion(min)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := exec.Command("git", "version").Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fields := strings.Fields(string(out))
|
||||
if len(fields) < 3 {
|
||||
return fmt.Errorf("Unexpected 'git version' output: %q", string(out))
|
||||
}
|
||||
|
||||
have, err := version.NewVersion(fields[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if have.LessThan(want) {
|
||||
return fmt.Errorf("Required git version = %s, have %s", want, have)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
425
vendor/github.com/hashicorp/go-getter/get_git_test.go
generated
vendored
Normal file
425
vendor/github.com/hashicorp/go-getter/get_git_test.go
generated
vendored
Normal file
@@ -0,0 +1,425 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testHasGit bool
|
||||
|
||||
func init() {
|
||||
if _, err := exec.LookPath("git"); err == nil {
|
||||
testHasGit = true
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitGetter_impl(t *testing.T) {
|
||||
var _ Getter = new(GitGetter)
|
||||
}
|
||||
|
||||
func TestGitGetter(t *testing.T) {
|
||||
if !testHasGit {
|
||||
t.Log("git not found, skipping")
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
g := new(GitGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
repo := testGitRepo(t, "basic")
|
||||
repo.commitFile("foo.txt", "hello")
|
||||
|
||||
// With a dir that doesn't exist
|
||||
if err := g.Get(dst, repo.url); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "foo.txt")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitGetter_branch(t *testing.T) {
|
||||
if !testHasGit {
|
||||
t.Log("git not found, skipping")
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
g := new(GitGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
repo := testGitRepo(t, "branch")
|
||||
repo.git("checkout", "-b", "test-branch")
|
||||
repo.commitFile("branch.txt", "branch")
|
||||
|
||||
q := repo.url.Query()
|
||||
q.Add("ref", "test-branch")
|
||||
repo.url.RawQuery = q.Encode()
|
||||
|
||||
if err := g.Get(dst, repo.url); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "branch.txt")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Get again should work
|
||||
if err := g.Get(dst, repo.url); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath = filepath.Join(dst, "branch.txt")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitGetter_branchUpdate(t *testing.T) {
|
||||
if !testHasGit {
|
||||
t.Log("git not found, skipping")
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
g := new(GitGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
// First setup the state with a fresh branch
|
||||
repo := testGitRepo(t, "branch-update")
|
||||
repo.git("checkout", "-b", "test-branch")
|
||||
repo.commitFile("branch.txt", "branch")
|
||||
|
||||
// Get the "test-branch" branch
|
||||
q := repo.url.Query()
|
||||
q.Add("ref", "test-branch")
|
||||
repo.url.RawQuery = q.Encode()
|
||||
if err := g.Get(dst, repo.url); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "branch.txt")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Commit an update to the branch
|
||||
repo.commitFile("branch-update.txt", "branch-update")
|
||||
|
||||
// Get again should work
|
||||
if err := g.Get(dst, repo.url); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath = filepath.Join(dst, "branch-update.txt")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitGetter_tag(t *testing.T) {
|
||||
if !testHasGit {
|
||||
t.Log("git not found, skipping")
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
g := new(GitGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
repo := testGitRepo(t, "tag")
|
||||
repo.commitFile("tag.txt", "tag")
|
||||
repo.git("tag", "v1.0")
|
||||
|
||||
q := repo.url.Query()
|
||||
q.Add("ref", "v1.0")
|
||||
repo.url.RawQuery = q.Encode()
|
||||
|
||||
if err := g.Get(dst, repo.url); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "tag.txt")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Get again should work
|
||||
if err := g.Get(dst, repo.url); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath = filepath.Join(dst, "tag.txt")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitGetter_GetFile(t *testing.T) {
|
||||
if !testHasGit {
|
||||
t.Log("git not found, skipping")
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
g := new(GitGetter)
|
||||
dst := tempFile(t)
|
||||
|
||||
repo := testGitRepo(t, "file")
|
||||
repo.commitFile("file.txt", "hello")
|
||||
|
||||
// Download the file
|
||||
repo.url.Path = filepath.Join(repo.url.Path, "file.txt")
|
||||
if err := g.GetFile(dst, repo.url); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
if _, err := os.Stat(dst); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
assertContents(t, dst, "hello")
|
||||
}
|
||||
|
||||
func TestGitGetter_gitVersion(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "go-getter")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
script := filepath.Join(dir, "git")
|
||||
err = ioutil.WriteFile(
|
||||
script,
|
||||
[]byte("#!/bin/sh\necho \"git version 2.0 (Some Metadata Here)\n\""),
|
||||
0700)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func(v string) {
|
||||
os.Setenv("PATH", v)
|
||||
}(os.Getenv("PATH"))
|
||||
|
||||
os.Setenv("PATH", dir)
|
||||
|
||||
// Asking for a higher version throws an error
|
||||
if err := checkGitVersion("2.3"); err == nil {
|
||||
t.Fatal("expect git version error")
|
||||
}
|
||||
|
||||
// Passes when version is satisfied
|
||||
if err := checkGitVersion("1.9"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitGetter_sshKey(t *testing.T) {
|
||||
if !testHasGit {
|
||||
t.Log("git not found, skipping")
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
g := new(GitGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
encodedKey := base64.StdEncoding.EncodeToString([]byte(testGitToken))
|
||||
|
||||
u, err := url.Parse("ssh://git@github.com/hashicorp/test-private-repo" +
|
||||
"?sshkey=" + encodedKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := g.Get(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
readmePath := filepath.Join(dst, "README.md")
|
||||
if _, err := os.Stat(readmePath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitGetter_submodule(t *testing.T) {
|
||||
if !testHasGit {
|
||||
t.Log("git not found, skipping")
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
g := new(GitGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
// Set up the grandchild
|
||||
gc := testGitRepo(t, "grandchild")
|
||||
gc.commitFile("grandchild.txt", "grandchild")
|
||||
|
||||
// Set up the child
|
||||
c := testGitRepo(t, "child")
|
||||
c.commitFile("child.txt", "child")
|
||||
c.git("submodule", "add", gc.dir)
|
||||
c.git("commit", "-m", "Add grandchild submodule")
|
||||
|
||||
// Set up the parent
|
||||
p := testGitRepo(t, "parent")
|
||||
p.commitFile("parent.txt", "parent")
|
||||
p.git("submodule", "add", c.dir)
|
||||
p.git("commit", "-m", "Add child submodule")
|
||||
|
||||
// Clone the root repository
|
||||
if err := g.Get(dst, p.url); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Check that the files exist
|
||||
for _, path := range []string{
|
||||
filepath.Join(dst, "parent.txt"),
|
||||
filepath.Join(dst, "child", "child.txt"),
|
||||
filepath.Join(dst, "child", "grandchild", "grandchild.txt"),
|
||||
} {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitGetter_setupGitEnv_sshKey(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skipf("skipping on windows since the test requires sh")
|
||||
return
|
||||
}
|
||||
|
||||
cmd := exec.Command("/bin/sh", "-c", "echo $GIT_SSH_COMMAND")
|
||||
setupGitEnv(cmd, "/tmp/foo.pem")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(string(out))
|
||||
if actual != "ssh -i /tmp/foo.pem" {
|
||||
t.Fatalf("unexpected GIT_SSH_COMMAND: %q", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitGetter_setupGitEnvWithExisting_sshKey(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skipf("skipping on windows since the test requires sh")
|
||||
return
|
||||
}
|
||||
|
||||
// start with an existing ssh command configuration
|
||||
os.Setenv("GIT_SSH_COMMAND", "ssh -o StrictHostKeyChecking=no")
|
||||
defer os.Setenv("GIT_SSH_COMMAND", "")
|
||||
|
||||
cmd := exec.Command("/bin/sh", "-c", "echo $GIT_SSH_COMMAND")
|
||||
setupGitEnv(cmd, "/tmp/foo.pem")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
actual := strings.TrimSpace(string(out))
|
||||
if actual != "ssh -o StrictHostKeyChecking=no -i /tmp/foo.pem" {
|
||||
t.Fatalf("unexpected GIT_SSH_COMMAND: %q", actual)
|
||||
}
|
||||
}
|
||||
|
||||
// gitRepo is a helper struct which controls a single temp git repo.
|
||||
type gitRepo struct {
|
||||
t *testing.T
|
||||
url *url.URL
|
||||
dir string
|
||||
}
|
||||
|
||||
// testGitRepo creates a new test git repository.
|
||||
func testGitRepo(t *testing.T, name string) *gitRepo {
|
||||
dir, err := ioutil.TempDir("", "go-getter")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dir = filepath.Join(dir, name)
|
||||
if err := os.Mkdir(dir, 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := &gitRepo{
|
||||
t: t,
|
||||
dir: dir,
|
||||
}
|
||||
|
||||
url, err := url.Parse("file://" + r.dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r.url = url
|
||||
|
||||
r.git("init")
|
||||
r.git("config", "user.name", "go-getter")
|
||||
r.git("config", "user.email", "go-getter@hashicorp.com")
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// git runs a git command against the repo.
|
||||
func (r *gitRepo) git(args ...string) {
|
||||
cmd := exec.Command("git", args...)
|
||||
cmd.Dir = r.dir
|
||||
if err := cmd.Run(); err != nil {
|
||||
r.t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// commitFile writes and commits a text file to the repo.
|
||||
func (r *gitRepo) commitFile(file, content string) {
|
||||
path := filepath.Join(r.dir, file)
|
||||
if err := ioutil.WriteFile(path, []byte(content), 0600); err != nil {
|
||||
r.t.Fatal(err)
|
||||
}
|
||||
r.git("add", file)
|
||||
r.git("commit", "-m", "Adding "+file)
|
||||
}
|
||||
|
||||
// This is a read-only deploy key for an empty test repository.
|
||||
// Note: This is split over multiple lines to avoid being disabled by key
|
||||
// scanners automatically.
|
||||
var testGitToken = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEA9cHsxCl3Jjgu9DHpwvmfFOl1XEdY+ShHDR/cMnzJ5ddk5/oV
|
||||
Wy6EWatvyHZfRSZMwzv4PtKeUPm6iXjqWp4xdWU9khlPzozyj+U9Fq70TRVUW9E5
|
||||
T1XdQVwJE421yffr4VMMwu60wBqjI1epapH2i2inYvw9Zl9X2MXq0+jTvFvDerbT
|
||||
mDtfStDPljenELAIZtWVETSvbI46gALwbxbM2292ZUIL4D6jRz0aZMmyy/twYv8r
|
||||
9WGJLwmYzU518Ie7zqKW/mCTdTrV0WRiDj0MeRaPgrGY9amuHE4r9iG/cJkwpKAO
|
||||
Ccz0Hs6i89u9vZnTqZU9V7weJqRAQcMjXXR6yQIDAQABAoIBAQDBzICKnGxiTlHw
|
||||
rd+6qqChnAy5jWYDbZjCJ8q8YZ3RS08+g/8NXZxvHftTqM0uOaq1FviHig3gq15H
|
||||
hHvCpBc6jXDFYoKFzq6FfO/0kFkE5HoWweIgxwRow0xBCDJAJ+ryUEyy+Ay/pQHb
|
||||
IAjwilRS0V+WdnVw4mTjBAhPvb4jPOo97Yfy3PYUyx2F3newkqXOZy+zx3G/ANoa
|
||||
ncypfMGyy76sfCWKqw4J1gVkVQLwbB6gQkXUFGYwY9sRrxbG93kQw76Flc/E/s52
|
||||
62j4v1IM0fq0t/St+Y/+s6Lkw` + `aqt3ft1nsqWcRaVDdqvMfkzgJGXlw0bGzJG5MEQ
|
||||
AIBq3dHRAoGBAP8OeG/DKG2Z1VmSfzuz1pas1fbZ+F7venOBrjez3sKlb3Pyl2aH
|
||||
mt2wjaTUi5v10VrHgYtOEdqyhQeUSYydWXIBKNMag0NLLrfFUKZK+57wrHWFdFjn
|
||||
VgpsdkLSNTOZpC8gA5OaJ+36IcOPfGqyyP9wuuRoaYnVT1KEzqLa9FEFAoGBAPaq
|
||||
pglwhil2rxjJE4zq0afQLNpAfi7Xqcrepij+xvJIcIj7nawxXuPxqRFxONE/h3yX
|
||||
zkybO8wLdbHX9Iw/wc1j50Uf1Z5gHdLf7/hQJoWKpz1RnkWRy6CYON8v1tpVp0tb
|
||||
OAajR/kZnzebq2mfa7pyy5zDCX++2kp/dcFwHf31AoGAE8oupBVTZLWj7TBFuP8q
|
||||
LkS40U92Sv9v09iDCQVmylmFvUxcXPM2m+7f/qMTNgWrucxzC7kB/6MMWVszHbrz
|
||||
vrnCTibnemgx9sZTjKOSxHFOIEw7i85fSa3Cu0qOIDPSnmlwfZpfcMKQrhjLAYhf
|
||||
uhooFiLX1X78iZ2OXup4PHUCgYEAsmBrm83sp1V1gAYBBlnVbXakyNv0pCk/Vz61
|
||||
iFXeRt1NzDGxLxGw3kQnED8BaIh5kQcyn8Fud7sdzJMv/LAqlT4Ww60mzNYTGyjo
|
||||
H3jOsqm3ESfRvduWFreeAQBWbiOczGjV1i8D4EbAFfWT+tjXjchwKBf+6Yt5zn/o
|
||||
Bw/uEHUCgYAFs+JPOR25oRyBs7ujrMo/OY1z/eXTVVgZxY+tYGe1FJqDeFyR7ytK
|
||||
+JBB1MuDwQKGm2wSIXdCzTNoIx2B9zTseiPTwT8G7vqNFhXoIaTBp4P2xIQb45mJ
|
||||
7GkTsMBHwpSMOXgX9Weq3v5xOJ2WxVtjENmd6qzxcYCO5lP15O17hA==
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
131
vendor/github.com/hashicorp/go-getter/get_hg.go
generated
vendored
Normal file
131
vendor/github.com/hashicorp/go-getter/get_hg.go
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
urlhelper "github.com/hashicorp/go-getter/helper/url"
|
||||
"github.com/hashicorp/go-safetemp"
|
||||
)
|
||||
|
||||
// HgGetter is a Getter implementation that will download a module from
|
||||
// a Mercurial repository.
|
||||
type HgGetter struct{}
|
||||
|
||||
func (g *HgGetter) ClientMode(_ *url.URL) (ClientMode, error) {
|
||||
return ClientModeDir, nil
|
||||
}
|
||||
|
||||
func (g *HgGetter) Get(dst string, u *url.URL) error {
|
||||
if _, err := exec.LookPath("hg"); err != nil {
|
||||
return fmt.Errorf("hg must be available and on the PATH")
|
||||
}
|
||||
|
||||
newURL, err := urlhelper.Parse(u.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fixWindowsDrivePath(newURL) {
|
||||
// See valid file path form on http://www.selenic.com/hg/help/urls
|
||||
newURL.Path = fmt.Sprintf("/%s", newURL.Path)
|
||||
}
|
||||
|
||||
// Extract some query parameters we use
|
||||
var rev string
|
||||
q := newURL.Query()
|
||||
if len(q) > 0 {
|
||||
rev = q.Get("rev")
|
||||
q.Del("rev")
|
||||
|
||||
newURL.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
_, err = os.Stat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
if err := g.clone(dst, newURL); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := g.pull(dst, newURL); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return g.update(dst, newURL, rev)
|
||||
}
|
||||
|
||||
// GetFile for Hg doesn't support updating at this time. It will download
|
||||
// the file every time.
|
||||
func (g *HgGetter) GetFile(dst string, u *url.URL) error {
|
||||
// Create a temporary directory to store the full source. This has to be
|
||||
// a non-existent directory.
|
||||
td, tdcloser, err := safetemp.Dir("", "getter")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tdcloser.Close()
|
||||
|
||||
// Get the filename, and strip the filename from the URL so we can
|
||||
// just get the repository directly.
|
||||
filename := filepath.Base(u.Path)
|
||||
u.Path = filepath.ToSlash(filepath.Dir(u.Path))
|
||||
|
||||
// If we're on Windows, we need to set the host to "localhost" for hg
|
||||
if runtime.GOOS == "windows" {
|
||||
u.Host = "localhost"
|
||||
}
|
||||
|
||||
// Get the full repository
|
||||
if err := g.Get(td, u); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy the single file
|
||||
u, err = urlhelper.Parse(fmtFileURL(filepath.Join(td, filename)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fg := &FileGetter{Copy: true}
|
||||
return fg.GetFile(dst, u)
|
||||
}
|
||||
|
||||
func (g *HgGetter) clone(dst string, u *url.URL) error {
|
||||
cmd := exec.Command("hg", "clone", "-U", u.String(), dst)
|
||||
return getRunCommand(cmd)
|
||||
}
|
||||
|
||||
func (g *HgGetter) pull(dst string, u *url.URL) error {
|
||||
cmd := exec.Command("hg", "pull")
|
||||
cmd.Dir = dst
|
||||
return getRunCommand(cmd)
|
||||
}
|
||||
|
||||
func (g *HgGetter) update(dst string, u *url.URL, rev string) error {
|
||||
args := []string{"update"}
|
||||
if rev != "" {
|
||||
args = append(args, rev)
|
||||
}
|
||||
|
||||
cmd := exec.Command("hg", args...)
|
||||
cmd.Dir = dst
|
||||
return getRunCommand(cmd)
|
||||
}
|
||||
|
||||
func fixWindowsDrivePath(u *url.URL) bool {
|
||||
// hg assumes a file:/// prefix for Windows drive letter file paths.
|
||||
// (e.g. file:///c:/foo/bar)
|
||||
// If the URL Path does not begin with a '/' character, the resulting URL
|
||||
// path will have a file:// prefix. (e.g. file://c:/foo/bar)
|
||||
// See http://www.selenic.com/hg/help/urls and the examples listed in
|
||||
// http://selenic.com/repo/hg-stable/file/1265a3a71d75/mercurial/util.py#l1936
|
||||
return runtime.GOOS == "windows" && u.Scheme == "file" &&
|
||||
len(u.Path) > 1 && u.Path[0] != '/' && u.Path[1] == ':'
|
||||
}
|
||||
98
vendor/github.com/hashicorp/go-getter/get_hg_test.go
generated
vendored
Normal file
98
vendor/github.com/hashicorp/go-getter/get_hg_test.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testHasHg bool
|
||||
|
||||
func init() {
|
||||
if _, err := exec.LookPath("hg"); err == nil {
|
||||
testHasHg = true
|
||||
}
|
||||
}
|
||||
|
||||
func TestHgGetter_impl(t *testing.T) {
|
||||
var _ Getter = new(HgGetter)
|
||||
}
|
||||
|
||||
func TestHgGetter(t *testing.T) {
|
||||
if !testHasHg {
|
||||
t.Log("hg not found, skipping")
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
g := new(HgGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
// With a dir that doesn't exist
|
||||
if err := g.Get(dst, testModuleURL("basic-hg")); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHgGetter_branch(t *testing.T) {
|
||||
if !testHasHg {
|
||||
t.Log("hg not found, skipping")
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
g := new(HgGetter)
|
||||
dst := tempDir(t)
|
||||
|
||||
url := testModuleURL("basic-hg")
|
||||
q := url.Query()
|
||||
q.Add("rev", "test-branch")
|
||||
url.RawQuery = q.Encode()
|
||||
|
||||
if err := g.Get(dst, url); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "main_branch.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Get again should work
|
||||
if err := g.Get(dst, url); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath = filepath.Join(dst, "main_branch.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHgGetter_GetFile(t *testing.T) {
|
||||
if !testHasHg {
|
||||
t.Log("hg not found, skipping")
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
g := new(HgGetter)
|
||||
dst := tempFile(t)
|
||||
|
||||
// Download
|
||||
if err := g.GetFile(dst, testModuleURL("basic-hg/foo.txt")); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
if _, err := os.Stat(dst); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
assertContents(t, dst, "Hello\n")
|
||||
}
|
||||
250
vendor/github.com/hashicorp/go-getter/get_http.go
generated
vendored
Normal file
250
vendor/github.com/hashicorp/go-getter/get_http.go
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-safetemp"
|
||||
)
|
||||
|
||||
// HttpGetter is a Getter implementation that will download from an HTTP
|
||||
// endpoint.
|
||||
//
|
||||
// For file downloads, HTTP is used directly.
|
||||
//
|
||||
// The protocol for downloading a directory from an HTTP endpoing is as follows:
|
||||
//
|
||||
// An HTTP GET request is made to the URL with the additional GET parameter
|
||||
// "terraform-get=1". This lets you handle that scenario specially if you
|
||||
// wish. The response must be a 2xx.
|
||||
//
|
||||
// First, a header is looked for "X-Terraform-Get" which should contain
|
||||
// a source URL to download.
|
||||
//
|
||||
// If the header is not present, then a meta tag is searched for named
|
||||
// "terraform-get" and the content should be a source URL.
|
||||
//
|
||||
// The source URL, whether from the header or meta tag, must be a fully
|
||||
// formed URL. The shorthand syntax of "github.com/foo/bar" or relative
|
||||
// paths are not allowed.
|
||||
type HttpGetter struct {
|
||||
// Netrc, if true, will lookup and use auth information found
|
||||
// in the user's netrc file if available.
|
||||
Netrc bool
|
||||
|
||||
// Client is the http.Client to use for Get requests.
|
||||
// This defaults to a cleanhttp.DefaultClient if left unset.
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
func (g *HttpGetter) ClientMode(u *url.URL) (ClientMode, error) {
|
||||
if strings.HasSuffix(u.Path, "/") {
|
||||
return ClientModeDir, nil
|
||||
}
|
||||
return ClientModeFile, nil
|
||||
}
|
||||
|
||||
func (g *HttpGetter) Get(dst string, u *url.URL) error {
|
||||
// Copy the URL so we can modify it
|
||||
var newU url.URL = *u
|
||||
u = &newU
|
||||
|
||||
if g.Netrc {
|
||||
// Add auth from netrc if we can
|
||||
if err := addAuthFromNetrc(u); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if g.Client == nil {
|
||||
g.Client = httpClient
|
||||
}
|
||||
|
||||
// Add terraform-get to the parameter.
|
||||
q := u.Query()
|
||||
q.Add("terraform-get", "1")
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
// Get the URL
|
||||
resp, err := g.Client.Get(u.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return fmt.Errorf("bad response code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Extract the source URL
|
||||
var source string
|
||||
if v := resp.Header.Get("X-Terraform-Get"); v != "" {
|
||||
source = v
|
||||
} else {
|
||||
source, err = g.parseMeta(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if source == "" {
|
||||
return fmt.Errorf("no source URL was returned")
|
||||
}
|
||||
|
||||
// If there is a subdir component, then we download the root separately
|
||||
// into a temporary directory, then copy over the proper subdir.
|
||||
source, subDir := SourceDirSubdir(source)
|
||||
if subDir == "" {
|
||||
return Get(dst, source)
|
||||
}
|
||||
|
||||
// We have a subdir, time to jump some hoops
|
||||
return g.getSubdir(dst, source, subDir)
|
||||
}
|
||||
|
||||
func (g *HttpGetter) GetFile(dst string, u *url.URL) error {
|
||||
if g.Netrc {
|
||||
// Add auth from netrc if we can
|
||||
if err := addAuthFromNetrc(u); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if g.Client == nil {
|
||||
g.Client = httpClient
|
||||
}
|
||||
|
||||
resp, err := g.Client.Get(u.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("bad response code: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := io.Copy(f, resp.Body)
|
||||
if err == nil && n < resp.ContentLength {
|
||||
err = io.ErrShortWrite
|
||||
}
|
||||
if err1 := f.Close(); err == nil {
|
||||
err = err1
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// getSubdir downloads the source into the destination, but with
|
||||
// the proper subdir.
|
||||
func (g *HttpGetter) getSubdir(dst, source, subDir string) error {
|
||||
// Create a temporary directory to store the full source. This has to be
|
||||
// a non-existent directory.
|
||||
td, tdcloser, err := safetemp.Dir("", "getter")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tdcloser.Close()
|
||||
|
||||
// Download that into the given directory
|
||||
if err := Get(td, source); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Process any globbing
|
||||
sourcePath, err := SubdirGlob(td, subDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make sure the subdir path actually exists
|
||||
if _, err := os.Stat(sourcePath); err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error downloading %s: %s", source, err)
|
||||
}
|
||||
|
||||
// Copy the subdirectory into our actual destination.
|
||||
if err := os.RemoveAll(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make the final destination
|
||||
if err := os.MkdirAll(dst, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return copyDir(dst, sourcePath, false)
|
||||
}
|
||||
|
||||
// parseMeta looks for the first meta tag in the given reader that
|
||||
// will give us the source URL.
|
||||
func (g *HttpGetter) parseMeta(r io.Reader) (string, error) {
|
||||
d := xml.NewDecoder(r)
|
||||
d.CharsetReader = charsetReader
|
||||
d.Strict = false
|
||||
var err error
|
||||
var t xml.Token
|
||||
for {
|
||||
t, err = d.Token()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
|
||||
return "", nil
|
||||
}
|
||||
if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
|
||||
return "", nil
|
||||
}
|
||||
e, ok := t.(xml.StartElement)
|
||||
if !ok || !strings.EqualFold(e.Name.Local, "meta") {
|
||||
continue
|
||||
}
|
||||
if attrValue(e.Attr, "name") != "terraform-get" {
|
||||
continue
|
||||
}
|
||||
if f := attrValue(e.Attr, "content"); f != "" {
|
||||
return f, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// attrValue returns the attribute value for the case-insensitive key
|
||||
// `name', or the empty string if nothing is found.
|
||||
func attrValue(attrs []xml.Attr, name string) string {
|
||||
for _, a := range attrs {
|
||||
if strings.EqualFold(a.Name.Local, name) {
|
||||
return a.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// charsetReader returns a reader for the given charset. Currently
|
||||
// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
|
||||
// error which is printed by go get, so the user can find why the package
|
||||
// wasn't downloaded if the encoding is not supported. Note that, in
|
||||
// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
|
||||
// greater than 0x7f are not rejected).
|
||||
func charsetReader(charset string, input io.Reader) (io.Reader, error) {
|
||||
switch strings.ToLower(charset) {
|
||||
case "ascii":
|
||||
return input, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
|
||||
}
|
||||
}
|
||||
331
vendor/github.com/hashicorp/go-getter/get_http_test.go
generated
vendored
Normal file
331
vendor/github.com/hashicorp/go-getter/get_http_test.go
generated
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHttpGetter_impl(t *testing.T) {
|
||||
var _ Getter = new(HttpGetter)
|
||||
}
|
||||
|
||||
func TestHttpGetter_header(t *testing.T) {
|
||||
ln := testHttpServer(t)
|
||||
defer ln.Close()
|
||||
|
||||
g := new(HttpGetter)
|
||||
dst := tempDir(t)
|
||||
defer os.RemoveAll(dst)
|
||||
|
||||
var u url.URL
|
||||
u.Scheme = "http"
|
||||
u.Host = ln.Addr().String()
|
||||
u.Path = "/header"
|
||||
|
||||
// Get it!
|
||||
if err := g.Get(dst, &u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHttpGetter_meta(t *testing.T) {
|
||||
ln := testHttpServer(t)
|
||||
defer ln.Close()
|
||||
|
||||
g := new(HttpGetter)
|
||||
dst := tempDir(t)
|
||||
defer os.RemoveAll(dst)
|
||||
|
||||
var u url.URL
|
||||
u.Scheme = "http"
|
||||
u.Host = ln.Addr().String()
|
||||
u.Path = "/meta"
|
||||
|
||||
// Get it!
|
||||
if err := g.Get(dst, &u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHttpGetter_metaSubdir(t *testing.T) {
|
||||
ln := testHttpServer(t)
|
||||
defer ln.Close()
|
||||
|
||||
g := new(HttpGetter)
|
||||
dst := tempDir(t)
|
||||
defer os.RemoveAll(dst)
|
||||
|
||||
var u url.URL
|
||||
u.Scheme = "http"
|
||||
u.Host = ln.Addr().String()
|
||||
u.Path = "/meta-subdir"
|
||||
|
||||
// Get it!
|
||||
if err := g.Get(dst, &u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "sub.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHttpGetter_metaSubdirGlob(t *testing.T) {
|
||||
ln := testHttpServer(t)
|
||||
defer ln.Close()
|
||||
|
||||
g := new(HttpGetter)
|
||||
dst := tempDir(t)
|
||||
defer os.RemoveAll(dst)
|
||||
|
||||
var u url.URL
|
||||
u.Scheme = "http"
|
||||
u.Host = ln.Addr().String()
|
||||
u.Path = "/meta-subdir-glob"
|
||||
|
||||
// Get it!
|
||||
if err := g.Get(dst, &u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "sub.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHttpGetter_none(t *testing.T) {
|
||||
ln := testHttpServer(t)
|
||||
defer ln.Close()
|
||||
|
||||
g := new(HttpGetter)
|
||||
dst := tempDir(t)
|
||||
defer os.RemoveAll(dst)
|
||||
|
||||
var u url.URL
|
||||
u.Scheme = "http"
|
||||
u.Host = ln.Addr().String()
|
||||
u.Path = "/none"
|
||||
|
||||
// Get it!
|
||||
if err := g.Get(dst, &u); err == nil {
|
||||
t.Fatal("should error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHttpGetter_file(t *testing.T) {
|
||||
ln := testHttpServer(t)
|
||||
defer ln.Close()
|
||||
|
||||
g := new(HttpGetter)
|
||||
dst := tempFile(t)
|
||||
defer os.RemoveAll(dst)
|
||||
|
||||
var u url.URL
|
||||
u.Scheme = "http"
|
||||
u.Host = ln.Addr().String()
|
||||
u.Path = "/file"
|
||||
|
||||
// Get it!
|
||||
if err := g.GetFile(dst, &u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
if _, err := os.Stat(dst); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
assertContents(t, dst, "Hello\n")
|
||||
}
|
||||
|
||||
func TestHttpGetter_auth(t *testing.T) {
|
||||
ln := testHttpServer(t)
|
||||
defer ln.Close()
|
||||
|
||||
g := new(HttpGetter)
|
||||
dst := tempDir(t)
|
||||
defer os.RemoveAll(dst)
|
||||
|
||||
var u url.URL
|
||||
u.Scheme = "http"
|
||||
u.Host = ln.Addr().String()
|
||||
u.Path = "/meta-auth"
|
||||
u.User = url.UserPassword("foo", "bar")
|
||||
|
||||
// Get it!
|
||||
if err := g.Get(dst, &u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHttpGetter_authNetrc(t *testing.T) {
|
||||
ln := testHttpServer(t)
|
||||
defer ln.Close()
|
||||
|
||||
g := new(HttpGetter)
|
||||
dst := tempDir(t)
|
||||
defer os.RemoveAll(dst)
|
||||
|
||||
var u url.URL
|
||||
u.Scheme = "http"
|
||||
u.Host = ln.Addr().String()
|
||||
u.Path = "/meta"
|
||||
|
||||
// Write the netrc file
|
||||
path, closer := tempFileContents(t, fmt.Sprintf(testHttpNetrc, ln.Addr().String()))
|
||||
defer closer()
|
||||
defer tempEnv(t, "NETRC", path)()
|
||||
|
||||
// Get it!
|
||||
if err := g.Get(dst, &u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// test round tripper that only returns an error
|
||||
type errRoundTripper struct{}
|
||||
|
||||
func (errRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||
return nil, errors.New("test round tripper")
|
||||
}
|
||||
|
||||
// verify that the default httpClient no longer comes from http.DefaultClient
|
||||
func TestHttpGetter_cleanhttp(t *testing.T) {
|
||||
ln := testHttpServer(t)
|
||||
defer ln.Close()
|
||||
|
||||
// break the default http client
|
||||
http.DefaultClient.Transport = errRoundTripper{}
|
||||
defer func() {
|
||||
http.DefaultClient.Transport = http.DefaultTransport
|
||||
}()
|
||||
|
||||
g := new(HttpGetter)
|
||||
dst := tempDir(t)
|
||||
defer os.RemoveAll(dst)
|
||||
|
||||
var u url.URL
|
||||
u.Scheme = "http"
|
||||
u.Host = ln.Addr().String()
|
||||
u.Path = "/header"
|
||||
|
||||
// Get it!
|
||||
if err := g.Get(dst, &u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testHttpServer(t *testing.T) net.Listener {
|
||||
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/file", testHttpHandlerFile)
|
||||
mux.HandleFunc("/header", testHttpHandlerHeader)
|
||||
mux.HandleFunc("/meta", testHttpHandlerMeta)
|
||||
mux.HandleFunc("/meta-auth", testHttpHandlerMetaAuth)
|
||||
mux.HandleFunc("/meta-subdir", testHttpHandlerMetaSubdir)
|
||||
mux.HandleFunc("/meta-subdir-glob", testHttpHandlerMetaSubdirGlob)
|
||||
|
||||
var server http.Server
|
||||
server.Handler = mux
|
||||
go server.Serve(ln)
|
||||
|
||||
return ln
|
||||
}
|
||||
|
||||
func testHttpHandlerFile(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("Hello\n"))
|
||||
}
|
||||
|
||||
func testHttpHandlerHeader(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("X-Terraform-Get", testModuleURL("basic").String())
|
||||
w.WriteHeader(200)
|
||||
}
|
||||
|
||||
func testHttpHandlerMeta(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic").String())))
|
||||
}
|
||||
|
||||
func testHttpHandlerMetaAuth(w http.ResponseWriter, r *http.Request) {
|
||||
user, pass, ok := r.BasicAuth()
|
||||
if !ok {
|
||||
w.WriteHeader(401)
|
||||
return
|
||||
}
|
||||
|
||||
if user != "foo" || pass != "bar" {
|
||||
w.WriteHeader(401)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic").String())))
|
||||
}
|
||||
|
||||
func testHttpHandlerMetaSubdir(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic//subdir").String())))
|
||||
}
|
||||
|
||||
func testHttpHandlerMetaSubdirGlob(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(fmt.Sprintf(testHttpMetaStr, testModuleURL("basic//sub*").String())))
|
||||
}
|
||||
|
||||
func testHttpHandlerNone(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(testHttpNoneStr))
|
||||
}
|
||||
|
||||
const testHttpMetaStr = `
|
||||
<html>
|
||||
<head>
|
||||
<meta name="terraform-get" content="%s">
|
||||
</head>
|
||||
</html>
|
||||
`
|
||||
|
||||
const testHttpNoneStr = `
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
</html>
|
||||
`
|
||||
|
||||
const testHttpNetrc = `
|
||||
machine %s
|
||||
login foo
|
||||
password bar
|
||||
`
|
||||
52
vendor/github.com/hashicorp/go-getter/get_mock.go
generated
vendored
Normal file
52
vendor/github.com/hashicorp/go-getter/get_mock.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// MockGetter is an implementation of Getter that can be used for tests.
|
||||
type MockGetter struct {
|
||||
// Proxy, if set, will be called after recording the calls below.
|
||||
// If it isn't set, then the *Err values will be returned.
|
||||
Proxy Getter
|
||||
|
||||
GetCalled bool
|
||||
GetDst string
|
||||
GetURL *url.URL
|
||||
GetErr error
|
||||
|
||||
GetFileCalled bool
|
||||
GetFileDst string
|
||||
GetFileURL *url.URL
|
||||
GetFileErr error
|
||||
}
|
||||
|
||||
func (g *MockGetter) Get(dst string, u *url.URL) error {
|
||||
g.GetCalled = true
|
||||
g.GetDst = dst
|
||||
g.GetURL = u
|
||||
|
||||
if g.Proxy != nil {
|
||||
return g.Proxy.Get(dst, u)
|
||||
}
|
||||
|
||||
return g.GetErr
|
||||
}
|
||||
|
||||
func (g *MockGetter) GetFile(dst string, u *url.URL) error {
|
||||
g.GetFileCalled = true
|
||||
g.GetFileDst = dst
|
||||
g.GetFileURL = u
|
||||
|
||||
if g.Proxy != nil {
|
||||
return g.Proxy.GetFile(dst, u)
|
||||
}
|
||||
return g.GetFileErr
|
||||
}
|
||||
|
||||
func (g *MockGetter) ClientMode(u *url.URL) (ClientMode, error) {
|
||||
if l := len(u.Path); l > 0 && u.Path[l-1:] == "/" {
|
||||
return ClientModeDir, nil
|
||||
}
|
||||
return ClientModeFile, nil
|
||||
}
|
||||
270
vendor/github.com/hashicorp/go-getter/get_s3.go
generated
vendored
Normal file
270
vendor/github.com/hashicorp/go-getter/get_s3.go
generated
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
|
||||
"github.com/aws/aws-sdk-go/aws/ec2metadata"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
// S3Getter is a Getter implementation that will download a module from
|
||||
// a S3 bucket.
|
||||
type S3Getter struct{}
|
||||
|
||||
func (g *S3Getter) ClientMode(u *url.URL) (ClientMode, error) {
|
||||
// Parse URL
|
||||
region, bucket, path, _, creds, err := g.parseUrl(u)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Create client config
|
||||
config := g.getAWSConfig(region, u, creds)
|
||||
sess := session.New(config)
|
||||
client := s3.New(sess)
|
||||
|
||||
// List the object(s) at the given prefix
|
||||
req := &s3.ListObjectsInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Prefix: aws.String(path),
|
||||
}
|
||||
resp, err := client.ListObjects(req)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
for _, o := range resp.Contents {
|
||||
// Use file mode on exact match.
|
||||
if *o.Key == path {
|
||||
return ClientModeFile, nil
|
||||
}
|
||||
|
||||
// Use dir mode if child keys are found.
|
||||
if strings.HasPrefix(*o.Key, path+"/") {
|
||||
return ClientModeDir, nil
|
||||
}
|
||||
}
|
||||
|
||||
// There was no match, so just return file mode. The download is going
|
||||
// to fail but we will let S3 return the proper error later.
|
||||
return ClientModeFile, nil
|
||||
}
|
||||
|
||||
func (g *S3Getter) Get(dst string, u *url.URL) error {
|
||||
// Parse URL
|
||||
region, bucket, path, _, creds, err := g.parseUrl(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove destination if it already exists
|
||||
_, err = os.Stat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
// Remove the destination
|
||||
if err := os.RemoveAll(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config := g.getAWSConfig(region, u, creds)
|
||||
sess := session.New(config)
|
||||
client := s3.New(sess)
|
||||
|
||||
// List files in path, keep listing until no more objects are found
|
||||
lastMarker := ""
|
||||
hasMore := true
|
||||
for hasMore {
|
||||
req := &s3.ListObjectsInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Prefix: aws.String(path),
|
||||
}
|
||||
if lastMarker != "" {
|
||||
req.Marker = aws.String(lastMarker)
|
||||
}
|
||||
|
||||
resp, err := client.ListObjects(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasMore = aws.BoolValue(resp.IsTruncated)
|
||||
|
||||
// Get each object storing each file relative to the destination path
|
||||
for _, object := range resp.Contents {
|
||||
lastMarker = aws.StringValue(object.Key)
|
||||
objPath := aws.StringValue(object.Key)
|
||||
|
||||
// If the key ends with a backslash assume it is a directory and ignore
|
||||
if strings.HasSuffix(objPath, "/") {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the object destination path
|
||||
objDst, err := filepath.Rel(path, objPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
objDst = filepath.Join(dst, objDst)
|
||||
|
||||
if err := g.getObject(client, objDst, bucket, objPath, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *S3Getter) GetFile(dst string, u *url.URL) error {
|
||||
region, bucket, path, version, creds, err := g.parseUrl(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config := g.getAWSConfig(region, u, creds)
|
||||
sess := session.New(config)
|
||||
client := s3.New(sess)
|
||||
return g.getObject(client, dst, bucket, path, version)
|
||||
}
|
||||
|
||||
func (g *S3Getter) getObject(client *s3.S3, dst, bucket, key, version string) error {
|
||||
req := &s3.GetObjectInput{
|
||||
Bucket: aws.String(bucket),
|
||||
Key: aws.String(key),
|
||||
}
|
||||
if version != "" {
|
||||
req.VersionId = aws.String(version)
|
||||
}
|
||||
|
||||
resp, err := client.GetObject(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create all the parent directories
|
||||
if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = io.Copy(f, resp.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *S3Getter) getAWSConfig(region string, url *url.URL, creds *credentials.Credentials) *aws.Config {
|
||||
conf := &aws.Config{}
|
||||
if creds == nil {
|
||||
// Grab the metadata URL
|
||||
metadataURL := os.Getenv("AWS_METADATA_URL")
|
||||
if metadataURL == "" {
|
||||
metadataURL = "http://169.254.169.254:80/latest"
|
||||
}
|
||||
|
||||
creds = credentials.NewChainCredentials(
|
||||
[]credentials.Provider{
|
||||
&credentials.EnvProvider{},
|
||||
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
||||
&ec2rolecreds.EC2RoleProvider{
|
||||
Client: ec2metadata.New(session.New(&aws.Config{
|
||||
Endpoint: aws.String(metadataURL),
|
||||
})),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if creds != nil {
|
||||
conf.Endpoint = &url.Host
|
||||
conf.S3ForcePathStyle = aws.Bool(true)
|
||||
if url.Scheme == "http" {
|
||||
conf.DisableSSL = aws.Bool(true)
|
||||
}
|
||||
}
|
||||
|
||||
conf.Credentials = creds
|
||||
if region != "" {
|
||||
conf.Region = aws.String(region)
|
||||
}
|
||||
|
||||
return conf
|
||||
}
|
||||
|
||||
func (g *S3Getter) parseUrl(u *url.URL) (region, bucket, path, version string, creds *credentials.Credentials, err error) {
|
||||
// This just check whether we are dealing with S3 or
|
||||
// any other S3 compliant service. S3 has a predictable
|
||||
// url as others do not
|
||||
if strings.Contains(u.Host, "amazonaws.com") {
|
||||
// Expected host style: s3.amazonaws.com. They always have 3 parts,
|
||||
// although the first may differ if we're accessing a specific region.
|
||||
hostParts := strings.Split(u.Host, ".")
|
||||
if len(hostParts) != 3 {
|
||||
err = fmt.Errorf("URL is not a valid S3 URL")
|
||||
return
|
||||
}
|
||||
|
||||
// Parse the region out of the first part of the host
|
||||
region = strings.TrimPrefix(strings.TrimPrefix(hostParts[0], "s3-"), "s3")
|
||||
if region == "" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
|
||||
pathParts := strings.SplitN(u.Path, "/", 3)
|
||||
if len(pathParts) != 3 {
|
||||
err = fmt.Errorf("URL is not a valid S3 URL")
|
||||
return
|
||||
}
|
||||
|
||||
bucket = pathParts[1]
|
||||
path = pathParts[2]
|
||||
version = u.Query().Get("version")
|
||||
|
||||
} else {
|
||||
pathParts := strings.SplitN(u.Path, "/", 3)
|
||||
if len(pathParts) != 3 {
|
||||
err = fmt.Errorf("URL is not a valid S3 complaint URL")
|
||||
return
|
||||
}
|
||||
bucket = pathParts[1]
|
||||
path = pathParts[2]
|
||||
version = u.Query().Get("version")
|
||||
region = u.Query().Get("region")
|
||||
if region == "" {
|
||||
region = "us-east-1"
|
||||
}
|
||||
}
|
||||
|
||||
_, hasAwsId := u.Query()["aws_access_key_id"]
|
||||
_, hasAwsSecret := u.Query()["aws_access_key_secret"]
|
||||
_, hasAwsToken := u.Query()["aws_access_token"]
|
||||
if hasAwsId || hasAwsSecret || hasAwsToken {
|
||||
creds = credentials.NewStaticCredentials(
|
||||
u.Query().Get("aws_access_key_id"),
|
||||
u.Query().Get("aws_access_key_secret"),
|
||||
u.Query().Get("aws_access_token"),
|
||||
)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
250
vendor/github.com/hashicorp/go-getter/get_s3_test.go
generated
vendored
Normal file
250
vendor/github.com/hashicorp/go-getter/get_s3_test.go
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// These are well known restricted IAM keys to a HashiCorp-managed bucket
|
||||
// in a private AWS account that only has access to the open source test
|
||||
// resources.
|
||||
//
|
||||
// We do the string concat below to avoid AWS autodetection of a key. This
|
||||
// key is locked down an IAM policy that is read-only so we're purposely
|
||||
// exposing it.
|
||||
os.Setenv("AWS_ACCESS_KEY", "AKIAITTDR"+"WY2STXOZE2A")
|
||||
os.Setenv("AWS_SECRET_KEY", "oMwSyqdass2kPF"+"/7ORZA9dlb/iegz+89B0Cy01Ea")
|
||||
}
|
||||
|
||||
func TestS3Getter_impl(t *testing.T) {
|
||||
var _ Getter = new(S3Getter)
|
||||
}
|
||||
|
||||
func TestS3Getter(t *testing.T) {
|
||||
g := new(S3Getter)
|
||||
dst := tempDir(t)
|
||||
|
||||
// With a dir that doesn't exist
|
||||
err := g.Get(
|
||||
dst, testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/folder"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3Getter_subdir(t *testing.T) {
|
||||
g := new(S3Getter)
|
||||
dst := tempDir(t)
|
||||
|
||||
// With a dir that doesn't exist
|
||||
err := g.Get(
|
||||
dst, testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/folder/subfolder"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
subPath := filepath.Join(dst, "sub.tf")
|
||||
if _, err := os.Stat(subPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3Getter_GetFile(t *testing.T) {
|
||||
g := new(S3Getter)
|
||||
dst := tempFile(t)
|
||||
|
||||
// Download
|
||||
err := g.GetFile(
|
||||
dst, testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/folder/main.tf"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
if _, err := os.Stat(dst); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
assertContents(t, dst, "# Main\n")
|
||||
}
|
||||
|
||||
func TestS3Getter_GetFile_badParams(t *testing.T) {
|
||||
g := new(S3Getter)
|
||||
dst := tempFile(t)
|
||||
|
||||
// Download
|
||||
err := g.GetFile(
|
||||
dst,
|
||||
testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/folder/main.tf?aws_access_key_id=foo&aws_access_key_secret=bar&aws_access_token=baz"))
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got none")
|
||||
}
|
||||
|
||||
if reqerr, ok := err.(awserr.RequestFailure); !ok || reqerr.StatusCode() != 403 {
|
||||
t.Fatalf("expected InvalidAccessKeyId error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3Getter_GetFile_notfound(t *testing.T) {
|
||||
g := new(S3Getter)
|
||||
dst := tempFile(t)
|
||||
|
||||
// Download
|
||||
err := g.GetFile(
|
||||
dst, testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/folder/404.tf"))
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3Getter_ClientMode_dir(t *testing.T) {
|
||||
g := new(S3Getter)
|
||||
|
||||
// Check client mode on a key prefix with only a single key.
|
||||
mode, err := g.ClientMode(
|
||||
testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/folder"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if mode != ClientModeDir {
|
||||
t.Fatal("expect ClientModeDir")
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3Getter_ClientMode_file(t *testing.T) {
|
||||
g := new(S3Getter)
|
||||
|
||||
// Check client mode on a key prefix which contains sub-keys.
|
||||
mode, err := g.ClientMode(
|
||||
testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/folder/main.tf"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if mode != ClientModeFile {
|
||||
t.Fatal("expect ClientModeFile")
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3Getter_ClientMode_notfound(t *testing.T) {
|
||||
g := new(S3Getter)
|
||||
|
||||
// Check the client mode when a non-existent key is looked up. This does not
|
||||
// return an error, but rather should just return the file mode so that S3
|
||||
// can return an appropriate error later on. This also checks that the
|
||||
// prefix is handled properly (e.g., "/fold" and "/folder" don't put the
|
||||
// client mode into "dir".
|
||||
mode, err := g.ClientMode(
|
||||
testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/fold"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if mode != ClientModeFile {
|
||||
t.Fatal("expect ClientModeFile")
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3Getter_ClientMode_collision(t *testing.T) {
|
||||
g := new(S3Getter)
|
||||
|
||||
// Check that the client mode is "file" if there is both an object and a
|
||||
// folder with a common prefix (i.e., a "collision" in the namespace).
|
||||
mode, err := g.ClientMode(
|
||||
testURL("https://s3.amazonaws.com/hc-oss-test/go-getter/collision/foo"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if mode != ClientModeFile {
|
||||
t.Fatal("expect ClientModeFile")
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3Getter_Url(t *testing.T) {
|
||||
var s3tests = []struct {
|
||||
name string
|
||||
url string
|
||||
region string
|
||||
bucket string
|
||||
path string
|
||||
version string
|
||||
}{
|
||||
{
|
||||
name: "AWSv1234",
|
||||
url: "s3::https://s3-eu-west-1.amazonaws.com/bucket/foo/bar.baz?version=1234",
|
||||
region: "eu-west-1",
|
||||
bucket: "bucket",
|
||||
path: "foo/bar.baz",
|
||||
version: "1234",
|
||||
},
|
||||
{
|
||||
name: "localhost-1",
|
||||
url: "s3::http://127.0.0.1:9000/test-bucket/hello.txt?aws_access_key_id=TESTID&aws_access_key_secret=TestSecret®ion=us-east-2&version=1",
|
||||
region: "us-east-2",
|
||||
bucket: "test-bucket",
|
||||
path: "hello.txt",
|
||||
version: "1",
|
||||
},
|
||||
{
|
||||
name: "localhost-2",
|
||||
url: "s3::http://127.0.0.1:9000/test-bucket/hello.txt?aws_access_key_id=TESTID&aws_access_key_secret=TestSecret&version=1",
|
||||
region: "us-east-1",
|
||||
bucket: "test-bucket",
|
||||
path: "hello.txt",
|
||||
version: "1",
|
||||
},
|
||||
{
|
||||
name: "localhost-3",
|
||||
url: "s3::http://127.0.0.1:9000/test-bucket/hello.txt?aws_access_key_id=TESTID&aws_access_key_secret=TestSecret",
|
||||
region: "us-east-1",
|
||||
bucket: "test-bucket",
|
||||
path: "hello.txt",
|
||||
version: "",
|
||||
},
|
||||
}
|
||||
|
||||
for i, pt := range s3tests {
|
||||
t.Run(pt.name, func(t *testing.T) {
|
||||
g := new(S3Getter)
|
||||
forced, src := getForcedGetter(pt.url)
|
||||
u, err := url.Parse(src)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("test %d: unexpected error: %s", i, err)
|
||||
}
|
||||
if forced != "s3" {
|
||||
t.Fatalf("expected forced protocol to be s3")
|
||||
}
|
||||
|
||||
region, bucket, path, version, creds, err := g.parseUrl(u)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if region != pt.region {
|
||||
t.Fatalf("expected %s, got %s", pt.region, region)
|
||||
}
|
||||
if bucket != pt.bucket {
|
||||
t.Fatalf("expected %s, got %s", pt.bucket, bucket)
|
||||
}
|
||||
if path != pt.path {
|
||||
t.Fatalf("expected %s, got %s", pt.path, path)
|
||||
}
|
||||
if version != pt.version {
|
||||
t.Fatalf("expected %s, got %s", pt.version, version)
|
||||
}
|
||||
if &creds == nil {
|
||||
t.Fatalf("expected to not be nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
380
vendor/github.com/hashicorp/go-getter/get_test.go
generated
vendored
Normal file
380
vendor/github.com/hashicorp/go-getter/get_test.go
generated
vendored
Normal file
@@ -0,0 +1,380 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGet_badSchema(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := testModule("basic")
|
||||
u = strings.Replace(u, "file", "nope", -1)
|
||||
|
||||
if err := Get(dst, u); err == nil {
|
||||
t.Fatal("should error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet_file(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := testModule("basic")
|
||||
|
||||
if err := Get(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/hashicorp/terraform/issues/11438
|
||||
func TestGet_fileDecompressorExt(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := testModule("basic-tgz")
|
||||
|
||||
if err := Get(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/hashicorp/terraform/issues/8418
|
||||
func TestGet_filePercent2F(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := testModule("basic%2Ftest")
|
||||
|
||||
if err := Get(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet_fileDetect(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := filepath.Join("./test-fixtures", "basic")
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
Src: u,
|
||||
Dst: dst,
|
||||
Pwd: pwd,
|
||||
Dir: true,
|
||||
}
|
||||
|
||||
if err := client.Get(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet_fileForced(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := testModule("basic")
|
||||
u = "file::" + u
|
||||
|
||||
if err := Get(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet_fileSubdir(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := testModule("basic//subdir")
|
||||
|
||||
if err := Get(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "sub.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet_archive(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := filepath.Join("./test-fixtures", "archive.tar.gz")
|
||||
u, _ = filepath.Abs(u)
|
||||
|
||||
if err := Get(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAny_archive(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := filepath.Join("./test-fixtures", "archive.tar.gz")
|
||||
u, _ = filepath.Abs(u)
|
||||
|
||||
if err := GetAny(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "main.tf")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet_archiveRooted(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := testModule("archive-rooted/archive.tar.gz")
|
||||
if err := Get(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "root", "hello.txt")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet_archiveSubdirWild(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := testModule("archive-rooted/archive.tar.gz")
|
||||
u += "//*"
|
||||
if err := Get(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "hello.txt")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet_archiveSubdirWildMultiMatch(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := testModule("archive-rooted-multi/archive.tar.gz")
|
||||
u += "//*"
|
||||
if err := Get(dst, u); err == nil {
|
||||
t.Fatal("should error")
|
||||
} else if !strings.Contains(err.Error(), "multiple") {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAny_file(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := testModule("basic-file/foo.txt")
|
||||
|
||||
if err := GetAny(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "foo.txt")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAny_dir(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := filepath.Join("./test-fixtures", "basic")
|
||||
u, _ = filepath.Abs(u)
|
||||
|
||||
if err := GetAny(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
check := []string{
|
||||
"main.tf",
|
||||
"foo/main.tf",
|
||||
}
|
||||
|
||||
for _, name := range check {
|
||||
mainPath := filepath.Join(dst, name)
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFile(t *testing.T) {
|
||||
dst := tempFile(t)
|
||||
u := testModule("basic-file/foo.txt")
|
||||
|
||||
if err := GetFile(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
assertContents(t, dst, "Hello\n")
|
||||
}
|
||||
|
||||
func TestGetFile_archive(t *testing.T) {
|
||||
dst := tempFile(t)
|
||||
u := testModule("basic-file-archive/archive.tar.gz")
|
||||
|
||||
if err := GetFile(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
assertContents(t, dst, "Hello\n")
|
||||
}
|
||||
|
||||
func TestGetFile_archiveChecksum(t *testing.T) {
|
||||
dst := tempFile(t)
|
||||
u := testModule(
|
||||
"basic-file-archive/archive.tar.gz?checksum=md5:fbd90037dacc4b1ab40811d610dde2f0")
|
||||
|
||||
if err := GetFile(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
assertContents(t, dst, "Hello\n")
|
||||
}
|
||||
|
||||
func TestGetFile_archiveNoUnarchive(t *testing.T) {
|
||||
dst := tempFile(t)
|
||||
u := testModule("basic-file-archive/archive.tar.gz")
|
||||
u += "?archive=false"
|
||||
|
||||
if err := GetFile(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
actual := testMD5(t, dst)
|
||||
expected := "fbd90037dacc4b1ab40811d610dde2f0"
|
||||
if actual != expected {
|
||||
t.Fatalf("bad: %s", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFile_checksum(t *testing.T) {
|
||||
cases := []struct {
|
||||
Append string
|
||||
Err bool
|
||||
}{
|
||||
{
|
||||
"",
|
||||
false,
|
||||
},
|
||||
|
||||
// MD5
|
||||
{
|
||||
"?checksum=md5:09f7e02f1290be211da707a266f153b3",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"?checksum=md5:09f7e02f1290be211da707a266f153b4",
|
||||
true,
|
||||
},
|
||||
|
||||
// SHA1
|
||||
{
|
||||
"?checksum=sha1:1d229271928d3f9e2bb0375bd6ce5db6c6d348d9",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"?checksum=sha1:1d229271928d3f9e2bb0375bd6ce5db6c6d348d0",
|
||||
true,
|
||||
},
|
||||
|
||||
// SHA256
|
||||
{
|
||||
"?checksum=sha256:66a045b452102c59d840ec097d59d9467e13a3f34f6494e539ffd32c1bb35f18",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"?checksum=sha256:66a045b452102c59d840ec097d59d9467e13a3f34f6494e539ffd32c1bb35f19",
|
||||
true,
|
||||
},
|
||||
|
||||
// SHA512
|
||||
{
|
||||
"?checksum=sha512:c2bad2223811194582af4d1508ac02cd69eeeeedeeb98d54fcae4dcefb13cc882e7640328206603d3fb9cd5f949a9be0db054dd34fbfa190c498a5fe09750cef",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"?checksum=sha512:c2bad2223811194582af4d1508ac02cd69eeeeedeeb98d54fcae4dcefb13cc882e7640328206603d3fb9cd5f949a9be0db054dd34fbfa190c498a5fe09750ced",
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
u := testModule("basic-file/foo.txt") + tc.Append
|
||||
|
||||
func() {
|
||||
dst := tempFile(t)
|
||||
defer os.Remove(dst)
|
||||
if err := GetFile(dst, u); (err != nil) != tc.Err {
|
||||
t.Fatalf("append: %s\n\nerr: %s", tc.Append, err)
|
||||
}
|
||||
|
||||
// Verify the main file exists
|
||||
assertContents(t, dst, "Hello\n")
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFile_checksumURL(t *testing.T) {
|
||||
dst := tempFile(t)
|
||||
u := testModule("basic-file/foo.txt") + "?checksum=md5:09f7e02f1290be211da707a266f153b3"
|
||||
|
||||
getter := &MockGetter{Proxy: new(FileGetter)}
|
||||
client := &Client{
|
||||
Src: u,
|
||||
Dst: dst,
|
||||
Dir: false,
|
||||
Getters: map[string]Getter{
|
||||
"file": getter,
|
||||
},
|
||||
}
|
||||
|
||||
if err := client.Get(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if v := getter.GetFileURL.Query().Get("checksum"); v != "" {
|
||||
t.Fatalf("bad: %s", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFile_filename(t *testing.T) {
|
||||
dst := tempDir(t)
|
||||
u := testModule("basic-file/foo.txt")
|
||||
|
||||
u += "?filename=bar.txt"
|
||||
|
||||
if err := GetAny(dst, u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
mainPath := filepath.Join(dst, "bar.txt")
|
||||
if _, err := os.Stat(mainPath); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
14
vendor/github.com/hashicorp/go-getter/helper/url/url.go
generated
vendored
Normal file
14
vendor/github.com/hashicorp/go-getter/helper/url/url.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package url
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// Parse parses rawURL into a URL structure.
|
||||
// The rawURL may be relative or absolute.
|
||||
//
|
||||
// Parse is a wrapper for the Go stdlib net/url Parse function, but returns
|
||||
// Windows "safe" URLs on Windows platforms.
|
||||
func Parse(rawURL string) (*url.URL, error) {
|
||||
return parse(rawURL)
|
||||
}
|
||||
88
vendor/github.com/hashicorp/go-getter/helper/url/url_test.go
generated
vendored
Normal file
88
vendor/github.com/hashicorp/go-getter/helper/url/url_test.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package url
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type parseTest struct {
|
||||
rawURL string
|
||||
scheme string
|
||||
host string
|
||||
path string
|
||||
str string
|
||||
err bool
|
||||
}
|
||||
|
||||
var parseTests = []parseTest{
|
||||
{
|
||||
rawURL: "/foo/bar",
|
||||
scheme: "",
|
||||
host: "",
|
||||
path: "/foo/bar",
|
||||
str: "/foo/bar",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
rawURL: "file:///dir/",
|
||||
scheme: "file",
|
||||
host: "",
|
||||
path: "/dir/",
|
||||
str: "file:///dir/",
|
||||
err: false,
|
||||
},
|
||||
}
|
||||
|
||||
var winParseTests = []parseTest{
|
||||
{
|
||||
rawURL: `C:\`,
|
||||
scheme: ``,
|
||||
host: ``,
|
||||
path: `C:/`,
|
||||
str: `C:/`,
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
rawURL: `file://C:\`,
|
||||
scheme: `file`,
|
||||
host: ``,
|
||||
path: `C:/`,
|
||||
str: `file://C:/`,
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
rawURL: `file:///C:\`,
|
||||
scheme: `file`,
|
||||
host: ``,
|
||||
path: `C:/`,
|
||||
str: `file://C:/`,
|
||||
err: false,
|
||||
},
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
parseTests = append(parseTests, winParseTests...)
|
||||
}
|
||||
for i, pt := range parseTests {
|
||||
url, err := Parse(pt.rawURL)
|
||||
if err != nil && !pt.err {
|
||||
t.Errorf("test %d: unexpected error: %s", i, err)
|
||||
}
|
||||
if err == nil && pt.err {
|
||||
t.Errorf("test %d: expected an error", i)
|
||||
}
|
||||
if url.Scheme != pt.scheme {
|
||||
t.Errorf("test %d: expected Scheme = %q, got %q", i, pt.scheme, url.Scheme)
|
||||
}
|
||||
if url.Host != pt.host {
|
||||
t.Errorf("test %d: expected Host = %q, got %q", i, pt.host, url.Host)
|
||||
}
|
||||
if url.Path != pt.path {
|
||||
t.Errorf("test %d: expected Path = %q, got %q", i, pt.path, url.Path)
|
||||
}
|
||||
if url.String() != pt.str {
|
||||
t.Errorf("test %d: expected url.String() = %q, got %q", i, pt.str, url.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
11
vendor/github.com/hashicorp/go-getter/helper/url/url_unix.go
generated
vendored
Normal file
11
vendor/github.com/hashicorp/go-getter/helper/url/url_unix.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// +build !windows
|
||||
|
||||
package url
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func parse(rawURL string) (*url.URL, error) {
|
||||
return url.Parse(rawURL)
|
||||
}
|
||||
40
vendor/github.com/hashicorp/go-getter/helper/url/url_windows.go
generated
vendored
Normal file
40
vendor/github.com/hashicorp/go-getter/helper/url/url_windows.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package url
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parse(rawURL string) (*url.URL, error) {
|
||||
// Make sure we're using "/" since URLs are "/"-based.
|
||||
rawURL = filepath.ToSlash(rawURL)
|
||||
|
||||
u, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(rawURL) > 1 && rawURL[1] == ':' {
|
||||
// Assume we're dealing with a drive letter file path where the drive
|
||||
// letter has been parsed into the URL Scheme, and the rest of the path
|
||||
// has been parsed into the URL Path without the leading ':' character.
|
||||
u.Path = fmt.Sprintf("%s:%s", string(rawURL[0]), u.Path)
|
||||
u.Scheme = ""
|
||||
}
|
||||
|
||||
if len(u.Host) > 1 && u.Host[1] == ':' && strings.HasPrefix(rawURL, "file://") {
|
||||
// Assume we're dealing with a drive letter file path where the drive
|
||||
// letter has been parsed into the URL Host.
|
||||
u.Path = fmt.Sprintf("%s%s", u.Host, u.Path)
|
||||
u.Host = ""
|
||||
}
|
||||
|
||||
// Remove leading slash for absolute file paths.
|
||||
if len(u.Path) > 2 && u.Path[0] == '/' && u.Path[2] == ':' {
|
||||
u.Path = u.Path[1:]
|
||||
}
|
||||
|
||||
return u, err
|
||||
}
|
||||
78
vendor/github.com/hashicorp/go-getter/module_test.go
generated
vendored
Normal file
78
vendor/github.com/hashicorp/go-getter/module_test.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
urlhelper "github.com/hashicorp/go-getter/helper/url"
|
||||
)
|
||||
|
||||
const fixtureDir = "./test-fixtures"
|
||||
|
||||
func tempDir(t *testing.T) string {
|
||||
dir, err := ioutil.TempDir("", "tf")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
return dir
|
||||
}
|
||||
|
||||
func tempFile(t *testing.T) string {
|
||||
dir := tempDir(t)
|
||||
return filepath.Join(dir, "foo")
|
||||
}
|
||||
|
||||
func testModule(n string) string {
|
||||
p := filepath.Join(fixtureDir, n)
|
||||
p, err := filepath.Abs(p)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return fmtFileURL(p)
|
||||
}
|
||||
|
||||
func testModuleURL(n string) *url.URL {
|
||||
n, subDir := SourceDirSubdir(n)
|
||||
u, err := urlhelper.Parse(testModule(n))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if subDir != "" {
|
||||
u.Path += "//" + subDir
|
||||
u.RawPath = u.Path
|
||||
}
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
func testURL(s string) *url.URL {
|
||||
u, err := urlhelper.Parse(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
func testStorage(t *testing.T) Storage {
|
||||
return &FolderStorage{StorageDir: tempDir(t)}
|
||||
}
|
||||
|
||||
func assertContents(t *testing.T, path string, contents string) {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(data, []byte(contents)) {
|
||||
t.Fatalf("bad. expected:\n\n%s\n\nGot:\n\n%s", contents, string(data))
|
||||
}
|
||||
}
|
||||
67
vendor/github.com/hashicorp/go-getter/netrc.go
generated
vendored
Normal file
67
vendor/github.com/hashicorp/go-getter/netrc.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/bgentry/go-netrc/netrc"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
// addAuthFromNetrc adds auth information to the URL from the user's
|
||||
// netrc file if it can be found. This will only add the auth info
|
||||
// if the URL doesn't already have auth info specified and the
|
||||
// the username is blank.
|
||||
func addAuthFromNetrc(u *url.URL) error {
|
||||
// If the URL already has auth information, do nothing
|
||||
if u.User != nil && u.User.Username() != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get the netrc file path
|
||||
path := os.Getenv("NETRC")
|
||||
if path == "" {
|
||||
filename := ".netrc"
|
||||
if runtime.GOOS == "windows" {
|
||||
filename = "_netrc"
|
||||
}
|
||||
|
||||
var err error
|
||||
path, err = homedir.Expand("~/" + filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If the file is not a file, then do nothing
|
||||
if fi, err := os.Stat(path); err != nil {
|
||||
// File doesn't exist, do nothing
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Some other error!
|
||||
return err
|
||||
} else if fi.IsDir() {
|
||||
// File is directory, ignore
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load up the netrc file
|
||||
net, err := netrc.ParseFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error parsing netrc file at %q: %s", path, err)
|
||||
}
|
||||
|
||||
machine := net.FindMachine(u.Host)
|
||||
if machine == nil {
|
||||
// Machine not found, no problem
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set the user info
|
||||
u.User = url.UserPassword(machine.Login, machine.Password)
|
||||
return nil
|
||||
}
|
||||
63
vendor/github.com/hashicorp/go-getter/netrc_test.go
generated
vendored
Normal file
63
vendor/github.com/hashicorp/go-getter/netrc_test.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAddAuthFromNetrc(t *testing.T) {
|
||||
defer tempEnv(t, "NETRC", "./test-fixtures/netrc/basic")()
|
||||
|
||||
u, err := url.Parse("http://example.com")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if err := addAuthFromNetrc(u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
expected := "http://foo:bar@example.com"
|
||||
actual := u.String()
|
||||
if expected != actual {
|
||||
t.Fatalf("Mismatch: %q != %q", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAuthFromNetrc_hasAuth(t *testing.T) {
|
||||
defer tempEnv(t, "NETRC", "./test-fixtures/netrc/basic")()
|
||||
|
||||
u, err := url.Parse("http://username:password@example.com")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
expected := u.String()
|
||||
if err := addAuthFromNetrc(u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := u.String()
|
||||
if expected != actual {
|
||||
t.Fatalf("Mismatch: %q != %q", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddAuthFromNetrc_hasUsername(t *testing.T) {
|
||||
defer tempEnv(t, "NETRC", "./test-fixtures/netrc/basic")()
|
||||
|
||||
u, err := url.Parse("http://username@example.com")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
expected := u.String()
|
||||
if err := addAuthFromNetrc(u); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := u.String()
|
||||
if expected != actual {
|
||||
t.Fatalf("Mismatch: %q != %q", actual, expected)
|
||||
}
|
||||
}
|
||||
62
vendor/github.com/hashicorp/go-getter/source.go
generated
vendored
Normal file
62
vendor/github.com/hashicorp/go-getter/source.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SourceDirSubdir takes a source and returns a tuple of the URL without
|
||||
// the subdir and the URL with the subdir.
|
||||
func SourceDirSubdir(src string) (string, string) {
|
||||
// Calcaulate an offset to avoid accidentally marking the scheme
|
||||
// as the dir.
|
||||
var offset int
|
||||
if idx := strings.Index(src, "://"); idx > -1 {
|
||||
offset = idx + 3
|
||||
}
|
||||
|
||||
// First see if we even have an explicit subdir
|
||||
idx := strings.Index(src[offset:], "//")
|
||||
if idx == -1 {
|
||||
return src, ""
|
||||
}
|
||||
|
||||
idx += offset
|
||||
subdir := src[idx+2:]
|
||||
src = src[:idx]
|
||||
|
||||
// Next, check if we have query parameters and push them onto the
|
||||
// URL.
|
||||
if idx = strings.Index(subdir, "?"); idx > -1 {
|
||||
query := subdir[idx:]
|
||||
subdir = subdir[:idx]
|
||||
src += query
|
||||
}
|
||||
|
||||
return src, subdir
|
||||
}
|
||||
|
||||
// SubdirGlob returns the actual subdir with globbing processed.
|
||||
//
|
||||
// dst should be a destination directory that is already populated (the
|
||||
// download is complete) and subDir should be the set subDir. If subDir
|
||||
// is an empty string, this returns an empty string.
|
||||
//
|
||||
// The returned path is the full absolute path.
|
||||
func SubdirGlob(dst, subDir string) (string, error) {
|
||||
matches, err := filepath.Glob(filepath.Join(dst, subDir))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(matches) == 0 {
|
||||
return "", fmt.Errorf("subdir %q not found", subDir)
|
||||
}
|
||||
|
||||
if len(matches) > 1 {
|
||||
return "", fmt.Errorf("subdir %q matches multiple paths", subDir)
|
||||
}
|
||||
|
||||
return matches[0], nil
|
||||
}
|
||||
98
vendor/github.com/hashicorp/go-getter/source_test.go
generated
vendored
Normal file
98
vendor/github.com/hashicorp/go-getter/source_test.go
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSourceDirSubdir(t *testing.T) {
|
||||
cases := []struct {
|
||||
Input string
|
||||
Dir, Sub string
|
||||
}{
|
||||
{
|
||||
"hashicorp.com",
|
||||
"hashicorp.com", "",
|
||||
},
|
||||
{
|
||||
"hashicorp.com//foo",
|
||||
"hashicorp.com", "foo",
|
||||
},
|
||||
{
|
||||
"hashicorp.com//foo?bar=baz",
|
||||
"hashicorp.com?bar=baz", "foo",
|
||||
},
|
||||
{
|
||||
"https://hashicorp.com/path//*?archive=foo",
|
||||
"https://hashicorp.com/path?archive=foo", "*",
|
||||
},
|
||||
{
|
||||
"file://foo//bar",
|
||||
"file://foo", "bar",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
adir, asub := SourceDirSubdir(tc.Input)
|
||||
if adir != tc.Dir {
|
||||
t.Fatalf("%d: bad dir: %#v", i, adir)
|
||||
}
|
||||
if asub != tc.Sub {
|
||||
t.Fatalf("%d: bad sub: %#v", i, asub)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSourceSubdirGlob(t *testing.T) {
|
||||
td, err := ioutil.TempDir("", "subdir-glob")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
|
||||
if err := os.Mkdir(filepath.Join(td, "subdir"), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := os.Mkdir(filepath.Join(td, "subdir/one"), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := os.Mkdir(filepath.Join(td, "subdir/two"), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
subdir := filepath.Join(td, "subdir")
|
||||
|
||||
// match the exact directory
|
||||
res, err := SubdirGlob(td, "subdir")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res != subdir {
|
||||
t.Fatalf(`expected "subdir", got: %q`, subdir)
|
||||
}
|
||||
|
||||
// single match from a wildcard
|
||||
res, err = SubdirGlob(td, "*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res != subdir {
|
||||
t.Fatalf(`expected "subdir", got: %q`, subdir)
|
||||
}
|
||||
|
||||
// multiple matches
|
||||
res, err = SubdirGlob(td, "subdir/*")
|
||||
if err == nil {
|
||||
t.Fatalf("expected multiple matches, got %q", res)
|
||||
}
|
||||
|
||||
// non-existent
|
||||
res, err = SubdirGlob(td, "foo")
|
||||
if err == nil {
|
||||
t.Fatalf("expected no matches, got %q", res)
|
||||
}
|
||||
}
|
||||
13
vendor/github.com/hashicorp/go-getter/storage.go
generated
vendored
Normal file
13
vendor/github.com/hashicorp/go-getter/storage.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package getter
|
||||
|
||||
// Storage is an interface that knows how to lookup downloaded directories
|
||||
// as well as download and update directories from their sources into the
|
||||
// proper location.
|
||||
type Storage interface {
|
||||
// Dir returns the directory on local disk where the directory source
|
||||
// can be loaded from.
|
||||
Dir(string) (string, bool, error)
|
||||
|
||||
// Get will download and optionally update the given directory.
|
||||
Get(string, string, bool) error
|
||||
}
|
||||
49
vendor/github.com/hashicorp/go-getter/util_test.go
generated
vendored
Normal file
49
vendor/github.com/hashicorp/go-getter/util_test.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// tempEnv sets the env var temporarily and returns a function that should
|
||||
// be deferred to clean it up.
|
||||
func tempEnv(t *testing.T, k, v string) func() {
|
||||
old := os.Getenv(k)
|
||||
|
||||
// Set env
|
||||
if err := os.Setenv(k, v); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Easy cleanup
|
||||
return func() {
|
||||
if err := os.Setenv(k, old); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tempFileContents writes a temporary file and returns the path and a function
|
||||
// to clean it up.
|
||||
func tempFileContents(t *testing.T, contents string) (string, func()) {
|
||||
tf, err := ioutil.TempFile("", "getter")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(tf, strings.NewReader(contents)); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
tf.Close()
|
||||
|
||||
path := tf.Name()
|
||||
return path, func() {
|
||||
if err := os.Remove(path); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
362
vendor/github.com/hashicorp/go-safetemp/LICENSE
generated
vendored
Normal file
362
vendor/github.com/hashicorp/go-safetemp/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
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.
|
||||
10
vendor/github.com/hashicorp/go-safetemp/README.md
generated
vendored
Normal file
10
vendor/github.com/hashicorp/go-safetemp/README.md
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# go-safetemp
|
||||
[](https://godoc.org/github.com/hashicorp/go-safetemp)
|
||||
|
||||
Functions for safely working with temporary directories and files.
|
||||
|
||||
## Why?
|
||||
|
||||
The Go standard library provides the excellent `ioutil` package for
|
||||
working with temporary directories and files. This library builds on top
|
||||
of that to provide safe abstractions above that.
|
||||
40
vendor/github.com/hashicorp/go-safetemp/safetemp.go
generated
vendored
Normal file
40
vendor/github.com/hashicorp/go-safetemp/safetemp.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package safetemp
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Dir creates a new temporary directory that isn't yet created. This
|
||||
// can be used with calls that expect a non-existent directory.
|
||||
//
|
||||
// The directory is created as a child of a temporary directory created
|
||||
// within the directory dir starting with prefix. The temporary directory
|
||||
// returned is always named "temp". The parent directory has the specified
|
||||
// prefix.
|
||||
//
|
||||
// The returned io.Closer should be used to clean up the returned directory.
|
||||
// This will properly remove the returned directory and any other temporary
|
||||
// files created.
|
||||
//
|
||||
// If an error is returned, the Closer does not need to be called (and will
|
||||
// be nil).
|
||||
func Dir(dir, prefix string) (string, io.Closer, error) {
|
||||
// Create the temporary directory
|
||||
td, err := ioutil.TempDir(dir, prefix)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
return filepath.Join(td, "temp"), pathCloser(td), nil
|
||||
}
|
||||
|
||||
// pathCloser implements io.Closer to remove the given path on Close.
|
||||
type pathCloser string
|
||||
|
||||
// Close deletes this path.
|
||||
func (p pathCloser) Close() error {
|
||||
return os.RemoveAll(string(p))
|
||||
}
|
||||
46
vendor/github.com/hashicorp/go-safetemp/safetemp_test.go
generated
vendored
Normal file
46
vendor/github.com/hashicorp/go-safetemp/safetemp_test.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package safetemp
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDir(t *testing.T) {
|
||||
d, c, err := Dir("", "test")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(d); err == nil || !os.IsNotExist(err) {
|
||||
t.Fatalf("directory %q should not exist", d)
|
||||
}
|
||||
|
||||
parent := filepath.Dir(d)
|
||||
fi, err := os.Stat(parent)
|
||||
if err != nil {
|
||||
t.Fatalf("parent directory error: %s", err)
|
||||
}
|
||||
if v := fi.Mode().Perm();v != 0700 {
|
||||
t.Fatalf("parent directory should be 0700: %s", v)
|
||||
}
|
||||
|
||||
// Create the directory
|
||||
if err := os.MkdirAll(d, 0755); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if _, err := os.Stat(d); err != nil {
|
||||
t.Fatalf("directory %q should exist", d)
|
||||
}
|
||||
|
||||
// Close should remove it
|
||||
if err := c.Close(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
if _, err := os.Stat(d); err == nil || !os.IsNotExist(err) {
|
||||
t.Fatalf("directory %q should not exist", d)
|
||||
}
|
||||
if _, err := os.Stat(parent); err == nil || !os.IsNotExist(err) {
|
||||
t.Fatalf("directory %q should not exist", parent)
|
||||
}
|
||||
}
|
||||
13
vendor/github.com/hashicorp/go-version/.travis.yml
generated
vendored
Normal file
13
vendor/github.com/hashicorp/go-version/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.0
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.9
|
||||
- "1.10"
|
||||
|
||||
script:
|
||||
- go test
|
||||
354
vendor/github.com/hashicorp/go-version/LICENSE
generated
vendored
Normal file
354
vendor/github.com/hashicorp/go-version/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
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.
|
||||
|
||||
65
vendor/github.com/hashicorp/go-version/README.md
generated
vendored
Normal file
65
vendor/github.com/hashicorp/go-version/README.md
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# Versioning Library for Go
|
||||
[](https://travis-ci.org/hashicorp/go-version)
|
||||
|
||||
go-version is a library for parsing versions and version constraints,
|
||||
and verifying versions against a set of constraints. go-version
|
||||
can sort a collection of versions properly, handles prerelease/beta
|
||||
versions, can increment versions, etc.
|
||||
|
||||
Versions used with go-version must follow [SemVer](http://semver.org/).
|
||||
|
||||
## Installation and Usage
|
||||
|
||||
Package documentation can be found on
|
||||
[GoDoc](http://godoc.org/github.com/hashicorp/go-version).
|
||||
|
||||
Installation can be done with a normal `go get`:
|
||||
|
||||
```
|
||||
$ go get github.com/hashicorp/go-version
|
||||
```
|
||||
|
||||
#### Version Parsing and Comparison
|
||||
|
||||
```go
|
||||
v1, err := version.NewVersion("1.2")
|
||||
v2, err := version.NewVersion("1.5+metadata")
|
||||
|
||||
// Comparison example. There is also GreaterThan, Equal, and just
|
||||
// a simple Compare that returns an int allowing easy >=, <=, etc.
|
||||
if v1.LessThan(v2) {
|
||||
fmt.Printf("%s is less than %s", v1, v2)
|
||||
}
|
||||
```
|
||||
|
||||
#### Version Constraints
|
||||
|
||||
```go
|
||||
v1, err := version.NewVersion("1.2")
|
||||
|
||||
// Constraints example.
|
||||
constraints, err := version.NewConstraint(">= 1.0, < 1.4")
|
||||
if constraints.Check(v1) {
|
||||
fmt.Printf("%s satisfies constraints %s", v1, constraints)
|
||||
}
|
||||
```
|
||||
|
||||
#### Version Sorting
|
||||
|
||||
```go
|
||||
versionsRaw := []string{"1.1", "0.7.1", "1.4-beta", "1.4", "2"}
|
||||
versions := make([]*version.Version, len(versionsRaw))
|
||||
for i, raw := range versionsRaw {
|
||||
v, _ := version.NewVersion(raw)
|
||||
versions[i] = v
|
||||
}
|
||||
|
||||
// After this, the versions are properly sorted
|
||||
sort.Sort(version.Collection(versions))
|
||||
```
|
||||
|
||||
## Issues and Contributing
|
||||
|
||||
If you find an issue with this library, please report an issue. If you'd
|
||||
like, we welcome any contributions. Fork this library and submit a pull
|
||||
request.
|
||||
204
vendor/github.com/hashicorp/go-version/constraint.go
generated
vendored
Normal file
204
vendor/github.com/hashicorp/go-version/constraint.go
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Constraint represents a single constraint for a version, such as
|
||||
// ">= 1.0".
|
||||
type Constraint struct {
|
||||
f constraintFunc
|
||||
check *Version
|
||||
original string
|
||||
}
|
||||
|
||||
// Constraints is a slice of constraints. We make a custom type so that
|
||||
// we can add methods to it.
|
||||
type Constraints []*Constraint
|
||||
|
||||
type constraintFunc func(v, c *Version) bool
|
||||
|
||||
var constraintOperators map[string]constraintFunc
|
||||
|
||||
var constraintRegexp *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
constraintOperators = map[string]constraintFunc{
|
||||
"": constraintEqual,
|
||||
"=": constraintEqual,
|
||||
"!=": constraintNotEqual,
|
||||
">": constraintGreaterThan,
|
||||
"<": constraintLessThan,
|
||||
">=": constraintGreaterThanEqual,
|
||||
"<=": constraintLessThanEqual,
|
||||
"~>": constraintPessimistic,
|
||||
}
|
||||
|
||||
ops := make([]string, 0, len(constraintOperators))
|
||||
for k := range constraintOperators {
|
||||
ops = append(ops, regexp.QuoteMeta(k))
|
||||
}
|
||||
|
||||
constraintRegexp = regexp.MustCompile(fmt.Sprintf(
|
||||
`^\s*(%s)\s*(%s)\s*$`,
|
||||
strings.Join(ops, "|"),
|
||||
VersionRegexpRaw))
|
||||
}
|
||||
|
||||
// NewConstraint will parse one or more constraints from the given
|
||||
// constraint string. The string must be a comma-separated list of
|
||||
// constraints.
|
||||
func NewConstraint(v string) (Constraints, error) {
|
||||
vs := strings.Split(v, ",")
|
||||
result := make([]*Constraint, len(vs))
|
||||
for i, single := range vs {
|
||||
c, err := parseSingle(single)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result[i] = c
|
||||
}
|
||||
|
||||
return Constraints(result), nil
|
||||
}
|
||||
|
||||
// Check tests if a version satisfies all the constraints.
|
||||
func (cs Constraints) Check(v *Version) bool {
|
||||
for _, c := range cs {
|
||||
if !c.Check(v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Returns the string format of the constraints
|
||||
func (cs Constraints) String() string {
|
||||
csStr := make([]string, len(cs))
|
||||
for i, c := range cs {
|
||||
csStr[i] = c.String()
|
||||
}
|
||||
|
||||
return strings.Join(csStr, ",")
|
||||
}
|
||||
|
||||
// Check tests if a constraint is validated by the given version.
|
||||
func (c *Constraint) Check(v *Version) bool {
|
||||
return c.f(v, c.check)
|
||||
}
|
||||
|
||||
func (c *Constraint) String() string {
|
||||
return c.original
|
||||
}
|
||||
|
||||
func parseSingle(v string) (*Constraint, error) {
|
||||
matches := constraintRegexp.FindStringSubmatch(v)
|
||||
if matches == nil {
|
||||
return nil, fmt.Errorf("Malformed constraint: %s", v)
|
||||
}
|
||||
|
||||
check, err := NewVersion(matches[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Constraint{
|
||||
f: constraintOperators[matches[1]],
|
||||
check: check,
|
||||
original: v,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func prereleaseCheck(v, c *Version) bool {
|
||||
switch vPre, cPre := v.Prerelease() != "", c.Prerelease() != ""; {
|
||||
case cPre && vPre:
|
||||
// A constraint with a pre-release can only match a pre-release version
|
||||
// with the same base segments.
|
||||
return reflect.DeepEqual(c.Segments64(), v.Segments64())
|
||||
|
||||
case !cPre && vPre:
|
||||
// A constraint without a pre-release can only match a version without a
|
||||
// pre-release.
|
||||
return false
|
||||
|
||||
case cPre && !vPre:
|
||||
// OK, except with the pessimistic operator
|
||||
case !cPre && !vPre:
|
||||
// OK
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Constraint functions
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
func constraintEqual(v, c *Version) bool {
|
||||
return v.Equal(c)
|
||||
}
|
||||
|
||||
func constraintNotEqual(v, c *Version) bool {
|
||||
return !v.Equal(c)
|
||||
}
|
||||
|
||||
func constraintGreaterThan(v, c *Version) bool {
|
||||
return prereleaseCheck(v, c) && v.Compare(c) == 1
|
||||
}
|
||||
|
||||
func constraintLessThan(v, c *Version) bool {
|
||||
return prereleaseCheck(v, c) && v.Compare(c) == -1
|
||||
}
|
||||
|
||||
func constraintGreaterThanEqual(v, c *Version) bool {
|
||||
return prereleaseCheck(v, c) && v.Compare(c) >= 0
|
||||
}
|
||||
|
||||
func constraintLessThanEqual(v, c *Version) bool {
|
||||
return prereleaseCheck(v, c) && v.Compare(c) <= 0
|
||||
}
|
||||
|
||||
func constraintPessimistic(v, c *Version) bool {
|
||||
// Using a pessimistic constraint with a pre-release, restricts versions to pre-releases
|
||||
if !prereleaseCheck(v, c) || (c.Prerelease() != "" && v.Prerelease() == "") {
|
||||
return false
|
||||
}
|
||||
|
||||
// If the version being checked is naturally less than the constraint, then there
|
||||
// is no way for the version to be valid against the constraint
|
||||
if v.LessThan(c) {
|
||||
return false
|
||||
}
|
||||
// We'll use this more than once, so grab the length now so it's a little cleaner
|
||||
// to write the later checks
|
||||
cs := len(c.segments)
|
||||
|
||||
// If the version being checked has less specificity than the constraint, then there
|
||||
// is no way for the version to be valid against the constraint
|
||||
if cs > len(v.segments) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check the segments in the constraint against those in the version. If the version
|
||||
// being checked, at any point, does not have the same values in each index of the
|
||||
// constraints segments, then it cannot be valid against the constraint.
|
||||
for i := 0; i < c.si-1; i++ {
|
||||
if v.segments[i] != c.segments[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Check the last part of the segment in the constraint. If the version segment at
|
||||
// this index is less than the constraints segment at this index, then it cannot
|
||||
// be valid against the constraint
|
||||
if c.segments[cs-1] > v.segments[cs-1] {
|
||||
return false
|
||||
}
|
||||
|
||||
// If nothing has rejected the version by now, it's valid
|
||||
return true
|
||||
}
|
||||
126
vendor/github.com/hashicorp/go-version/constraint_test.go
generated
vendored
Normal file
126
vendor/github.com/hashicorp/go-version/constraint_test.go
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewConstraint(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
count int
|
||||
err bool
|
||||
}{
|
||||
{">= 1.2", 1, false},
|
||||
{"1.0", 1, false},
|
||||
{">= 1.x", 0, true},
|
||||
{">= 1.2, < 1.0", 2, false},
|
||||
|
||||
// Out of bounds
|
||||
{"11387778780781445675529500000000000000000", 0, true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
v, err := NewConstraint(tc.input)
|
||||
if tc.err && err == nil {
|
||||
t.Fatalf("expected error for input: %s", tc.input)
|
||||
} else if !tc.err && err != nil {
|
||||
t.Fatalf("error for input %s: %s", tc.input, err)
|
||||
}
|
||||
|
||||
if len(v) != tc.count {
|
||||
t.Fatalf("input: %s\nexpected len: %d\nactual: %d",
|
||||
tc.input, tc.count, len(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConstraintCheck(t *testing.T) {
|
||||
cases := []struct {
|
||||
constraint string
|
||||
version string
|
||||
check bool
|
||||
}{
|
||||
{">= 1.0, < 1.2", "1.1.5", true},
|
||||
{"< 1.0, < 1.2", "1.1.5", false},
|
||||
{"= 1.0", "1.1.5", false},
|
||||
{"= 1.0", "1.0.0", true},
|
||||
{"1.0", "1.0.0", true},
|
||||
{"~> 1.0", "2.0", false},
|
||||
{"~> 1.0", "1.1", true},
|
||||
{"~> 1.0", "1.2.3", true},
|
||||
{"~> 1.0.0", "1.2.3", false},
|
||||
{"~> 1.0.0", "1.0.7", true},
|
||||
{"~> 1.0.0", "1.1.0", false},
|
||||
{"~> 1.0.7", "1.0.4", false},
|
||||
{"~> 1.0.7", "1.0.7", true},
|
||||
{"~> 1.0.7", "1.0.8", true},
|
||||
{"~> 1.0.7", "1.0.7.5", true},
|
||||
{"~> 1.0.7", "1.0.6.99", false},
|
||||
{"~> 1.0.7", "1.0.8.0", true},
|
||||
{"~> 1.0.9.5", "1.0.9.5", true},
|
||||
{"~> 1.0.9.5", "1.0.9.4", false},
|
||||
{"~> 1.0.9.5", "1.0.9.6", true},
|
||||
{"~> 1.0.9.5", "1.0.9.5.0", true},
|
||||
{"~> 1.0.9.5", "1.0.9.5.1", true},
|
||||
{"~> 2.0", "2.1.0-beta", false},
|
||||
{"~> 2.1.0-a", "2.2.0", false},
|
||||
{"~> 2.1.0-a", "2.1.0", false},
|
||||
{"~> 2.1.0-a", "2.1.0-beta", true},
|
||||
{"~> 2.1.0-a", "2.2.0-alpha", false},
|
||||
{"> 2.0", "2.1.0-beta", false},
|
||||
{">= 2.1.0-a", "2.1.0-beta", true},
|
||||
{">= 2.1.0-a", "2.1.1-beta", false},
|
||||
{">= 2.0.0", "2.1.0-beta", false},
|
||||
{">= 2.1.0-a", "2.1.1", true},
|
||||
{">= 2.1.0-a", "2.1.1-beta", false},
|
||||
{">= 2.1.0-a", "2.1.0", true},
|
||||
{"<= 2.1.0-a", "2.0.0", true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
c, err := NewConstraint(tc.constraint)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
v, err := NewVersion(tc.version)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := c.Check(v)
|
||||
expected := tc.check
|
||||
if actual != expected {
|
||||
t.Fatalf("Version: %s\nConstraint: %s\nExpected: %#v",
|
||||
tc.version, tc.constraint, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConstraintsString(t *testing.T) {
|
||||
cases := []struct {
|
||||
constraint string
|
||||
result string
|
||||
}{
|
||||
{">= 1.0, < 1.2", ""},
|
||||
{"~> 1.0.7", ""},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
c, err := NewConstraint(tc.constraint)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := c.String()
|
||||
expected := tc.result
|
||||
if expected == "" {
|
||||
expected = tc.constraint
|
||||
}
|
||||
|
||||
if actual != expected {
|
||||
t.Fatalf("Constraint: %s\nExpected: %#v\nActual: %s",
|
||||
tc.constraint, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
347
vendor/github.com/hashicorp/go-version/version.go
generated
vendored
Normal file
347
vendor/github.com/hashicorp/go-version/version.go
generated
vendored
Normal file
@@ -0,0 +1,347 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The compiled regular expression used to test the validity of a version.
|
||||
var versionRegexp *regexp.Regexp
|
||||
|
||||
// The raw regular expression string used for testing the validity
|
||||
// of a version.
|
||||
const VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` +
|
||||
`(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-?([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` +
|
||||
`(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` +
|
||||
`?`
|
||||
|
||||
// Version represents a single version.
|
||||
type Version struct {
|
||||
metadata string
|
||||
pre string
|
||||
segments []int64
|
||||
si int
|
||||
original string
|
||||
}
|
||||
|
||||
func init() {
|
||||
versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$")
|
||||
}
|
||||
|
||||
// NewVersion parses the given version and returns a new
|
||||
// Version.
|
||||
func NewVersion(v string) (*Version, error) {
|
||||
matches := versionRegexp.FindStringSubmatch(v)
|
||||
if matches == nil {
|
||||
return nil, fmt.Errorf("Malformed version: %s", v)
|
||||
}
|
||||
segmentsStr := strings.Split(matches[1], ".")
|
||||
segments := make([]int64, len(segmentsStr))
|
||||
si := 0
|
||||
for i, str := range segmentsStr {
|
||||
val, err := strconv.ParseInt(str, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error parsing version: %s", err)
|
||||
}
|
||||
|
||||
segments[i] = int64(val)
|
||||
si++
|
||||
}
|
||||
|
||||
// Even though we could support more than three segments, if we
|
||||
// got less than three, pad it with 0s. This is to cover the basic
|
||||
// default usecase of semver, which is MAJOR.MINOR.PATCH at the minimum
|
||||
for i := len(segments); i < 3; i++ {
|
||||
segments = append(segments, 0)
|
||||
}
|
||||
|
||||
pre := matches[7]
|
||||
if pre == "" {
|
||||
pre = matches[4]
|
||||
}
|
||||
|
||||
return &Version{
|
||||
metadata: matches[10],
|
||||
pre: pre,
|
||||
segments: segments,
|
||||
si: si,
|
||||
original: v,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Must is a helper that wraps a call to a function returning (*Version, error)
|
||||
// and panics if error is non-nil.
|
||||
func Must(v *Version, err error) *Version {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// Compare compares this version to another version. This
|
||||
// returns -1, 0, or 1 if this version is smaller, equal,
|
||||
// or larger than the other version, respectively.
|
||||
//
|
||||
// If you want boolean results, use the LessThan, Equal,
|
||||
// or GreaterThan methods.
|
||||
func (v *Version) Compare(other *Version) int {
|
||||
// A quick, efficient equality check
|
||||
if v.String() == other.String() {
|
||||
return 0
|
||||
}
|
||||
|
||||
segmentsSelf := v.Segments64()
|
||||
segmentsOther := other.Segments64()
|
||||
|
||||
// If the segments are the same, we must compare on prerelease info
|
||||
if reflect.DeepEqual(segmentsSelf, segmentsOther) {
|
||||
preSelf := v.Prerelease()
|
||||
preOther := other.Prerelease()
|
||||
if preSelf == "" && preOther == "" {
|
||||
return 0
|
||||
}
|
||||
if preSelf == "" {
|
||||
return 1
|
||||
}
|
||||
if preOther == "" {
|
||||
return -1
|
||||
}
|
||||
|
||||
return comparePrereleases(preSelf, preOther)
|
||||
}
|
||||
|
||||
// Get the highest specificity (hS), or if they're equal, just use segmentSelf length
|
||||
lenSelf := len(segmentsSelf)
|
||||
lenOther := len(segmentsOther)
|
||||
hS := lenSelf
|
||||
if lenSelf < lenOther {
|
||||
hS = lenOther
|
||||
}
|
||||
// Compare the segments
|
||||
// Because a constraint could have more/less specificity than the version it's
|
||||
// checking, we need to account for a lopsided or jagged comparison
|
||||
for i := 0; i < hS; i++ {
|
||||
if i > lenSelf-1 {
|
||||
// This means Self had the lower specificity
|
||||
// Check to see if the remaining segments in Other are all zeros
|
||||
if !allZero(segmentsOther[i:]) {
|
||||
// if not, it means that Other has to be greater than Self
|
||||
return -1
|
||||
}
|
||||
break
|
||||
} else if i > lenOther-1 {
|
||||
// this means Other had the lower specificity
|
||||
// Check to see if the remaining segments in Self are all zeros -
|
||||
if !allZero(segmentsSelf[i:]) {
|
||||
//if not, it means that Self has to be greater than Other
|
||||
return 1
|
||||
}
|
||||
break
|
||||
}
|
||||
lhs := segmentsSelf[i]
|
||||
rhs := segmentsOther[i]
|
||||
if lhs == rhs {
|
||||
continue
|
||||
} else if lhs < rhs {
|
||||
return -1
|
||||
}
|
||||
// Otherwis, rhs was > lhs, they're not equal
|
||||
return 1
|
||||
}
|
||||
|
||||
// if we got this far, they're equal
|
||||
return 0
|
||||
}
|
||||
|
||||
func allZero(segs []int64) bool {
|
||||
for _, s := range segs {
|
||||
if s != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func comparePart(preSelf string, preOther string) int {
|
||||
if preSelf == preOther {
|
||||
return 0
|
||||
}
|
||||
|
||||
var selfInt int64
|
||||
selfNumeric := true
|
||||
selfInt, err := strconv.ParseInt(preSelf, 10, 64)
|
||||
if err != nil {
|
||||
selfNumeric = false
|
||||
}
|
||||
|
||||
var otherInt int64
|
||||
otherNumeric := true
|
||||
otherInt, err = strconv.ParseInt(preOther, 10, 64)
|
||||
if err != nil {
|
||||
otherNumeric = false
|
||||
}
|
||||
|
||||
// if a part is empty, we use the other to decide
|
||||
if preSelf == "" {
|
||||
if otherNumeric {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
if preOther == "" {
|
||||
if selfNumeric {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
if selfNumeric && !otherNumeric {
|
||||
return -1
|
||||
} else if !selfNumeric && otherNumeric {
|
||||
return 1
|
||||
} else if !selfNumeric && !otherNumeric && preSelf > preOther {
|
||||
return 1
|
||||
} else if selfInt > otherInt {
|
||||
return 1
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func comparePrereleases(v string, other string) int {
|
||||
// the same pre release!
|
||||
if v == other {
|
||||
return 0
|
||||
}
|
||||
|
||||
// split both pre releases for analyse their parts
|
||||
selfPreReleaseMeta := strings.Split(v, ".")
|
||||
otherPreReleaseMeta := strings.Split(other, ".")
|
||||
|
||||
selfPreReleaseLen := len(selfPreReleaseMeta)
|
||||
otherPreReleaseLen := len(otherPreReleaseMeta)
|
||||
|
||||
biggestLen := otherPreReleaseLen
|
||||
if selfPreReleaseLen > otherPreReleaseLen {
|
||||
biggestLen = selfPreReleaseLen
|
||||
}
|
||||
|
||||
// loop for parts to find the first difference
|
||||
for i := 0; i < biggestLen; i = i + 1 {
|
||||
partSelfPre := ""
|
||||
if i < selfPreReleaseLen {
|
||||
partSelfPre = selfPreReleaseMeta[i]
|
||||
}
|
||||
|
||||
partOtherPre := ""
|
||||
if i < otherPreReleaseLen {
|
||||
partOtherPre = otherPreReleaseMeta[i]
|
||||
}
|
||||
|
||||
compare := comparePart(partSelfPre, partOtherPre)
|
||||
// if parts are equals, continue the loop
|
||||
if compare != 0 {
|
||||
return compare
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Equal tests if two versions are equal.
|
||||
func (v *Version) Equal(o *Version) bool {
|
||||
return v.Compare(o) == 0
|
||||
}
|
||||
|
||||
// GreaterThan tests if this version is greater than another version.
|
||||
func (v *Version) GreaterThan(o *Version) bool {
|
||||
return v.Compare(o) > 0
|
||||
}
|
||||
|
||||
// LessThan tests if this version is less than another version.
|
||||
func (v *Version) LessThan(o *Version) bool {
|
||||
return v.Compare(o) < 0
|
||||
}
|
||||
|
||||
// Metadata returns any metadata that was part of the version
|
||||
// string.
|
||||
//
|
||||
// Metadata is anything that comes after the "+" in the version.
|
||||
// For example, with "1.2.3+beta", the metadata is "beta".
|
||||
func (v *Version) Metadata() string {
|
||||
return v.metadata
|
||||
}
|
||||
|
||||
// Prerelease returns any prerelease data that is part of the version,
|
||||
// or blank if there is no prerelease data.
|
||||
//
|
||||
// Prerelease information is anything that comes after the "-" in the
|
||||
// version (but before any metadata). For example, with "1.2.3-beta",
|
||||
// the prerelease information is "beta".
|
||||
func (v *Version) Prerelease() string {
|
||||
return v.pre
|
||||
}
|
||||
|
||||
// Segments returns the numeric segments of the version as a slice of ints.
|
||||
//
|
||||
// This excludes any metadata or pre-release information. For example,
|
||||
// for a version "1.2.3-beta", segments will return a slice of
|
||||
// 1, 2, 3.
|
||||
func (v *Version) Segments() []int {
|
||||
segmentSlice := make([]int, len(v.segments))
|
||||
for i, v := range v.segments {
|
||||
segmentSlice[i] = int(v)
|
||||
}
|
||||
return segmentSlice
|
||||
}
|
||||
|
||||
// Segments64 returns the numeric segments of the version as a slice of int64s.
|
||||
//
|
||||
// This excludes any metadata or pre-release information. For example,
|
||||
// for a version "1.2.3-beta", segments will return a slice of
|
||||
// 1, 2, 3.
|
||||
func (v *Version) Segments64() []int64 {
|
||||
result := make([]int64, len(v.segments))
|
||||
copy(result, v.segments)
|
||||
return result
|
||||
}
|
||||
|
||||
// String returns the full version string included pre-release
|
||||
// and metadata information.
|
||||
//
|
||||
// This value is rebuilt according to the parsed segments and other
|
||||
// information. Therefore, ambiguities in the version string such as
|
||||
// prefixed zeroes (1.04.0 => 1.4.0), `v` prefix (v1.0.0 => 1.0.0), and
|
||||
// missing parts (1.0 => 1.0.0) will be made into a canonicalized form
|
||||
// as shown in the parenthesized examples.
|
||||
func (v *Version) String() string {
|
||||
var buf bytes.Buffer
|
||||
fmtParts := make([]string, len(v.segments))
|
||||
for i, s := range v.segments {
|
||||
// We can ignore err here since we've pre-parsed the values in segments
|
||||
str := strconv.FormatInt(s, 10)
|
||||
fmtParts[i] = str
|
||||
}
|
||||
fmt.Fprintf(&buf, strings.Join(fmtParts, "."))
|
||||
if v.pre != "" {
|
||||
fmt.Fprintf(&buf, "-%s", v.pre)
|
||||
}
|
||||
if v.metadata != "" {
|
||||
fmt.Fprintf(&buf, "+%s", v.metadata)
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Original returns the original parsed version as-is, including any
|
||||
// potential whitespace, `v` prefix, etc.
|
||||
func (v *Version) Original() string {
|
||||
return v.original
|
||||
}
|
||||
17
vendor/github.com/hashicorp/go-version/version_collection.go
generated
vendored
Normal file
17
vendor/github.com/hashicorp/go-version/version_collection.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package version
|
||||
|
||||
// Collection is a type that implements the sort.Interface interface
|
||||
// so that versions can be sorted.
|
||||
type Collection []*Version
|
||||
|
||||
func (v Collection) Len() int {
|
||||
return len(v)
|
||||
}
|
||||
|
||||
func (v Collection) Less(i, j int) bool {
|
||||
return v[i].LessThan(v[j])
|
||||
}
|
||||
|
||||
func (v Collection) Swap(i, j int) {
|
||||
v[i], v[j] = v[j], v[i]
|
||||
}
|
||||
46
vendor/github.com/hashicorp/go-version/version_collection_test.go
generated
vendored
Normal file
46
vendor/github.com/hashicorp/go-version/version_collection_test.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCollection(t *testing.T) {
|
||||
versionsRaw := []string{
|
||||
"1.1.1",
|
||||
"1.0",
|
||||
"1.2",
|
||||
"2",
|
||||
"0.7.1",
|
||||
}
|
||||
|
||||
versions := make([]*Version, len(versionsRaw))
|
||||
for i, raw := range versionsRaw {
|
||||
v, err := NewVersion(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
versions[i] = v
|
||||
}
|
||||
|
||||
sort.Sort(Collection(versions))
|
||||
|
||||
actual := make([]string, len(versions))
|
||||
for i, v := range versions {
|
||||
actual[i] = v.String()
|
||||
}
|
||||
|
||||
expected := []string{
|
||||
"0.7.1",
|
||||
"1.0.0",
|
||||
"1.1.1",
|
||||
"1.2.0",
|
||||
"2.0.0",
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("bad: %#v", actual)
|
||||
}
|
||||
}
|
||||
282
vendor/github.com/hashicorp/go-version/version_test.go
generated
vendored
Normal file
282
vendor/github.com/hashicorp/go-version/version_test.go
generated
vendored
Normal file
@@ -0,0 +1,282 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewVersion(t *testing.T) {
|
||||
cases := []struct {
|
||||
version string
|
||||
err bool
|
||||
}{
|
||||
{"1.2.3", false},
|
||||
{"1.0", false},
|
||||
{"1", false},
|
||||
{"1.2.beta", true},
|
||||
{"1.21.beta", true},
|
||||
{"foo", true},
|
||||
{"1.2-5", false},
|
||||
{"1.2-beta.5", false},
|
||||
{"\n1.2", true},
|
||||
{"1.2.0-x.Y.0+metadata", false},
|
||||
{"1.2.0-x.Y.0+metadata-width-hypen", false},
|
||||
{"1.2.3-rc1-with-hypen", false},
|
||||
{"1.2.3.4", false},
|
||||
{"1.2.0.4-x.Y.0+metadata", false},
|
||||
{"1.2.0.4-x.Y.0+metadata-width-hypen", false},
|
||||
{"1.2.0-X-1.2.0+metadata~dist", false},
|
||||
{"1.2.3.4-rc1-with-hypen", false},
|
||||
{"1.2.3.4", false},
|
||||
{"v1.2.3", false},
|
||||
{"foo1.2.3", true},
|
||||
{"1.7rc2", false},
|
||||
{"v1.7rc2", false},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
_, err := NewVersion(tc.version)
|
||||
if tc.err && err == nil {
|
||||
t.Fatalf("expected error for version: %s", tc.version)
|
||||
} else if !tc.err && err != nil {
|
||||
t.Fatalf("error for version %s: %s", tc.version, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionCompare(t *testing.T) {
|
||||
cases := []struct {
|
||||
v1 string
|
||||
v2 string
|
||||
expected int
|
||||
}{
|
||||
{"1.2.3", "1.4.5", -1},
|
||||
{"1.2-beta", "1.2-beta", 0},
|
||||
{"1.2", "1.1.4", 1},
|
||||
{"1.2", "1.2-beta", 1},
|
||||
{"1.2+foo", "1.2+beta", 0},
|
||||
{"v1.2", "v1.2-beta", 1},
|
||||
{"v1.2+foo", "v1.2+beta", 0},
|
||||
{"v1.2.3.4", "v1.2.3.4", 0},
|
||||
{"v1.2.0.0", "v1.2", 0},
|
||||
{"v1.2.0.0.1", "v1.2", 1},
|
||||
{"v1.2", "v1.2.0.0", 0},
|
||||
{"v1.2", "v1.2.0.0.1", -1},
|
||||
{"v1.2.0.0", "v1.2.0.0.1", -1},
|
||||
{"v1.2.3.0", "v1.2.3.4", -1},
|
||||
{"1.7rc2", "1.7rc1", 1},
|
||||
{"1.7rc2", "1.7", -1},
|
||||
{"1.2.0", "1.2.0-X-1.2.0+metadata~dist", 1},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
v1, err := NewVersion(tc.v1)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
v2, err := NewVersion(tc.v2)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := v1.Compare(v2)
|
||||
expected := tc.expected
|
||||
if actual != expected {
|
||||
t.Fatalf(
|
||||
"%s <=> %s\nexpected: %d\nactual: %d",
|
||||
tc.v1, tc.v2,
|
||||
expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestComparePreReleases(t *testing.T) {
|
||||
cases := []struct {
|
||||
v1 string
|
||||
v2 string
|
||||
expected int
|
||||
}{
|
||||
{"1.2-beta.2", "1.2-beta.2", 0},
|
||||
{"1.2-beta.1", "1.2-beta.2", -1},
|
||||
{"1.2-beta.2", "1.2-beta.11", -1},
|
||||
{"3.2-alpha.1", "3.2-alpha", 1},
|
||||
{"1.2-beta.2", "1.2-beta.1", 1},
|
||||
{"1.2-beta.11", "1.2-beta.2", 1},
|
||||
{"1.2-beta", "1.2-beta.3", -1},
|
||||
{"1.2-alpha", "1.2-beta.3", -1},
|
||||
{"1.2-beta", "1.2-alpha.3", 1},
|
||||
{"3.0-alpha.3", "3.0-rc.1", -1},
|
||||
{"3.0-alpha3", "3.0-rc1", -1},
|
||||
{"3.0-alpha.1", "3.0-alpha.beta", -1},
|
||||
{"5.4-alpha", "5.4-alpha.beta", 1},
|
||||
{"v1.2-beta.2", "v1.2-beta.2", 0},
|
||||
{"v1.2-beta.1", "v1.2-beta.2", -1},
|
||||
{"v3.2-alpha.1", "v3.2-alpha", 1},
|
||||
{"v3.2-rc.1-1-g123", "v3.2-rc.2", 1},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
v1, err := NewVersion(tc.v1)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
v2, err := NewVersion(tc.v2)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := v1.Compare(v2)
|
||||
expected := tc.expected
|
||||
if actual != expected {
|
||||
t.Fatalf(
|
||||
"%s <=> %s\nexpected: %d\nactual: %d",
|
||||
tc.v1, tc.v2,
|
||||
expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionMetadata(t *testing.T) {
|
||||
cases := []struct {
|
||||
version string
|
||||
expected string
|
||||
}{
|
||||
{"1.2.3", ""},
|
||||
{"1.2-beta", ""},
|
||||
{"1.2.0-x.Y.0", ""},
|
||||
{"1.2.0-x.Y.0+metadata", "metadata"},
|
||||
{"1.2.0-metadata-1.2.0+metadata~dist", "metadata~dist"},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
v, err := NewVersion(tc.version)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := v.Metadata()
|
||||
expected := tc.expected
|
||||
if actual != expected {
|
||||
t.Fatalf("expected: %s\nactual: %s", expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionPrerelease(t *testing.T) {
|
||||
cases := []struct {
|
||||
version string
|
||||
expected string
|
||||
}{
|
||||
{"1.2.3", ""},
|
||||
{"1.2-beta", "beta"},
|
||||
{"1.2.0-x.Y.0", "x.Y.0"},
|
||||
{"1.2.0-7.Y.0", "7.Y.0"},
|
||||
{"1.2.0-x.Y.0+metadata", "x.Y.0"},
|
||||
{"1.2.0-metadata-1.2.0+metadata~dist", "metadata-1.2.0"},
|
||||
{"17.03.0-ce", "ce"}, // zero-padded fields
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
v, err := NewVersion(tc.version)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := v.Prerelease()
|
||||
expected := tc.expected
|
||||
if actual != expected {
|
||||
t.Fatalf("expected: %s\nactual: %s", expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionSegments(t *testing.T) {
|
||||
cases := []struct {
|
||||
version string
|
||||
expected []int
|
||||
}{
|
||||
{"1.2.3", []int{1, 2, 3}},
|
||||
{"1.2-beta", []int{1, 2, 0}},
|
||||
{"1-x.Y.0", []int{1, 0, 0}},
|
||||
{"1.2.0-x.Y.0+metadata", []int{1, 2, 0}},
|
||||
{"1.2.0-metadata-1.2.0+metadata~dist", []int{1, 2, 0}},
|
||||
{"17.03.0-ce", []int{17, 3, 0}}, // zero-padded fields
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
v, err := NewVersion(tc.version)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := v.Segments()
|
||||
expected := tc.expected
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("expected: %#v\nactual: %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionSegments64(t *testing.T) {
|
||||
cases := []struct {
|
||||
version string
|
||||
expected []int64
|
||||
}{
|
||||
{"1.2.3", []int64{1, 2, 3}},
|
||||
{"1.2-beta", []int64{1, 2, 0}},
|
||||
{"1-x.Y.0", []int64{1, 0, 0}},
|
||||
{"1.2.0-x.Y.0+metadata", []int64{1, 2, 0}},
|
||||
{"1.4.9223372036854775807", []int64{1, 4, 9223372036854775807}},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
v, err := NewVersion(tc.version)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := v.Segments64()
|
||||
expected := tc.expected
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("expected: %#v\nactual: %#v", expected, actual)
|
||||
}
|
||||
|
||||
{
|
||||
expected := actual[0]
|
||||
actual[0]++
|
||||
actual = v.Segments64()
|
||||
if actual[0] != expected {
|
||||
t.Fatalf("Segments64 is mutable")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionString(t *testing.T) {
|
||||
cases := [][]string{
|
||||
{"1.2.3", "1.2.3"},
|
||||
{"1.2-beta", "1.2.0-beta"},
|
||||
{"1.2.0-x.Y.0", "1.2.0-x.Y.0"},
|
||||
{"1.2.0-x.Y.0+metadata", "1.2.0-x.Y.0+metadata"},
|
||||
{"1.2.0-metadata-1.2.0+metadata~dist", "1.2.0-metadata-1.2.0+metadata~dist"},
|
||||
{"17.03.0-ce", "17.3.0-ce"}, // zero-padded fields
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
v, err := NewVersion(tc[0])
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
actual := v.String()
|
||||
expected := tc[1]
|
||||
if actual != expected {
|
||||
t.Fatalf("expected: %s\nactual: %s", expected, actual)
|
||||
}
|
||||
if actual := v.Original(); actual != tc[0] {
|
||||
t.Fatalf("expected original: %q\nactual: %q", tc[0], actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user