Integrate public as bindata optionally (#293)

* Dropped unused codekit config

* Integrated dynamic and static bindata for public

* Ignore public bindata

* Add a general generate make task

* Integrated flexible public assets into web command

* Updated vendoring, added all missiong govendor deps

* Made the linter happy with the bindata and dynamic code

* Moved public bindata definition to modules directory

* Ignoring the new bindata path now

* Updated to the new public modules import path

* Updated public bindata command and drop the new prefix
This commit is contained in:
Thomas Boerger 2016-11-29 17:26:36 +01:00 committed by Lunny Xiao
parent 4680c349dd
commit b6a95a8cb3
691 changed files with 305318 additions and 1272 deletions

20
vendor/github.com/twinj/uuid/LICENSE generated vendored Normal file
View file

@ -0,0 +1,20 @@
Copyright (C) 2011 by Krzysztof Kowalik <chris@nu7hat.ch>
Copyright (C) 2014 by Daniel Kemp <twinj@github.com> Derivative work
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

86
vendor/github.com/twinj/uuid/README.md generated vendored Normal file
View file

@ -0,0 +1,86 @@
Go UUID implementation
========================
[![Build Status](https://travis-ci.org/twinj/uuid.png?branch=master)](https://travis-ci.org/twinj/uuid)
[![GoDoc](http://godoc.org/github.com/twinj/uuid?status.png)](http://godoc.org/github.com/twinj/uuid)
This package provides RFC 4122 compliant UUIDs.
It will generate the following:
* Version 1: based on timestamp and MAC address
* Version 3: based on MD5 hash
* Version 4: based on cryptographically secure random numbers
* Version 5: based on SHA-1 hash
Functions NewV1, NewV3, NewV4, NewV5, New, NewHex and Parse() for generating versions 3, 4
and 5 UUIDs are as specified in [RFC 4122](http://www.ietf.org/rfc/rfc4122.txt).
# Requirements
Go 1.4, 1.3, 1.2 and tip supported.
# Recent Changes
* Removed use of OS Thread locking and runtime package requirement
* Changed String() output to CleanHyphen to match the canonical standard
* Plenty of minor change and housekeeping
* Removed default saver and replaced with interface
* API changes to simplify use.
* Added formatting support for user defined formats
* Added support for Google App Engine
* Variant type bits are now set correctly
* Variant type can now be retrieved more efficiently
* New tests for variant setting to confirm correctness
* New tests added to confirm proper version setting
* Type UUID change to UUIDArray for V3-5 UUIDs and UUIDStruct added for V1 UUIDs
** These implement the BinaryMarshaller and BinaryUnmarshaller interfaces
* New was added to create a base UUID from a []byte slice - this uses UUIDArray
* ParseHex was renamed to ParseUUID
* NewHex now performs unsafe creation of UUID from a hex string
* NewV3 and NewV5 now take anything that implements the Stringer interface
* V1 UUIDs can now be created
* The printing format can be changed
## Installation
Use the `go` tool:
$ go get github.com/twinj/uuid
## Usage
See [documentation and examples](http://godoc.org/github.com/twinj/uuid)
for more information.
var config = uuid.StateSaverConfig{SaveReport: true, SaveSchedule: 30 * time.Minute}
uuid.SetupFileSystemStateSaver(config)
u1 := uuid.NewV1()
uP, _ := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
u3 := uuid.NewV3(uP, uuid.Name("test"))
u4 := uuid.NewV4()
fmt.Printf(print, u4.Version(), u4.Variant(), u4)
u5 := uuid.NewV5(uuid.NamespaceURL, uuid.Name("test"))
if uuid.Equal(u1, u3) {
fmt.Printf("Will never happen")
}
fmt.Printf(uuid.Formatter(u5, uuid.CurlyHyphen))
uuid.SwitchFormat(uuid.BracketHyphen)
## Copyright
This is a derivative work
Orginal version from
Copyright (C) 2011 by Krzysztof Kowalik <chris@nu7hat.ch>.
See [COPYING](https://github.com/nu7hatch/gouuid/tree/master/COPYING)
file for details.
Also see: Algorithm details in [RFC 4122](http://www.ietf.org/rfc/rfc4122.txt).
Copyright (C) 2014 twinj@github.com
See [LICENSE](https://github.com/twinj/uuid/tree/master/LICENSE)
file for details.

68
vendor/github.com/twinj/uuid/array.go generated vendored Normal file
View file

@ -0,0 +1,68 @@
package uuid
/****************
* Date: 1/02/14
* Time: 10:08 AM
***************/
const (
variantIndex = 8
versionIndex = 6
)
// A clean UUID type for simpler UUID versions
type Array [length]byte
func (Array) Size() int {
return length
}
func (o Array) Version() int {
return int(o[versionIndex]) >> 4
}
func (o *Array) setVersion(pVersion int) {
o[versionIndex] &= 0x0F
o[versionIndex] |= byte(pVersion) << 4
}
func (o *Array) Variant() byte {
return variant(o[variantIndex])
}
func (o *Array) setVariant(pVariant byte) {
setVariant(&o[variantIndex], pVariant)
}
func (o *Array) Unmarshal(pData []byte) {
copy(o[:], pData)
}
func (o *Array) Bytes() []byte {
return o[:]
}
func (o Array) String() string {
return formatter(&o, format)
}
func (o Array) Format(pFormat string) string {
return formatter(&o, pFormat)
}
// Set the three most significant bits (bits 0, 1 and 2) of the
// sequenceHiAndVariant equivalent in the array to ReservedRFC4122.
func (o *Array) setRFC4122Variant() {
o[variantIndex] &= 0x3F
o[variantIndex] |= ReservedRFC4122
}
// Marshals the UUID bytes into a slice
func (o *Array) MarshalBinary() ([]byte, error) {
return o.Bytes(), nil
}
// Un-marshals the data bytes into the UUID.
func (o *Array) UnmarshalBinary(pData []byte) error {
return UnmarshalBinary(o, pData)
}

146
vendor/github.com/twinj/uuid/rfc4122.go generated vendored Normal file
View file

@ -0,0 +1,146 @@
package uuid
/***************
* Date: 14/02/14
* Time: 7:44 PM
***************/
import (
"crypto/md5"
"crypto/rand"
"crypto/sha1"
"encoding/binary"
"log"
seed "math/rand"
"net"
)
const (
length = 16
// 3F used by RFC4122 although 1F works for all
variantSet = 0x3F
// rather than using 0xC0 we use 0xE0 to retrieve the variant
// The result is the same for all other variants
// 0x80 and 0xA0 are used to identify RFC4122 compliance
variantGet = 0xE0
)
var (
// nodeID is the default Namespace node
nodeId = []byte{
// 00.192.79.212.48.200
0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8,
}
// The following standard UUIDs are for use with V3 or V5 UUIDs.
NamespaceDNS = &Struct{0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
NamespaceURL = &Struct{0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
NamespaceOID = &Struct{0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
NamespaceX500 = &Struct{0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, nodeId, length}
state State
)
func init() {
seed.Seed((int64(timestamp())^int64(gregorianToUNIXOffset))*0x6ba7b814<<0x6ba7b812 | 1391463463)
state = State{
randomNode: true,
randomSequence: true,
past: Timestamp((1391463463 * 10000000) + (100 * 10) + gregorianToUNIXOffset),
node: nodeId,
sequence: uint16(seed.Int()) & 0x3FFF,
saver: nil,
}
}
// NewV1 will generate a new RFC4122 version 1 UUID
func NewV1() UUID {
state.Lock()
defer state.Unlock()
now := currentUUIDTimestamp()
state.read(now, currentUUIDNodeId())
state.persist()
return formatV1(now, uint16(1), ReservedRFC4122, state.node)
}
// NewV3 will generate a new RFC4122 version 3 UUID
// V3 is based on the MD5 hash of a namespace identifier UUID and
// any type which implements the UniqueName interface for the name.
// For strings and slices cast to a Name type
func NewV3(pNs UUID, pName UniqueName) UUID {
o := new(Array)
// Set all bits to MD5 hash generated from namespace and name.
Digest(o, pNs, pName, md5.New())
o.setRFC4122Variant()
o.setVersion(3)
return o
}
// NewV4 will generate a new RFC4122 version 4 UUID
// A cryptographically secure random UUID.
func NewV4() UUID {
o := new(Array)
// Read random values (or pseudo-randomly) into Array type.
_, err := rand.Read(o[:length])
if err != nil {
panic(err)
}
o.setRFC4122Variant()
o.setVersion(4)
return o
}
// NewV5 will generate a new RFC4122 version 5 UUID
// Generate a UUID based on the SHA-1 hash of a namespace
// identifier and a name.
func NewV5(pNs UUID, pName UniqueName) UUID {
o := new(Array)
Digest(o, pNs, pName, sha1.New())
o.setRFC4122Variant()
o.setVersion(5)
return o
}
// either generates a random node when there is an error or gets
// the pre initialised one
func currentUUIDNodeId() (node net.HardwareAddr) {
if state.randomNode {
b := make([]byte, 16+6)
_, err := rand.Read(b)
if err != nil {
log.Println("UUID.currentUUIDNodeId error:", err)
node = nodeId
return
}
h := sha1.New()
h.Write(b)
binary.Write(h, binary.LittleEndian, state.sequence)
node = h.Sum(nil)[:6]
if err != nil {
log.Println("UUID.currentUUIDNodeId error:", err)
node = nodeId
return
}
// Mark as randomly generated
node[0] |= 0x01
} else {
node = state.node
}
return
}
// Unmarshal data into struct for V1 UUIDs
func formatV1(pNow Timestamp, pVersion uint16, pVariant byte, pNode []byte) UUID {
o := new(Struct)
o.timeLow = uint32(pNow & 0xFFFFFFFF)
o.timeMid = uint16((pNow >> 32) & 0xFFFF)
o.timeHiAndVersion = uint16((pNow >> 48) & 0x0FFF)
o.timeHiAndVersion |= uint16(pVersion << 12)
o.sequenceLow = byte(state.sequence & 0xFF)
o.sequenceHiAndVariant = byte((state.sequence & 0x3F00) >> 8)
o.sequenceHiAndVariant |= pVariant
o.node = pNode
o.size = length
return o
}

140
vendor/github.com/twinj/uuid/saver.go generated vendored Normal file
View file

@ -0,0 +1,140 @@
package uuid
/****************
* Date: 21/06/15
* Time: 5:48 PM
***************/
import (
"encoding/gob"
"log"
"os"
"time"
)
func init() {
gob.Register(stateEntity{})
}
func SetupFileSystemStateSaver(pConfig StateSaverConfig) {
saver := &FileSystemSaver{}
saver.saveReport = pConfig.SaveReport
saver.saveSchedule = int64(pConfig.SaveSchedule)
SetupCustomStateSaver(saver)
}
// A wrapper for default setup of the FileSystemStateSaver
type StateSaverConfig struct {
// Print save log
SaveReport bool
// Save every x nanoseconds
SaveSchedule time.Duration
}
// *********************************************** StateEntity
// StateEntity acts as a marshaller struct for the state
type stateEntity struct {
Past Timestamp
Node []byte
Sequence uint16
}
// This implements the StateSaver interface for UUIDs
type FileSystemSaver struct {
cache *os.File
saveState uint64
saveReport bool
saveSchedule int64
}
// Saves the current state of the generator
// If the scheduled file save is reached then the file is synced
func (o *FileSystemSaver) Save(pState *State) {
if pState.past >= pState.next {
err := o.open()
defer o.cache.Close()
if err != nil {
log.Println("uuid.State.save:", err)
return
}
// do the save
o.encode(pState)
// a tick is 100 nano seconds
pState.next = pState.past + Timestamp(o.saveSchedule / 100)
if o.saveReport {
log.Printf("UUID STATE: SAVED %d", pState.past)
}
}
}
func (o *FileSystemSaver) Init(pState *State) {
pState.saver = o
err := o.open()
defer o.cache.Close()
if err != nil {
if os.IsNotExist(err) {
log.Printf("'%s' created\n", "uuid.SaveState")
var err error
o.cache, err = os.Create(os.TempDir() + "/state.unique")
if err != nil {
log.Println("uuid.State.init: SaveState error:", err)
goto pastInit
}
o.encode(pState)
} else {
log.Println("uuid.State.init: SaveState error:", err)
goto pastInit
}
}
err = o.decode(pState)
if err != nil {
goto pastInit
}
pState.randomSequence = false
pastInit:
if timestamp() <= pState.past {
pState.sequence++
}
pState.next = pState.past
}
func (o *FileSystemSaver) reset() {
o.cache.Seek(0, 0)
}
func (o *FileSystemSaver) open() error {
var err error
o.cache, err = os.OpenFile(os.TempDir()+"/state.unique", os.O_RDWR, os.ModeExclusive)
return err
}
// Encodes State generator data into a saved file
func (o *FileSystemSaver) encode(pState *State) {
// ensure reader state is ready for use
o.reset()
enc := gob.NewEncoder(o.cache)
// Wrap private State data into the StateEntity
err := enc.Encode(&stateEntity{pState.past, pState.node, pState.sequence})
if err != nil {
log.Panic("UUID.encode error:", err)
}
}
// Decodes StateEntity data into the main State
func (o *FileSystemSaver) decode(pState *State) error {
o.reset()
dec := gob.NewDecoder(o.cache)
entity := stateEntity{}
err := dec.Decode(&entity)
if err != nil {
log.Println("uuid.decode error:", err)
return err
}
pState.past = entity.Past
pState.node = entity.Node
pState.sequence = entity.Sequence
return nil
}

137
vendor/github.com/twinj/uuid/state.go generated vendored Normal file
View file

@ -0,0 +1,137 @@
package uuid
/****************
* Date: 14/02/14
* Time: 7:43 PM
***************/
import (
"bytes"
"log"
seed "math/rand"
"net"
"sync"
)
// **************************************************** State
func SetupCustomStateSaver(pSaver StateSaver) {
state.Lock()
pSaver.Init(&state)
state.init()
state.Unlock()
}
// Holds package information about the current
// state of the UUID generator
type State struct {
// A flag which informs whether to
// randomly create a node id
randomNode bool
// A flag which informs whether to
// randomly create the sequence
randomSequence bool
// the last time UUID was saved
past Timestamp
// the next time the state will be saved
next Timestamp
// the last node which saved a UUID
node []byte
// An iterated value to help ensure different
// values across the same domain
sequence uint16
sync.Mutex
// save state interface
saver StateSaver
}
// Changes the state with current data
// Compares the current found node to the last node stored,
// If they are the same or randomSequence is already set due
// to an earlier read issue then the sequence is randomly generated
// else if there is an issue with the time the sequence is incremented
func (o *State) read(pNow Timestamp, pNode net.HardwareAddr) {
if bytes.Equal([]byte(pNode), o.node) || o.randomSequence {
o.sequence = uint16(seed.Int()) & 0x3FFF
} else if pNow < o.past {
o.sequence++
}
o.past = pNow
o.node = pNode
}
func (o *State) persist() {
if o.saver != nil {
o.saver.Save(o)
}
}
// Initialises the UUID state when the package is first loaded
// it first attempts to decode the file state into State
// if this file does not exist it will create the file and do a flush
// of the random state which gets loaded at package runtime
// second it will attempt to resolve the current hardware address nodeId
// thirdly it will check the state of the clock
func (o *State) init() {
if o.saver != nil {
intfcs, err := net.Interfaces()
if err != nil {
log.Println("uuid.State.init: address error: will generate random node id instead", err)
return
}
a := getHardwareAddress(intfcs)
if a == nil {
log.Println("uuid.State.init: address error: will generate random node id instead", err)
return
}
// Don't use random as we have a real address
o.randomSequence = false
if bytes.Equal([]byte(a), state.node) {
state.sequence++
}
state.node = a
state.randomNode = false
}
}
func getHardwareAddress(pInterfaces []net.Interface) net.HardwareAddr {
for _, inter := range pInterfaces {
// Initially I could multicast out the Flags to get
// whether the interface was up but started failing
if (inter.Flags & (1 << net.FlagUp)) != 0 {
//if inter.Flags.String() != "0" {
if addrs, err := inter.Addrs(); err == nil {
for _, addr := range addrs {
if addr.String() != "0.0.0.0" && !bytes.Equal([]byte(inter.HardwareAddr), make([]byte, len(inter.HardwareAddr))) {
return inter.HardwareAddr
}
}
}
}
}
return nil
}
// *********************************************** StateSaver interface
// Use this interface to setup a custom state saver if you wish to have
// v1 UUIDs based on your node id and constant time.
type StateSaver interface {
// Init is run if Setup() is false
// Init should setup the system to save the state
Init(*State)
// Save saves the state and is called only if const V1Save and
// Setup() is true
Save(*State)
}

103
vendor/github.com/twinj/uuid/struct.go generated vendored Normal file
View file

@ -0,0 +1,103 @@
package uuid
/****************
* Date: 31/01/14
* Time: 3:34 PM
***************/
import "net"
// Struct is used for RFC4122 Version 1 UUIDs
type Struct struct {
timeLow uint32
timeMid uint16
timeHiAndVersion uint16
sequenceHiAndVariant byte
sequenceLow byte
node []byte
size int
}
func (o Struct) Size() int {
return o.size
}
func (o Struct) Version() int {
return int(o.timeHiAndVersion >> 12)
}
func (o Struct) Variant() byte {
return variant(o.sequenceHiAndVariant)
}
// Sets the four most significant bits (bits 12 through 15) of the
// timeHiAndVersion field to the 4-bit version number.
func (o *Struct) setVersion(pVersion int) {
o.timeHiAndVersion &= 0x0FFF
o.timeHiAndVersion |= (uint16(pVersion) << 12)
}
func (o *Struct) setVariant(pVariant byte) {
setVariant(&o.sequenceHiAndVariant, pVariant)
}
func (o *Struct) Unmarshal(pData []byte) {
o.timeLow = uint32(pData[3]) | uint32(pData[2])<<8 | uint32(pData[1])<<16 | uint32(pData[0])<<24
o.timeMid = uint16(pData[5]) | uint16(pData[4])<<8
o.timeHiAndVersion = uint16(pData[7]) | uint16(pData[6])<<8
o.sequenceHiAndVariant = pData[8]
o.sequenceLow = pData[9]
o.node = pData[10:o.Size()]
}
func (o *Struct) Bytes() (data []byte) {
data = []byte{
byte(o.timeLow >> 24), byte(o.timeLow >> 16), byte(o.timeLow >> 8), byte(o.timeLow),
byte(o.timeMid >> 8), byte(o.timeMid),
byte(o.timeHiAndVersion >> 8), byte(o.timeHiAndVersion),
}
data = append(data, o.sequenceHiAndVariant)
data = append(data, o.sequenceLow)
data = append(data, o.node...)
return
}
// Marshals the UUID bytes into a slice
func (o *Struct) MarshalBinary() ([]byte, error) {
return o.Bytes(), nil
}
// Un-marshals the data bytes into the UUID struct.
// Implements the BinaryUn-marshaller interface
func (o *Struct) UnmarshalBinary(pData []byte) error {
return UnmarshalBinary(o, pData)
}
func (o Struct) String() string {
return formatter(&o, format)
}
func (o Struct) Format(pFormat string) string {
return formatter(&o, pFormat)
}
// Set the three most significant bits (bits 0, 1 and 2) of the
// sequenceHiAndVariant to variant mask 0x80.
func (o *Struct) setRFC4122Variant() {
o.sequenceHiAndVariant &= variantSet
o.sequenceHiAndVariant |= ReservedRFC4122
}
// Unmarshals data into struct for V1 UUIDs
func newV1(pNow Timestamp, pVersion uint16, pVariant byte, pNode net.HardwareAddr) UUID {
o := new(Struct)
o.timeLow = uint32(pNow & 0xFFFFFFFF)
o.timeMid = uint16((pNow >> 32) & 0xFFFF)
o.timeHiAndVersion = uint16((pNow >> 48) & 0x0FFF)
o.timeHiAndVersion |= uint16(pVersion << 12)
o.sequenceLow = byte(state.sequence & 0xFF)
o.sequenceHiAndVariant = byte((state.sequence & 0x3F00) >> 8)
o.sequenceHiAndVariant |= pVariant
o.node = pNode
return o
}

81
vendor/github.com/twinj/uuid/timestamp.go generated vendored Normal file
View file

@ -0,0 +1,81 @@
package uuid
/****************
* Date: 14/02/14
* Time: 7:46 PM
***************/
import (
"time"
)
const (
// A tick is 100 ns
ticksPerSecond = 10000000
// Difference between
gregorianToUNIXOffset uint64 = 0x01B21DD213814000
// set the following to the number of 100ns ticks of the actual
// resolution of your system's clock
idsPerTimestamp = 1024
)
var (
lastTimestamp Timestamp
idsThisTimestamp = idsPerTimestamp
)
// ********************************************** Timestamp
type Timestamp uint64
// TODO Create c version same as package runtime and time
func Now() (sec int64, nsec int32) {
t := time.Now()
sec = t.Unix()
nsec = int32(t.Nanosecond())
return
}
// Converts Unix formatted time to RFC4122 UUID formatted times
// UUID UTC base time is October 15, 1582.
// Unix base time is January 1, 1970.
// Converts time to 100 nanosecond ticks since epoch
// There are 1000000000 nanoseconds in a second,
// 1000000000 / 100 = 10000000 tiks per second
func timestamp() Timestamp {
sec, nsec := Now()
return Timestamp(uint64(sec)*ticksPerSecond +
uint64(nsec)/100 + gregorianToUNIXOffset)
}
func (o Timestamp) Unix() time.Time {
t := uint64(o) - gregorianToUNIXOffset
return time.Unix(0, int64(t*100))
}
// Get time as 60-bit 100ns ticks since UUID epoch.
// Compensate for the fact that real clock resolution is
// less than 100ns.
func currentUUIDTimestamp() Timestamp {
var timeNow Timestamp
for {
timeNow = timestamp()
// if clock reading changed since last UUID generated
if lastTimestamp != timeNow {
// reset count of UUIDs with this timestamp
idsThisTimestamp = 0
lastTimestamp = timeNow
break
}
if idsThisTimestamp < idsPerTimestamp {
idsThisTimestamp++
break
}
// going too fast for the clock; spin
}
// add the count of UUIDs to low order bits of the clock reading
return timeNow + Timestamp(idsThisTimestamp)
}

296
vendor/github.com/twinj/uuid/uuids.go generated vendored Normal file
View file

@ -0,0 +1,296 @@
// This package provides RFC4122 UUIDs.
//
// NewV1, NewV3, NewV4, NewV5, for generating versions 1, 3, 4
// and 5 UUIDs as specified in RFC-4122.
//
// New([]byte), unsafe; NewHex(string); and Parse(string) for
// creating UUIDs from existing data.
//
// The original version was from Krzysztof Kowalik <chris@nu7hat.ch>
// Unfortunately, that version was non compliant with RFC4122.
// I forked it but have since heavily redesigned it.
//
// The example code in the specification was also used as reference
// for design.
//
// Copyright (C) 2014 twinj@github.com 2014 MIT style licence
package uuid
/****************
* Date: 31/01/14
* Time: 3:35 PM
***************/
import (
"encoding"
"encoding/hex"
"errors"
"fmt"
"hash"
"regexp"
"strings"
"bytes"
)
const (
ReservedNCS byte = 0x00
ReservedRFC4122 byte = 0x80 // or and A0 if masked with 1F
ReservedMicrosoft byte = 0xC0
ReservedFuture byte = 0xE0
TakeBack byte = 0xF0
)
const (
// Pattern used to parse string representation of the UUID.
// Current one allows to parse string where only one opening
// or closing bracket or any of the hyphens are optional.
// It is only used to extract the main bytes to create a UUID,
// so these imperfections are of no consequence.
hexPattern = `^(urn\:uuid\:)?[\{(\[]?([A-Fa-f0-9]{8})-?([A-Fa-f0-9]{4})-?([1-5][A-Fa-f0-9]{3})-?([A-Fa-f0-9]{4})-?([A-Fa-f0-9]{12})[\]\})]?$`
)
var (
parseUUIDRegex = regexp.MustCompile(hexPattern)
format string
)
func init() {
SwitchFormat(CleanHyphen)
}
// ****************************************************** UUID
// The main interface for UUIDs
// Each implementation must also implement the UniqueName interface
type UUID interface {
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
// Marshals the UUID bytes or data
Bytes() (data []byte)
// Organises data into a new UUID
Unmarshal(pData []byte)
// Size is used where different implementations require
// different sizes. Should return the number of bytes in
// the implementation.
// Enables unmarshal and Bytes to screen for size
Size() int
// Version returns a version number of the algorithm used
// to generate the UUID.
// This may may behave independently across non RFC4122 UUIDs
Version() int
// Variant returns the UUID Variant
// This will be one of the constants:
// ReservedRFC4122,
// ReservedMicrosoft,
// ReservedFuture,
// ReservedNCS.
// This may behave differently across non RFC4122 UUIDs
Variant() byte
// UUID can be used as a Name within a namespace
// Is simply just a String() string method
// Returns a formatted version of the UUID.
String() string
}
// New creates a UUID from a slice of bytes.
// Truncates any bytes past the default length of 16
// Will panic if data slice is too small.
func New(pData []byte) UUID {
o := new(Array)
o.Unmarshal(pData[:length])
return o
}
// Creates a UUID from a hex string
// Will panic if hex string is invalid - will panic even with hyphens and brackets
// Expects a clean string use Parse otherwise.
func NewHex(pUuid string) UUID {
bytes, err := hex.DecodeString(pUuid)
if err != nil {
panic(err)
}
return New(bytes)
}
// Parse creates a UUID from a valid string representation.
// Accepts UUID string in following formats:
// 6ba7b8149dad11d180b400c04fd430c8
// 6ba7b814-9dad-11d1-80b4-00c04fd430c8
// {6ba7b814-9dad-11d1-80b4-00c04fd430c8}
// urn:uuid:6ba7b814-9dad-11d1-80b4-00c04fd430c8
// [6ba7b814-9dad-11d1-80b4-00c04fd430c8]
//
func Parse(pUUID string) (UUID, error) {
md := parseUUIDRegex.FindStringSubmatch(pUUID)
if md == nil {
return nil, errors.New("uuid.Parse: invalid string")
}
return NewHex(md[2] + md[3] + md[4] + md[5] + md[6]), nil
}
// Digest a namespace UUID and a UniqueName, which then marshals to
// a new UUID
func Digest(o, pNs UUID, pName UniqueName, pHash hash.Hash) {
// Hash writer never returns an error
pHash.Write(pNs.Bytes())
pHash.Write([]byte(pName.String()))
o.Unmarshal(pHash.Sum(nil)[:o.Size()])
}
// Function provides a safe way to unmarshal bytes into an
// existing UUID.
// Checks for length.
func UnmarshalBinary(o UUID, pData []byte) error {
if len(pData) != o.Size() {
return errors.New("uuid.UnmarshalBinary: invalid length")
}
o.Unmarshal(pData)
return nil
}
// ********************************************** UUID Names
// A UUID Name is a simple string which implements UniqueName
// which satisfies the Stringer interface.
type Name string
// Returns the name as a string. Satisfies the Stringer interface.
func (o Name) String() string {
return string(o)
}
// NewName will create a unique name from several sources
func NewName(salt string, pNames ...UniqueName) UniqueName {
var s string
for _, s2 := range pNames {
s += s2.String()
}
return Name(s + salt)
}
// UniqueName is a Stinger interface
// Made for easy passing of IPs, URLs, the several Address types,
// Buffers and any other type which implements Stringer
// string, []byte types and Hash sums will need to be cast to
// the Name type or some other type which implements
// Stringer or UniqueName
type UniqueName interface {
// Many go types implement this method for use with printing
// Will convert the current type to its native string format
String() string
}
// ********************************************** UUID Printing
// A Format is a pattern used by the stringer interface with which to print
// the UUID.
type Format string
const (
Clean Format = "%x%x%x%x%x%x"
Curly Format = "{%x%x%x%x%x%x}"
Bracket Format = "(%x%x%x%x%x%x)"
// This is the default format.
CleanHyphen Format = "%x-%x-%x-%x%x-%x"
CurlyHyphen Format = "{%x-%x-%x-%x%x-%x}"
BracketHyphen Format = "(%x-%x-%x-%x%x-%x)"
GoIdFormat Format = "[%X-%X-%x-%X%X-%x]"
)
// Gets the current default format pattern
func GetFormat() string {
return format
}
// Switches the default printing format for ALL UUID strings
// A valid format will have 6 groups if the supplied Format does not
func SwitchFormat(pFormat Format) {
form := string(pFormat)
if strings.Count(form, "%") != 6 {
panic(errors.New("uuid.switchFormat: invalid formatting"))
}
format = form
}
// Same as SwitchFormat but will make it uppercase
func SwitchFormatUpperCase(pFormat Format) {
form := strings.ToUpper(string(pFormat))
SwitchFormat(Format(form))
}
// Compares whether each UUID is the same
func Equal(p1 UUID, p2 UUID) bool {
return bytes.Equal(p1.Bytes(), p2.Bytes())
}
// Format a UUID into a human readable string which matches the given Format
// Use this for one time formatting when setting the default using SwitchFormat
// is overkill.
func Formatter(pUUID UUID, pFormat Format) string {
form := string(pFormat)
if strings.Count(form, "%") != 6 {
panic(errors.New("uuid.Formatter: invalid formatting"))
}
return formatter(pUUID, form)
}
// ********************************************** UUID Versions
type UUIDVersion int
const (
NONE UUIDVersion = iota
RFC4122v1
DunnoYetv2
RFC4122v3
RFC4122v4
RFC4122v5
)
// *************************************************** Helpers
// Retrieves the variant from the given byte
func variant(pVariant byte) byte {
switch pVariant & variantGet {
case ReservedRFC4122, 0xA0:
return ReservedRFC4122
case ReservedMicrosoft:
return ReservedMicrosoft
case ReservedFuture:
return ReservedFuture
}
return ReservedNCS
}
// not strictly required
func setVariant(pByte *byte, pVariant byte) {
switch pVariant {
case ReservedRFC4122:
*pByte &= variantSet
case ReservedFuture, ReservedMicrosoft:
*pByte &= 0x1F
case ReservedNCS:
*pByte &= 0x7F
default:
panic(errors.New("uuid.setVariant: invalid variant mask"))
}
*pByte |= pVariant
}
// format a UUID into a human readable string
func formatter(pUUID UUID, pFormat string) string {
b := pUUID.Bytes()
return fmt.Sprintf(pFormat, b[0:4], b[4:6], b[6:8], b[8:9], b[9:10], b[10:pUUID.Size()])
}