Instead of using the ostree.RequestParams in the OSTReeImageOptions, define a new struct specific to ImageOptions for the ostree parameters. This is almost identical to the new ostree.CommitSpec but the meaning of the parameters changes based on image type and it would not be clear if the CommitSpec was used in all cases. For example, the parameters of the new OSTreeImageOptions do not always refer to the same commit. The URL and Checksum may point to a parent commit to be pulled in to base the new commit on, while the Ref refers to the new commit that will be built (which may have a different ref from the parent). The ostree.ResolveParams() function now returns two strings, the resolved ref, which is replaced by the defaultRef if it's not specified in the request, and the resolved parent checksum if a URL is specified. The URL does not need to be returned since it's always the same as the one specified in the request. The function has been rewritten to make the logic more clear. The docstring for the function has been rewritten to cover all use cases and error conditions.
127 lines
3.7 KiB
Go
127 lines
3.7 KiB
Go
package ostree
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/url"
|
|
"path"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
var ostreeRefRE = regexp.MustCompile(`^(?:[\w\d][-._\w\d]*\/)*[\w\d][-._\w\d]*$`)
|
|
|
|
type RequestParams struct {
|
|
URL string `json:"url"`
|
|
Ref string `json:"ref"`
|
|
Parent string `json:"parent"`
|
|
}
|
|
|
|
// CommitSpec specifies an ostree commit using any combination of Ref (branch), URL (source), and Checksum (commit ID).
|
|
type CommitSpec struct {
|
|
|
|
// Ref for the commit. Can be empty.
|
|
Ref string
|
|
|
|
// URL of the repo where the commit can be fetched, if available.
|
|
URL string
|
|
|
|
// Checksum of the commit.
|
|
Checksum string
|
|
}
|
|
|
|
// Remote defines the options that can be set for an OSTree Remote configuration.
|
|
type Remote struct {
|
|
Name string
|
|
URL string
|
|
ContentURL string
|
|
GPGKeyPaths []string
|
|
}
|
|
|
|
func VerifyRef(ref string) bool {
|
|
return len(ref) > 0 && ostreeRefRE.MatchString(ref)
|
|
}
|
|
|
|
// ResolveRef resolves the URL path specified by the location and ref
|
|
// (location+"refs/heads/"+ref) and returns the commit ID for the named ref. If
|
|
// there is an error, it will be of type ResolveRefError.
|
|
func ResolveRef(location, ref string) (string, error) {
|
|
u, err := url.Parse(location)
|
|
if err != nil {
|
|
return "", NewResolveRefError(err.Error())
|
|
}
|
|
u.Path = path.Join(u.Path, "refs/heads/", ref)
|
|
resp, err := http.Get(u.String())
|
|
if err != nil {
|
|
return "", NewResolveRefError(err.Error())
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return "", NewResolveRefError("ostree repository %q returned status: %s", u.String(), resp.Status)
|
|
}
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return "", NewResolveRefError(err.Error())
|
|
}
|
|
parent := strings.TrimSpace(string(body))
|
|
// Check that this is at least a hex string.
|
|
_, err = hex.DecodeString(parent)
|
|
if err != nil {
|
|
return "", NewResolveRefError("ostree repository %q returned invalid reference", u.String())
|
|
}
|
|
return parent, nil
|
|
}
|
|
|
|
// ResolveParams resolves the ostree request parameters into the necessary ref
|
|
// for the image build pipeline and a commit (checksum) to be fetched.
|
|
//
|
|
// If a URL is defined in the RequestParams, the checksum of the Parent ref is
|
|
// resolved, otherwise the checksum is an empty string. Specifying Parent
|
|
// without URL results in a ParameterComboError. Failure to resolve the
|
|
// checksum results in a ResolveRefError.
|
|
//
|
|
// If Ref is not specified in the RequestParams, the defaultRef is used.
|
|
// If Parent is not specified in the RequestParams, the value of Ref is used
|
|
// (which will be defaultRef if neither is specified).
|
|
//
|
|
// If any ref (Ref or Parent) is malformed, the function returns with a RefError.
|
|
func ResolveParams(params RequestParams, defaultRef string) (ref, checksum string, err error) {
|
|
// Determine value of ref
|
|
ref = params.Ref
|
|
if ref != "" {
|
|
// verify format of provided ref
|
|
if !VerifyRef(params.Ref) {
|
|
return "", "", NewRefError("Invalid ostree ref %q", params.Ref)
|
|
}
|
|
} else {
|
|
// if ref is not provided, use distro default
|
|
ref = defaultRef
|
|
}
|
|
|
|
// Determine value of parentRef
|
|
parentRef := params.Parent
|
|
if parentRef != "" {
|
|
// verify format of parent ref
|
|
if !VerifyRef(params.Parent) {
|
|
return "", "", NewRefError("Invalid ostree parent ref %q", params.Parent)
|
|
}
|
|
if params.URL == "" {
|
|
// specifying parent ref also requires URL
|
|
return "", "", NewParameterComboError("ostree parent ref specified, but no URL to retrieve it")
|
|
}
|
|
} else {
|
|
// if parent is not provided, use ref
|
|
parentRef = ref
|
|
}
|
|
|
|
// Resolve parent checksum
|
|
if params.URL != "" {
|
|
// If a URL is specified, we need to fetch the commit at the URL.
|
|
parent, err := ResolveRef(params.URL, parentRef)
|
|
if err != nil {
|
|
return "", "", err // ResolveRefError
|
|
}
|
|
checksum = parent
|
|
}
|
|
return
|
|
}
|