Documentation ¶
Overview ¶
Package capability provides abstract structures to keep a history of capabilities and features.
Capabilities and Targets should be exported. Versions can be either composed into another struct or exported as well, depending on the use case.
Code relying on a capability (e.g. a workaround for a missing capability or bug) can then check against the version:
In git.domain.tld/libA/libACaps:
package libACaps import "github.com/SAP/go-dblib/capability" var ( // Bug appeared in version 0.9.0, no published version has a fix Bug1 = capability.NewCapability("ticket #15", "0.9.0") Target = capability.Target{nil, {Bug1}} )
In git.domain.tld/module2/cmd/aCmd:
package main import "git.domain.tld/libA/libACaps" func main() { x := connectToServer() version, _ := libACaps.Target.Version(x.Version) if version.Has(libACaps.Bug1) { // Bugfix not yet applied, use workaround } else { // Bugfix is applied, use normally } }
See defaultVersion_test.go for more elaborate and commented examples.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func VersionCompareSemantic ¶
VersionCompareSemantic is the default method used to compare versions and only support semantic versioning.
The underlying library used to compare versions is github.com/hashicorp/go-version.
Types ¶
type Capability ¶
type Capability struct { // The description is optional and not used by this package. Description string // Ranges in which the Capability exists. See main_test.go for more // elaborate examples. VersionRanges []VersionRange }
Capability is a representation for a defined behaviour of an application, API, library, etc.pp.
func NewCapability ¶
func NewCapability(description string, versionRanges ...string) *Capability
NewCapability creates a new Capability instance with the description and ranges provided.
Versions are read in pairs and considered the lower and upper bound of a range respectively. If the last passed version does not have a partner the upper bound is set as empty.
Examples:
versionRanges: 0.1.0, 0.2.0, 0.5.0, 1.0.0 Result: - 0.1.0 -> 0.2.0 - 0.5.0 -> 1.0.0 versionRanges: 1.0.0 Result: - 1.0.0 -> (no upper bound) versionRanges: 1.0.0, "" Result: - 1.0.0 -> (no upper bound) versionRanges: "", 5.1.0, 1.0.0, 2.0.0, 3.5.0 Result: - (no lower bound) -> 5.1.0 - 1.0.0 -> 2.0.0 - 3.5.0 -> (no upper bound)
Example ¶
caps := []*Capability{ NewCapability("cap1", "0.2.5-6", "0.4"), NewCapability("cap2", "1.0.2-alpha"), NewCapability("cap3"), NewCapability("cap4", "1.0.0", "", "0.2.5", "0.2.6"), } for _, cap := range caps { fmt.Println(cap) }
Output: Capability cap1 -> ('0.2.5-6' -> '0.4') Capability cap2 -> ('1.0.2-alpha' -> '') Capability cap3 -> () Capability cap4 -> ('1.0.0' -> '', '0.2.5' -> '0.2.6')
func (Capability) String ¶
func (cap Capability) String() string
type DefaultVersion ¶
type DefaultVersion struct {
// contains filtered or unexported fields
}
DefaultVersion implements the Version interface.
func (DefaultVersion) Has ¶
func (v DefaultVersion) Has(cap *Capability) bool
Has implements the capability.Version interface.
func (*DefaultVersion) SetCapability ¶
func (v *DefaultVersion) SetCapability(cap *Capability, b bool)
SetCapability implements the capability.Version interface.
func (DefaultVersion) VersionString ¶
func (v DefaultVersion) VersionString() string
VersionString implements the capability.Version interface.
type Target ¶
type Target struct { // Function used to compare versions. VersionComparer VersionComparer // The list of registered capabilities. Capabilities []*Capability }
Target describes an application, API, library, etc.pp. and its capabilities.
func (Target) SetCapabilities ¶
SetVersion enables and disabled capabilities on a Version based on its capabilities and their version ranges.
An error is only returned in two cases:
- VersionComparer cannot parse the version of Version.VersionString or the version of a lower/upper bound in a VersionRange.
- A VersionRange of a Capability has lower and upper bound set with the lower bound being equal or greater than the upper bound.
func (Target) Version ¶
Version returns a new version with passed specs and sets the respective capabilities.
Example ¶
cap1 := NewCapability("cap1", "1.0.0") cap2 := NewCapability("cap2", "0.9.5", "1.5.0") t := Target{nil, []*Capability{cap1, cap2}} v1, err := t.Version("1.0.1") if err != nil { fmt.Fprintf(os.Stderr, "Error occurred retrieving Version 1.0.1: %v", err) return } v2, err := t.Version("0.9.5") if err != nil { fmt.Fprintf(os.Stderr, "Error occurred retrieving Version 0.9.5: %v", err) return } for _, version := range []Version{v1, v2} { fmt.Printf("Version: %s, Capability cap1: %t, Capability cap2: %t\n", version.VersionString(), version.Has(cap1), version.Has(cap2)) }
Output: Version: 1.0.1, Capability cap1: true, Capability cap2: true Version: 0.9.5, Capability cap1: false, Capability cap2: true
type Version ¶
type Version interface { // VersionString returns the version spec. VersionString() string // SetCapability sets the capability as enabled or disabled. SetCapability(*Capability, bool) // Has returns whether the capability is enabled or disabled. Has(*Capability) bool }
Version is the interface that allows a Target to set capabilities.
Example ¶
// SPDX-FileCopyrightText: 2020 SAP SE // SPDX-FileCopyrightText: 2021 SAP SE // SPDX-FileCopyrightText: 2022 SAP SE // SPDX-FileCopyrightText: 2023 SAP SE // // SPDX-License-Identifier: Apache-2.0 package main import "log" var ( ExampleVersionCapOtherthing = NewCapability("otherthing", "1.5.0") ExampleVersionBug50 = NewCapability("bug reported in ticket #50", "0.1.0", "0.2.0", "0.9.0", "1.1.0") ExampleVersionCapSpeedyAction = NewCapability("cap1", "1.0.0") ExampleVersionTarget = Target{nil, []*Capability{ ExampleVersionCapOtherthing, ExampleVersionBug50, ExampleVersionCapSpeedyAction, }} ) // ExampleSatisfyInterface shows how a struct could be modelled to satisfy the // Version interface. // // The example struct models a struct storing information to connect to // and communicate with a remote server. type ExampleSatisfyInterface struct { Dsn string // Other members // ServerVersion stores the version of the server after connecting // to it. ServerVersion string // caps stores the available capabilities of the server caps map[*Capability]bool } // Connect connects to the server, stores the server version in the // struct and calls the targets SetCapabilities func (v *ExampleSatisfyInterface) Connect() error { v.ServerVersion = "1.0.5" // Set capabilities based on server version return ExampleVersionTarget.SetCapabilities(v) } func (v ExampleSatisfyInterface) VersionString() string { return v.ServerVersion } func (v ExampleSatisfyInterface) SetCapability(cap *Capability, set bool) { v.caps[cap] = set } // Do emulates any action on the remote server. func (v ExampleSatisfyInterface) Do(s string) string { return s } func (v ExampleSatisfyInterface) Has(cap *Capability) bool { can, ok := v.caps[cap] if !ok { return false } return can } func main() { // Create connection to server and connect connection := &ExampleSatisfyInterface{} if err := connection.Connect(); err != nil { log.Printf("Error setting up example connection: %v", err) return } // Perform actions against server connection.Do("something") // The action 'otherthing' has only been implemented from version // 1.5.0 but should be used by the application if the server // supports it. // By guarding the call with a call to .Has the capability can be // supported without restricting users to specific versions of the // application. if connection.Has(ExampleVersionCapOtherthing) { connection.Do("otherthing") } // Ticket #50 reported a serious bug that would cause the remote // server to shutdown on specific actions. // The bug appeared in version 0.1.0, a fix was implemented in // 0.2.0. The bug reappeared in 0.9.0 and has been fixed again in // 1.1.0. // Assuming a workaround has been found it can be applied outside of // these version ranges: if connection.Has(ExampleVersionBug50) { // Workaround for bug } connection.Do("action that would break the server without the bugfix or workaround") // The application should execute an action on the server that takes // a long time to finish. In version 1.0.0 a new action performing // the same task in less time was added. The capabilities can be // used to support both pre-1.0.0 and post-1.0.0 servers: if connection.Has(ExampleVersionCapSpeedyAction) { connection.Do("speedy action") } else { connection.Do("slow action") } } type ExampleEmbed struct { DefaultVersion Dsn string } type ExampleMember struct { Version DefaultVersion Dsn string }
Output:
func NewDefaultVersion ¶
NewDefaultVersion returns an initialized DefaultVersion.
type VersionComparer ¶
VersionComparer compares two versions and returns the following values:
-1 when a is lower than b 0 when a and b are equal 1 when a is higher than b
type VersionRange ¶
type VersionRange struct {
Introduced, Removed string
}
VersionRange describes the range of versions a capability is available for.
VersionIntroduced is an inclusive bound, describing the version in which the capability was introduced.
VersionRemoved is an exclusive bound, describing the version in which the capability is not available anymore.
func (VersionRange) String ¶
func (vrange VersionRange) String() string