capability

package
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 15, 2024 License: Apache-2.0 Imports: 2 Imported by: 0

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

func VersionCompareSemantic(a, b string) (int, error)

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

func (target Target) SetCapabilities(v Version) error

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

func (target Target) Version(spec string) (Version, error)

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

func NewDefaultVersion(spec string) Version

NewDefaultVersion returns an initialized DefaultVersion.

type VersionComparer

type VersionComparer func(a, b string) (int, error)

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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL