uuid 2.2.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/README.rdoc +24 -5
- data/Rakefile +0 -18
- data/bin/uuid +55 -0
- data/lib/uuid.rb +129 -2
- data/uuid.gemspec +3 -1
- metadata +29 -13
data/CHANGELOG
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
2.3.0 (2010-04-07)
|
2
|
+
* Added: UUID.generator returns the current UUID generator. Particularly useful for calling
|
3
|
+
next_sequence on the generator when forking a process.
|
4
|
+
* Added: UUID::Server and UUID::Client so you can have one process serving you UUIDs.
|
5
|
+
* Added: UUID command line tool. Yay!
|
6
|
+
|
1
7
|
2.2.0 (2010-02-18)
|
2
8
|
* Added: set UUID.state_file = false if you cannot use a state file (e.g. shared hosting environment)
|
3
9
|
|
data/README.rdoc
CHANGED
@@ -76,15 +76,34 @@ Engine) you can simple turn it off:
|
|
76
76
|
|
77
77
|
State files are not portable across machines.
|
78
78
|
|
79
|
+
Note: when using a forking server (Unicorn, Resque, Pipemaster, etc) you don't
|
80
|
+
want your forked processes using the same sequence number. Make sure to
|
81
|
+
increment the sequence number each time a worker forks.
|
79
82
|
|
80
|
-
|
83
|
+
For example, in config/unicorn.rb:
|
84
|
+
|
85
|
+
after_fork do |server, worker|
|
86
|
+
UUID.generator.next_sequence
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
== Command Line
|
91
|
+
|
92
|
+
You can run uuid from the command line, generating new UUID to stdout:
|
81
93
|
|
82
|
-
|
94
|
+
$ uuid
|
83
95
|
|
84
|
-
|
96
|
+
Multiple UUIDs in a sequence, separated with a newline:
|
85
97
|
|
86
|
-
|
87
|
-
|
98
|
+
$ uuid --count 10
|
99
|
+
|
100
|
+
You can also run client and server from the command line
|
101
|
+
|
102
|
+
$ uuid --server &
|
103
|
+
$ uuid --socket /var/lib/uuid.sock
|
104
|
+
|
105
|
+
|
106
|
+
== Latest and Greatest
|
88
107
|
|
89
108
|
Source code and documentation hosted on Github: http://github.com/assaf/uuid
|
90
109
|
|
data/Rakefile
CHANGED
@@ -8,24 +8,6 @@ desc "Default Task"
|
|
8
8
|
task :default => :test
|
9
9
|
|
10
10
|
|
11
|
-
desc "If you're building from sources, run this task first to setup the necessary dependencies"
|
12
|
-
task 'setup' do
|
13
|
-
missing = spec.dependencies.select { |dep| Gem::SourceIndex.from_installed_gems.search(dep).empty? }
|
14
|
-
missing.each do |dep|
|
15
|
-
if Gem::SourceIndex.from_installed_gems.search(dep).empty?
|
16
|
-
puts "Installing #{dep.name} ..."
|
17
|
-
rb_bin = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
|
18
|
-
args = []
|
19
|
-
args << rb_bin << '-S' << 'gem' << 'install' << dep.name
|
20
|
-
args << '--version' << dep.version_requirements.to_s
|
21
|
-
args << '--source' << 'http://gems.rubyforge.org'
|
22
|
-
args << '--install-dir' << ENV['GEM_HOME'] if ENV['GEM_HOME']
|
23
|
-
sh *args
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
11
|
desc "Run all test cases"
|
30
12
|
Rake::TestTask.new do |test|
|
31
13
|
test.verbose = true
|
data/bin/uuid
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "uuid"
|
3
|
+
require "optparse"
|
4
|
+
|
5
|
+
address = nil
|
6
|
+
count = 1
|
7
|
+
format = :default
|
8
|
+
server = false
|
9
|
+
|
10
|
+
opts = OptionParser.new("", 24, ' ') do |opts|
|
11
|
+
opts.banner = "Usage: #{File.basename($0)} [options]"
|
12
|
+
|
13
|
+
opts.separator "\nOptions:"
|
14
|
+
opts.on("-s", "--socket {HOST:PORT|PATH}",
|
15
|
+
"communicate on HOST:PORT or PATH (default: #{UUID::SOCKET_NAME})") do |value|
|
16
|
+
address = value
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.on("-S", "--server", "run as a server") do |value|
|
20
|
+
server = value ? true : false
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on("-F", "--format {FORMAT}", "UUID format (client only)") do |value|
|
24
|
+
format = value.to_sym
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-C", "--count {COUNT}", "returns give number of UUIDs") do |value|
|
28
|
+
count = value.to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("-h", "--help", "Show this message") do
|
32
|
+
puts opts.to_s.gsub(/^.*DEPRECATED.*$/s, '')
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.on("-v", "--version", "Show version") do
|
37
|
+
puts "UUID v#{UUID::VERSION}"
|
38
|
+
exit
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.parse! ARGV
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
if server
|
46
|
+
$stdout << "Starting UUID server on #{address}\n"
|
47
|
+
UUID::Server.new.listen(address || UUID::SOCKET_NAME)
|
48
|
+
else
|
49
|
+
UUID.server = address if address
|
50
|
+
$stdout << UUID.generate(format)
|
51
|
+
(count - 1).times do
|
52
|
+
$stdout.putc "\n"
|
53
|
+
$stdout << UUID.generate(format)
|
54
|
+
end
|
55
|
+
end
|
data/lib/uuid.rb
CHANGED
@@ -9,8 +9,7 @@
|
|
9
9
|
require 'fileutils'
|
10
10
|
require 'thread'
|
11
11
|
require 'tmpdir'
|
12
|
-
|
13
|
-
require 'rubygems'
|
12
|
+
require 'socket'
|
14
13
|
require 'macaddr'
|
15
14
|
|
16
15
|
|
@@ -122,6 +121,24 @@ class UUID
|
|
122
121
|
@uuid.generate format
|
123
122
|
end
|
124
123
|
|
124
|
+
##
|
125
|
+
# Returns the UUID generator used by generate. Useful if you need to mess
|
126
|
+
# with it, e.g. force next sequence when forking (e.g. Unicorn, Resque):
|
127
|
+
#
|
128
|
+
# after_fork do
|
129
|
+
# UUID.generator.next_sequence
|
130
|
+
# end
|
131
|
+
def self.generator
|
132
|
+
@uuid ||= new
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# Call this to use a UUID Server. Expects address to bind to (SOCKET_NAME is
|
137
|
+
# a good default)
|
138
|
+
def self.server=(address)
|
139
|
+
@uuid = Client.new(address) unless Client === @uuid
|
140
|
+
end
|
141
|
+
|
125
142
|
##
|
126
143
|
# Creates an empty state file in /var/tmp/ruby-uuid or the windows common
|
127
144
|
# application data directory using mode 0644. Call with a different mode
|
@@ -313,4 +330,114 @@ protected
|
|
313
330
|
io.write [mac1, mac2, @sequence, @last_clock].pack(STATE_FILE_FORMAT)
|
314
331
|
end
|
315
332
|
|
333
|
+
|
334
|
+
# You don't have to use this, it's just a good default.
|
335
|
+
SOCKET_NAME ="/var/lib/uuid.sock"
|
336
|
+
|
337
|
+
# With UUID server you don't have to worry about multiple processes
|
338
|
+
# synchronizing over the state file, calling next_sequence when forking a
|
339
|
+
# process and other things you're probably not worried about (because
|
340
|
+
# statistically they're very unlikely to break your code).
|
341
|
+
#
|
342
|
+
# But if you are worried about and thought to yourself, "what would a simple
|
343
|
+
# UUID server look like?", here's the answer. The protocol is dead simple:
|
344
|
+
# client sends a byte, server responds with a UUID. Can use TCP or domain
|
345
|
+
# sockets.
|
346
|
+
class Server
|
347
|
+
|
348
|
+
# Create new server. Nothing interesting happens until you call listen.
|
349
|
+
def initialize()
|
350
|
+
@generator = UUID.new
|
351
|
+
end
|
352
|
+
|
353
|
+
# Start the server listening on the specific address. Blocks and never
|
354
|
+
# returns. Address can be:
|
355
|
+
# - A Socket object
|
356
|
+
# - UNIX domain socket name (e.g. /var/run/uuid.sock, must start with /)
|
357
|
+
# - IP address, colon, port (e.g. localhost:1337)
|
358
|
+
def listen(address)
|
359
|
+
sock = bind(address)
|
360
|
+
while client = sock.accept
|
361
|
+
Thread.start(client) do |client|
|
362
|
+
while client.read 1
|
363
|
+
client.write @generator.generate
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
# Returns UNIXServer or TCPServer from address. Returns argument if not a
|
370
|
+
# string, so can pass through (see #listen).
|
371
|
+
def bind(address)
|
372
|
+
return address unless String === address
|
373
|
+
if address[0] == ?/
|
374
|
+
if File.exist?(address)
|
375
|
+
raise ArgumentError, "#{address} is not a socket" unless File.socket?(address)
|
376
|
+
File.unlink(address)
|
377
|
+
end
|
378
|
+
sock = UNIXServer.new(address)
|
379
|
+
File.chmod 0666, address
|
380
|
+
elsif address =~ /^(\d+\.\d+\.\d+\.\d+):(\d+)$/
|
381
|
+
sock = TCPServer.new($1, $2.to_i)
|
382
|
+
else
|
383
|
+
raise ArgumentError, "Don't know how to bind #{address}"
|
384
|
+
end
|
385
|
+
sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1) if defined?(TCP_NODELAY)
|
386
|
+
sock
|
387
|
+
end
|
388
|
+
|
389
|
+
end
|
390
|
+
|
391
|
+
|
392
|
+
# Every server needs a client. Client provides you with the single ultimate
|
393
|
+
# method: #generate. Typically you'll use this instead of the local UUID
|
394
|
+
# generator:
|
395
|
+
# UUID.server = UUID::SOCKET_NAME
|
396
|
+
class Client
|
397
|
+
|
398
|
+
def initialize(address)
|
399
|
+
@socket = connect(address)
|
400
|
+
at_exit { close }
|
401
|
+
end
|
402
|
+
|
403
|
+
# Talks to server and returns new UUID in specified format.
|
404
|
+
def generate(format = :default)
|
405
|
+
@socket.write "\0"
|
406
|
+
uuid = @socket.read(36)
|
407
|
+
return uuid if format == :default
|
408
|
+
template = FORMATS[format]
|
409
|
+
raise ArgumentError, "invalid UUID format #{format.inspect}" unless template
|
410
|
+
template % uuid.split("-").map { |p| p.to_i(16) }
|
411
|
+
end
|
412
|
+
|
413
|
+
# Returns UNIXSocket or TCPSocket from address. Returns argument if not a
|
414
|
+
# string, so can pass through.
|
415
|
+
def connect(address)
|
416
|
+
return address unless String === address
|
417
|
+
if address[0] == ?/
|
418
|
+
sock = UNIXSocket.new(address)
|
419
|
+
elsif address =~ /^(\d+\.\d+\.\d+\.\d+):(\d+)$/
|
420
|
+
sock = TCPSocket.new($1, $2.to_i)
|
421
|
+
else
|
422
|
+
raise ArgumentError, "Don't know how to connect to #{address}"
|
423
|
+
end
|
424
|
+
sock.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1) if defined?(TCP_NODELAY)
|
425
|
+
sock
|
426
|
+
end
|
427
|
+
|
428
|
+
def next_sequence #:nodoc: Stubbed to do nothing.
|
429
|
+
end
|
430
|
+
|
431
|
+
def inspect
|
432
|
+
@socket ? "Server on #{Socket.unpack_sockaddr_in(@socket.getsockname).reverse!.join(':')}" : "Connection closed"
|
433
|
+
end
|
434
|
+
|
435
|
+
# Close the socket.
|
436
|
+
def close
|
437
|
+
@socket.shutdown if @socket
|
438
|
+
@socket = nil
|
439
|
+
end
|
440
|
+
|
441
|
+
end
|
442
|
+
|
316
443
|
end
|
data/uuid.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
spec = Gem::Specification.new do |spec|
|
2
2
|
spec.name = 'uuid'
|
3
|
-
spec.version = '2.
|
3
|
+
spec.version = '2.3.0'
|
4
4
|
spec.summary = "UUID generator"
|
5
5
|
spec.description = <<-EOF
|
6
6
|
UUID generator for producing universally unique identifiers based on RFC 4122
|
@@ -12,6 +12,8 @@ EOF
|
|
12
12
|
spec.homepage = 'http://github.com/assaf/uuid'
|
13
13
|
|
14
14
|
spec.files = Dir['{bin,test,lib,docs}/**/*'] + ['README.rdoc', 'MIT-LICENSE', 'Rakefile', 'CHANGELOG', 'uuid.gemspec']
|
15
|
+
spec.executables = "uuid"
|
16
|
+
|
15
17
|
spec.has_rdoc = true
|
16
18
|
spec.rdoc_options << '--main' << 'README.rdoc' << '--title' << 'UUID generator' << '--line-numbers'
|
17
19
|
'--webcvs' << 'http://github.com/assaf/uuid'
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uuid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 2
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 2.3.0
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Assaf Arkin
|
@@ -10,29 +15,36 @@ autorequire:
|
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
17
|
|
13
|
-
date: 2010-
|
18
|
+
date: 2010-04-07 00:00:00 -07:00
|
14
19
|
default_executable:
|
15
20
|
dependencies:
|
16
21
|
- !ruby/object:Gem::Dependency
|
17
22
|
name: macaddr
|
18
|
-
|
19
|
-
|
20
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
21
25
|
requirements:
|
22
26
|
- - ~>
|
23
27
|
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 0
|
24
31
|
version: "1.0"
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: |
|
35
|
+
UUID generator for producing universally unique identifiers based on RFC 4122
|
36
|
+
(http://www.ietf.org/rfc/rfc4122.txt).
|
29
37
|
|
38
|
+
email: assaf@labnotes.org
|
39
|
+
executables:
|
40
|
+
- uuid
|
30
41
|
extensions: []
|
31
42
|
|
32
43
|
extra_rdoc_files:
|
33
44
|
- README.rdoc
|
34
45
|
- MIT-LICENSE
|
35
46
|
files:
|
47
|
+
- bin/uuid
|
36
48
|
- test/test-uuid.rb
|
37
49
|
- lib/uuid.rb
|
38
50
|
- README.rdoc
|
@@ -42,6 +54,8 @@ files:
|
|
42
54
|
- uuid.gemspec
|
43
55
|
has_rdoc: true
|
44
56
|
homepage: http://github.com/assaf/uuid
|
57
|
+
licenses: []
|
58
|
+
|
45
59
|
post_install_message:
|
46
60
|
rdoc_options:
|
47
61
|
- --main
|
@@ -55,20 +69,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
69
|
requirements:
|
56
70
|
- - ">="
|
57
71
|
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 0
|
58
74
|
version: "0"
|
59
|
-
version:
|
60
75
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
76
|
requirements:
|
62
77
|
- - ">="
|
63
78
|
- !ruby/object:Gem::Version
|
79
|
+
segments:
|
80
|
+
- 0
|
64
81
|
version: "0"
|
65
|
-
version:
|
66
82
|
requirements: []
|
67
83
|
|
68
84
|
rubyforge_project:
|
69
|
-
rubygems_version: 1.3.
|
85
|
+
rubygems_version: 1.3.6
|
70
86
|
signing_key:
|
71
|
-
specification_version:
|
87
|
+
specification_version: 3
|
72
88
|
summary: UUID generator
|
73
89
|
test_files: []
|
74
90
|
|