Commit 17f22d77 authored by jackgr's avatar jackgr

Merge changes from #172.

parent 3cca3065
......@@ -190,7 +190,7 @@ type Registry struct {
type RegistryType string
const (
Github RegistryType = "github"
GithubRegistryType RegistryType = "github"
)
// RegistryFormat defines the format of the registry
......
......@@ -82,7 +82,7 @@ var usage = func() {
}
func getGitRegistry() (registry.Registry, error) {
return registry.NewDefaultRegistryProvider().GetRegistry(*template_registry)
return registry.NewDefaultRegistryProvider().GetRegistryByURL(*template_registry)
}
func main() {
......
......@@ -50,6 +50,9 @@ var deployments = []Route{
{"ListTypes", "/types", "GET", listTypesHandlerFunc, ""},
{"ListTypeInstances", "/types/{type}/instances", "GET", listTypeInstancesHandlerFunc, ""},
{"ListRegistries", "/registries", "GET", listRegistriesHandlerFunc, ""},
{"GetRegistry", "/registries/{registry}", "GET", getRegistryHandlerFunc, ""},
{"ListCharts", "/registries/{registry}/charts", "GET", listChartsHandlerFunc, ""},
{"GetChart", "/registries/{registry}/charts/{chart}", "GET", getChartHandlerFunc, ""},
}
var (
......@@ -72,11 +75,13 @@ func init() {
}
func newManager() manager.Manager {
expander := manager.NewExpander(getServiceURL(*expanderURL, *expanderName), manager.NewTypeResolver(registry.NewDefaultRegistryProvider()))
provider := registry.NewDefaultRegistryProvider()
resolver := manager.NewTypeResolver(provider)
expander := manager.NewExpander(getServiceURL(*expanderURL, *expanderName), resolver)
deployer := manager.NewDeployer(getServiceURL(*deployerURL, *deployerName))
r := repository.NewMapBasedRepository()
registryService := registry.NewInmemRepositoryService()
return manager.NewManager(expander, deployer, r, registryService)
service := registry.NewInmemRegistryService()
return manager.NewManager(expander, deployer, r, provider, service)
}
func getServiceURL(serviceURL, serviceName string) string {
......@@ -342,5 +347,62 @@ func listRegistriesHandlerFunc(w http.ResponseWriter, r *http.Request) {
if err != nil {
return
}
util.LogHandlerExitWithJSON(handler, w, registries, http.StatusOK)
}
func getRegistryHandlerFunc(w http.ResponseWriter, r *http.Request) {
handler := "manager: get registry"
util.LogHandlerEntry(handler, r)
registryName, err := getPathVariable(w, r, "registry", handler)
if err != nil {
return
}
cr, err := backend.GetRegistry(registryName)
if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w)
return
}
util.LogHandlerExitWithJSON(handler, w, cr, http.StatusOK)
}
func listChartsHandlerFunc(w http.ResponseWriter, r *http.Request) {
handler := "manager: list charts"
util.LogHandlerEntry(handler, r)
registryName, err := getPathVariable(w, r, "registry", handler)
if err != nil {
return
}
chartNames, err := backend.ListCharts(registryName)
if err != nil {
util.LogAndReturnError(handler, http.StatusInternalServerError, err, w)
return
}
util.LogHandlerExitWithJSON(handler, w, chartNames, http.StatusOK)
}
func getChartHandlerFunc(w http.ResponseWriter, r *http.Request) {
handler := "manager: get chart"
util.LogHandlerEntry(handler, r)
registryName, err := getPathVariable(w, r, "registry", handler)
if err != nil {
return
}
chartName, err := getPathVariable(w, r, "chart", handler)
if err != nil {
return
}
c, err := backend.GetChart(registryName, chartName)
if err != nil {
util.LogAndReturnError(handler, http.StatusBadRequest, err, w)
return
}
util.LogHandlerExitWithJSON(handler, w, c, http.StatusOK)
}
......@@ -28,33 +28,48 @@ import (
// Manager manages a persistent set of Deployments.
type Manager interface {
// Deployments
ListDeployments() ([]common.Deployment, error)
GetDeployment(name string) (*common.Deployment, error)
CreateDeployment(t *common.Template) (*common.Deployment, error)
DeleteDeployment(name string, forget bool) (*common.Deployment, error)
PutDeployment(name string, t *common.Template) (*common.Deployment, error)
// Manifests
ListManifests(deploymentName string) (map[string]*common.Manifest, error)
GetManifest(deploymentName string, manifest string) (*common.Manifest, error)
Expand(t *common.Template) (*common.Manifest, error)
// Types
ListTypes() []string
ListInstances(typeName string) []*common.TypeInstance
// Registry related functions
// Registries
ListRegistries() ([]*common.Registry, error)
CreateRegistry(pr *common.Registry) error
GetRegistry(name string) (*common.Registry, error)
DeleteRegistry(name string) error
// Charts
ListCharts(registryName string) ([]string, error)
GetChart(registryName, chartName string) (*registry.Chart, error)
}
type manager struct {
expander Expander
deployer Deployer
repository repository.Repository
registryService registry.RegistryService
expander Expander
deployer Deployer
repository repository.Repository
provider registry.RegistryProvider
service registry.RegistryService
}
// NewManager returns a new initialized Manager.
func NewManager(expander Expander, deployer Deployer, repository repository.Repository, registryService registry.RegistryService) Manager {
return &manager{expander, deployer, repository, registryService}
func NewManager(expander Expander,
deployer Deployer,
repository repository.Repository,
provider registry.RegistryProvider,
service registry.RegistryService) Manager {
return &manager{expander, deployer, repository, provider, service}
}
// ListDeployments returns the list of deployments
......@@ -309,20 +324,21 @@ func (m *manager) ListInstances(typeName string) []*common.TypeInstance {
return m.repository.GetTypeInstances(typeName)
}
// ListRegistries returns the list of registries
func (m *manager) ListRegistries() ([]*common.Registry, error) {
return m.registryService.List()
return m.service.List()
}
func (m *manager) CreateRegistry(pr *common.Registry) error {
return m.registryService.Create(pr)
return m.service.Create(pr)
}
func (m *manager) GetRegistry(name string) (*common.Registry, error) {
return m.registryService.Get(name)
return m.service.Get(name)
}
func (m *manager) DeleteRegistry(name string) error {
return m.registryService.Delete(name)
return m.service.Delete(name)
}
func generateManifestName() string {
......@@ -346,3 +362,23 @@ func getResourceErrors(c *common.Configuration) []string {
return errs
}
// ListCharts retrieves the names of the charts in a given registry.
func (m *manager) ListCharts(registryName string) ([]string, error) {
r, err := m.provider.GetRegistryByName(registryName)
if err != nil {
return nil, err
}
return r.ListCharts()
}
// GetChart retrieves a given chart in a given registry.
func (m *manager) GetChart(registryName, chartName string) (*registry.Chart, error) {
r, err := m.provider.GetRegistryByName(registryName)
if err != nil {
return nil, err
}
return r.GetChart(chartName)
}
......@@ -66,7 +66,7 @@ var deploymentList = []common.Deployment{deployment, {Name: "test2"}}
var typeInstMap = map[string][]string{"test": []string{"test"}}
var errTest = errors.New("test")
var errTest = errors.New("test error")
type expanderStub struct{}
......@@ -164,6 +164,7 @@ func (repository *repositoryStub) ListDeployments() ([]common.Deployment, error)
if repository.FailListDeployments {
return deploymentList, errTest
}
return deploymentList, nil
}
......@@ -249,11 +250,102 @@ func (r *repositoryStub) SetTypeInstances(d string, is map[string][]*common.Type
}
}
type registryStub struct {
FailListCharts bool
FailGetChart bool
ListChartsCalled bool
GetChartCalled bool
}
func newRegistryStub() *registryStub {
ret := &registryStub{}
return ret
}
func (r *registryStub) reset() {
r.FailListCharts = false
r.FailGetChart = false
r.ListChartsCalled = false
r.GetChartCalled = false
}
var testRegistryName = "TestRegistry"
var testRegistryURL = "https://github.com/helm/charts"
var testChartName = "TestChart"
var testChart = registry.Chart{
Name: testChartName,
}
var testChartList = []string{testChartName, "TestChart2"}
func (r *registryStub) GetRegistryName() string {
return testRegistryName
}
func (r *registryStub) GetRegistryType() common.RegistryType {
return common.GithubRegistryType
}
func (r *registryStub) GetRegistryURL() string {
return testRegistryURL
}
func (r *registryStub) ListCharts() ([]string, error) {
if r.FailListCharts {
return nil, errTest
}
return testChartList, nil
}
func (r *registryStub) GetChart(chartName string) (*registry.Chart, error) {
if !r.FailGetChart {
if chartName == testChartName {
return &testChart, nil
}
}
return nil, errTest
}
// Deprecated: Use ListCharts, instead.
func (r *registryStub) List() ([]registry.Type, error) {
return []registry.Type{}, nil
}
// Deprecated: Use GetChart, instead.
func (r *registryStub) GetURLs(t registry.Type) ([]string, error) {
return []string{}, nil
}
type registryProviderStub struct {
FailGetGithubRegistry bool
FailGetGithubPackageRegistry bool
}
var testRegistryOwner = "TestOwner"
var testRegistryRepository = "TestRepository"
func newRegistryProviderStub() *registryProviderStub {
ret := &registryProviderStub{}
return ret
}
func (rp *registryProviderStub) GetRegistryByURL(URL string) (registry.Registry, error) {
return newRegistryStub(), nil
}
func (rp *registryProviderStub) GetRegistryByName(registryName string) (registry.Registry, error) {
return newRegistryStub(), nil
}
var testExpander = &expanderStub{}
var testRepository = newRepositoryStub()
var testDeployer = newDeployerStub()
var testRegistryService = registry.NewInmemRepositoryService()
var testManager = NewManager(testExpander, testDeployer, testRepository, testRegistryService)
var testRegistryService = registry.NewInmemRegistryService()
var testProvider = newRegistryProviderStub()
var testManager = NewManager(testExpander, testDeployer, testRepository, testProvider, testRegistryService)
func TestListDeployments(t *testing.T) {
testRepository.reset()
......
......@@ -244,7 +244,7 @@ func (tr *typeResolver) ShortTypeToDownloadURLs(template string) ([]string, erro
if len(m) != 6 {
return []string{}, fmt.Errorf("Failed to parse short github url: %s", template)
}
r, err := tr.rp.GetRegistry(template)
r, err := tr.rp.GetRegistryByURL(template)
if err != nil {
return []string{}, err
}
......@@ -262,7 +262,7 @@ func (tr *typeResolver) ShortTypeToPackageDownloadURLs(template string) ([]strin
if len(m) != 4 {
return []string{}, fmt.Errorf("Failed to parse short github url: %s", template)
}
r, err := tr.rp.GetRegistry(template)
r, err := tr.rp.GetRegistryByURL(template)
if err != nil {
return []string{}, err
}
......
......@@ -74,26 +74,58 @@ func newTestRegistryProvider(URLPrefix string, tests map[registry.Type]urlAndErr
return &testRegistryProvider{URLPrefix, r}
}
// Deprecated: Use GetRegistryByURL, instead.
func (trp *testRegistryProvider) GetRegistry(URL string) (registry.Registry, error) {
return trp.GetRegistryByURL(URL)
}
func (trp *testRegistryProvider) GetRegistryByURL(URL string) (registry.Registry, error) {
for key, r := range trp.r {
if strings.HasPrefix(URL, key) {
return r, nil
}
}
return nil, fmt.Errorf("No registry found for %s", URL)
}
func (trp *testRegistryProvider) GetRegistryByName(registryName string) (registry.Registry, error) {
return newRegistryStub(), nil
}
type testGithubRegistry struct {
responses map[registry.Type]urlAndError
count int
}
func (r *testGithubRegistry) GetRegistryName() string {
return ""
}
func (r *testGithubRegistry) GetRegistryType() common.RegistryType {
return common.GithubRegistryType
}
func (r *testGithubRegistry) GetRegistryURL() string {
return ""
}
func (r *testGithubRegistry) ListCharts() ([]string, error) {
return []string{}, fmt.Errorf("ListCharts should not be called in the test")
}
func (r *testGithubRegistry) GetChart(chartName string) (*registry.Chart, error) {
return nil, fmt.Errorf("GetChart should not be called in the test")
}
// Deprecated: Use GetChart, instead.
func (tgr *testGithubRegistry) GetURLs(t registry.Type) ([]string, error) {
tgr.count = tgr.count + 1
ret := tgr.responses[t]
return []string{ret.u}, ret.e
}
// Deprecated: Use ListCharts, instead.
func (tgr *testGithubRegistry) List() ([]registry.Type, error) {
return []registry.Type{}, fmt.Errorf("List should not be called in the test")
}
......
......@@ -17,10 +17,11 @@ limitations under the License.
package registry
import (
"github.com/google/go-github/github"
"github.com/kubernetes/deployment-manager/common"
"log"
"strings"
"github.com/google/go-github/github"
)
// GithubPackageRegistry implements the Registry interface that talks to github and
......@@ -47,6 +48,37 @@ func NewGithubPackageRegistry(owner, repository string, client *github.Client) *
}
}
// GetRegistryName returns the name of this registry
func (g *GithubPackageRegistry) GetRegistryName() string {
// TODO(jackgr): implement this method
return ""
}
// GetRegistryType returns the type of this registry.
func (g *GithubPackageRegistry) GetRegistryType() common.RegistryType {
// TODO(jackgr): implement this method
return common.GithubRegistryType
}
// GetRegistryURL returns the URL for this registry.
func (g *GithubPackageRegistry) GetRegistryURL() string {
// TODO(jackgr): implement this method
return ""
}
// ListCharts lists the versioned chart names in this registry.
func (g *GithubPackageRegistry) ListCharts() ([]string, error) {
// TODO(jackgr): implement this method
return []string{}, nil
}
// GetChart fetches the contents of a given chart.
func (g *GithubPackageRegistry) GetChart(chartName string) (*Chart, error) {
// TODO(jackgr): implement this method
return nil, nil
}
// Deprecated: Use ListCharts, instead.
// List the types from the Registry.
func (g *GithubPackageRegistry) List() ([]Type, error) {
// Just list all the types at the top level.
......@@ -74,6 +106,7 @@ func (g *GithubPackageRegistry) List() ([]Type, error) {
return retTypes, nil
}
// Deprecated: Use GetChart, instead.
// GetURLs fetches the download URLs for a given Type.
func (g *GithubPackageRegistry) GetURLs(t Type) ([]string, error) {
path, err := g.MakeRepositoryPath(t)
......
......@@ -18,6 +18,7 @@ package registry
import (
"github.com/google/go-github/github"
"github.com/kubernetes/deployment-manager/common"
"fmt"
"log"
......@@ -64,6 +65,58 @@ func NewGithubRegistry(owner, repository, path string, client *github.Client) *G
}
}
// GetRegistryName returns the name of this registry
func (g *GithubRegistry) GetRegistryName() string {
// TODO(jackgr): implement this method
return ""
}
// GetRegistryType returns the type of this registry.
func (g *GithubRegistry) GetRegistryType() common.RegistryType {
// TODO(jackgr): implement this method
return common.GithubRegistryType
}
// GetRegistryURL returns the URL for this registry.
func (g *GithubRegistry) GetRegistryURL() string {
// TODO(jackgr): implement this method
return ""
}
// ListCharts lists the versioned chart names in this registry.
func (g *GithubRegistry) ListCharts() ([]string, error) {
var result []string
names, err := g.getDirs("")
if err != nil {
log.Printf("Failed to fetch chart names from registry: %s/%s/%s", g.owner, g.repository, g.path)
return nil, err
}
// Fetch the chart names
for _, name := range names {
// Then fetch the versions for each chart name
versions, err := g.getDirs("/" + name)
if err != nil {
log.Printf("Failed to fetch versions for chart name: %s/%s/%s/%s",
g.owner, g.repository, g.path, name)
return nil, err
}
for _, version := range versions {
result = append(result, fmt.Sprintf("%s#%s", name, version))
}
}
return result, nil
}
// GetChart fetches the contents of a given chart.
func (g *GithubRegistry) GetChart(chartName string) (*Chart, error) {
// TODO(jackgr): implement this method
return nil, nil
}
// Deprecated: Use ListCharts, instead.
// List the types from the Registry.
func (g *GithubRegistry) List() ([]Type, error) {
// First list all the collections at the top level.
......@@ -98,6 +151,7 @@ func (g *GithubRegistry) List() ([]Type, error) {
return retTypes, nil
}
// Deprecated: Use GetChart, instead.
// GetURL fetches the download URL for a given Type and checks for existence of a schema file.
func (g *GithubRegistry) GetURLs(t Type) ([]string, error) {
path, err := g.MakeRepositoryPath(t)
......
......@@ -23,53 +23,53 @@ import (
"github.com/kubernetes/deployment-manager/common"
)
type inmemRepositoryService struct {
repositories map[string]*common.Registry
type inmemRegistryService struct {
registries map[string]*common.Registry
}
func NewInmemRepositoryService() RegistryService {
rs := &inmemRepositoryService{
repositories: make(map[string]*common.Registry),
func NewInmemRegistryService() RegistryService {
rs := &inmemRegistryService{
registries: make(map[string]*common.Registry),
}
rs.Create(&common.Registry{
Name: "charts",
Type: common.Github,
Type: common.GithubRegistryType,
URL: "github.com/helm/charts",
Format: common.UnversionedRegistry,
})
rs.Create(&common.Registry{
Name: "application-dm-templates",
Type: common.Github,
Type: common.GithubRegistryType,
URL: "github.com/kubernetes/application-dm-templates",
Format: common.VersionedRegistry,
})
return rs
}
func (rs *inmemRepositoryService) List() ([]*common.Registry, error) {
func (rs *inmemRegistryService) List() ([]*common.Registry, error) {
ret := []*common.Registry{}
for _, r := range rs.repositories {
for _, r := range rs.registries {
ret = append(ret, r)
}
return ret, nil
}
func (rs *inmemRepositoryService) Create(repository *common.Registry) error {
rs.repositories[repository.URL] = repository
func (rs *inmemRegistryService) Create(registry *common.Registry) error {
rs.registries[registry.URL] = registry
return nil
}
func (rs *inmemRepositoryService) Get(name string) (*common.Registry, error) {
func (rs *inmemRegistryService) Get(name string) (*common.Registry, error) {
return &common.Registry{}, nil
}
func (rs *inmemRepositoryService) Delete(name string) error {
func (rs *inmemRegistryService) Delete(name string) error {
return nil
}
// GetByURL returns a registry that handles the types for a given URL.
func (rs *inmemRepositoryService) GetByURL(URL string) (*common.Registry, error) {
for _, r := range rs.repositories {
func (rs *inmemRegistryService) GetByURL(URL string) (*common.Registry, error) {
for _, r := range rs.registries {
if strings.HasPrefix(URL, r.URL) {
return r, nil
}
......
......@@ -20,13 +20,37 @@ import (
"strings"
"github.com/kubernetes/deployment-manager/common"
"net/url"
)
// Registry abstracts a registry that holds charts, which can be
// used in a Deployment Manager configuration. There can be multiple
// registry implementations.
type Registry interface {
// GetRegistryName returns the name of this registry
GetRegistryName() string
// GetRegistryType returns the type of this registry.
GetRegistryType() common.RegistryType
// GetRegistryURL returns the URL for this registry.
GetRegistryURL() string
// ListCharts lists the versioned chart names in this registry.
ListCharts() ([]string, error)
// GetChart fetches the contents of a given chart.
GetChart(chartName string) (*Chart, error)
// Deprecated: Use ListCharts, instead.
List() ([]Type, error)
// Deprecated: Use GetChart, instead.
GetURLs(t Type) ([]string, error)
}
type RegistryService interface {
// List all the registries
List() ([]*common.Registry, error)
// Create a new registry
Create(repository *common.Registry) error
Create(registry *common.Registry) error
// Get a registry
Get(name string) (*common.Registry, error)
// Delete a registry
......@@ -35,13 +59,7 @@ type RegistryService interface {
GetByURL(URL string) (*common.Registry, error)
}
// Registry abstracts a registry that holds templates, which can be
// used in a Deployment Manager configurations. There can be multiple
// implementations of a registry. Currently we support Deployment Manager
// github.com/kubernetes/application-dm-templates
// and helm packages
// github.com/helm/charts
//
// Deprecated: Use Chart, instead
type Type struct {
Collection string
Name string
......@@ -68,10 +86,12 @@ func ParseType(name string) *Type {
return tt
}
// Registry abstracts type interactions.
type Registry interface {
// List all the templates at the given path
List() ([]Type, error)
// Get the download URL(s) for a given type
GetURLs(t Type) ([]string, error)
type Chart struct {
Name string
Version SemVer
RegistryURL string
DownloadURLs []url.URL
// TODO(jackgr): Should the metadata be strongly typed?
Metadata map[string]interface{}
}
......@@ -18,38 +18,97 @@ package registry
import (
"fmt"
"strings"
"sync"
"github.com/google/go-github/github"
"github.com/kubernetes/deployment-manager/common"
)
// RegistryProvider returns factories for creating registries for a given RegistryType.
// RegistryProvider returns factories for creating registry clients.
type RegistryProvider interface {
GetRegistry(prefix string) (Registry, error)
GetRegistryByURL(URL string) (Registry, error)
GetRegistryByName(registryName string) (Registry, error)
}
func NewDefaultRegistryProvider() RegistryProvider {
rs := NewInmemRepositoryService()
return &DefaultRegistryProvider{rs: rs}
registries := make(map[string]Registry)
rs := NewInmemRegistryService()
return &DefaultRegistryProvider{registries: registries, rs: rs}
}
type DefaultRegistryProvider struct {
rs RegistryService
sync.RWMutex
registries map[string]Registry
rs RegistryService
}
func (drp *DefaultRegistryProvider) GetRegistry(URL string) (Registry, error) {
r, err := drp.rs.GetByURL(URL)
if err != nil {
return nil, err
func (drp *DefaultRegistryProvider) GetRegistryByURL(URL string) (Registry, error) {
drp.RLock()
defer drp.RUnlock()
ghr := drp.findRegistryByURL(URL)
if ghr == nil {
cr, err := drp.rs.GetByURL(URL)
if err != nil {
return nil, err
}
ghr, err := drp.getGithubRegistry(cr)
if err != nil {
return nil, err
}
drp.registries[ghr.GetRegistryName()] = ghr
}
if r.Type == common.Github {
if r.Format == common.UnversionedRegistry {
return NewGithubPackageRegistry("helm", "charts", github.NewClient(nil)), nil
return ghr, nil
}
func (drp *DefaultRegistryProvider) findRegistryByURL(URL string) Registry {
for _, ghr := range drp.registries {
if strings.HasPrefix(URL, ghr.GetRegistryURL()) {
return ghr
}
if r.Format == common.VersionedRegistry {
}
return nil
}
func (drp *DefaultRegistryProvider) GetRegistryByName(registryName string) (Registry, error) {
drp.RLock()
defer drp.RUnlock()
ghr, ok := drp.registries[registryName]
if !ok {
cr, err := drp.rs.Get(registryName)
if err != nil {
return nil, err
}
ghr, err := drp.getGithubRegistry(cr)
if err != nil {
return nil, err
}
drp.registries[ghr.GetRegistryName()] = ghr
}
return ghr, nil
}
func (drp *DefaultRegistryProvider) getGithubRegistry(cr *common.Registry) (Registry, error) {
// TODO(jackgr): Take owner and repository from cr instead of hard wiring
if cr.Type == common.GithubRegistryType {
switch cr.Format {
case common.UnversionedRegistry:
return NewGithubPackageRegistry("helm", "charts", github.NewClient(nil)), nil
case common.VersionedRegistry:
return NewGithubRegistry("kubernetes", "application-dm-templates", "", github.NewClient(nil)), nil
default:
return nil, fmt.Errorf("unknown registry format: %s", cr.Format)
}
}
return nil, fmt.Errorf("cannot find registry backing url %s", URL)
return nil, fmt.Errorf("unknown registry type: %s", cr.Type)
}
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 registry
import (
"fmt"
"strconv"
"strings"
)
type SemVer struct {
Major uint
Minor uint
Patch uint
}
func NewSemVer(version string) (*SemVer, error) {
result := &SemVer{}
parts := strings.SplitN(version, ".", 3)
if len(parts) > 3 {
return nil, fmt.Errorf("invalid semantic version: %s", version)
}
major, err := strconv.ParseUint(parts[0], 10, 0)
if err != nil {
return nil, fmt.Errorf("invalid semantic version: %s", version)
}
result.Major = uint(major)
if len(parts) < 3 {
if len(parts) < 2 {
if len(parts) < 1 {
return nil, fmt.Errorf("invalid semantic version: %s", version)
}
} else {
minor, err := strconv.ParseUint(parts[1], 10, 0)
if err != nil {
return nil, fmt.Errorf("invalid semantic version: %s", version)
}
result.Minor = uint(minor)
}
} else {
patch, err := strconv.ParseUint(parts[2], 10, 0)
if err != nil {
return nil, fmt.Errorf("invalid semantic version: %s", version)
}
result.Patch = uint(patch)
}
return result, nil
}
func (s *SemVer) String() string {
result := strconv.Itoa(int(s.Major))
if s.Minor != 0 || s.Patch != 0 {
result = result + "." + strconv.Itoa(int(s.Minor))
}
if s.Patch != 0 {
result = result + "." + strconv.Itoa(int(s.Patch))
}
return result
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment