nogoth-gitjour 6.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2008-05-29
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Chad Fowler, Evan Phoenix, Rich Kilmer
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,25 @@
1
+ bin/gitjour
2
+ History.txt
3
+ License.txt
4
+ Manifest.txt
5
+ README.txt
6
+ Rakefile
7
+ config/hoe.rb
8
+ config/requirements.rb
9
+ lib/gitjour.rb
10
+ lib/gitjour/application.rb
11
+ lib/gitjour/version.rb
12
+ script/destroy
13
+ script/generate
14
+ script/txt2html
15
+ setup.rb
16
+ tasks/deployment.rake
17
+ tasks/environment.rake
18
+ tasks/website.rake
19
+ test/test_gitjour.rb
20
+ test/test_helper.rb
21
+ website/index.html
22
+ website/index.txt
23
+ website/javascripts/rounded_corners_lite.inc.js
24
+ website/stylesheets/screen.css
25
+ website/template.rhtml
data/README.txt ADDED
@@ -0,0 +1,11 @@
1
+ README
2
+
3
+ Requires 1.5.5 or greater of git. 1.5.4.3 from old versions of Ubuntu debian will not work
4
+
5
+
6
+ DEVELOPMENT
7
+
8
+ How to test from the console:
9
+
10
+ irb -r 'lib/gitjour/application'
11
+ > Gitjour::Application.run "list"
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
data/bin/gitjour ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'gitjour'
4
+
5
+ trap "INT" do
6
+ exit!
7
+ end
8
+
9
+ Gitjour::Application.run(*ARGV)
data/config/hoe.rb ADDED
@@ -0,0 +1,71 @@
1
+ require 'gitjour/version'
2
+
3
+ AUTHOR = ['Chad Fowler', 'Rich Kilmer', 'Evan Phoenix','Ben Livingood'] # can also be an array of Authors
4
+ EMAIL = "chad@chadfowler.com"
5
+ DESCRIPTION = "Automates DNSSD-powered serving and cloning of git repositories."
6
+ GEM_NAME = 'gitjour' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'gitjour' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+
11
+ @config_file = "~/.rubyforge/user-config.yml"
12
+ @config = nil
13
+ RUBYFORGE_USERNAME = "chadfowler"
14
+ def rubyforge_username
15
+ unless @config
16
+ begin
17
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
18
+ rescue
19
+ puts <<-EOS
20
+ ERROR: No rubyforge config file found: #{@config_file}
21
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
23
+ EOS
24
+ exit
25
+ end
26
+ end
27
+ RUBYFORGE_USERNAME.replace @config["username"]
28
+ end
29
+
30
+
31
+ REV = nil
32
+ # UNCOMMENT IF REQUIRED:
33
+ # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
+ VERS = Gitjour::VERSION::STRING + (REV ? ".#{REV}" : "")
35
+ RDOC_OPTS = ['--quiet', '--title', 'gitjour documentation',
36
+ "--opname", "index.html",
37
+ "--line-numbers",
38
+ "--main", "README",
39
+ "--inline-source"]
40
+
41
+ class Hoe
42
+ def extra_deps
43
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
44
+ @extra_deps
45
+ end
46
+ end
47
+
48
+ # Generate all the Rake tasks
49
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
+ p.author = AUTHOR
52
+ p.description = DESCRIPTION
53
+ p.email = EMAIL
54
+ p.summary = DESCRIPTION
55
+ p.url = HOMEPATH
56
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
57
+ p.test_globs = ["test/**/test_*.rb"]
58
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
59
+ p.extra_deps = [['net-mdns','>= 0.4.0']]
60
+ # == Optional
61
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
62
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
63
+
64
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
65
+
66
+ end
67
+
68
+ CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
69
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
70
+ hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
71
+ hoe.rsync_args = '-av --delete --ignore-errors'
@@ -0,0 +1,17 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
16
+
17
+ require 'gitjour'
data/lib/gitjour.rb ADDED
@@ -0,0 +1 @@
1
+ require 'gitjour/application'
@@ -0,0 +1,347 @@
1
+ require 'rubygems'
2
+ require 'net/dns/mdns-sd'
3
+ require 'set'
4
+ require 'webrick'
5
+ require 'gitjour/version'
6
+
7
+ DNSSD = Net::DNS::MDNSSD
8
+
9
+ Thread.abort_on_exception = true
10
+
11
+ module Gitjour
12
+ GitService = Struct.new(:name, :host, :port, :description)
13
+
14
+ class Application
15
+
16
+ class << self
17
+ def run(*args)
18
+ case args.shift
19
+ when "list"
20
+ list
21
+ when "clone"
22
+ clone(*args)
23
+ when "serve"
24
+ serve(*args)
25
+ when "remote"
26
+ remote(*args);
27
+ when "web"
28
+ web(*args)
29
+ when "browse"
30
+ browse(*args)
31
+ else
32
+ help
33
+ end
34
+ end
35
+
36
+ private
37
+ def list
38
+ service_list("_git._tcp").each do |service|
39
+ puts "=== #{service.name} on #{service.host}:#{service.port} ==="
40
+ puts " gitjour clone #{service.name}"
41
+ if service.description != '' && service.description !~ /^Unnamed repository/
42
+ puts " #{service.description}"
43
+ end
44
+ puts
45
+ end
46
+ end
47
+
48
+ def clone(repository_name, *rest)
49
+ dir = rest.shift || repository_name
50
+ if File.exists?(dir)
51
+ exit_with! "ERROR: Clone directory '#{dir}' already exists."
52
+ end
53
+
54
+ puts "Cloning '#{repository_name}' into directory '#{dir}'..."
55
+
56
+ unless service = locate_repo(repository_name)
57
+ exit_with! "ERROR: Unable to find project named '#{repository_name}'"
58
+ end
59
+
60
+ unless service = locate_repo(repository_name)
61
+ exit_with! "ERROR: Unable to find project named '#{repository_name}'"
62
+ end
63
+
64
+ puts "Connecting to #{service.host}:#{service.port}"
65
+
66
+ system "git clone git://#{service.host}:#{service.port}/ #{dir}/"
67
+ end
68
+
69
+ def remote(repository_name, *rest)
70
+ dir = rest.shift || repository_name
71
+ service = locate_repo repository_name
72
+ system "git remote add #{dir} git://#{service.host}:#{service.port}/"
73
+ end
74
+
75
+ def serve(path=Dir.pwd, *rest)
76
+ path = File.expand_path(path)
77
+ name = service_name(rest.shift || File.basename(path))
78
+ port = rest.shift || 9418
79
+
80
+ if File.exists?("#{path}/.git")
81
+ announce_git(path, name, port.to_i)
82
+ else
83
+ Dir["#{path}/*"].each do |dir|
84
+ if File.directory?(dir)
85
+ name = File.basename(dir)
86
+ announce_git(dir, name, 9418)
87
+ end
88
+ end
89
+ end
90
+
91
+ `git-daemon --verbose --export-all --port=#{port} --base-path=#{path} --base-path-relaxed`
92
+ end
93
+
94
+ def web(path=Dir.pwd, *rest)
95
+ path = File.expand_path(path)
96
+ name = service_name(rest.shift || File.basename(path))
97
+ port = rest.shift || 1234
98
+ httpd = rest.shift || "webrick"
99
+
100
+ if File.exists?("#{path}/.git")
101
+ announce_web(path, name, port.to_i)
102
+ `git-instaweb --httpd=#{httpd} --port=#{port}`
103
+ trap("INT") do
104
+ puts "Stopping instaweb..."
105
+ `git-instaweb stop`
106
+ exit 0
107
+ end
108
+ while true; sleep 30; end
109
+ else
110
+ $stderr.puts "You must specify a proper git project"
111
+ exit 1
112
+ end
113
+ end
114
+
115
+ def service_name(name)
116
+ # If the name starts with ^, then don't apply the prefix
117
+ if name[0] == ?^
118
+ name = name[1..-1]
119
+ else
120
+ prefix = `git config --get gitjour.prefix`.chomp
121
+ prefix = ENV["USER"] if prefix.empty?
122
+ name = [prefix, name].compact.join("-")
123
+ end
124
+ name
125
+ end
126
+
127
+ def help
128
+ puts "Gitjour #{Gitjour::VERSION::STRING}"
129
+ puts "Serve up and use git repositories via Bonjour/DNSSD."
130
+ puts "\nUsage: gitjour <command> [args]"
131
+ puts
132
+ puts " list"
133
+ puts " Lists available repositories."
134
+ puts
135
+ puts " clone <project> [<directory>]"
136
+ puts " Clone a gitjour served repository."
137
+ puts
138
+ puts " serve <path_to_project> [<name_of_project>] [<port>] or"
139
+ puts " <path_to_projects>"
140
+ puts " Serve up the current directory or projects via gitjour."
141
+ puts
142
+ puts " The name of your project is automatically prefixed with"
143
+ puts " `git config --get gitjour.prefix` or your username (preference"
144
+ puts " in that order). If you don't want a prefix, put a ^ on the front"
145
+ puts " of the name_of_project (the ^ is removed before announcing)."
146
+ puts
147
+ puts " web <path_to_project> [<name_of_project>] [<port>] [<httpd_daemon>]"
148
+ puts " Serve up the current directory via git instaweb for browsers."
149
+ puts " The default port is 1234 and the httpd_daemon is defaulted to"
150
+ puts " webrick. Other options are 'lighttpd' and 'apache2' (See the"
151
+ puts " git-instaweb man page for more details)"
152
+ puts
153
+ puts " browse [<port>] [<browser>]"
154
+ puts " Browse git repositories published with the 'web' command (see"
155
+ puts " above). This command takes two optional arguments: the first"
156
+ puts " is the port for the local web server (default 9850), the second"
157
+ puts " is the path to your web browser (see man git-web--browse for"
158
+ puts " details)."
159
+ puts
160
+ puts " remote <project> [<name>]"
161
+ puts " Add a Bonjour remote into your current repository."
162
+ puts " Optionally pass name to not use pwd."
163
+ puts
164
+ end
165
+
166
+ def exit_with!(message)
167
+ STDERR.puts message
168
+ exit!
169
+ end
170
+
171
+ class Done < RuntimeError; end
172
+
173
+ def discover(type, timeout=5)
174
+ waiting_thread = Thread.current
175
+
176
+ dns = DNSSD.browse type do |reply|
177
+ DNSSD.resolve reply.name, reply.type, reply.domain do |resolve_reply|
178
+ service = GitService.new(reply.name,
179
+ resolve_reply.target,
180
+ resolve_reply.port,
181
+ resolve_reply.text_record['description'].to_s)
182
+ begin
183
+ yield service
184
+ rescue Done
185
+ waiting_thread.run
186
+ end
187
+ end
188
+ end
189
+
190
+ puts "Gathering for up to #{timeout} seconds..."
191
+ sleep timeout
192
+ dns.stop
193
+ end
194
+
195
+ def locate_repo(name)
196
+ found = nil
197
+
198
+ discover("_git._tcp") do |obj|
199
+ if obj.name == name
200
+ found = obj
201
+ raise Done
202
+ end
203
+ end
204
+
205
+ return found
206
+ end
207
+
208
+ def service_list(type)
209
+ list = Set.new
210
+ discover(type) { |obj| list << obj }
211
+
212
+ return list
213
+ end
214
+
215
+ def browse(*args)
216
+ Browser.new(*args).start
217
+ end
218
+
219
+ def http_services
220
+ service_list("_http._tcp,git")
221
+ end
222
+
223
+ def announce_git(path, name, port)
224
+ announce_repo(path, name, port, "_git._tcp")
225
+ end
226
+
227
+ def announce_web(path, name, port)
228
+ announce_repo(path, name, port, "_http._tcp,git")
229
+ end
230
+
231
+ def announce_repo(path, name, port, type)
232
+ return unless File.exists?("#{path}/.git")
233
+
234
+ description = File.read("#{path}/.git/description") rescue "a git project"
235
+
236
+ DNSSD.register(name, type, 'local', port, {"description"=>description}) do |rr|
237
+ puts "Registered #{name} on port #{port}. Starting service."
238
+ end
239
+ end
240
+
241
+ end
242
+ end
243
+
244
+ class Browser
245
+ require "erb"
246
+
247
+ def initialize(*args)
248
+ @port = args.shift || 9850
249
+ @browser = args.shift
250
+ @services = Set.new
251
+ @mutex = Mutex.new
252
+ end
253
+
254
+ def start
255
+ DNSSD.browse("_http._tcp,git") do |reply|
256
+ begin
257
+ DNSSD.resolve reply.name, reply.type, reply.domain do |resolve_reply|
258
+ service = GitService.new(reply.name,
259
+ resolve_reply.target,
260
+ resolve_reply.port,
261
+ resolve_reply.text_record['description'].to_s)
262
+
263
+ @mutex.synchronize do
264
+ if @services.member? service
265
+ @services.delete service
266
+ else
267
+ @services << service
268
+ end
269
+ end
270
+ end
271
+ rescue ArgumentError # usually a jacked DNS text record
272
+ end
273
+ end
274
+
275
+ http = WEBrick::HTTPServer.new(:Port => @port.to_i)
276
+ http.mount_proc("/") { |req, res| index(req, res) }
277
+ http.mount_proc("/style.css") { |req, res| stylesheet(req, res) }
278
+ trap("INT") { http.shutdown }
279
+ t = Thread.new { http.start }
280
+
281
+ url = "http://localhost:#{@port}"
282
+ if @browser
283
+ `git web--browse -b '#{@browser}' http://localhost:9850`
284
+ else
285
+ `git web--browse -c "instaweb.browser" http://localhost:9850`
286
+ end
287
+ t.join
288
+ end
289
+
290
+ def index(req, res)
291
+ res['Content-Type'] = 'text/html'
292
+ res.body = index_html.result(binding)
293
+ end
294
+
295
+ def index_html
296
+ @index_html ||= ERB.new(<<-HTML)
297
+ <html>
298
+ <body>
299
+ <head>
300
+ <link rel="stylesheet" href="/style.css" type="text/css" media="screen"/>
301
+ <title>Browseable Git Repositories</title>
302
+ </head>
303
+ <h1>Browseable Git Repositories</h1>
304
+ <ul>
305
+ <% @mutex.synchronize do %>
306
+ <% @services.map do |s| %>
307
+ <li>
308
+ <a href='http://<%= s.host %>:<%= s.port %>' target="_new">
309
+ <%= s.name %>
310
+ </a>
311
+ <%= s.description unless s.description =~ /^Unnamed repository/ %>
312
+ </li>
313
+ <% end %>
314
+ <% end %>
315
+ </ul>
316
+ </body>
317
+ </html>
318
+ HTML
319
+ end
320
+
321
+ def stylesheet(req, res)
322
+ res['Content-Type'] = 'text/css'
323
+ res.body = css
324
+ end
325
+
326
+ def css
327
+ @css ||= <<-CSS
328
+ body {
329
+ font-family: sans-serif;
330
+ font-size: 12px;
331
+ background-color: #fff;
332
+ }
333
+
334
+ h1 {
335
+ font-size: 20px;
336
+ font-weight: bold;
337
+ }
338
+
339
+ ul {
340
+ border: 1px dashed #999;
341
+ padding: 10 10 10 20;
342
+ background-color: #ccc;
343
+ }
344
+ CSS
345
+ end
346
+ end
347
+ end