blob: cdfee698faf1f718c1c13d8c5db6965b51d64c89 [file] [log] [blame]
// Copyright 2018 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"context"
"google.golang.org/grpc/codes"
"go.chromium.org/luci/common/errors"
"go.chromium.org/luci/grpc/grpcutil"
"go.chromium.org/luci/cipd/common"
)
// ResolveVersion takes a version identifier (an instance ID, a ref or a tag)
// and resolves it into a concrete package instance, ensuring it exists.
//
// Returns gRPC-tagged errors:
// InvalidArgument if the version string format is invalid.
// NotFound if there's no such package or such version.
// FailedPrecondition if the tag resolves to multiple instances.
func ResolveVersion(c context.Context, pkg, version string) (*Instance, error) {
// Pick a resolution method based on the format of the version string.
var iid string
var err error
switch {
case common.ValidateInstanceID(version, common.KnownHash) == nil:
iid = version
case common.ValidatePackageRef(version) == nil:
var ref *Ref
if ref, err = GetRef(c, pkg, version); err == nil {
iid = ref.InstanceID
}
case common.ValidateInstanceTag(version) == nil:
iid, err = ResolveTag(c, pkg, common.MustParseInstanceTag(version))
default:
return nil, errors.Reason("not a valid version identifier").Tag(grpcutil.InvalidArgumentTag).Err()
}
if err != nil {
// If there's no such ref or tag, maybe the package is missing completely.
if grpcutil.Code(err) == codes.NotFound {
if pkgErr := CheckPackageExists(c, pkg); pkgErr != nil {
return nil, pkgErr
}
}
return nil, err
}
// Verify the instance exists and fetch its details. This is particularly
// important for the case when 'version' is raw instance ID already. For
// cases of tags and refs, the instance MUST exist per checks we do in SetRef
// and AttachTags, but being defensive here doesn't hurt.
inst := &Instance{
InstanceID: iid,
Package: PackageKey(c, pkg),
}
if err := CheckInstanceExists(c, inst); err != nil {
return nil, err
}
return inst, nil
}