bananajour 2.1.9

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,66 @@
1
+ require "rubygems"
2
+
3
+ $:.unshift "#{File.dirname(__FILE__)}/lib"
4
+
5
+ require "bananajour/version"
6
+ require "bananajour/gem_dependencies"
7
+
8
+ gem = Gem::Specification.new do |gem|
9
+ gem.name = "bananajour"
10
+ gem.version = Bananajour::VERSION
11
+ gem.platform = Gem::Platform::RUBY
12
+ gem.extra_rdoc_files = ["Readme.md"]
13
+ gem.summary = "Local git repository hosting with a sexy web interface and bonjour discovery. It's like your own little adhoc, network-aware github!"
14
+ gem.description = gem.summary
15
+ gem.authors = ["Tim Lucas"]
16
+ gem.email = "t.lucas@toolmantim.com"
17
+ gem.homepage = "http://github.com/toolmantim/bananajour"
18
+ gem.require_path = "lib"
19
+ gem.files = %w(Readme.md Rakefile) + Dir.glob("{bin,lib,sinatra}/**/*")
20
+ gem.has_rdoc = false
21
+ gem.bindir = 'bin'
22
+ gem.executables = [ 'bananajour' ]
23
+ Bananajour::GemDependencies.all.each {|dep| gem.add_runtime_dependency( dep.name, dep.version ) }
24
+ end
25
+
26
+ task :clean do
27
+ FileUtils.rm_rf Dir['*.gem', '*.gemspec']
28
+ end
29
+
30
+ namespace :gem do
31
+
32
+ desc "Rebuild and install bananajour as a gem"
33
+ task :install => :package do
34
+ require 'rubygems/installer'
35
+ Dir['*.gem'].each do |gem|
36
+ Gem::Installer.new(gem).install
37
+ end
38
+ end
39
+
40
+ desc "Create the gem"
41
+ task :package => [:clean, "spec:generate"] do
42
+ require 'rubygems/builder'
43
+ Gem::Builder.new( gem ).build
44
+ end
45
+
46
+ namespace :spec do
47
+
48
+ desc "Update #{gem.name}.gemspec"
49
+ task :generate do
50
+ File.open("#{gem.name}.gemspec", "w") do |f|
51
+ f.puts(gem.to_ruby)
52
+ end
53
+ end
54
+
55
+ desc "Test spec in github cleanroom"
56
+ task :test => :generate do
57
+ require 'rubygems/specification'
58
+ data = File.read("#{gem.name}.gemspec")
59
+ spec = nil
60
+ Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
61
+ puts "#{spec} - Good to go!"
62
+ end
63
+
64
+ end
65
+
66
+ end
data/Readme.md ADDED
@@ -0,0 +1,86 @@
1
+ Bananajour - Local git publication and collaboration
2
+ ====================================================
3
+
4
+ Local git repository hosting with a sexy web interface and Bonjour discovery. It's like a bunch of adhoc, local, network-aware githubs!
5
+
6
+ Unlike Gitjour, the repositories you're serving are not your working git repositories, they're served from `~/.bananajour/repositories`. You can push to your bananajour repositories from your working copies just like you do with github.
7
+
8
+ Bananajour is the baby of [Tim Lucas](http://toolmantim.com/) with much railscamp hackage by [Nathan de Vries](http://github.com/atnan), [Lachlan Hardy](http://github.com/lachlanhardy), [Josh Bassett](http://github.com/nullobject), [Myles Byrne](http://github.com/quackingduck), [Ben Hoskings](http://github.com/benhoskings), [Brett Goulder](http://github.com/brettgo1), [Tony Issakov](https://github.com/tissak), and [Mark Bennett](http://github.com/MarkBennett). The rad logo was by [Carla Hackett](http://carlahackettdesign.com/). Other various fixes and contributions by [Travis Swicegood](http://github.com/tswicegood) and [Nate Haas](http://github.com/natehaas).
9
+
10
+ ![Screenshot of local view of Bananajour 2.1.3](http://cloud.github.com/downloads/toolmantim/bananajour/screenshot.png)
11
+
12
+ Installation and usage
13
+ ----------------------
14
+
15
+ You'll need at least [git version 1.6](http://git-scm.com/). Run `git --version` if you're unsure.
16
+
17
+ Install it from github via gems:
18
+
19
+ gem install toolmantim-bananajour
20
+
21
+ (you might need to do a `gem sources -a http://gems.github.com` beforehand!)
22
+
23
+ Start it up:
24
+
25
+ bananajour
26
+
27
+ Go into an existing project and add it to bananajour:
28
+
29
+ cd ~/code/myproj
30
+ bananajour add
31
+
32
+ Publish your codez:
33
+
34
+ git push banana master
35
+
36
+ Fire up [http://localhost:9331/](http://localhost:9331/) to check it out.
37
+
38
+ If somebody starts sharing a Bananajour repository with the same name on the
39
+ network it'll automatically show up in the network thanks to the wonder that is Bonjour.
40
+
41
+ For a list of all the commands:
42
+
43
+ bananajour help
44
+
45
+ Linux support
46
+ -------------
47
+
48
+ To install the dnssd gem on linux you'll need [avahi](http://avahi.org/). For Ubunutu peeps this means:
49
+
50
+ sudo apt-get install libavahi-compat-libdnssd-dev
51
+
52
+ Using with Ginatra
53
+ ------------------
54
+
55
+ Rumour has it [ginatra](http://github.com/lenary/ginatra) can be used to provide richer gitweb-like browsing of your bananajour repositories. Symlink ginatra's `repos` directory to `~/.bananajour/repositories` to serve up your bananajour repositories.
56
+
57
+ Official repository and support
58
+ -------------------------------
59
+
60
+ The official repo and support issues/tickets live at [github.com/toolmantim/bananajour](http://github.com/toolmantim/bananajour).
61
+
62
+ Feature and support discussions live at [groups.google.com/group/bananajour](http://groups.google.com/group/bananajour).
63
+
64
+ Developing
65
+ ----------
66
+
67
+ If you want to hack on the sinatra app then do so from a local clone but run your actual bananjour from the gem version. Running the sinatra app directly won't broadcast it onto the network and it'll run on a different port:
68
+
69
+ ruby sinatra/app.rb -s thin
70
+
71
+ If you want code reloading use [shotgun](http://github.com/rtomayko/shotgun) instead:
72
+
73
+ shotgun sinatra/app.rb -s thin
74
+
75
+ If you then want to run your working copy as your public bananajour rebuild and install it as a gem:
76
+
77
+ sudo rake gem:install
78
+
79
+ License
80
+ -------
81
+
82
+ All directories and files are MIT Licensed.
83
+
84
+ Warning to all those who still believe secrecy will save their revenue stream
85
+ -----------------------------------------------------------------------------
86
+ Bananas were meant to be shared. There are no secret bananas.
data/bin/bananajour ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require (File.symlink?(__FILE__) ? "bananajour" : File.join(File.dirname(__FILE__), "/../lib/bananajour"))
5
+
6
+ Thread.abort_on_exception = true
7
+
8
+ Bananajour.setup! if !Bananajour.setup?
9
+ Bananajour.check_git!
10
+ Bananajour.check_git_config!
11
+
12
+ case ARGV.first
13
+
14
+ when nil
15
+ Bananajour.serve_web!
16
+ Bananajour.serve_git!
17
+ Bananajour.advertise!
18
+ Process.wait
19
+
20
+ when "add", "init"
21
+ repo = Bananajour.add!(ARGV[1] || File.expand_path("."))
22
+
23
+ when "remove", "rm"
24
+ name = ARGV[1]
25
+
26
+ if !name || name.empty?
27
+ abort "You need to specify the name of the repository you'd like to remove:\n#{File.basename($0)} remove <path>"
28
+ elsif !(repo = Bananajour::Repository.for_name(name))
29
+ abort "#{name.inspect} is not a valid repository name"
30
+ end
31
+
32
+ repo.remove!
33
+
34
+ when "clone"
35
+ if ARGV[1].nil? || ARGV[1].empty?
36
+ abort "You need to specify the path to the repository you'd like to clone:\n$ bananajour clone <path>"
37
+ end
38
+ repo = Bananajour.clone!(ARGV[1], ARGV[2])
39
+
40
+ when "help", "--help", "-h"
41
+ puts <<-HELP
42
+ Usage: #{File.basename($0)} [<command>]
43
+
44
+ Commands:
45
+ none - Start the web, git and bonjour serving
46
+ add [path] - Add an existing git repo to bananajour
47
+ remove <name> - Remove a repo
48
+ clone <url> [path] - Clone a remote repo and add it to bananajour
49
+ help
50
+ version
51
+ HELP
52
+
53
+ when "version", "--version", "-v"
54
+ puts "bananajour version #{Bananajour::VERSION}"
55
+
56
+ else
57
+ abort "Say what? Try: #{File.basename($0)} help"
58
+ end
data/lib/bananajour.rb ADDED
@@ -0,0 +1,99 @@
1
+ libdir = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
4
+ require 'yaml'
5
+ require 'ostruct'
6
+ require 'socket'
7
+ require 'md5'
8
+
9
+ require 'bananajour/gem_dependencies'
10
+
11
+ Bananajour.require_gem 'rainbow'
12
+ Bananajour.require_gem 'dnssd'
13
+ Bananajour.require_gem 'chrislloyd-fancypath', 'fancypath'
14
+
15
+ require 'bananajour/repository'
16
+ require 'bananajour/grit_extensions'
17
+ require 'bananajour/version'
18
+ require 'bananajour/bonjour'
19
+ require 'bananajour/helpers'
20
+ require 'bananajour/commands'
21
+
22
+ module Bananajour
23
+
24
+ class << self
25
+
26
+ include DateHelpers
27
+ include GravatarHelpers
28
+ include Commands
29
+
30
+ def setup?
31
+ repositories_path.exists?
32
+ end
33
+
34
+ def setup!
35
+ repositories_path.create_dir
36
+ end
37
+
38
+ def path
39
+ Fancypath("~/.bananajour").expand_path
40
+ end
41
+
42
+ def repositories_path
43
+ path/"repositories"
44
+ end
45
+
46
+ def get_git_global_config(key)
47
+ `git config --global #{key}`.strip
48
+ end
49
+
50
+ def config
51
+ @config ||= begin
52
+ OpenStruct.new({
53
+ :name => get_git_global_config("user.name"),
54
+ :email => get_git_global_config("user.email")
55
+ })
56
+ end
57
+ end
58
+
59
+ def web_port
60
+ 9331
61
+ end
62
+
63
+ def web_uri
64
+ "http://#{host_name}:#{web_port}/"
65
+ end
66
+
67
+ def host_name
68
+ Socket.gethostname
69
+ end
70
+
71
+ def git_uri
72
+ "git://#{host_name}/"
73
+ end
74
+
75
+ def repositories
76
+ repositories_path.children.map {|r| Repository.new(r)}.sort_by {|r| r.name}
77
+ end
78
+
79
+ def repository(name)
80
+ repositories.find {|r| r.name == name}
81
+ end
82
+
83
+ def to_hash
84
+ {
85
+ "name" => config.name,
86
+ "email" => config.email,
87
+ "uri" => web_uri,
88
+ "git-uri" => git_uri,
89
+ "gravatar" => Bananajour.gravatar,
90
+ "version" => Bananajour::VERSION,
91
+ "repositories" => repositories.collect do |r|
92
+ {"name" => r.name, "uri" => r.uri}
93
+ end
94
+ }
95
+ end
96
+
97
+ end
98
+
99
+ end
@@ -0,0 +1,9 @@
1
+ module Bananajour::Bonjour
2
+ end
3
+
4
+ require 'bananajour/bonjour/person'
5
+ require 'bananajour/bonjour/repository'
6
+ require 'bananajour/bonjour/browser'
7
+ require 'bananajour/bonjour/repository_browser'
8
+ require 'bananajour/bonjour/bananajour_browser'
9
+ require 'bananajour/bonjour/advertiser'
@@ -0,0 +1,57 @@
1
+ class Bananajour::Bonjour::Advertiser
2
+ def initialize
3
+ @services = []
4
+ end
5
+ def go!
6
+ register_app
7
+ register_repos
8
+ end
9
+ private
10
+ def register_app
11
+ STDOUT.puts "Registering #{Bananajour.web_uri}"
12
+ tr = DNSSD::TextRecord.new
13
+ tr["name"] = Bananajour.config.name
14
+ tr["email"] = Bananajour.config.email
15
+ tr["uri"] = Bananajour.web_uri
16
+ tr["gravatar"] = Bananajour.gravatar
17
+ tr["version"] = Bananajour::VERSION
18
+ DNSSD.register("#{Bananajour.config.name}'s bananajour", "_http._tcp,_bananajour", nil, Bananajour.web_port, tr) {}
19
+ end
20
+ def register_repos
21
+ loop do
22
+ stop_old_services
23
+ register_new_repositories
24
+ sleep(1)
25
+ end
26
+ end
27
+ def stop_old_services
28
+ old_services.each do |old_service|
29
+ STDOUT.puts "Unregistering #{old_service.repository.uri}"
30
+ old_service.stop
31
+ @services.delete(old_service)
32
+ end
33
+ end
34
+ def old_services
35
+ @services.reject {|s| Bananajour.repositories.include?(s.repository)}
36
+ end
37
+ def register_new_repositories
38
+ new_repositories.each do |new_repo|
39
+ STDOUT.puts "Registering #{new_repo.uri}"
40
+ tr = DNSSD::TextRecord.new
41
+ tr["name"] = new_repo.name
42
+ tr["uri"] = new_repo.uri
43
+ tr["bjour-name"] = Bananajour.config.name
44
+ tr["bjour-email"] = Bananajour.config.email
45
+ tr["bjour-uri"] = Bananajour.web_uri
46
+ tr["bjour-gravatar"] = Bananajour.gravatar
47
+ tr["bjour-version"] = Bananajour::VERSION
48
+ service = DNSSD.register(new_repo.name, "_git._tcp,_bananajour", nil, 9418, tr) {}
49
+ service.class.instance_eval { attr_accessor(:repository) }
50
+ service.repository = new_repo
51
+ @services << service
52
+ end
53
+ end
54
+ def new_repositories
55
+ Bananajour.repositories.select {|repo| !@services.any? {|s| s.repository == repo } }
56
+ end
57
+ end
@@ -0,0 +1,24 @@
1
+ module Bananajour::Bonjour
2
+ class BananajourBrowser
3
+
4
+ def initialize
5
+ @browser = Browser.new('_bananajour._http._tcp')
6
+ end
7
+
8
+ def bananajours
9
+ @browser.replies.map do |reply|
10
+ Person.new(
11
+ reply.text_record["name"],
12
+ reply.text_record["email"],
13
+ reply.text_record["uri"],
14
+ reply.text_record["gravatar"]
15
+ )
16
+ end
17
+ end
18
+
19
+ def other_bananajours
20
+ bananajours.reject {|b| b.uri == Bananajour.web_uri}
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,52 @@
1
+ Bananajour.require_gem 'dnssd'
2
+
3
+ require 'thread'
4
+ require 'timeout'
5
+
6
+ Thread.abort_on_exception = true
7
+
8
+ # Generic bonjour browser
9
+ #
10
+ # Example use:
11
+ #
12
+ # browser = BonjourBrowser.new("_bananajour._git._tcp")
13
+ # loop do
14
+ # sleep(1)
15
+ # pp browser.replies.map {|r| r.name}
16
+ # end
17
+ #
18
+ # Probably gem-worthy
19
+ class Bananajour::Bonjour::Browser
20
+ attr_reader :replies
21
+ def initialize(service)
22
+ @service = service
23
+ @mutex = Mutex.new
24
+ @replies = []
25
+ watch!
26
+ end
27
+ private
28
+ def watch!
29
+ DNSSD.browse(@service) do |br|
30
+ begin
31
+ Timeout.timeout(5) do
32
+ DNSSD.resolve(br.name, br.type, br.domain) do |rr|
33
+ begin
34
+ @mutex.synchronize do
35
+ rr_exists = Proc.new {|existing_rr| existing_rr.target == rr.target && existing_rr.fullname == rr.fullname}
36
+ if (DNSSD::Flags::Add & br.flags.to_i) != 0
37
+ @replies << rr unless @replies.any?(&rr_exists)
38
+ else
39
+ @replies.delete_if(&rr_exists)
40
+ end
41
+ end
42
+ ensure
43
+ rr.service.stop
44
+ end
45
+ end
46
+ end
47
+ rescue Timeout::Error
48
+ # Do nothing
49
+ end
50
+ end
51
+ end
52
+ end