nullobject-gemjour 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,50 @@
1
+ = Gemjour
2
+
3
+ Advertise, list, and install gems over Bonjour.
4
+
5
+ == Installation
6
+
7
+ sudo gem install dnssd
8
+ sudo gem install evanphx-gemjour --source=http://gems.github.com
9
+
10
+ == Usage
11
+
12
+ alice$ gemjour serve # advertises gems over Bonjour
13
+ bob$ gemjour list # finds alice
14
+ bob$ gemjour list alice # shows alice's gems
15
+ bob$ gemjour diff alice # shows differences between bob and alice gems
16
+ bob$ gemjour install_diff alice # installs any gem bob doesn't have installed from alice
17
+ bob$ gemjour search foo # searches for a gem "foo"
18
+
19
+ alice$ gem install foo.gem; gitjour serve
20
+ bob$ gemjour install alice foo
21
+ bob$ gemjour install alice foo -v 1.1.0
22
+
23
+ Prefix the commands with "sudo" as necessary.
24
+
25
+ == Awesome!
26
+
27
+ You know it.
28
+
29
+ == License
30
+
31
+ Copyright (c) 2008 Evan Phoenix
32
+
33
+ Permission is hereby granted, free of charge, to any person obtaining
34
+ a copy of this software and associated documentation files (the
35
+ "Software"), to deal in the Software without restriction, including
36
+ without limitation the rights to use, copy, modify, merge, publish,
37
+ distribute, sublicense, and/or sell copies of the Software, and to
38
+ permit persons to whom the Software is furnished to do so, subject to
39
+ the following conditions:
40
+
41
+ The above copyright notice and this permission notice shall be
42
+ included in all copies or substantial portions of the Software.
43
+
44
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
45
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
46
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
47
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
48
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
49
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
50
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ require "date"
2
+ require "fileutils"
3
+ require "rubygems"
4
+ require "rake/gempackagetask"
5
+
6
+ require "./lib/gemjour/version.rb"
7
+
8
+ gemjour_gemspec = Gem::Specification.new do |s|
9
+ s.name = "gemjour"
10
+ s.version = Gemjour::VERSION
11
+ s.platform = Gem::Platform::RUBY
12
+ s.has_rdoc = true
13
+ s.extra_rdoc_files = ["README.rdoc"]
14
+ s.summary = "Advertise, list, and install gems over Bonjour."
15
+ s.description = s.summary
16
+ s.authors = ["Evan Phoenix", "Josh Bassett"]
17
+ s.email = "evan@fallingsnow.net"
18
+ s.homepage = "http://github.com/evanphx/gemjour"
19
+ s.require_path = "lib"
20
+ s.autorequire = "gemjour"
21
+ s.files = %w(README.rdoc Rakefile) + Dir.glob("{bin,lib}/**/*")
22
+ s.executables = %w(gemjour)
23
+
24
+ s.add_dependency "net-mdns", ">= 0.4.0"
25
+ end
26
+
27
+ Rake::GemPackageTask.new(gemjour_gemspec) do |pkg|
28
+ pkg.gem_spec = gemjour_gemspec
29
+ end
30
+
31
+ namespace :gem do
32
+ namespace :spec do
33
+ desc "Update gemjour.gemspec"
34
+ task :generate do
35
+ File.open("gemjour.gemspec", "w") do |f|
36
+ f.puts(gemjour_gemspec.to_ruby)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ task :install => :package do
43
+ sh %{sudo gem install --local pkg/gemjour-#{Gemjour::VERSION}}
44
+ end
45
+
46
+ desc "Remove all generated artifacts"
47
+ task :clean => :clobber_package
data/bin/gemjour ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require File.dirname(__FILE__) + '/../lib/gemjour'
5
+
6
+ begin
7
+ cmd = ARGV.shift
8
+
9
+ case cmd
10
+ when "serve"
11
+ Gemjour.serve(*ARGV)
12
+ when "list"
13
+ Gemjour.list(*ARGV)
14
+ when "show"
15
+ Gemjour.show(*ARGV)
16
+ when "search"
17
+ Gemjour.search(*ARGV)
18
+ when "diff"
19
+ Gemjour.diff(*ARGV)
20
+ when "install_diff"
21
+ Gemjour.install_diff(*ARGV)
22
+ when "install"
23
+ Gemjour.install(*ARGV)
24
+ else
25
+ Gemjour.usage
26
+ end
27
+ rescue => e
28
+ puts "ERROR: running '#{cmd}': #{e.message} (#{e.class})"
29
+ puts
30
+ Gemjour.usage
31
+ end
@@ -0,0 +1,3 @@
1
+ module Gemjour
2
+ VERSION = "1.1.0".freeze
3
+ end
data/lib/gemjour.rb ADDED
@@ -0,0 +1,217 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'net/dns/mdns-sd'
5
+ require 'set'
6
+ require 'gemjour/version'
7
+
8
+ DNSSD = Net::DNS::MDNSSD
9
+
10
+ Thread.abort_on_exception = true
11
+
12
+ module Gemjour
13
+ Server = Struct.new(:name, :host, :port)
14
+ PORT = 8808
15
+ SERVICE = "_rubygems._tcp"
16
+
17
+ GEM_PREAMBLE_RE = /$\s*\*\*\* REMOTE GEMS \*\*\*\s*/
18
+
19
+ def self.usage
20
+ puts <<-HELP
21
+ Usage:
22
+
23
+ serve [<name>] [<port>]
24
+ Start up a gem server as <name> on <port>. <name> is your username
25
+ by default, and <port> is 8088. If you want to use the default <name>,
26
+ pass it as "".
27
+
28
+ install <server> <gem> [<version>]
29
+ Installs <gem> from <server>. <server> is the name the server announces
30
+ itself as.
31
+
32
+ list
33
+ List all available gem servers.
34
+
35
+ show <server>
36
+ List all gems available from <server>.
37
+
38
+ search <string>
39
+ List all gems which contain <string>.
40
+
41
+ HELP
42
+ end
43
+
44
+ # Finds the host with the specified name.
45
+ def self.find(name)
46
+ host = nil
47
+
48
+ waiting = Thread.current
49
+
50
+ service = DNSSD.browse(SERVICE) do |reply|
51
+ if name === reply.name
52
+ DNSSD.resolve(reply.name, reply.type, reply.domain) do |rr|
53
+ host = Server.new(reply.name, rr.target, rr.port)
54
+ waiting.run
55
+ end
56
+ end
57
+ end
58
+
59
+ sleep 5
60
+ service.stop
61
+
62
+ host
63
+ end
64
+
65
+ # Finds all hosts.
66
+ def self.find_all
67
+ hosts = []
68
+
69
+ puts "Gathering for up to 5 seconds..."
70
+
71
+ waiting = Thread.current
72
+
73
+ service = DNSSD.browse(SERVICE) do |reply|
74
+ DNSSD.resolve(reply.name, reply.type, reply.domain) do |rr|
75
+ host = Server.new(reply.name, rr.target, rr.port)
76
+ unless hosts.include? host
77
+ hosts << host
78
+ end
79
+ end
80
+ end
81
+
82
+ sleep 5
83
+ service.stop
84
+
85
+ hosts
86
+ end
87
+
88
+ # Lists the hosts. Aliased to the show command if a name is specified.
89
+ def self.list(name = nil)
90
+ if name
91
+ show(name)
92
+ else
93
+ hosts = find_all
94
+ hosts.each { |host| print_host(host) }
95
+ end
96
+ end
97
+
98
+ def self.show(name)
99
+ results = {}
100
+ host = find(name)
101
+
102
+ unless host
103
+ puts "ERROR: Unable to find server '#{name}'"
104
+ return
105
+ end
106
+
107
+ # List gems on host.
108
+ output =`gem list -a -r --source=http://#{host.host}:#{host.port}`
109
+
110
+ gems = parse_gems(output)
111
+ results[host] = gems unless gems.empty?
112
+
113
+ print_gems(results)
114
+ end
115
+
116
+ def self.search(q)
117
+ results = {}
118
+ hosts = find_all
119
+
120
+ unless hosts.empty?
121
+ puts "Searching #{hosts.length} hosts..."
122
+
123
+ hosts.each do |host|
124
+ # Search for gems on host.
125
+ output = `gem search #{q} -a -r --source=http://#{host.host}:#{host.port}`
126
+
127
+ gems = parse_gems(output)
128
+ results[host] = gems unless gems.empty?
129
+ end
130
+ end
131
+
132
+ if results.empty?
133
+ puts "Search returned no results"
134
+ else
135
+ print_gems(results)
136
+ end
137
+ end
138
+
139
+ # Parses the gems from the raw gem output.
140
+ def self.parse_gems(s)
141
+ # Strip the preamble off the gem output.
142
+ s.gsub!(GEM_PREAMBLE_RE, '')
143
+
144
+ s.split(/\n/)
145
+ end
146
+
147
+ # Prints the gems for each host.
148
+ def self.print_gems(results)
149
+ results.each do |host, gems|
150
+ print_host(host)
151
+ gems.each do |gem|
152
+ puts "\t#{gem}"
153
+ end
154
+ end
155
+ end
156
+
157
+ def self.print_host(host)
158
+ puts "=== #{host.name} (#{host.host}:#{host.port})"
159
+ end
160
+
161
+ def self._diff(name)
162
+ host = find(name)
163
+
164
+ unless host
165
+ puts "ERROR: Unable to find server named '#{name}'"
166
+ return
167
+ end
168
+
169
+ require "tempfile"
170
+ local_gems, remote_gems = Tempfile.new("local_gems"), Tempfile.new("remote_gems")
171
+ local_gems.print(`gem list --no-versions --no-verbose`)
172
+ local_gems.close
173
+ remote_gems.print(`gem list --no-versions --no-verbose -r --source=http://#{host.host}:#{host.port}`)
174
+ remote_gems.close
175
+ `diff -u #{local_gems.path} #{remote_gems.path}`
176
+ end
177
+
178
+ def self.diff(name)
179
+ return unless diff = _diff(name)
180
+ puts diff
181
+ end
182
+
183
+ def self.install_diff(name)
184
+ return unless gem_diff = _diff(name)
185
+ gem_diff.scan(/^\+([\w_\-]+)/) do |match|
186
+ install(name, match)
187
+ end
188
+ end
189
+
190
+ def self.install(name, gem, version = nil)
191
+ host = find(name)
192
+
193
+ unless host
194
+ puts "ERROR: Unable to find server named '#{name}'"
195
+ return
196
+ end
197
+
198
+ puts "Installing gem '#{gem}' from #{host.host}:#{host.port}"
199
+
200
+ command = "gem install #{gem} -s http://#{host.host}:#{host.port}"
201
+ command << " #{version}" if version
202
+ system command
203
+ end
204
+
205
+ def self.serve(name = "", port = PORT)
206
+ name = ENV['USER'] if name.empty?
207
+
208
+ tr = DNSSD::TextRecord.new
209
+ tr['description'] = "#{name}'s gem server"
210
+
211
+ DNSSD.register(name, SERVICE, "local", port, tr.encode) do |reply|
212
+ puts "Serving gems under name '#{name}'..."
213
+ end
214
+
215
+ system "gem server --port=#{port} -q > /dev/null 2>&1"
216
+ end
217
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nullobject-gemjour
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Evan Phoenix
8
+ - Josh Bassett
9
+ autorequire: gemjour
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-03-26 00:00:00 -07:00
14
+ default_executable: gemjour
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: net-mdns
18
+ type: :runtime
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 0.4.0
25
+ version:
26
+ description: Advertise, list, and install gems over Bonjour.
27
+ email: evan@fallingsnow.net
28
+ executables:
29
+ - gemjour
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - README.rdoc
34
+ files:
35
+ - README.rdoc
36
+ - Rakefile
37
+ - bin/gemjour
38
+ - lib/gemjour
39
+ - lib/gemjour/version.rb
40
+ - lib/gemjour.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/evanphx/gemjour
43
+ post_install_message:
44
+ rdoc_options: []
45
+
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.2.0
64
+ signing_key:
65
+ specification_version: 2
66
+ summary: Advertise, list, and install gems over Bonjour.
67
+ test_files: []
68
+