blob: 101284e8f5aec8c6cd43e879584c78229fa694c3 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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 resolve
import (
"context"
"errors"
"fmt"
"io"
)
import (
"gorm.io/gorm"
)
import (
"github.com/apache/dubbo-kubernetes/pkg/bufman/bufpkg/bufconfig"
"github.com/apache/dubbo-kubernetes/pkg/bufman/bufpkg/bufmodule/bufmoduleref"
"github.com/apache/dubbo-kubernetes/pkg/bufman/config"
"github.com/apache/dubbo-kubernetes/pkg/bufman/core/storage"
"github.com/apache/dubbo-kubernetes/pkg/bufman/e"
"github.com/apache/dubbo-kubernetes/pkg/bufman/mapper"
"github.com/apache/dubbo-kubernetes/pkg/bufman/model"
manifest2 "github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/manifest"
)
type Resolver interface {
GetAllDependenciesFromBufConfig(ctx context.Context, bufConfig *bufconfig.Config) (model.Commits, e.ResponseError) // 获取全部依赖
GetDirectDependenciesFromBufConfig(ctx context.Context, bufConfig *bufconfig.Config) (model.Commits, e.ResponseError) // 获取直接依赖
GetAllDependenciesFromModuleRefs(ctx context.Context, moduleReferences []bufmoduleref.ModuleReference) (model.Commits, e.ResponseError) // 获取全部依赖
GetDirectDependenciesFromModuleRefs(ctx context.Context, moduleReferences []bufmoduleref.ModuleReference) (model.Commits, e.ResponseError) // 获取直接依赖
}
type ResolverImpl struct {
repositoryMapper mapper.RepositoryMapper
commitMapper mapper.CommitMapper
fileMapper mapper.FileMapper
storageHelper storage.StorageHelper
}
func NewResolver() Resolver {
return &ResolverImpl{
repositoryMapper: &mapper.RepositoryMapperImpl{},
commitMapper: &mapper.CommitMapperImpl{},
fileMapper: &mapper.FileMapperImpl{},
storageHelper: storage.NewStorageHelper(),
}
}
func (resolver *ResolverImpl) GetAllDependenciesFromBufConfig(ctx context.Context, bufConfig *bufconfig.Config) (model.Commits, e.ResponseError) {
var dependentCommitSet map[string]*model.Commit
var err e.ResponseError
dependentCommitSet, err = resolver.doGetDependencies(ctx, dependentCommitSet, bufConfig.Build.DependencyModuleReferences, true)
if err != nil {
return nil, err
}
commits := make([]*model.Commit, 0, len(dependentCommitSet))
for _, commit := range dependentCommitSet {
commits = append(commits, commit)
}
return commits, nil
}
func (resolver *ResolverImpl) GetDirectDependenciesFromBufConfig(ctx context.Context, bufConfig *bufconfig.Config) (model.Commits, e.ResponseError) {
var dependentCommitSet map[string]*model.Commit
var err e.ResponseError
dependentCommitSet, err = resolver.doGetDependencies(ctx, dependentCommitSet, bufConfig.Build.DependencyModuleReferences, false)
if err != nil {
return nil, err
}
commits := make([]*model.Commit, 0, len(dependentCommitSet))
for _, commit := range dependentCommitSet {
commits = append(commits, commit)
}
return commits, nil
}
func (resolver *ResolverImpl) GetAllDependenciesFromModuleRefs(ctx context.Context, moduleReferences []bufmoduleref.ModuleReference) (model.Commits, e.ResponseError) {
var dependentCommitSet map[string]*model.Commit
var err e.ResponseError
dependentCommitSet, err = resolver.doGetDependencies(ctx, dependentCommitSet, moduleReferences, true)
if err != nil {
return nil, err
}
commits := make([]*model.Commit, 0, len(dependentCommitSet))
for _, commit := range dependentCommitSet {
commits = append(commits, commit)
}
return commits, nil
}
func (resolver *ResolverImpl) GetDirectDependenciesFromModuleRefs(ctx context.Context, moduleReferences []bufmoduleref.ModuleReference) (model.Commits, e.ResponseError) {
var dependentCommitSet map[string]*model.Commit
var err e.ResponseError
dependentCommitSet, err = resolver.doGetDependencies(ctx, dependentCommitSet, moduleReferences, false)
if err != nil {
return nil, err
}
commits := make([]*model.Commit, 0, len(dependentCommitSet))
for _, commit := range dependentCommitSet {
commits = append(commits, commit)
}
return commits, nil
}
func (resolver *ResolverImpl) GetBufConfigFromCommitID(ctx context.Context, commitID string) (*bufconfig.Config, e.ResponseError) {
// 查询manifest名称
manifestModel, err := resolver.fileMapper.FindCommitManifestByCommitID(commitID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, e.NewNotFoundError(fmt.Errorf("manifest(commit id = %s)", commitID))
}
return nil, e.NewInternalError(errors.New("GetDependenciesByCommitID"))
}
// 读取manifest
reader, err := resolver.storageHelper.ReadManifestToReader(ctx, manifestModel.Digest)
if err != nil {
return nil, nil
}
fileManifest, err := manifest2.NewFromReader(reader)
if err != nil {
return nil, e.NewInternalError(errors.New("GetDependenciesByCommitID"))
}
// 根据文件manifest查找配置文件
var configFileExist bool
var configFileData []byte
err = fileManifest.Range(func(path string, digest manifest2.Digest) error {
// 如果遇到配置文件,就记录下来
for _, configFilePath := range bufconfig.AllConfigFilePaths {
if path == configFilePath {
if configFileExist {
return errors.New("two config files")
}
reader, err := resolver.storageHelper.ReadBlobToReader(ctx, digest.Hex())
if err != nil {
return err
}
configFileData, err = io.ReadAll(reader)
if err != nil {
return err
}
configFileExist = true
}
}
return nil
})
if err != nil {
return nil, e.NewInvalidArgumentError(err)
}
if !configFileExist {
// 不存在配置文件
return nil, e.NewInvalidArgumentError(errors.New("no config file"))
}
bufConfig, err := bufconfig.GetConfigForData(ctx, configFileData)
if err != nil {
return nil, e.NewInternalError(errors.New("GetDependenciesByCommitID"))
}
return bufConfig, nil
}
func (resolver *ResolverImpl) doGetDependencies(ctx context.Context, dependentCommitSet map[string]*model.Commit, dependencyReferences []bufmoduleref.ModuleReference, getAll bool) (map[string]*model.Commit, e.ResponseError) {
if dependentCommitSet == nil {
dependentCommitSet = map[string]*model.Commit{}
}
for i := 0; i < len(dependencyReferences); i++ {
dependencyReference := dependencyReferences[i]
if dependencyReference.Remote() == config.Properties.Server.ServerHost {
// 查询repo
repo, err := resolver.repositoryMapper.FindByUserNameAndRepositoryName(dependencyReference.Owner(), dependencyReference.Repository())
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, e.NewNotFoundError(errors.New(dependencyReference.IdentityString()))
}
return nil, e.NewInternalError(fmt.Errorf("find repository(%s)", err.Error()))
}
// 查询当前reference,版本号是否一样
commit, err := resolver.commitMapper.FindByRepositoryIDAndReference(repo.RepositoryID, dependencyReference.Reference())
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, e.NewNotFoundError(fmt.Errorf("%s:%s", dependencyReference.IdentityString(), dependencyReference.Reference()))
}
return nil, e.NewInternalError(fmt.Errorf("find reference(%s)", err.Error()))
}
dependentCommit, ok := dependentCommitSet[dependencyReference.IdentityString()]
if ok && dependentCommit.CommitName == dependencyReference.Reference() {
continue
}
if ok {
// 之前已经记录过 owner/repository 的commit
if commit.CommitName != dependentCommit.CommitName {
// 同一个仓库下的依赖版本号不同,返回错误
return nil, e.NewInternalError(fmt.Errorf("two different version %s and %s for %s", dependentCommit.CommitName, dependencyReference.Reference(), dependencyReference.IdentityString()))
}
// 当前依赖已经记录,跳过
continue
} else {
// 如果之前没有记录过,记录依赖commit
dependentCommitSet[dependencyReference.IdentityString()] = commit
if getAll {
// 需要获取全部依赖,记录这个依赖下的依赖关系
dependentBufConfig, configErr := resolver.GetBufConfigFromCommitID(ctx, commit.CommitID)
if configErr != nil {
return nil, configErr
}
var dependentErr e.ResponseError
dependentCommitSet, dependentErr = resolver.doGetDependencies(ctx, dependentCommitSet, dependentBufConfig.Build.DependencyModuleReferences, true)
if dependentErr != nil {
return nil, dependentErr
}
}
}
}
}
// 通过
return dependentCommitSet, nil
}