nogoth-gitjour 6.2.1

Sign up to get free protection for your applications and to get access to all the features.
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