bigbananajour 0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,64 @@
1
+ $:.unshift "#{File.dirname(__FILE__)}/lib"
2
+
3
+ require "bigbananajour/gem_dependencies"
4
+ require "bigbananajour/version"
5
+
6
+ gem = Gem::Specification.new do |gem|
7
+ gem.name = "bigbananajour"
8
+ gem.version = BigBananajour::VERSION
9
+ gem.platform = Gem::Platform::RUBY
10
+ gem.extra_rdoc_files = ["Readme.md"]
11
+ gem.summary = "Bananajour mirroring FTW!"
12
+ gem.description = gem.summary
13
+ gem.authors = ["James Sadler"]
14
+ gem.email = "freshtonic@gmail.com"
15
+ gem.homepage = "http://github.com/freshtonic/bigbananajour"
16
+ gem.require_path = "lib"
17
+ gem.files = %w(Readme.md Rakefile) + Dir.glob("{bin,lib,sinatra}/**/*")
18
+ gem.has_rdoc = false
19
+ gem.bindir = 'bin'
20
+ gem.executables = [ 'bigbananajour']
21
+ BigBananajour::GemDependencies.all.each {|dep| gem.add_runtime_dependency( dep.name, dep.version ) }
22
+ end
23
+
24
+ task :clean do
25
+ FileUtils.rm_rf Dir['*.gem', '*.gemspec']
26
+ end
27
+
28
+ namespace :gem do
29
+
30
+ desc "Rebuild and install bigbananajour as a gem"
31
+ task :install => :package do
32
+ require 'rubygems/installer'
33
+ Dir['*.gem'].each do |gem|
34
+ Gem::Installer.new(gem).install
35
+ end
36
+ end
37
+
38
+ desc "Create the gem"
39
+ task :package => [:clean, "spec:generate"] do
40
+ require 'rubygems/builder'
41
+ Gem::Builder.new( gem ).build
42
+ end
43
+
44
+ namespace :spec do
45
+
46
+ desc "Update #{gem.name}.gemspec"
47
+ task :generate do
48
+ File.open("#{gem.name}.gemspec", "w") do |f|
49
+ f.puts(gem.to_ruby)
50
+ end
51
+ end
52
+
53
+ desc "Test spec in github cleanroom"
54
+ task :test => :generate do
55
+ require 'rubygems/specification'
56
+ data = File.read("#{gem.name}.gemspec")
57
+ spec = nil
58
+ Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
59
+ puts "#{spec} - Good to go!"
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,118 @@
1
+ BigBananajour - Local git mirroring for Bananajour!
2
+ ===================================================
3
+
4
+ ![Screenshot of local view of Bigbananajour 2.1.3](http://github.com/freshtonic/bigbananajour/raw/master/screenshot.png)
5
+
6
+ Installation and usage
7
+ ----------------------
8
+
9
+ You'll need at least [git version 1.6](http://git-scm.com/). Run `git --version` if you're unsure.
10
+
11
+ Install it from [gemcutter](http://gemcutter.org/) via gems:
12
+
13
+ gem install bigbananajour
14
+
15
+ (you might need to do a `gem sources -a http://gemcutter.org` beforehand!)
16
+
17
+ Start it up:
18
+
19
+ bigbananajour
20
+
21
+ Fire up [http://localhost:9332/](http://localhost:9332/) to check it out.
22
+
23
+ Whenever somebody starts a Bananajour instance on the network, Bigbananajour will slurp up all the published git repos, including all branches.
24
+ And when some updates a repo, Bigbananajour notices and gets the latest changes. You get backups happening automatically and in one place,
25
+ plus an alternative place to clone from should the other user switch off their bananajour or go AWOL.
26
+
27
+ For a list of all the commands:
28
+
29
+ bigbananajour help
30
+
31
+ Optional configuration: you can override the hostname by setting a global git config option like so:
32
+
33
+ git config --global bananajour.hostname foobar
34
+
35
+ If you set this setting, then bananajour will assume that you know precisely what you're doing, it will not append .local, it will not check this hostname is valid, or do anything to it. If you set this, then you're on your own.
36
+
37
+ If you set this setting, then bananajour will assume that you know precisely what you're doing, it will not append .local, it will not check this hostname is valid, or do anything to it. If you set this, then you're on your own.
38
+
39
+ Make sure you have these ports open on your firewall:
40
+
41
+ 9417 - git - bigbananajour
42
+ 9418 - git - bananajour
43
+ 9331 - bananajour
44
+ 9332 - bigbananajour
45
+
46
+ Linux support
47
+ -------------
48
+
49
+ To install the dnssd gem on Linux you'll need [avahi](http://avahi.org/). For Ubunutu peeps this means:
50
+
51
+ sudo apt-get install libavahi-compat-libdnssd-dev libavahi-discover
52
+
53
+ You can debug whether or not Avahi can see Bananajour and git-daemon Bonjour statuses using the command 'avahi-browse'. This command can be found in the package 'avahi-utils'.
54
+
55
+ The following command will show you all of the Bonjour services running on your local network:
56
+
57
+ avahi-browse --all
58
+
59
+ If you kill bananajour with kill -9 it doesn't get a chance to unregister the Bonjour services, and when it is restarted it will die with DNSSD::AlreadyRegisteredError. Although not ideal, you can work around this my restarting avahi-daemon first.
60
+
61
+ You will also need to uncomment the following line in your /etc/avahi/avahi-daemon.conf.
62
+
63
+ domain-name=local
64
+
65
+ And then restart the Avahi service:
66
+
67
+ sudo service avahi-daemon restart
68
+
69
+ Note: You might have to restart the avahi-daemon sometimes if you are having problems seeing other bananajours.
70
+
71
+
72
+ Official repository and support
73
+ -------------------------------
74
+
75
+ The official repo and support issues/tickets live at [github.com/freshtonic/bigbananajour](http://github.com/freshtonic/bigbananajour).
76
+
77
+ Developing
78
+ ----------
79
+
80
+ 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:
81
+
82
+ ruby sinatra/app.rb -s thin
83
+
84
+ If you want code reloading use [shotgun](http://github.com/rtomayko/shotgun) instead:
85
+
86
+ shotgun sinatra/app.rb -s thin
87
+
88
+ If you then want to run your working copy as your public bananajour rebuild and install it as a gem:
89
+
90
+ sudo rake gem:install
91
+
92
+ Contributors
93
+ ------------
94
+
95
+ * [James Sadler](http://github.com/freshtonic)
96
+
97
+ But the real credit should go to all these awesome people for making Bananajour:
98
+
99
+ * [Tim Lucas](http://github.com/toolmantim)
100
+ * [Carla Hackett](http://carlahackettdesign.com/) (logo)
101
+ * [Nathan de Vries](http://github.com/atnan)
102
+ * [Lachlan Hardy](http://github.com/lachlanhardy)
103
+ * [Josh Bassett](http://github.com/nullobject)
104
+ * [Myles Byrne](http://github.com/quackingduck)
105
+ * [Ben Hoskings](http://github.com/benhoskings)
106
+ * [Brett Goulder](http://github.com/brettgo1)
107
+ * [Tony Issakov](https://github.com/tissak)
108
+ * [Mark Bennett](http://github.com/MarkBennett)
109
+ * [Travis Swicegood](http://github.com/tswicegood)
110
+ * [Nate Haas](http://github.com/natehaas)
111
+ * [James Sadler](http://github.com/freshtonic)
112
+ * [Jason King](http://github.com/JasonKing)
113
+
114
+ License
115
+ -------
116
+
117
+ All directories and files are MIT Licensed.
118
+
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require (File.symlink?(__FILE__) ? "bigbananajour" : File.join(File.dirname(__FILE__), "/../lib/bigbananajour"))
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
+ parent_process_pid = Process.pid
13
+ pids = []
14
+ at_exit do
15
+ if Process.pid == parent_process_pid
16
+ pids.each do |pid|
17
+ Process.kill("TERM", pid) rescue nil
18
+ sleep 0.2
19
+ end
20
+ end
21
+ end
22
+
23
+ case ARGV.first
24
+
25
+ when nil
26
+ pids << Bananajour.serve_web!
27
+ pids << Bananajour.serve_git!
28
+ pids << Bananajour.eat_me_some_bananas!
29
+ pids << Bananajour.advertise!
30
+ Process.waitall
31
+
32
+ when "help", "--help", "-h"
33
+ puts <<-HELP
34
+ Usage: #{File.basename($0)} [<command>]
35
+
36
+ Commands:
37
+ none - Mirror all bananajour repositories and start web, git and bonjour serving
38
+ help
39
+ version
40
+ HELP
41
+
42
+ when "version", "--version", "-v"
43
+ puts "bigbananajour version #{BigBananajour::VERSION}"
44
+ else
45
+ abort "Say what? Try: #{File.basename($0)} help"
46
+ end
@@ -0,0 +1,16 @@
1
+ libdir = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
4
+ require "bananajour"
5
+
6
+ require 'bigbananajour/email_mangle_helper'
7
+ require 'bigbananajour/eater'
8
+ require 'bigbananajour/version'
9
+
10
+ # Bananajour monkeypatches.
11
+ require 'bigbananajour/bananajour/bananajour'
12
+ require 'bigbananajour/bananajour/commands'
13
+ require 'bigbananajour/bananajour/repository'
14
+ require 'bigbananajour/bananajour/bonjour/advertiser'
15
+ require 'bigbananajour/bananajour/bonjour/repository'
16
+ require 'bigbananajour/bananajour/bonjour/repository_browser'
@@ -0,0 +1,34 @@
1
+
2
+ # Monkeypatch bananajour to override ports
3
+ # and repository resolution behaviour.
4
+ module Bananajour
5
+
6
+ class << self
7
+
8
+ include BigBananajour::EmailMangleHelper
9
+
10
+ def repositories_path
11
+ path/"mirrored_repositories"
12
+ end
13
+
14
+ def web_port
15
+ 9332
16
+ end
17
+
18
+ def git_port
19
+ 9419
20
+ end
21
+
22
+ def git_uri
23
+ "git://#{host_name}:#{git_port}/"
24
+ end
25
+
26
+ def repositories
27
+ repositories_path.children.map {|dir| Fancypath(dir).children.map{|r| Repository.new(r)}.sort_by{|r| r.name}}.flatten
28
+ end
29
+
30
+ def people_that_have_repository(repository_name)
31
+ repositories.select{|r| r.name == repository_name}.map{|r| demangle_email(r.path.expand_path.to_s.split("/")[-2]) }.sort
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,30 @@
1
+ class Bananajour::Bonjour::Advertiser
2
+ private
3
+ def register_app
4
+ STDOUT.puts "Registering #{Bananajour.web_uri}"
5
+ tr = DNSSD::TextRecord.new
6
+ tr["name"] = Bananajour.config.name
7
+ tr["email"] = Bananajour.config.email
8
+ tr["uri"] = Bananajour.web_uri
9
+ tr["gravatar"] = Bananajour.gravatar
10
+ tr["version"] = Bananajour::VERSION
11
+ DNSSD.register("#{Bananajour.config.name}'s BIG bananajour", "_http._tcp,_bigbananajour", nil, Bananajour.web_port, tr) {}
12
+ end
13
+ def register_new_repositories
14
+ new_repositories.each do |new_repo|
15
+ STDOUT.puts "Registering #{new_repo.uri}"
16
+ tr = DNSSD::TextRecord.new
17
+ tr["name"] = new_repo.name
18
+ tr["uri"] = new_repo.uri
19
+ tr["bjour-name"] = Bananajour.config.name
20
+ tr["bjour-email"] = Bananajour.config.email
21
+ tr["bjour-uri"] = Bananajour.web_uri
22
+ tr["bjour-gravatar"] = Bananajour.gravatar
23
+ tr["bjour-version"] = BigBananajour::VERSION
24
+ service = DNSSD.register(new_repo.name, "_git._tcp,_bigbananajour", nil, Bananajour.git_port, tr) {}
25
+ service.class.instance_eval { attr_accessor(:repository) }
26
+ service.repository = new_repo
27
+ @services << service
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,9 @@
1
+ class Bananajour::Bonjour::Repository
2
+
3
+ attr_accessor :name, :uri, :ismirror, :person
4
+
5
+ def initialize(name, uri, person)
6
+ @name, @uri, @person = name, uri, person
7
+ end
8
+
9
+ end
@@ -0,0 +1,19 @@
1
+ module Bananajour::Bonjour
2
+ class RepositoryBrowser
3
+
4
+ def repositories
5
+ @browser.replies.map do |reply|
6
+ Repository.new(
7
+ reply.text_record["name"],
8
+ reply.text_record["uri"],
9
+ Person.new(
10
+ reply.text_record["bjour-name"],
11
+ reply.text_record["bjour-email"],
12
+ reply.text_record["bjour-uri"],
13
+ reply.text_record["bjour-gravatar"]
14
+ )
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,25 @@
1
+ module Bananajour::Commands
2
+
3
+ def serve_web!
4
+ pid = fork { exec "/usr/bin/env ruby #{File.dirname(__FILE__)}/../../../sinatra/app.rb -p #{web_port} -e production" }
5
+ puts "* Started " + web_uri.foreground(:yellow)
6
+ pid
7
+ end
8
+
9
+ def serve_git!
10
+ pid = fork { exec "git daemon --base-path=#{repositories_path} --export-all --port=#{git_port}" }
11
+ puts "* Started " + "#{git_uri}".foreground(:yellow)
12
+ pid
13
+ end
14
+
15
+ def advertise!
16
+ pid = fork { Bananajour::Bonjour::Advertiser.new.go! }
17
+ pid
18
+ end
19
+
20
+ def eat_me_some_bananas!
21
+ pid = fork { Bananajour::Eater.new.go! }
22
+ pid
23
+ end
24
+
25
+ end
@@ -0,0 +1,18 @@
1
+ Bananajour.require_gem 'grit'
2
+
3
+ module Bananajour
4
+ class Repository
5
+ def uri
6
+ Bananajour.git_uri + path.expand_path.to_s.split("/")[-2..-1].join("/")
7
+ end
8
+ # TODO: put this in Bananajour.
9
+ def get_config(key)
10
+ `cd #{path} && git config --get #{key}`
11
+ end
12
+ def set_config(key,value)
13
+ $stderr.puts "setting '#{key}' to '#{value}'"
14
+ `cd #{path} && git config --unset-all #{key}`
15
+ `cd #{path} && git config --replace-all #{key} "#{value}"`
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,54 @@
1
+ class Bananajour::Eater
2
+ def initialize
3
+ @browser = Bananajour::Bonjour::RepositoryBrowser.new
4
+ end
5
+ def go!
6
+ $stderr.puts "Starting the EATER!!!"
7
+ while true do
8
+ @browser.repositories.each do |remote_repo|
9
+ $stderr.puts "Eater has seen remote repo '#{remote_repo}'"
10
+ local_repo = Bananajour::Repository.for_name(make_local_repo_name(remote_repo))
11
+ if local_repo.exists?
12
+ $stderr.puts "Eater, fetching changes from remote repo #{remote_repo.name}"
13
+ fetch_latest(local_repo)
14
+ capture_personal_details(local_repo, remote_repo)
15
+ else
16
+ $stderr.puts "Eater, cloning remote repo #{remote_repo.name}"
17
+ clone_repo(remote_repo)
18
+ fetch_latest(local_repo)
19
+ capture_personal_details(local_repo, remote_repo)
20
+ end
21
+ end
22
+ $stderr.puts "Eater thread SLEEPING"
23
+ sleep 30
24
+ end
25
+ $stderr.puts "Eater thread exiting."
26
+ end
27
+ private
28
+ def fetch_latest(repo)
29
+ # Grit doesn't do fetching(!) so, we'll invoke this ourselves.
30
+ # Note: the repo's were created with git --mirror
31
+ # This means that when when we do git fetch, it's actually updating the BRANCHES.
32
+ # This is so that git clone will create remote refs in the cloned repo.
33
+ `cd #{repo.path} && git fetch -f`
34
+ end
35
+ def clone_repo(remote_repo)
36
+ # FYI: git clone --bare doesn't add the remote 'origin', need to do it manually.
37
+ system(["cd #{Bananajour.repositories_path}",
38
+ "(mkdir #{sanitize_email(remote_repo.person.email)} || true)",
39
+ "git clone --mirror #{remote_repo.uri} #{make_local_repo_name(remote_repo)}.git"
40
+ ].join(" && "))
41
+ end
42
+ # TODO: Re-use the helper version
43
+ def sanitize_email(email)
44
+ email.gsub(/@/, "_at_").gsub(/\./, "_dot_")
45
+ end
46
+ def make_local_repo_name(remote_repo)
47
+ sanitize_email(remote_repo.person.email) + "/" + remote_repo.name
48
+ end
49
+ def capture_personal_details(local_repo, remote_repo)
50
+ $stderr.puts "capturing personal details for #{local_repo.path}"
51
+ local_repo.set_config("bigbananajour.gravatar", remote_repo.person.gravatar)
52
+ local_repo.set_config("bigbananajour.person", remote_repo.person.name)
53
+ end
54
+ end