Replace uuid dependency with internal library
Signed-off-by: Stephen J Day <stephen.day@docker.com>master
							parent
							
								
									2317f721a3
								
							
						
					
					
						commit
						36e34a55ad
					
				|  | @ -5,11 +5,6 @@ | |||
| 		"./..." | ||||
| 	], | ||||
| 	"Deps": [ | ||||
| 		{ | ||||
| 			"ImportPath": "code.google.com/p/go-uuid/uuid", | ||||
| 			"Comment": "null-15", | ||||
| 			"Rev": "35bc42037350f0078e3c974c6ea690f1926603ab" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "github.com/AdRoll/goamz/aws", | ||||
| 			"Rev": "cc210f45dcb9889c2769a274522be2bf70edfb99" | ||||
|  |  | |||
|  | @ -1,27 +0,0 @@ | |||
| Copyright (c) 2009,2014 Google Inc. All rights reserved. | ||||
| 
 | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
| 
 | ||||
|    * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
|    * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following disclaimer | ||||
| in the documentation and/or other materials provided with the | ||||
| distribution. | ||||
|    * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
| 
 | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  | @ -1,84 +0,0 @@ | |||
| // Copyright 2011 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| ) | ||||
| 
 | ||||
| // A Domain represents a Version 2 domain
 | ||||
| type Domain byte | ||||
| 
 | ||||
| // Domain constants for DCE Security (Version 2) UUIDs.
 | ||||
| const ( | ||||
| 	Person = Domain(0) | ||||
| 	Group  = Domain(1) | ||||
| 	Org    = Domain(2) | ||||
| ) | ||||
| 
 | ||||
| // NewDCESecurity returns a DCE Security (Version 2) UUID.
 | ||||
| //
 | ||||
| // The domain should be one of Person, Group or Org.
 | ||||
| // On a POSIX system the id should be the users UID for the Person
 | ||||
| // domain and the users GID for the Group.  The meaning of id for
 | ||||
| // the domain Org or on non-POSIX systems is site defined.
 | ||||
| //
 | ||||
| // For a given domain/id pair the same token may be returned for up to
 | ||||
| // 7 minutes and 10 seconds.
 | ||||
| func NewDCESecurity(domain Domain, id uint32) UUID { | ||||
| 	uuid := NewUUID() | ||||
| 	if uuid != nil { | ||||
| 		uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
 | ||||
| 		uuid[9] = byte(domain) | ||||
| 		binary.BigEndian.PutUint32(uuid[0:], id) | ||||
| 	} | ||||
| 	return uuid | ||||
| } | ||||
| 
 | ||||
| // NewDCEPerson returns a DCE Security (Version 2) UUID in the person
 | ||||
| // domain with the id returned by os.Getuid.
 | ||||
| //
 | ||||
| //  NewDCEPerson(Person, uint32(os.Getuid()))
 | ||||
| func NewDCEPerson() UUID { | ||||
| 	return NewDCESecurity(Person, uint32(os.Getuid())) | ||||
| } | ||||
| 
 | ||||
| // NewDCEGroup returns a DCE Security (Version 2) UUID in the group
 | ||||
| // domain with the id returned by os.Getgid.
 | ||||
| //
 | ||||
| //  NewDCEGroup(Group, uint32(os.Getgid()))
 | ||||
| func NewDCEGroup() UUID { | ||||
| 	return NewDCESecurity(Group, uint32(os.Getgid())) | ||||
| } | ||||
| 
 | ||||
| // Domain returns the domain for a Version 2 UUID or false.
 | ||||
| func (uuid UUID) Domain() (Domain, bool) { | ||||
| 	if v, _ := uuid.Version(); v != 2 { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	return Domain(uuid[9]), true | ||||
| } | ||||
| 
 | ||||
| // Id returns the id for a Version 2 UUID or false.
 | ||||
| func (uuid UUID) Id() (uint32, bool) { | ||||
| 	if v, _ := uuid.Version(); v != 2 { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	return binary.BigEndian.Uint32(uuid[0:4]), true | ||||
| } | ||||
| 
 | ||||
| func (d Domain) String() string { | ||||
| 	switch d { | ||||
| 	case Person: | ||||
| 		return "Person" | ||||
| 	case Group: | ||||
| 		return "Group" | ||||
| 	case Org: | ||||
| 		return "Org" | ||||
| 	} | ||||
| 	return fmt.Sprintf("Domain%d", int(d)) | ||||
| } | ||||
|  | @ -1,8 +0,0 @@ | |||
| // Copyright 2011 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| // The uuid package generates and inspects UUIDs.
 | ||||
| //
 | ||||
| // UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services.
 | ||||
| package uuid | ||||
|  | @ -1,53 +0,0 @@ | |||
| // Copyright 2011 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/md5" | ||||
| 	"crypto/sha1" | ||||
| 	"hash" | ||||
| ) | ||||
| 
 | ||||
| // Well known Name Space IDs and UUIDs
 | ||||
| var ( | ||||
| 	NameSpace_DNS  = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") | ||||
| 	NameSpace_URL  = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8") | ||||
| 	NameSpace_OID  = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8") | ||||
| 	NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8") | ||||
| 	NIL            = Parse("00000000-0000-0000-0000-000000000000") | ||||
| ) | ||||
| 
 | ||||
| // NewHash returns a new UUID dervied from the hash of space concatenated with
 | ||||
| // data generated by h.  The hash should be at least 16 byte in length.  The
 | ||||
| // first 16 bytes of the hash are used to form the UUID.  The version of the
 | ||||
| // UUID will be the lower 4 bits of version.  NewHash is used to implement
 | ||||
| // NewMD5 and NewSHA1.
 | ||||
| func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { | ||||
| 	h.Reset() | ||||
| 	h.Write(space) | ||||
| 	h.Write([]byte(data)) | ||||
| 	s := h.Sum(nil) | ||||
| 	uuid := make([]byte, 16) | ||||
| 	copy(uuid, s) | ||||
| 	uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) | ||||
| 	uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
 | ||||
| 	return uuid | ||||
| } | ||||
| 
 | ||||
| // NewMD5 returns a new MD5 (Version 3) UUID based on the
 | ||||
| // supplied name space and data.
 | ||||
| //
 | ||||
| //  NewHash(md5.New(), space, data, 3)
 | ||||
| func NewMD5(space UUID, data []byte) UUID { | ||||
| 	return NewHash(md5.New(), space, data, 3) | ||||
| } | ||||
| 
 | ||||
| // NewSHA1 returns a new SHA1 (Version 5) UUID based on the
 | ||||
| // supplied name space and data.
 | ||||
| //
 | ||||
| //  NewHash(sha1.New(), space, data, 5)
 | ||||
| func NewSHA1(space UUID, data []byte) UUID { | ||||
| 	return NewHash(sha1.New(), space, data, 5) | ||||
| } | ||||
|  | @ -1,30 +0,0 @@ | |||
| // Copyright 2014 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| import "errors" | ||||
| 
 | ||||
| func (u UUID) MarshalJSON() ([]byte, error) { | ||||
| 	if len(u) == 0 { | ||||
| 		return []byte(`""`), nil | ||||
| 	} | ||||
| 	return []byte(`"` + u.String() + `"`), nil | ||||
| } | ||||
| 
 | ||||
| func (u *UUID) UnmarshalJSON(data []byte) error { | ||||
| 	if len(data) == 0 || string(data) == `""` { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' { | ||||
| 		return errors.New("invalid UUID format") | ||||
| 	} | ||||
| 	data = data[1 : len(data)-1] | ||||
| 	uu := Parse(string(data)) | ||||
| 	if uu == nil { | ||||
| 		return errors.New("invalid UUID format") | ||||
| 	} | ||||
| 	*u = uu | ||||
| 	return nil | ||||
| } | ||||
|  | @ -1,32 +0,0 @@ | |||
| // Copyright 2014 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"reflect" | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| var testUUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479") | ||||
| 
 | ||||
| func TestJSON(t *testing.T) { | ||||
| 	type S struct { | ||||
| 		ID1 UUID | ||||
| 		ID2 UUID | ||||
| 	} | ||||
| 	s1 := S{ID1: testUUID} | ||||
| 	data, err := json.Marshal(&s1) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	var s2 S | ||||
| 	if err := json.Unmarshal(data, &s2); err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if !reflect.DeepEqual(&s1, &s2) { | ||||
| 		t.Errorf("got %#v, want %#v", s2, s1) | ||||
| 	} | ||||
| } | ||||
|  | @ -1,101 +0,0 @@ | |||
| // Copyright 2011 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| import "net" | ||||
| 
 | ||||
| var ( | ||||
| 	interfaces []net.Interface // cached list of interfaces
 | ||||
| 	ifname     string          // name of interface being used
 | ||||
| 	nodeID     []byte          // hardware for version 1 UUIDs
 | ||||
| ) | ||||
| 
 | ||||
| // NodeInterface returns the name of the interface from which the NodeID was
 | ||||
| // derived.  The interface "user" is returned if the NodeID was set by
 | ||||
| // SetNodeID.
 | ||||
| func NodeInterface() string { | ||||
| 	return ifname | ||||
| } | ||||
| 
 | ||||
| // SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
 | ||||
| // If name is "" then the first usable interface found will be used or a random
 | ||||
| // Node ID will be generated.  If a named interface cannot be found then false
 | ||||
| // is returned.
 | ||||
| //
 | ||||
| // SetNodeInterface never fails when name is "".
 | ||||
| func SetNodeInterface(name string) bool { | ||||
| 	if interfaces == nil { | ||||
| 		var err error | ||||
| 		interfaces, err = net.Interfaces() | ||||
| 		if err != nil && name != "" { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for _, ifs := range interfaces { | ||||
| 		if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { | ||||
| 			if setNodeID(ifs.HardwareAddr) { | ||||
| 				ifname = ifs.Name | ||||
| 				return true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// We found no interfaces with a valid hardware address.  If name
 | ||||
| 	// does not specify a specific interface generate a random Node ID
 | ||||
| 	// (section 4.1.6)
 | ||||
| 	if name == "" { | ||||
| 		if nodeID == nil { | ||||
| 			nodeID = make([]byte, 6) | ||||
| 		} | ||||
| 		randomBits(nodeID) | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // NodeID returns a slice of a copy of the current Node ID, setting the Node ID
 | ||||
| // if not already set.
 | ||||
| func NodeID() []byte { | ||||
| 	if nodeID == nil { | ||||
| 		SetNodeInterface("") | ||||
| 	} | ||||
| 	nid := make([]byte, 6) | ||||
| 	copy(nid, nodeID) | ||||
| 	return nid | ||||
| } | ||||
| 
 | ||||
| // SetNodeID sets the Node ID to be used for Version 1 UUIDs.  The first 6 bytes
 | ||||
| // of id are used.  If id is less than 6 bytes then false is returned and the
 | ||||
| // Node ID is not set.
 | ||||
| func SetNodeID(id []byte) bool { | ||||
| 	if setNodeID(id) { | ||||
| 		ifname = "user" | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func setNodeID(id []byte) bool { | ||||
| 	if len(id) < 6 { | ||||
| 		return false | ||||
| 	} | ||||
| 	if nodeID == nil { | ||||
| 		nodeID = make([]byte, 6) | ||||
| 	} | ||||
| 	copy(nodeID, id) | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // NodeID returns the 6 byte node id encoded in uuid.  It returns nil if uuid is
 | ||||
| // not valid.  The NodeID is only well defined for version 1 and 2 UUIDs.
 | ||||
| func (uuid UUID) NodeID() []byte { | ||||
| 	if len(uuid) != 16 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	node := make([]byte, 6) | ||||
| 	copy(node, uuid[10:]) | ||||
| 	return node | ||||
| } | ||||
|  | @ -1,66 +0,0 @@ | |||
| // Copyright 2014 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| import ( | ||||
| 	"flag" | ||||
| 	"runtime" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| // This test is only run when --regressions is passed on the go test line.
 | ||||
| var regressions = flag.Bool("regressions", false, "run uuid regression tests") | ||||
| 
 | ||||
| // TestClockSeqRace tests for a particular race condition of returning two
 | ||||
| // identical Version1 UUIDs.  The duration of 1 minute was chosen as the race
 | ||||
| // condition, before being fixed, nearly always occured in under 30 seconds.
 | ||||
| func TestClockSeqRace(t *testing.T) { | ||||
| 	if !*regressions { | ||||
| 		t.Skip("skipping regression tests") | ||||
| 	} | ||||
| 	duration := time.Minute | ||||
| 
 | ||||
| 	done := make(chan struct{}) | ||||
| 	defer close(done) | ||||
| 
 | ||||
| 	ch := make(chan UUID, 10000) | ||||
| 	ncpu := runtime.NumCPU() | ||||
| 	switch ncpu { | ||||
| 	case 0, 1: | ||||
| 		// We can't run the test effectively.
 | ||||
| 		t.Skip("skipping race test, only one CPU detected") | ||||
| 		return | ||||
| 	default: | ||||
| 		runtime.GOMAXPROCS(ncpu) | ||||
| 	} | ||||
| 	for i := 0; i < ncpu; i++ { | ||||
| 		go func() { | ||||
| 			for { | ||||
| 				select { | ||||
| 				case <-done: | ||||
| 					return | ||||
| 				case ch <- NewUUID(): | ||||
| 				} | ||||
| 			} | ||||
| 		}() | ||||
| 	} | ||||
| 
 | ||||
| 	uuids := make(map[string]bool) | ||||
| 	cnt := 0 | ||||
| 	start := time.Now() | ||||
| 	for u := range ch { | ||||
| 		s := u.String() | ||||
| 		if uuids[s] { | ||||
| 			t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s) | ||||
| 			return | ||||
| 		} | ||||
| 		uuids[s] = true | ||||
| 		if time.Since(start) > duration { | ||||
| 			return | ||||
| 		} | ||||
| 		cnt++ | ||||
| 	} | ||||
| } | ||||
|  | @ -1,132 +0,0 @@ | |||
| // Copyright 2014 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| // A Time represents a time as the number of 100's of nanoseconds since 15 Oct
 | ||||
| // 1582.
 | ||||
| type Time int64 | ||||
| 
 | ||||
| const ( | ||||
| 	lillian    = 2299160          // Julian day of 15 Oct 1582
 | ||||
| 	unix       = 2440587          // Julian day of 1 Jan 1970
 | ||||
| 	epoch      = unix - lillian   // Days between epochs
 | ||||
| 	g1582      = epoch * 86400    // seconds between epochs
 | ||||
| 	g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
 | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	mu        sync.Mutex | ||||
| 	lasttime  uint64 // last time we returned
 | ||||
| 	clock_seq uint16 // clock sequence for this run
 | ||||
| 
 | ||||
| 	timeNow = time.Now // for testing
 | ||||
| ) | ||||
| 
 | ||||
| // UnixTime converts t the number of seconds and nanoseconds using the Unix
 | ||||
| // epoch of 1 Jan 1970.
 | ||||
| func (t Time) UnixTime() (sec, nsec int64) { | ||||
| 	sec = int64(t - g1582ns100) | ||||
| 	nsec = (sec % 10000000) * 100 | ||||
| 	sec /= 10000000 | ||||
| 	return sec, nsec | ||||
| } | ||||
| 
 | ||||
| // GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
 | ||||
| // clock sequence as well as adjusting the clock sequence as needed.  An error
 | ||||
| // is returned if the current time cannot be determined.
 | ||||
| func GetTime() (Time, uint16, error) { | ||||
| 	defer mu.Unlock() | ||||
| 	mu.Lock() | ||||
| 	return getTime() | ||||
| } | ||||
| 
 | ||||
| func getTime() (Time, uint16, error) { | ||||
| 	t := timeNow() | ||||
| 
 | ||||
| 	// If we don't have a clock sequence already, set one.
 | ||||
| 	if clock_seq == 0 { | ||||
| 		setClockSequence(-1) | ||||
| 	} | ||||
| 	now := uint64(t.UnixNano()/100) + g1582ns100 | ||||
| 
 | ||||
| 	// If time has gone backwards with this clock sequence then we
 | ||||
| 	// increment the clock sequence
 | ||||
| 	if now <= lasttime { | ||||
| 		clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000 | ||||
| 	} | ||||
| 	lasttime = now | ||||
| 	return Time(now), clock_seq, nil | ||||
| } | ||||
| 
 | ||||
| // ClockSequence returns the current clock sequence, generating one if not
 | ||||
| // already set.  The clock sequence is only used for Version 1 UUIDs.
 | ||||
| //
 | ||||
| // The uuid package does not use global static storage for the clock sequence or
 | ||||
| // the last time a UUID was generated.  Unless SetClockSequence a new random
 | ||||
| // clock sequence is generated the first time a clock sequence is requested by
 | ||||
| // ClockSequence, GetTime, or NewUUID.  (section 4.2.1.1) sequence is generated
 | ||||
| // for
 | ||||
| func ClockSequence() int { | ||||
| 	defer mu.Unlock() | ||||
| 	mu.Lock() | ||||
| 	return clockSequence() | ||||
| } | ||||
| 
 | ||||
| func clockSequence() int { | ||||
| 	if clock_seq == 0 { | ||||
| 		setClockSequence(-1) | ||||
| 	} | ||||
| 	return int(clock_seq & 0x3fff) | ||||
| } | ||||
| 
 | ||||
| // SetClockSeq sets the clock sequence to the lower 14 bits of seq.  Setting to
 | ||||
| // -1 causes a new sequence to be generated.
 | ||||
| func SetClockSequence(seq int) { | ||||
| 	defer mu.Unlock() | ||||
| 	mu.Lock() | ||||
| 	setClockSequence(seq) | ||||
| } | ||||
| 
 | ||||
| func setClockSequence(seq int) { | ||||
| 	if seq == -1 { | ||||
| 		var b [2]byte | ||||
| 		randomBits(b[:]) // clock sequence
 | ||||
| 		seq = int(b[0])<<8 | int(b[1]) | ||||
| 	} | ||||
| 	old_seq := clock_seq | ||||
| 	clock_seq = uint16(seq&0x3fff) | 0x8000 // Set our variant
 | ||||
| 	if old_seq != clock_seq { | ||||
| 		lasttime = 0 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
 | ||||
| // uuid.  It returns false if uuid is not valid.  The time is only well defined
 | ||||
| // for version 1 and 2 UUIDs.
 | ||||
| func (uuid UUID) Time() (Time, bool) { | ||||
| 	if len(uuid) != 16 { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	time := int64(binary.BigEndian.Uint32(uuid[0:4])) | ||||
| 	time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 | ||||
| 	time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 | ||||
| 	return Time(time), true | ||||
| } | ||||
| 
 | ||||
| // ClockSequence returns the clock sequence encoded in uuid.  It returns false
 | ||||
| // if uuid is not valid.  The clock sequence is only well defined for version 1
 | ||||
| // and 2 UUIDs.
 | ||||
| func (uuid UUID) ClockSequence() (int, bool) { | ||||
| 	if len(uuid) != 16 { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true | ||||
| } | ||||
|  | @ -1,43 +0,0 @@ | |||
| // Copyright 2011 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| import ( | ||||
| 	"io" | ||||
| ) | ||||
| 
 | ||||
| // randomBits completely fills slice b with random data.
 | ||||
| func randomBits(b []byte) { | ||||
| 	if _, err := io.ReadFull(rander, b); err != nil { | ||||
| 		panic(err.Error()) // rand should never fail
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // xvalues returns the value of a byte as a hexadecimal digit or 255.
 | ||||
| var xvalues = []byte{ | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| 	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, | ||||
| } | ||||
| 
 | ||||
| // xtob converts the the first two hex bytes of x into a byte.
 | ||||
| func xtob(x string) (byte, bool) { | ||||
| 	b1 := xvalues[x[0]] | ||||
| 	b2 := xvalues[x[1]] | ||||
| 	return (b1 << 4) | b2, b1 != 255 && b2 != 255 | ||||
| } | ||||
|  | @ -1,163 +0,0 @@ | |||
| // Copyright 2011 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/rand" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| // A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
 | ||||
| // 4122.
 | ||||
| type UUID []byte | ||||
| 
 | ||||
| // A Version represents a UUIDs version.
 | ||||
| type Version byte | ||||
| 
 | ||||
| // A Variant represents a UUIDs variant.
 | ||||
| type Variant byte | ||||
| 
 | ||||
| // Constants returned by Variant.
 | ||||
| const ( | ||||
| 	Invalid   = Variant(iota) // Invalid UUID
 | ||||
| 	RFC4122                   // The variant specified in RFC4122
 | ||||
| 	Reserved                  // Reserved, NCS backward compatibility.
 | ||||
| 	Microsoft                 // Reserved, Microsoft Corporation backward compatibility.
 | ||||
| 	Future                    // Reserved for future definition.
 | ||||
| ) | ||||
| 
 | ||||
| var rander = rand.Reader // random function
 | ||||
| 
 | ||||
| // New returns a new random (version 4) UUID as a string.  It is a convenience
 | ||||
| // function for NewRandom().String().
 | ||||
| func New() string { | ||||
| 	return NewRandom().String() | ||||
| } | ||||
| 
 | ||||
| // Parse decodes s into a UUID or returns nil.  Both the UUID form of
 | ||||
| // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
 | ||||
| // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded.
 | ||||
| func Parse(s string) UUID { | ||||
| 	if len(s) == 36+9 { | ||||
| 		if strings.ToLower(s[:9]) != "urn:uuid:" { | ||||
| 			return nil | ||||
| 		} | ||||
| 		s = s[9:] | ||||
| 	} else if len(s) != 36 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { | ||||
| 		return nil | ||||
| 	} | ||||
| 	uuid := make([]byte, 16) | ||||
| 	for i, x := range []int{ | ||||
| 		0, 2, 4, 6, | ||||
| 		9, 11, | ||||
| 		14, 16, | ||||
| 		19, 21, | ||||
| 		24, 26, 28, 30, 32, 34} { | ||||
| 		if v, ok := xtob(s[x:]); !ok { | ||||
| 			return nil | ||||
| 		} else { | ||||
| 			uuid[i] = v | ||||
| 		} | ||||
| 	} | ||||
| 	return uuid | ||||
| } | ||||
| 
 | ||||
| // Equal returns true if uuid1 and uuid2 are equal.
 | ||||
| func Equal(uuid1, uuid2 UUID) bool { | ||||
| 	return bytes.Equal(uuid1, uuid2) | ||||
| } | ||||
| 
 | ||||
| // String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
 | ||||
| // , or "" if uuid is invalid.
 | ||||
| func (uuid UUID) String() string { | ||||
| 	if uuid == nil || len(uuid) != 16 { | ||||
| 		return "" | ||||
| 	} | ||||
| 	b := []byte(uuid) | ||||
| 	return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", | ||||
| 		b[:4], b[4:6], b[6:8], b[8:10], b[10:]) | ||||
| } | ||||
| 
 | ||||
| // URN returns the RFC 2141 URN form of uuid,
 | ||||
| // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx,  or "" if uuid is invalid.
 | ||||
| func (uuid UUID) URN() string { | ||||
| 	if uuid == nil || len(uuid) != 16 { | ||||
| 		return "" | ||||
| 	} | ||||
| 	b := []byte(uuid) | ||||
| 	return fmt.Sprintf("urn:uuid:%08x-%04x-%04x-%04x-%012x", | ||||
| 		b[:4], b[4:6], b[6:8], b[8:10], b[10:]) | ||||
| } | ||||
| 
 | ||||
| // Variant returns the variant encoded in uuid.  It returns Invalid if
 | ||||
| // uuid is invalid.
 | ||||
| func (uuid UUID) Variant() Variant { | ||||
| 	if len(uuid) != 16 { | ||||
| 		return Invalid | ||||
| 	} | ||||
| 	switch { | ||||
| 	case (uuid[8] & 0xc0) == 0x80: | ||||
| 		return RFC4122 | ||||
| 	case (uuid[8] & 0xe0) == 0xc0: | ||||
| 		return Microsoft | ||||
| 	case (uuid[8] & 0xe0) == 0xe0: | ||||
| 		return Future | ||||
| 	default: | ||||
| 		return Reserved | ||||
| 	} | ||||
| 	panic("unreachable") | ||||
| } | ||||
| 
 | ||||
| // Version returns the verison of uuid.  It returns false if uuid is not
 | ||||
| // valid.
 | ||||
| func (uuid UUID) Version() (Version, bool) { | ||||
| 	if len(uuid) != 16 { | ||||
| 		return 0, false | ||||
| 	} | ||||
| 	return Version(uuid[6] >> 4), true | ||||
| } | ||||
| 
 | ||||
| func (v Version) String() string { | ||||
| 	if v > 15 { | ||||
| 		return fmt.Sprintf("BAD_VERSION_%d", v) | ||||
| 	} | ||||
| 	return fmt.Sprintf("VERSION_%d", v) | ||||
| } | ||||
| 
 | ||||
| func (v Variant) String() string { | ||||
| 	switch v { | ||||
| 	case RFC4122: | ||||
| 		return "RFC4122" | ||||
| 	case Reserved: | ||||
| 		return "Reserved" | ||||
| 	case Microsoft: | ||||
| 		return "Microsoft" | ||||
| 	case Future: | ||||
| 		return "Future" | ||||
| 	case Invalid: | ||||
| 		return "Invalid" | ||||
| 	} | ||||
| 	return fmt.Sprintf("BadVariant%d", int(v)) | ||||
| } | ||||
| 
 | ||||
| // SetRand sets the random number generator to r, which implents io.Reader.
 | ||||
| // If r.Read returns an error when the package requests random data then
 | ||||
| // a panic will be issued.
 | ||||
| //
 | ||||
| // Calling SetRand with nil sets the random number generator to the default
 | ||||
| // generator.
 | ||||
| func SetRand(r io.Reader) { | ||||
| 	if r == nil { | ||||
| 		rander = rand.Reader | ||||
| 		return | ||||
| 	} | ||||
| 	rander = r | ||||
| } | ||||
|  | @ -1,390 +0,0 @@ | |||
| // Copyright 2011 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| type test struct { | ||||
| 	in      string | ||||
| 	version Version | ||||
| 	variant Variant | ||||
| 	isuuid  bool | ||||
| } | ||||
| 
 | ||||
| var tests = []test{ | ||||
| 	{"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true}, | ||||
| 
 | ||||
| 	{"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, | ||||
| 	{"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, | ||||
| 	{"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true}, | ||||
| 	{"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true}, | ||||
| 	{"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true}, | ||||
| 	{"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true}, | ||||
| 	{"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true}, | ||||
| 	{"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true}, | ||||
| 	{"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true}, | ||||
| 	{"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true}, | ||||
| 	{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true}, | ||||
| 	{"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true}, | ||||
| 	{"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true}, | ||||
| 	{"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true}, | ||||
| 	{"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true}, | ||||
| 
 | ||||
| 	{"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false}, | ||||
| 	{"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false}, | ||||
| 	{"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false}, | ||||
| 	{"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false}, | ||||
| 	{"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false}, | ||||
| 	{"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false}, | ||||
| } | ||||
| 
 | ||||
| var constants = []struct { | ||||
| 	c    interface{} | ||||
| 	name string | ||||
| }{ | ||||
| 	{Person, "Person"}, | ||||
| 	{Group, "Group"}, | ||||
| 	{Org, "Org"}, | ||||
| 	{Invalid, "Invalid"}, | ||||
| 	{RFC4122, "RFC4122"}, | ||||
| 	{Reserved, "Reserved"}, | ||||
| 	{Microsoft, "Microsoft"}, | ||||
| 	{Future, "Future"}, | ||||
| 	{Domain(17), "Domain17"}, | ||||
| 	{Variant(42), "BadVariant42"}, | ||||
| } | ||||
| 
 | ||||
| func testTest(t *testing.T, in string, tt test) { | ||||
| 	uuid := Parse(in) | ||||
| 	if ok := (uuid != nil); ok != tt.isuuid { | ||||
| 		t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid) | ||||
| 	} | ||||
| 	if uuid == nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if v := uuid.Variant(); v != tt.variant { | ||||
| 		t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant) | ||||
| 	} | ||||
| 	if v, _ := uuid.Version(); v != tt.version { | ||||
| 		t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestUUID(t *testing.T) { | ||||
| 	for _, tt := range tests { | ||||
| 		testTest(t, tt.in, tt) | ||||
| 		testTest(t, strings.ToUpper(tt.in), tt) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestConstants(t *testing.T) { | ||||
| 	for x, tt := range constants { | ||||
| 		v, ok := tt.c.(fmt.Stringer) | ||||
| 		if !ok { | ||||
| 			t.Errorf("%x: %v: not a stringer", x, v) | ||||
| 		} else if s := v.String(); s != tt.name { | ||||
| 			v, _ := tt.c.(int) | ||||
| 			t.Errorf("%x: Constant %T:%d gives %q, expected %q\n", x, tt.c, v, s, tt.name) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestRandomUUID(t *testing.T) { | ||||
| 	m := make(map[string]bool) | ||||
| 	for x := 1; x < 32; x++ { | ||||
| 		uuid := NewRandom() | ||||
| 		s := uuid.String() | ||||
| 		if m[s] { | ||||
| 			t.Errorf("NewRandom returned duplicated UUID %s\n", s) | ||||
| 		} | ||||
| 		m[s] = true | ||||
| 		if v, _ := uuid.Version(); v != 4 { | ||||
| 			t.Errorf("Random UUID of version %s\n", v) | ||||
| 		} | ||||
| 		if uuid.Variant() != RFC4122 { | ||||
| 			t.Errorf("Random UUID is variant %d\n", uuid.Variant()) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestNew(t *testing.T) { | ||||
| 	m := make(map[string]bool) | ||||
| 	for x := 1; x < 32; x++ { | ||||
| 		s := New() | ||||
| 		if m[s] { | ||||
| 			t.Errorf("New returned duplicated UUID %s\n", s) | ||||
| 		} | ||||
| 		m[s] = true | ||||
| 		uuid := Parse(s) | ||||
| 		if uuid == nil { | ||||
| 			t.Errorf("New returned %q which does not decode\n", s) | ||||
| 			continue | ||||
| 		} | ||||
| 		if v, _ := uuid.Version(); v != 4 { | ||||
| 			t.Errorf("Random UUID of version %s\n", v) | ||||
| 		} | ||||
| 		if uuid.Variant() != RFC4122 { | ||||
| 			t.Errorf("Random UUID is variant %d\n", uuid.Variant()) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func clockSeq(t *testing.T, uuid UUID) int { | ||||
| 	seq, ok := uuid.ClockSequence() | ||||
| 	if !ok { | ||||
| 		t.Fatalf("%s: invalid clock sequence\n", uuid) | ||||
| 	} | ||||
| 	return seq | ||||
| } | ||||
| 
 | ||||
| func TestClockSeq(t *testing.T) { | ||||
| 	// Fake time.Now for this test to return a monotonically advancing time; restore it at end.
 | ||||
| 	defer func(orig func() time.Time) { timeNow = orig }(timeNow) | ||||
| 	monTime := time.Now() | ||||
| 	timeNow = func() time.Time { | ||||
| 		monTime = monTime.Add(1 * time.Second) | ||||
| 		return monTime | ||||
| 	} | ||||
| 
 | ||||
| 	SetClockSequence(-1) | ||||
| 	uuid1 := NewUUID() | ||||
| 	uuid2 := NewUUID() | ||||
| 
 | ||||
| 	if clockSeq(t, uuid1) != clockSeq(t, uuid2) { | ||||
| 		t.Errorf("clock sequence %d != %d\n", clockSeq(t, uuid1), clockSeq(t, uuid2)) | ||||
| 	} | ||||
| 
 | ||||
| 	SetClockSequence(-1) | ||||
| 	uuid2 = NewUUID() | ||||
| 
 | ||||
| 	// Just on the very off chance we generated the same sequence
 | ||||
| 	// two times we try again.
 | ||||
| 	if clockSeq(t, uuid1) == clockSeq(t, uuid2) { | ||||
| 		SetClockSequence(-1) | ||||
| 		uuid2 = NewUUID() | ||||
| 	} | ||||
| 	if clockSeq(t, uuid1) == clockSeq(t, uuid2) { | ||||
| 		t.Errorf("Duplicate clock sequence %d\n", clockSeq(t, uuid1)) | ||||
| 	} | ||||
| 
 | ||||
| 	SetClockSequence(0x1234) | ||||
| 	uuid1 = NewUUID() | ||||
| 	if seq := clockSeq(t, uuid1); seq != 0x1234 { | ||||
| 		t.Errorf("%s: expected seq 0x1234 got 0x%04x\n", uuid1, seq) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestCoding(t *testing.T) { | ||||
| 	text := "7d444840-9dc0-11d1-b245-5ffdce74fad2" | ||||
| 	urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2" | ||||
| 	data := UUID{ | ||||
| 		0x7d, 0x44, 0x48, 0x40, | ||||
| 		0x9d, 0xc0, | ||||
| 		0x11, 0xd1, | ||||
| 		0xb2, 0x45, | ||||
| 		0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2, | ||||
| 	} | ||||
| 	if v := data.String(); v != text { | ||||
| 		t.Errorf("%x: encoded to %s, expected %s\n", data, v, text) | ||||
| 	} | ||||
| 	if v := data.URN(); v != urn { | ||||
| 		t.Errorf("%x: urn is %s, expected %s\n", data, v, urn) | ||||
| 	} | ||||
| 
 | ||||
| 	uuid := Parse(text) | ||||
| 	if !Equal(uuid, data) { | ||||
| 		t.Errorf("%s: decoded to %s, expected %s\n", text, uuid, data) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestVersion1(t *testing.T) { | ||||
| 	uuid1 := NewUUID() | ||||
| 	uuid2 := NewUUID() | ||||
| 
 | ||||
| 	if Equal(uuid1, uuid2) { | ||||
| 		t.Errorf("%s:duplicate uuid\n", uuid1) | ||||
| 	} | ||||
| 	if v, _ := uuid1.Version(); v != 1 { | ||||
| 		t.Errorf("%s: version %s expected 1\n", uuid1, v) | ||||
| 	} | ||||
| 	if v, _ := uuid2.Version(); v != 1 { | ||||
| 		t.Errorf("%s: version %s expected 1\n", uuid2, v) | ||||
| 	} | ||||
| 	n1 := uuid1.NodeID() | ||||
| 	n2 := uuid2.NodeID() | ||||
| 	if !bytes.Equal(n1, n2) { | ||||
| 		t.Errorf("Different nodes %x != %x\n", n1, n2) | ||||
| 	} | ||||
| 	t1, ok := uuid1.Time() | ||||
| 	if !ok { | ||||
| 		t.Errorf("%s: invalid time\n", uuid1) | ||||
| 	} | ||||
| 	t2, ok := uuid2.Time() | ||||
| 	if !ok { | ||||
| 		t.Errorf("%s: invalid time\n", uuid2) | ||||
| 	} | ||||
| 	q1, ok := uuid1.ClockSequence() | ||||
| 	if !ok { | ||||
| 		t.Errorf("%s: invalid clock sequence\n", uuid1) | ||||
| 	} | ||||
| 	q2, ok := uuid2.ClockSequence() | ||||
| 	if !ok { | ||||
| 		t.Errorf("%s: invalid clock sequence", uuid2) | ||||
| 	} | ||||
| 
 | ||||
| 	switch { | ||||
| 	case t1 == t2 && q1 == q2: | ||||
| 		t.Errorf("time stopped\n") | ||||
| 	case t1 > t2 && q1 == q2: | ||||
| 		t.Errorf("time reversed\n") | ||||
| 	case t1 < t2 && q1 != q2: | ||||
| 		t.Errorf("clock sequence chaned unexpectedly\n") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestNodeAndTime(t *testing.T) { | ||||
| 	// Time is February 5, 1998 12:30:23.136364800 AM GMT
 | ||||
| 
 | ||||
| 	uuid := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2") | ||||
| 	node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2} | ||||
| 
 | ||||
| 	ts, ok := uuid.Time() | ||||
| 	if ok { | ||||
| 		c := time.Unix(ts.UnixTime()) | ||||
| 		want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC) | ||||
| 		if !c.Equal(want) { | ||||
| 			t.Errorf("Got time %v, want %v", c, want) | ||||
| 		} | ||||
| 	} else { | ||||
| 		t.Errorf("%s: bad time\n", uuid) | ||||
| 	} | ||||
| 	if !bytes.Equal(node, uuid.NodeID()) { | ||||
| 		t.Errorf("Expected node %v got %v\n", node, uuid.NodeID()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestMD5(t *testing.T) { | ||||
| 	uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String() | ||||
| 	want := "6fa459ea-ee8a-3ca4-894e-db77e160355e" | ||||
| 	if uuid != want { | ||||
| 		t.Errorf("MD5: got %q expected %q\n", uuid, want) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestSHA1(t *testing.T) { | ||||
| 	uuid := NewSHA1(NameSpace_DNS, []byte("python.org")).String() | ||||
| 	want := "886313e1-3b8a-5372-9b90-0c9aee199e5d" | ||||
| 	if uuid != want { | ||||
| 		t.Errorf("SHA1: got %q expected %q\n", uuid, want) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestNodeID(t *testing.T) { | ||||
| 	nid := []byte{1, 2, 3, 4, 5, 6} | ||||
| 	SetNodeInterface("") | ||||
| 	s := NodeInterface() | ||||
| 	if s == "" || s == "user" { | ||||
| 		t.Errorf("NodeInterface %q after SetInteface\n", s) | ||||
| 	} | ||||
| 	node1 := NodeID() | ||||
| 	if node1 == nil { | ||||
| 		t.Errorf("NodeID nil after SetNodeInterface\n", s) | ||||
| 	} | ||||
| 	SetNodeID(nid) | ||||
| 	s = NodeInterface() | ||||
| 	if s != "user" { | ||||
| 		t.Errorf("Expected NodeInterface %q got %q\n", "user", s) | ||||
| 	} | ||||
| 	node2 := NodeID() | ||||
| 	if node2 == nil { | ||||
| 		t.Errorf("NodeID nil after SetNodeID\n", s) | ||||
| 	} | ||||
| 	if bytes.Equal(node1, node2) { | ||||
| 		t.Errorf("NodeID not changed after SetNodeID\n", s) | ||||
| 	} else if !bytes.Equal(nid, node2) { | ||||
| 		t.Errorf("NodeID is %x, expected %x\n", node2, nid) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) { | ||||
| 	if uuid == nil { | ||||
| 		t.Errorf("%s failed\n", name) | ||||
| 		return | ||||
| 	} | ||||
| 	if v, _ := uuid.Version(); v != 2 { | ||||
| 		t.Errorf("%s: %s: expected version 2, got %s\n", name, uuid, v) | ||||
| 		return | ||||
| 	} | ||||
| 	if v, ok := uuid.Domain(); !ok || v != domain { | ||||
| 		if !ok { | ||||
| 			t.Errorf("%s: %d: Domain failed\n", name, uuid) | ||||
| 		} else { | ||||
| 			t.Errorf("%s: %s: expected domain %d, got %d\n", name, uuid, domain, v) | ||||
| 		} | ||||
| 	} | ||||
| 	if v, ok := uuid.Id(); !ok || v != id { | ||||
| 		if !ok { | ||||
| 			t.Errorf("%s: %d: Id failed\n", name, uuid) | ||||
| 		} else { | ||||
| 			t.Errorf("%s: %s: expected id %d, got %d\n", name, uuid, id, v) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestDCE(t *testing.T) { | ||||
| 	testDCE(t, "NewDCESecurity", NewDCESecurity(42, 12345678), 42, 12345678) | ||||
| 	testDCE(t, "NewDCEPerson", NewDCEPerson(), Person, uint32(os.Getuid())) | ||||
| 	testDCE(t, "NewDCEGroup", NewDCEGroup(), Group, uint32(os.Getgid())) | ||||
| } | ||||
| 
 | ||||
| type badRand struct{} | ||||
| 
 | ||||
| func (r badRand) Read(buf []byte) (int, error) { | ||||
| 	for i, _ := range buf { | ||||
| 		buf[i] = byte(i) | ||||
| 	} | ||||
| 	return len(buf), nil | ||||
| } | ||||
| 
 | ||||
| func TestBadRand(t *testing.T) { | ||||
| 	SetRand(badRand{}) | ||||
| 	uuid1 := New() | ||||
| 	uuid2 := New() | ||||
| 	if uuid1 != uuid2 { | ||||
| 		t.Errorf("execpted duplicates, got %q and %q\n", uuid1, uuid2) | ||||
| 	} | ||||
| 	SetRand(nil) | ||||
| 	uuid1 = New() | ||||
| 	uuid2 = New() | ||||
| 	if uuid1 == uuid2 { | ||||
| 		t.Errorf("unexecpted duplicates, got %q\n", uuid1) | ||||
| 	} | ||||
| } | ||||
|  | @ -1,41 +0,0 @@ | |||
| // Copyright 2011 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/binary" | ||||
| ) | ||||
| 
 | ||||
| // NewUUID returns a Version 1 UUID based on the current NodeID and clock
 | ||||
| // sequence, and the current time.  If the NodeID has not been set by SetNodeID
 | ||||
| // or SetNodeInterface then it will be set automatically.  If the NodeID cannot
 | ||||
| // be set NewUUID returns nil.  If clock sequence has not been set by
 | ||||
| // SetClockSequence then it will be set automatically.  If GetTime fails to
 | ||||
| // return the current NewUUID returns nil.
 | ||||
| func NewUUID() UUID { | ||||
| 	if nodeID == nil { | ||||
| 		SetNodeInterface("") | ||||
| 	} | ||||
| 
 | ||||
| 	now, seq, err := GetTime() | ||||
| 	if err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	uuid := make([]byte, 16) | ||||
| 
 | ||||
| 	time_low := uint32(now & 0xffffffff) | ||||
| 	time_mid := uint16((now >> 32) & 0xffff) | ||||
| 	time_hi := uint16((now >> 48) & 0x0fff) | ||||
| 	time_hi |= 0x1000 // Version 1
 | ||||
| 
 | ||||
| 	binary.BigEndian.PutUint32(uuid[0:], time_low) | ||||
| 	binary.BigEndian.PutUint16(uuid[4:], time_mid) | ||||
| 	binary.BigEndian.PutUint16(uuid[6:], time_hi) | ||||
| 	binary.BigEndian.PutUint16(uuid[8:], seq) | ||||
| 	copy(uuid[10:], nodeID) | ||||
| 
 | ||||
| 	return uuid | ||||
| } | ||||
|  | @ -1,25 +0,0 @@ | |||
| // Copyright 2011 Google Inc.  All rights reserved.
 | ||||
| // Use of this source code is governed by a BSD-style
 | ||||
| // license that can be found in the LICENSE file.
 | ||||
| 
 | ||||
| package uuid | ||||
| 
 | ||||
| // Random returns a Random (Version 4) UUID or panics.
 | ||||
| //
 | ||||
| // The strength of the UUIDs is based on the strength of the crypto/rand
 | ||||
| // package.
 | ||||
| //
 | ||||
| // A note about uniqueness derived from from the UUID Wikipedia entry:
 | ||||
| //
 | ||||
| //  Randomly generated UUIDs have 122 random bits.  One's annual risk of being
 | ||||
| //  hit by a meteorite is estimated to be one chance in 17 billion, that
 | ||||
| //  means the probability is about 0.00000000006 (6 × 10−11),
 | ||||
| //  equivalent to the odds of creating a few tens of trillions of UUIDs in a
 | ||||
| //  year and having one duplicate.
 | ||||
| func NewRandom() UUID { | ||||
| 	uuid := make([]byte, 16) | ||||
| 	randomBits([]byte(uuid)) | ||||
| 	uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
 | ||||
| 	uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
 | ||||
| 	return uuid | ||||
| } | ||||
|  | @ -1,7 +1,7 @@ | |||
| package context | ||||
| 
 | ||||
| import ( | ||||
| 	"code.google.com/p/go-uuid/uuid" | ||||
| 	"github.com/docker/distribution/uuid" | ||||
| 	"golang.org/x/net/context" | ||||
| ) | ||||
| 
 | ||||
|  | @ -27,7 +27,7 @@ func (ic *instanceContext) Value(key interface{}) interface{} { | |||
| 
 | ||||
| var background = &instanceContext{ | ||||
| 	Context: context.Background(), | ||||
| 	id:      uuid.New(), | ||||
| 	id:      uuid.Generate().String(), | ||||
| } | ||||
| 
 | ||||
| // Background returns a non-nil, empty Context. The background context
 | ||||
|  |  | |||
|  | @ -8,8 +8,8 @@ import ( | |||
| 	"sync" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"code.google.com/p/go-uuid/uuid" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/docker/distribution/uuid" | ||||
| 	"github.com/gorilla/mux" | ||||
| ) | ||||
| 
 | ||||
|  | @ -79,7 +79,7 @@ func WithRequest(ctx Context, r *http.Request) Context { | |||
| 	return &httpRequestContext{ | ||||
| 		Context:   ctx, | ||||
| 		startedAt: time.Now(), | ||||
| 		id:        uuid.New(), // assign the request a unique.
 | ||||
| 		id:        uuid.Generate().String(), | ||||
| 		r:         r, | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ package context | |||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/docker/distribution/uuid" | ||||
| 
 | ||||
| 	"github.com/Sirupsen/logrus" | ||||
| ) | ||||
| 
 | ||||
|  | @ -99,3 +101,8 @@ func getLogrusLogger(ctx Context, keys ...interface{}) *logrus.Entry { | |||
| 
 | ||||
| 	return logger.WithFields(fields) | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	// inject a logger into the uuid library.
 | ||||
| 	uuid.Loggerf = GetLogger(Background()).Warnf | ||||
| } | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ import ( | |||
| 	"runtime" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"code.google.com/p/go-uuid/uuid" | ||||
| 	"github.com/docker/distribution/uuid" | ||||
| ) | ||||
| 
 | ||||
| // WithTrace allocates a traced timing span in a new context. This allows a
 | ||||
|  | @ -45,7 +45,7 @@ func WithTrace(ctx Context) (Context, func(format string, a ...interface{})) { | |||
| 	f := runtime.FuncForPC(pc) | ||||
| 	ctx = &traced{ | ||||
| 		Context: ctx, | ||||
| 		id:      uuid.New(), | ||||
| 		id:      uuid.Generate().String(), | ||||
| 		start:   time.Now(), | ||||
| 		parent:  GetStringValue(ctx, "trace.id"), | ||||
| 		fnname:  f.Name(), | ||||
|  |  | |||
|  | @ -4,11 +4,11 @@ import ( | |||
| 	"net/http" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"code.google.com/p/go-uuid/uuid" | ||||
| 	"github.com/docker/distribution" | ||||
| 	"github.com/docker/distribution/context" | ||||
| 	"github.com/docker/distribution/digest" | ||||
| 	"github.com/docker/distribution/manifest" | ||||
| 	"github.com/docker/distribution/uuid" | ||||
| ) | ||||
| 
 | ||||
| type bridge struct { | ||||
|  | @ -149,7 +149,7 @@ func (b *bridge) createEvent(action string) *Event { | |||
| // createEvent returns a new event, timestamped, with the specified action.
 | ||||
| func createEvent(action string) *Event { | ||||
| 	return &Event{ | ||||
| 		ID:        uuid.New(), | ||||
| 		ID:        uuid.Generate().String(), | ||||
| 		Timestamp: time.Now(), | ||||
| 		Action:    action, | ||||
| 	} | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ import ( | |||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"code.google.com/p/go-uuid/uuid" | ||||
| 	"github.com/docker/distribution/uuid" | ||||
| 
 | ||||
| 	"github.com/docker/distribution" | ||||
| 	"github.com/docker/distribution/context" | ||||
|  | @ -141,7 +141,7 @@ func TestBlobUploadChunked(t *testing.T) { | |||
| 		b1[513:1024], | ||||
| 	} | ||||
| 	repo := "test.example.com/uploadrepo" | ||||
| 	uuids := []string{uuid.New()} | ||||
| 	uuids := []string{uuid.Generate().String()} | ||||
| 	m = append(m, testutil.RequestResponseMapping{ | ||||
| 		Request: testutil.Request{ | ||||
| 			Method: "POST", | ||||
|  | @ -159,7 +159,7 @@ func TestBlobUploadChunked(t *testing.T) { | |||
| 	}) | ||||
| 	offset := 0 | ||||
| 	for i, chunk := range chunks { | ||||
| 		uuids = append(uuids, uuid.New()) | ||||
| 		uuids = append(uuids, uuid.Generate().String()) | ||||
| 		newOffset := offset + len(chunk) | ||||
| 		m = append(m, testutil.RequestResponseMapping{ | ||||
| 			Request: testutil.Request{ | ||||
|  | @ -256,7 +256,7 @@ func TestBlobUploadMonolithic(t *testing.T) { | |||
| 	dgst, b1 := newRandomBlob(1024) | ||||
| 	var m testutil.RequestResponseMap | ||||
| 	repo := "test.example.com/uploadrepo" | ||||
| 	uploadID := uuid.New() | ||||
| 	uploadID := uuid.Generate().String() | ||||
| 	m = append(m, testutil.RequestResponseMapping{ | ||||
| 		Request: testutil.Request{ | ||||
| 			Method: "POST", | ||||
|  |  | |||
|  | @ -4,11 +4,11 @@ import ( | |||
| 	"net/http" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"code.google.com/p/go-uuid/uuid" | ||||
| 	"github.com/docker/distribution" | ||||
| 	"github.com/docker/distribution/context" | ||||
| 	"github.com/docker/distribution/digest" | ||||
| 	"github.com/docker/distribution/registry/storage/driver" | ||||
| 	"github.com/docker/distribution/uuid" | ||||
| ) | ||||
| 
 | ||||
| // linkedBlobStore provides a full BlobService that namespaces the blobs to a
 | ||||
|  | @ -85,7 +85,7 @@ func (lbs *linkedBlobStore) Put(ctx context.Context, mediaType string, p []byte) | |||
| func (lbs *linkedBlobStore) Create(ctx context.Context) (distribution.BlobWriter, error) { | ||||
| 	context.GetLogger(ctx).Debug("(*linkedBlobStore).Writer") | ||||
| 
 | ||||
| 	uuid := uuid.New() | ||||
| 	uuid := uuid.Generate().String() | ||||
| 	startedAt := time.Now().UTC() | ||||
| 
 | ||||
| 	path, err := lbs.blobStore.pm.path(uploadDataPathSpec{ | ||||
|  |  | |||
|  | @ -5,10 +5,10 @@ import ( | |||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"code.google.com/p/go-uuid/uuid" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/docker/distribution/context" | ||||
| 	storageDriver "github.com/docker/distribution/registry/storage/driver" | ||||
| 	"github.com/docker/distribution/uuid" | ||||
| ) | ||||
| 
 | ||||
| // uploadData stored the location of temporary files created during a layer upload
 | ||||
|  | @ -116,8 +116,8 @@ func getOutstandingUploads(ctx context.Context, driver storageDriver.StorageDriv | |||
| func uUIDFromPath(path string) (string, bool) { | ||||
| 	components := strings.Split(path, "/") | ||||
| 	for i := len(components) - 1; i >= 0; i-- { | ||||
| 		if uuid := uuid.Parse(components[i]); uuid != nil { | ||||
| 			return uuid.String(), i == len(components)-1 | ||||
| 		if u, err := uuid.Parse(components[i]); err == nil { | ||||
| 			return u.String(), i == len(components)-1 | ||||
| 		} | ||||
| 	} | ||||
| 	return "", false | ||||
|  |  | |||
|  | @ -6,10 +6,10 @@ import ( | |||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"code.google.com/p/go-uuid/uuid" | ||||
| 	"github.com/docker/distribution/context" | ||||
| 	"github.com/docker/distribution/registry/storage/driver" | ||||
| 	"github.com/docker/distribution/registry/storage/driver/inmemory" | ||||
| 	"github.com/docker/distribution/uuid" | ||||
| ) | ||||
| 
 | ||||
| var pm = defaultPathMapper | ||||
|  | @ -18,7 +18,7 @@ func testUploadFS(t *testing.T, numUploads int, repoName string, startedAt time. | |||
| 	d := inmemory.New() | ||||
| 	ctx := context.Background() | ||||
| 	for i := 0; i < numUploads; i++ { | ||||
| 		addUploads(ctx, t, d, uuid.New(), repoName, startedAt) | ||||
| 		addUploads(ctx, t, d, uuid.Generate().String(), repoName, startedAt) | ||||
| 	} | ||||
| 	return d, ctx | ||||
| } | ||||
|  | @ -73,7 +73,7 @@ func TestPurgeAll(t *testing.T) { | |||
| 	fs, ctx := testUploadFS(t, uploadCount, "test-repo", oneHourAgo) | ||||
| 
 | ||||
| 	// Ensure > 1 repos are purged
 | ||||
| 	addUploads(ctx, t, fs, uuid.New(), "test-repo2", oneHourAgo) | ||||
| 	addUploads(ctx, t, fs, uuid.Generate().String(), "test-repo2", oneHourAgo) | ||||
| 	uploadCount++ | ||||
| 
 | ||||
| 	deleted, errs := PurgeUploads(ctx, fs, time.Now(), true) | ||||
|  | @ -95,7 +95,7 @@ func TestPurgeSome(t *testing.T) { | |||
| 	newUploadCount := 4 | ||||
| 
 | ||||
| 	for i := 0; i < newUploadCount; i++ { | ||||
| 		addUploads(ctx, t, fs, uuid.New(), "test-repo", time.Now().Add(1*time.Hour)) | ||||
| 		addUploads(ctx, t, fs, uuid.Generate().String(), "test-repo", time.Now().Add(1*time.Hour)) | ||||
| 	} | ||||
| 
 | ||||
| 	deleted, errs := PurgeUploads(ctx, fs, time.Now(), true) | ||||
|  | @ -115,7 +115,7 @@ func TestPurgeOnlyUploads(t *testing.T) { | |||
| 
 | ||||
| 	// Create a directory tree outside _uploads and ensure
 | ||||
| 	// these files aren't deleted.
 | ||||
| 	dataPath, err := pm.path(uploadDataPathSpec{name: "test-repo", id: uuid.New()}) | ||||
| 	dataPath, err := pm.path(uploadDataPathSpec{name: "test-repo", id: uuid.Generate().String()}) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf(err.Error()) | ||||
| 	} | ||||
|  |  | |||
|  | @ -0,0 +1,112 @@ | |||
| // Package uuid provides simple UUID generation. Only version 4 style UUIDs
 | ||||
| // can be generated.
 | ||||
| //
 | ||||
| // Please see http://tools.ietf.org/html/rfc4122 for details on UUIDs.
 | ||||
| package uuid | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/rand" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	// Bits is the number of bits in a UUID
 | ||||
| 	Bits = 128 | ||||
| 
 | ||||
| 	// Size is the number of bytes in a UUID
 | ||||
| 	Size = Bits / 8 | ||||
| 
 | ||||
| 	format = "%08x-%04x-%04x-%04x-%012x" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	// ErrUUIDInvalid indicates a parsed string is not a valid uuid.
 | ||||
| 	ErrUUIDInvalid = fmt.Errorf("invalid uuid") | ||||
| 
 | ||||
| 	// Loggerf can be used to override the default logging destination. Such
 | ||||
| 	// log messages in this library should be logged at warning or higher.
 | ||||
| 	Loggerf = log.Printf | ||||
| ) | ||||
| 
 | ||||
| // UUID represents a UUID value. UUIDs can be compared and set to other values
 | ||||
| // and accessed by byte.
 | ||||
| type UUID [Size]byte | ||||
| 
 | ||||
| // Generate creates a new, version 4 uuid.
 | ||||
| func Generate() (u UUID) { | ||||
| 	const ( | ||||
| 		// ensures we backoff for less than 450ms total. Use the following to
 | ||||
| 		// select new value, in units of 10ms:
 | ||||
| 		// 	n*(n+1)/2 = d -> n^2 + n - 2d -> n = (sqrt(8d + 1) - 1)/2
 | ||||
| 		maxretries = 9 | ||||
| 		backoff    = time.Millisecond * 10 | ||||
| 	) | ||||
| 
 | ||||
| 	var ( | ||||
| 		totalBackoff time.Duration | ||||
| 		retries      int | ||||
| 	) | ||||
| 
 | ||||
| 	for { | ||||
| 		// This should never block but the read may fail. Because of this,
 | ||||
| 		// we just try to read the random number generator until we get
 | ||||
| 		// something. This is a very rare condition but may happen.
 | ||||
| 		b := time.Duration(retries) * backoff | ||||
| 		time.Sleep(b) | ||||
| 		totalBackoff += b | ||||
| 
 | ||||
| 		_, err := io.ReadFull(rand.Reader, u[:]) | ||||
| 		if err != nil { | ||||
| 			if err == syscall.EPERM { | ||||
| 				// EPERM represents an entropy pool exhaustion, a condition under
 | ||||
| 				// which we backoff and retry.
 | ||||
| 				if retries < maxretries { | ||||
| 					retries++ | ||||
| 					Loggerf("error generating version 4 uuid, retrying: %v", err) | ||||
| 					continue | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Any other errors represent a system problem. What did someone
 | ||||
| 			// do to /dev/urandom?
 | ||||
| 			panic(fmt.Errorf("error reading random number generator, retried for %v: %v", totalBackoff, err)) | ||||
| 		} | ||||
| 
 | ||||
| 		break | ||||
| 	} | ||||
| 
 | ||||
| 	u[6] = (u[6] & 0x0f) | 0x40 // set version byte
 | ||||
| 	u[8] = (u[8] & 0x3f) | 0x80 // set high order byte 0b10{8,9,a,b}
 | ||||
| 
 | ||||
| 	return u | ||||
| } | ||||
| 
 | ||||
| // Parse attempts to extract a uuid from the string or returns an error.
 | ||||
| func Parse(s string) (u UUID, err error) { | ||||
| 	if len(s) != 36 { | ||||
| 		return UUID{}, ErrUUIDInvalid | ||||
| 	} | ||||
| 
 | ||||
| 	// create stack addresses for each section of the uuid.
 | ||||
| 	p := make([][]byte, 5) | ||||
| 
 | ||||
| 	if _, err := fmt.Sscanf(s, format, &p[0], &p[1], &p[2], &p[3], &p[4]); err != nil { | ||||
| 		return u, err | ||||
| 	} | ||||
| 
 | ||||
| 	copy(u[0:4], p[0]) | ||||
| 	copy(u[4:6], p[1]) | ||||
| 	copy(u[6:8], p[2]) | ||||
| 	copy(u[8:10], p[3]) | ||||
| 	copy(u[10:16], p[4]) | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func (u UUID) String() string { | ||||
| 	return fmt.Sprintf(format, u[:4], u[4:6], u[6:8], u[8:10], u[10:]) | ||||
| } | ||||
|  | @ -0,0 +1,48 @@ | |||
| package uuid | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| const iterations = 1000 | ||||
| 
 | ||||
| func TestUUID4Generation(t *testing.T) { | ||||
| 	for i := 0; i < iterations; i++ { | ||||
| 		u := Generate() | ||||
| 
 | ||||
| 		if u[6]&0xf0 != 0x40 { | ||||
| 			t.Fatalf("version byte not correctly set: %v, %08b %08b", u, u[6], u[6]&0xf0) | ||||
| 		} | ||||
| 
 | ||||
| 		if u[8]&0xc0 != 0x80 { | ||||
| 			t.Fatalf("top order 8th byte not correctly set: %v, %b", u, u[8]) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestParseAndEquality(t *testing.T) { | ||||
| 	for i := 0; i < iterations; i++ { | ||||
| 		u := Generate() | ||||
| 
 | ||||
| 		parsed, err := Parse(u.String()) | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("error parsing uuid %v: %v", u, err) | ||||
| 		} | ||||
| 
 | ||||
| 		if parsed != u { | ||||
| 			t.Fatalf("parsing round trip failed: %v != %v", parsed, u) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for _, c := range []string{ | ||||
| 		"bad", | ||||
| 		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",    // correct length, incorrect format
 | ||||
| 		"  20cc7775-2671-43c7-8742-51d1cfa23258",  // leading space
 | ||||
| 		"20cc7775-2671-43c7-8742-51d1cfa23258   ", // trailing space
 | ||||
| 		"00000000-0000-0000-0000-x00000000000   ", // out of range character
 | ||||
| 	} { | ||||
| 		if _, err := Parse(c); err == nil { | ||||
| 			t.Fatalf("parsing %q should have failed", c) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in New Issue