bananajour 2.1.9

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/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