debian-forge-composer/internal/ostree/ostree.go
Achilleas Koutsou 390ae15eaa distro: replace ostree.RequestParams with new OSTreeImageOptions
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.
2022-10-11 10:00:22 +02:00

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
}