mirror of https://github.com/kubevela/kubevela.git
747 lines
19 KiB
Go
747 lines
19 KiB
Go
/*
|
|
Copyright 2021 The KubeVela 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 cli
|
|
|
|
import (
|
|
"context"
|
|
"encoding/base64"
|
|
"encoding/xml"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/google/go-github/v32/github"
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/cobra"
|
|
"golang.org/x/oauth2"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"sigs.k8s.io/yaml"
|
|
|
|
"github.com/oam-dev/kubevela/apis/types"
|
|
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
|
"github.com/oam-dev/kubevela/pkg/utils/common"
|
|
"github.com/oam-dev/kubevela/pkg/utils/system"
|
|
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
|
"github.com/oam-dev/kubevela/references/apis"
|
|
"github.com/oam-dev/kubevela/references/docgen"
|
|
)
|
|
|
|
// NewRegistryCommand Manage Capability Center
|
|
func NewRegistryCommand(ioStream cmdutil.IOStreams, order string) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "registry",
|
|
Short: "Manage Registry",
|
|
Long: "Manage Registry of X-Definitions for extension.",
|
|
Annotations: map[string]string{
|
|
types.TagCommandOrder: order,
|
|
types.TagCommandType: types.TypeExtension,
|
|
},
|
|
}
|
|
cmd.AddCommand(
|
|
NewRegistryConfigCommand(ioStream),
|
|
NewRegistryListCommand(ioStream),
|
|
NewRegistryRemoveCommand(ioStream),
|
|
)
|
|
return cmd
|
|
}
|
|
|
|
// NewRegistryListCommand List all registry
|
|
func NewRegistryListCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "ls",
|
|
Aliases: []string{"list"},
|
|
Short: "List all registry",
|
|
Long: "List all configured registry",
|
|
Example: `vela registry ls`,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return listCapRegistrys(ioStreams)
|
|
},
|
|
}
|
|
return cmd
|
|
}
|
|
|
|
// NewRegistryConfigCommand Configure (add if not exist) a registry, default is local (built-in capabilities)
|
|
func NewRegistryConfigCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Use: "config <registryName> <centerURL>",
|
|
Short: "Configure (add if not exist) a registry, default is local (built-in capabilities)",
|
|
Long: "Configure (add if not exist) a registry, default is local (built-in capabilities)",
|
|
Example: `vela registry config my-registry https://github.com/oam-dev/catalog/tree/master/registry`,
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
argsLength := len(args)
|
|
if argsLength < 2 {
|
|
return errors.New("please set registry with <centerName> and <centerURL>")
|
|
}
|
|
capName := args[0]
|
|
capURL := args[1]
|
|
token := cmd.Flag("token").Value.String()
|
|
if err := addRegistry(capName, capURL, token); err != nil {
|
|
return err
|
|
}
|
|
ioStreams.Infof("Successfully configured registry %s\n", capName)
|
|
return nil
|
|
},
|
|
}
|
|
cmd.PersistentFlags().StringP("token", "t", "", "Github Repo token")
|
|
return cmd
|
|
}
|
|
|
|
// NewRegistryRemoveCommand Remove specified registry
|
|
func NewRegistryRemoveCommand(ioStreams cmdutil.IOStreams) *cobra.Command {
|
|
cmd := &cobra.Command{
|
|
Aliases: []string{"rm"},
|
|
Use: "remove <centerName>",
|
|
Short: "Remove specified registry",
|
|
Long: "Remove specified registry",
|
|
Example: "vela registry remove mycenter",
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
if len(args) < 1 {
|
|
return errors.New("you must specify <name> for capability center you want to remove")
|
|
}
|
|
centerName := args[0]
|
|
msg, err := removeRegistry(centerName)
|
|
if err == nil {
|
|
ioStreams.Info(msg)
|
|
}
|
|
return err
|
|
},
|
|
}
|
|
return cmd
|
|
}
|
|
|
|
func listCapRegistrys(ioStreams cmdutil.IOStreams) error {
|
|
table := newUITable()
|
|
table.MaxColWidth = 80
|
|
table.AddRow("NAME", "URL")
|
|
|
|
registrys, err := ListRegistryConfig()
|
|
if err != nil {
|
|
return errors.Wrap(err, "list registry error")
|
|
}
|
|
for _, c := range registrys {
|
|
tokenShow := ""
|
|
if len(c.Token) > 0 {
|
|
tokenShow = "***"
|
|
}
|
|
table.AddRow(c.Name, c.URL, tokenShow)
|
|
}
|
|
ioStreams.Info(table.String())
|
|
return nil
|
|
}
|
|
|
|
// addRegistry will add a registry
|
|
func addRegistry(regName, regURL, regToken string) error {
|
|
regConfig := apis.RegistryConfig{
|
|
Name: regName, URL: regURL, Token: regToken,
|
|
}
|
|
repos, err := ListRegistryConfig()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var updated bool
|
|
for idx, r := range repos {
|
|
if r.Name == regConfig.Name {
|
|
repos[idx] = regConfig
|
|
updated = true
|
|
break
|
|
}
|
|
}
|
|
if !updated {
|
|
repos = append(repos, regConfig)
|
|
}
|
|
if err = StoreRepos(repos); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// removeRegistry will remove a registry from local
|
|
func removeRegistry(regName string) (string, error) {
|
|
var message string
|
|
var err error
|
|
|
|
regConfigs, err := ListRegistryConfig()
|
|
if err != nil {
|
|
return message, err
|
|
}
|
|
found := false
|
|
for idx, r := range regConfigs {
|
|
if r.Name == regName {
|
|
regConfigs = append(regConfigs[:idx], regConfigs[idx+1:]...)
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return fmt.Sprintf("registry %s not found", regName), nil
|
|
}
|
|
if err = StoreRepos(regConfigs); err != nil {
|
|
return message, err
|
|
}
|
|
message = fmt.Sprintf("Successfully remove registry %s", regName)
|
|
return message, err
|
|
}
|
|
|
|
// DefaultRegistry is default registry
|
|
const DefaultRegistry = "default"
|
|
|
|
// Registry define a registry used to get and list types.Capability
|
|
type Registry interface {
|
|
GetName() string
|
|
GetURL() string
|
|
GetCap(addonName string) (types.Capability, []byte, error)
|
|
ListCaps() ([]types.Capability, error)
|
|
}
|
|
|
|
// GithubRegistry is Registry's implementation treat github url as resource
|
|
type GithubRegistry struct {
|
|
URL string `json:"url"`
|
|
RegistryName string `json:"registry_name"`
|
|
client *github.Client
|
|
cfg *GithubContent
|
|
ctx context.Context
|
|
}
|
|
|
|
// NewRegistryFromConfig return Registry interface to get capabilities
|
|
func NewRegistryFromConfig(config apis.RegistryConfig) (Registry, error) {
|
|
return NewRegistry(context.TODO(), config.Token, config.Name, config.URL)
|
|
}
|
|
|
|
// NewRegistry will create a registry implementation
|
|
func NewRegistry(ctx context.Context, token, registryName string, regURL string) (Registry, error) {
|
|
tp, cfg, err := Parse(regURL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
switch tp {
|
|
case TypeGithub:
|
|
var tc *http.Client
|
|
if token != "" {
|
|
ts := oauth2.StaticTokenSource(
|
|
&oauth2.Token{AccessToken: token},
|
|
)
|
|
tc = oauth2.NewClient(ctx, ts)
|
|
}
|
|
return GithubRegistry{
|
|
URL: cfg.URL,
|
|
RegistryName: registryName,
|
|
client: github.NewClient(tc),
|
|
cfg: &cfg.GithubContent,
|
|
ctx: ctx,
|
|
}, nil
|
|
case TypeOss:
|
|
var tc http.Client
|
|
return OssRegistry{
|
|
Client: &tc,
|
|
BucketURL: fmt.Sprintf("https://%s/", cfg.BucketURL),
|
|
RegistryName: registryName,
|
|
}, nil
|
|
case TypeLocal:
|
|
_, err := os.Stat(cfg.AbsDir)
|
|
if os.IsNotExist(err) {
|
|
return LocalRegistry{}, err
|
|
}
|
|
return LocalRegistry{
|
|
AbsPath: cfg.AbsDir,
|
|
RegistryName: registryName,
|
|
}, nil
|
|
case TypeUnknown:
|
|
return nil, fmt.Errorf("not supported url")
|
|
}
|
|
|
|
return nil, fmt.Errorf("not supported url")
|
|
}
|
|
|
|
// ListRegistryConfig will get all registry config stored in local
|
|
// this will return at least one config, which is DefaultRegistry
|
|
func ListRegistryConfig() ([]apis.RegistryConfig, error) {
|
|
|
|
defaultRegistryConfig := apis.RegistryConfig{Name: DefaultRegistry, URL: "oss://registry.kubevela.net/"}
|
|
config, err := system.GetRepoConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
data, err := os.ReadFile(filepath.Clean(config))
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
err := StoreRepos([]apis.RegistryConfig{defaultRegistryConfig})
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "error initialize default registry")
|
|
}
|
|
return ListRegistryConfig()
|
|
}
|
|
return nil, err
|
|
}
|
|
var regConfigs []apis.RegistryConfig
|
|
if err = yaml.Unmarshal(data, ®Configs); err != nil {
|
|
return nil, err
|
|
}
|
|
haveDefault := false
|
|
for _, r := range regConfigs {
|
|
if r.URL == defaultRegistryConfig.URL {
|
|
haveDefault = true
|
|
break
|
|
}
|
|
}
|
|
if !haveDefault {
|
|
regConfigs = append(regConfigs, defaultRegistryConfig)
|
|
}
|
|
return regConfigs, nil
|
|
}
|
|
|
|
// GetRegistry get a Registry implementation by name
|
|
func GetRegistry(regName string) (Registry, error) {
|
|
regConfigs, err := ListRegistryConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, conf := range regConfigs {
|
|
if conf.Name == regName {
|
|
return NewRegistryFromConfig(conf)
|
|
}
|
|
}
|
|
return nil, errors.Errorf("registry %s not found", regName)
|
|
}
|
|
|
|
// GetName will return registry name
|
|
func (g GithubRegistry) GetName() string {
|
|
return g.RegistryName
|
|
}
|
|
|
|
// GetURL will return github registry url
|
|
func (g GithubRegistry) GetURL() string {
|
|
return g.cfg.URL
|
|
}
|
|
|
|
// ListCaps list all capabilities of registry
|
|
func (g GithubRegistry) ListCaps() ([]types.Capability, error) {
|
|
var addons []types.Capability
|
|
|
|
itemContents, err := g.getRepoFile()
|
|
if err != nil {
|
|
return []types.Capability{}, err
|
|
}
|
|
for _, item := range itemContents {
|
|
capa, err := item.toCapability()
|
|
if err != nil {
|
|
fmt.Printf("parse definition of %s err %v\n", item.name, err)
|
|
continue
|
|
}
|
|
addons = append(addons, capa)
|
|
}
|
|
return addons, nil
|
|
}
|
|
|
|
// GetCap return capability object and raw data specified by cap name
|
|
func (g GithubRegistry) GetCap(addonName string) (types.Capability, []byte, error) {
|
|
fileContent, _, _, err := g.client.Repositories.GetContents(context.Background(), g.cfg.Owner, g.cfg.Repo, fmt.Sprintf("%s/%s.yaml", g.cfg.Path, addonName), &github.RepositoryContentGetOptions{Ref: g.cfg.Ref})
|
|
if err != nil {
|
|
return types.Capability{}, []byte{}, err
|
|
}
|
|
var data []byte
|
|
if *fileContent.Encoding == "base64" {
|
|
data, err = base64.StdEncoding.DecodeString(*fileContent.Content)
|
|
if err != nil {
|
|
fmt.Printf("decode github content %s err %s\n", fileContent.GetPath(), err)
|
|
}
|
|
}
|
|
repoFile := RegistryFile{
|
|
data: data,
|
|
name: *fileContent.Name,
|
|
}
|
|
capa, err := repoFile.toCapability()
|
|
if err != nil {
|
|
return types.Capability{}, []byte{}, err
|
|
}
|
|
capa.Source = &types.Source{RepoName: g.RegistryName}
|
|
return capa, data, nil
|
|
}
|
|
|
|
func (g *GithubRegistry) getRepoFile() ([]RegistryFile, error) {
|
|
var items []RegistryFile
|
|
_, dirs, _, err := g.client.Repositories.GetContents(g.ctx, g.cfg.Owner, g.cfg.Repo, g.cfg.Path, &github.RepositoryContentGetOptions{Ref: g.cfg.Ref})
|
|
if err != nil {
|
|
return []RegistryFile{}, err
|
|
}
|
|
for _, repoItem := range dirs {
|
|
if *repoItem.Type != "file" {
|
|
continue
|
|
}
|
|
fileContent, _, _, err := g.client.Repositories.GetContents(g.ctx, g.cfg.Owner, g.cfg.Repo, *repoItem.Path, &github.RepositoryContentGetOptions{Ref: g.cfg.Ref})
|
|
if err != nil {
|
|
fmt.Printf("Getting content URL %s error: %s\n", repoItem.GetURL(), err)
|
|
continue
|
|
}
|
|
var data []byte
|
|
if *fileContent.Encoding == "base64" {
|
|
data, err = base64.StdEncoding.DecodeString(*fileContent.Content)
|
|
if err != nil {
|
|
fmt.Printf("decode github content %s err %s\n", fileContent.GetPath(), err)
|
|
continue
|
|
}
|
|
}
|
|
items = append(items, RegistryFile{
|
|
data: data,
|
|
name: *fileContent.Name,
|
|
})
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
// OssRegistry is Registry's implementation treat OSS url as resource
|
|
type OssRegistry struct {
|
|
*http.Client `json:"-"`
|
|
BucketURL string `json:"bucket_url"`
|
|
RegistryName string `json:"registry_name"`
|
|
}
|
|
|
|
// GetName return name of OssRegistry
|
|
func (o OssRegistry) GetName() string {
|
|
return o.RegistryName
|
|
}
|
|
|
|
// GetURL return URL of OssRegistry's bucket
|
|
func (o OssRegistry) GetURL() string {
|
|
return o.BucketURL
|
|
}
|
|
|
|
// GetCap return capability object and raw data specified by cap name
|
|
func (o OssRegistry) GetCap(addonName string) (types.Capability, []byte, error) {
|
|
filename := addonName + ".yaml"
|
|
req, _ := http.NewRequestWithContext(
|
|
context.Background(),
|
|
http.MethodGet,
|
|
o.BucketURL+filename,
|
|
nil,
|
|
)
|
|
resp, err := o.Client.Do(req)
|
|
if err != nil {
|
|
return types.Capability{}, nil, err
|
|
}
|
|
data, err := io.ReadAll(resp.Body)
|
|
_ = resp.Body.Close()
|
|
if err != nil {
|
|
return types.Capability{}, nil, err
|
|
}
|
|
rf := RegistryFile{
|
|
data: data,
|
|
name: filename,
|
|
}
|
|
capa, err := rf.toCapability()
|
|
if err != nil {
|
|
return types.Capability{}, nil, err
|
|
}
|
|
capa.Source = &types.Source{RepoName: o.RegistryName}
|
|
|
|
return capa, data, nil
|
|
}
|
|
|
|
// ListCaps list all capabilities of registry
|
|
func (o OssRegistry) ListCaps() ([]types.Capability, error) {
|
|
rfs, err := o.getRegFiles()
|
|
if err != nil {
|
|
return []types.Capability{}, errors.Wrap(err, "Get raw files fail")
|
|
}
|
|
capas := make([]types.Capability, 0)
|
|
|
|
for _, rf := range rfs {
|
|
capa, err := rf.toCapability()
|
|
if err != nil {
|
|
fmt.Printf("[WARN] Parse file %s fail: %s\n", rf.name, err.Error())
|
|
}
|
|
capas = append(capas, capa)
|
|
}
|
|
return capas, nil
|
|
}
|
|
|
|
func (o OssRegistry) getRegFiles() ([]RegistryFile, error) {
|
|
req, _ := http.NewRequestWithContext(
|
|
context.Background(),
|
|
http.MethodGet,
|
|
o.BucketURL+"?list-type=2",
|
|
nil,
|
|
)
|
|
resp, err := o.Client.Do(req)
|
|
if err != nil {
|
|
return []RegistryFile{}, err
|
|
}
|
|
data, err := io.ReadAll(resp.Body)
|
|
_ = resp.Body.Close()
|
|
if err != nil {
|
|
return []RegistryFile{}, err
|
|
}
|
|
list := &ListBucketResult{}
|
|
err = xml.Unmarshal(data, list)
|
|
if err != nil {
|
|
return []RegistryFile{}, err
|
|
}
|
|
rfs := make([]RegistryFile, 0)
|
|
|
|
for _, fileName := range list.File {
|
|
req, _ := http.NewRequestWithContext(
|
|
context.Background(),
|
|
http.MethodGet,
|
|
o.BucketURL+fileName,
|
|
nil,
|
|
)
|
|
resp, err := o.Client.Do(req)
|
|
if err != nil {
|
|
fmt.Printf("[WARN] %s download fail\n", fileName)
|
|
continue
|
|
}
|
|
data, _ := io.ReadAll(resp.Body)
|
|
_ = resp.Body.Close()
|
|
rf := RegistryFile{
|
|
data: data,
|
|
name: fileName,
|
|
}
|
|
rfs = append(rfs, rf)
|
|
|
|
}
|
|
return rfs, nil
|
|
}
|
|
|
|
// LocalRegistry is Registry's implementation treat local url as resource
|
|
type LocalRegistry struct {
|
|
AbsPath string `json:"abs_path"`
|
|
RegistryName string `json:"registry_name"`
|
|
}
|
|
|
|
// GetName return name of LocalRegistry
|
|
func (l LocalRegistry) GetName() string {
|
|
return l.RegistryName
|
|
}
|
|
|
|
// GetURL return path of LocalRegistry
|
|
func (l LocalRegistry) GetURL() string {
|
|
return l.AbsPath
|
|
}
|
|
|
|
// GetCap return capability object and raw data specified by cap name
|
|
func (l LocalRegistry) GetCap(addonName string) (types.Capability, []byte, error) {
|
|
fileName := addonName + ".yaml"
|
|
filePath := fmt.Sprintf("%s/%s", l.AbsPath, fileName)
|
|
data, err := os.ReadFile(filePath) // nolint
|
|
if err != nil {
|
|
return types.Capability{}, []byte{}, err
|
|
}
|
|
file := RegistryFile{
|
|
data: data,
|
|
name: fileName,
|
|
}
|
|
capa, err := file.toCapability()
|
|
if err != nil {
|
|
return types.Capability{}, []byte{}, err
|
|
}
|
|
capa.Source = &types.Source{RepoName: l.RegistryName}
|
|
|
|
return capa, data, nil
|
|
}
|
|
|
|
// ListCaps list all capabilities of registry
|
|
func (l LocalRegistry) ListCaps() ([]types.Capability, error) {
|
|
glob := filepath.Join(filepath.Clean(l.AbsPath), "*")
|
|
files, _ := filepath.Glob(glob)
|
|
capas := make([]types.Capability, 0)
|
|
for _, file := range files {
|
|
// nolint:gosec
|
|
data, err := os.ReadFile(file)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
capa, err := RegistryFile{
|
|
data: data,
|
|
name: path.Base(file),
|
|
}.toCapability()
|
|
if err != nil {
|
|
fmt.Printf("parsing file: %s err: %s\n", file, err)
|
|
continue
|
|
}
|
|
capas = append(capas, capa)
|
|
}
|
|
return capas, nil
|
|
}
|
|
|
|
func (item RegistryFile) toCapability() (types.Capability, error) {
|
|
dm, err := (&common.Args{}).GetDiscoveryMapper()
|
|
if err != nil {
|
|
return types.Capability{}, err
|
|
}
|
|
capability, err := ParseCapability(dm, item.data)
|
|
if err != nil {
|
|
return types.Capability{}, err
|
|
}
|
|
return capability, nil
|
|
}
|
|
|
|
// RegistryFile describes a file item in registry
|
|
type RegistryFile struct {
|
|
data []byte // file content
|
|
name string // file's name
|
|
}
|
|
|
|
// ListBucketResult describe a file list from OSS
|
|
type ListBucketResult struct {
|
|
File []string `xml:"Contents>Key"`
|
|
Count int `xml:"KeyCount"`
|
|
}
|
|
|
|
// Content contains different type of content needed when building Registry
|
|
type Content struct {
|
|
OssContent
|
|
GithubContent
|
|
LocalContent
|
|
}
|
|
|
|
// LocalContent for local registry
|
|
type LocalContent struct {
|
|
AbsDir string `json:"abs_dir"`
|
|
}
|
|
|
|
// OssContent for oss registry
|
|
type OssContent struct {
|
|
BucketURL string `json:"bucket_url"`
|
|
}
|
|
|
|
// GithubContent for registry
|
|
type GithubContent struct {
|
|
URL string `json:"url"`
|
|
Owner string `json:"owner"`
|
|
Repo string `json:"repo"`
|
|
Path string `json:"path"`
|
|
Ref string `json:"ref"`
|
|
}
|
|
|
|
// TypeLocal represents github
|
|
const TypeLocal = "local"
|
|
|
|
// TypeOss represent oss
|
|
const TypeOss = "oss"
|
|
|
|
// TypeGithub represents github
|
|
const TypeGithub = "github"
|
|
|
|
// TypeUnknown represents parse failed
|
|
const TypeUnknown = "unknown"
|
|
|
|
// Parse will parse config from address
|
|
func Parse(addr string) (string, *Content, error) {
|
|
URL, err := url.Parse(addr)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
l := strings.Split(strings.TrimPrefix(URL.Path, "/"), "/")
|
|
switch URL.Scheme {
|
|
case "http", "https":
|
|
switch URL.Host {
|
|
case "github.com":
|
|
// We support two valid format:
|
|
// 1. https://github.com/<owner>/<repo>/tree/<branch>/<path-to-dir>
|
|
// 2. https://github.com/<owner>/<repo>/<path-to-dir>
|
|
if len(l) < 3 {
|
|
return "", nil, errors.New("invalid format " + addr)
|
|
}
|
|
if l[2] == "tree" {
|
|
// https://github.com/<owner>/<repo>/tree/<branch>/<path-to-dir>
|
|
if len(l) < 5 {
|
|
return "", nil, errors.New("invalid format " + addr)
|
|
}
|
|
return TypeGithub, &Content{
|
|
GithubContent: GithubContent{
|
|
URL: addr,
|
|
Owner: l[0],
|
|
Repo: l[1],
|
|
Path: strings.Join(l[4:], "/"),
|
|
Ref: l[3],
|
|
},
|
|
}, nil
|
|
}
|
|
// https://github.com/<owner>/<repo>/<path-to-dir>
|
|
return TypeGithub, &Content{
|
|
GithubContent: GithubContent{
|
|
URL: addr,
|
|
Owner: l[0],
|
|
Repo: l[1],
|
|
Path: strings.Join(l[2:], "/"),
|
|
Ref: "", // use default branch
|
|
},
|
|
},
|
|
nil
|
|
case "api.github.com":
|
|
if len(l) != 5 {
|
|
return "", nil, errors.New("invalid format " + addr)
|
|
}
|
|
//https://api.github.com/repos/<owner>/<repo>/contents/<path-to-dir>
|
|
return TypeGithub, &Content{
|
|
GithubContent: GithubContent{
|
|
URL: addr,
|
|
Owner: l[1],
|
|
Repo: l[2],
|
|
Path: l[4],
|
|
Ref: URL.Query().Get("ref"),
|
|
},
|
|
},
|
|
nil
|
|
default:
|
|
}
|
|
case "oss":
|
|
return TypeOss, &Content{
|
|
OssContent: OssContent{
|
|
BucketURL: URL.Host,
|
|
},
|
|
}, nil
|
|
case "file":
|
|
return TypeLocal, &Content{
|
|
LocalContent: LocalContent{
|
|
AbsDir: URL.Path,
|
|
},
|
|
}, nil
|
|
|
|
}
|
|
|
|
return TypeUnknown, nil, nil
|
|
}
|
|
|
|
// StoreRepos will store registry repo locally
|
|
func StoreRepos(registries []apis.RegistryConfig) error {
|
|
config, err := system.GetRepoConfig()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
data, err := yaml.Marshal(registries)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//nolint:gosec
|
|
return os.WriteFile(config, data, 0644)
|
|
}
|
|
|
|
// ParseCapability will convert config from remote center to capability
|
|
func ParseCapability(mapper discoverymapper.DiscoveryMapper, data []byte) (types.Capability, error) {
|
|
var obj = unstructured.Unstructured{Object: make(map[string]interface{})}
|
|
err := yaml.Unmarshal(data, &obj.Object)
|
|
if err != nil {
|
|
return types.Capability{}, err
|
|
}
|
|
return docgen.ParseCapabilityFromUnstructured(mapper, nil, obj)
|
|
}
|