dolt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.gitmodules +3 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +53 -0
  4. data/Rakefile +10 -0
  5. data/Readme.md +25 -0
  6. data/bin/dolt +46 -0
  7. data/dolt.gemspec +39 -0
  8. data/lib/dolt/async/deferrable_child_process.rb +49 -0
  9. data/lib/dolt/async/when.rb +87 -0
  10. data/lib/dolt/disk_repo_resolver.rb +41 -0
  11. data/lib/dolt/git/blob.rb +31 -0
  12. data/lib/dolt/git/repository.rb +47 -0
  13. data/lib/dolt/git/shell.rb +39 -0
  14. data/lib/dolt/repo_actions.rb +41 -0
  15. data/lib/dolt/sinatra/actions.rb +38 -0
  16. data/lib/dolt/sinatra/base.rb +36 -0
  17. data/lib/dolt/sinatra/multi_repo_browser.rb +37 -0
  18. data/lib/dolt/sinatra/single_repo_browser.rb +44 -0
  19. data/lib/dolt/template_renderer.rb +60 -0
  20. data/lib/dolt/version.rb +21 -0
  21. data/lib/dolt/view.rb +58 -0
  22. data/lib/dolt/view/breadcrumb.rb +45 -0
  23. data/lib/dolt/view/highlighter.rb +49 -0
  24. data/test/dolt/git/blob_test.rb +49 -0
  25. data/test/dolt/git/repository_test.rb +70 -0
  26. data/test/dolt/git/shell_test.rb +78 -0
  27. data/test/dolt/repo_actions_test.rb +73 -0
  28. data/test/dolt/sinatra/actions_test.rb +81 -0
  29. data/test/dolt/template_renderer_test.rb +80 -0
  30. data/test/dolt/view_test.rb +88 -0
  31. data/test/dolt/views/blob_test.rb +96 -0
  32. data/test/test_helper.rb +43 -0
  33. data/vendor/ui/bootstrap/css/bootstrap-responsive.min.css +9 -0
  34. data/vendor/ui/bootstrap/css/bootstrap.min.css +9 -0
  35. data/vendor/ui/bootstrap/img/glyphicons-halflings-white.png +0 -0
  36. data/vendor/ui/bootstrap/img/glyphicons-halflings.png +0 -0
  37. data/vendor/ui/bootstrap/js/bootstrap.min.js +6 -0
  38. data/vendor/ui/css/gitorious.css +535 -0
  39. data/vendor/ui/css/pygments.css +133 -0
  40. data/vendor/ui/iconic/lock_stroke.svg +17 -0
  41. data/vendor/ui/images/f5f5f5-980x1.png +0 -0
  42. data/vendor/ui/images/gitorious.png +0 -0
  43. data/vendor/ui/images/powered-by.png +0 -0
  44. data/vendor/ui/images/white-980x1.png +0 -0
  45. data/vendor/ui/js/gitorious.js +87 -0
  46. data/views/blob.erb +43 -0
  47. data/views/layout.erb +42 -0
  48. metadata +263 -0
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/ui"]
2
+ path = vendor/ui
3
+ url = git://gitorious.org/gitorious/ui3.git
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,53 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dolt (0.1.1)
5
+ async_sinatra (~> 1.0)
6
+ eventmachine (~> 0.12)
7
+ pygments.rb (~> 0.2)
8
+ sinatra (~> 1.3)
9
+ thin (~> 1.4)
10
+ tilt (~> 1.3)
11
+
12
+ GEM
13
+ remote: http://rubygems.org/
14
+ specs:
15
+ async_sinatra (1.0.0)
16
+ rack (>= 1.4.1)
17
+ sinatra (>= 1.3.2)
18
+ blankslate (2.1.2.4)
19
+ daemons (1.1.9)
20
+ em-minitest-spec (1.1.1)
21
+ eventmachine
22
+ eventmachine (0.12.10)
23
+ ffi (1.0.11)
24
+ minitest (2.1.0)
25
+ mocha (0.9.12)
26
+ pygments.rb (0.2.13)
27
+ rubypython (~> 0.5.3)
28
+ rack (1.4.1)
29
+ rack-protection (1.2.0)
30
+ rack
31
+ rake (0.9.2.2)
32
+ rubypython (0.5.3)
33
+ blankslate (>= 2.1.2.3)
34
+ ffi (~> 1.0.7)
35
+ sinatra (1.3.3)
36
+ rack (~> 1.3, >= 1.3.6)
37
+ rack-protection (~> 1.2)
38
+ tilt (~> 1.3, >= 1.3.3)
39
+ thin (1.4.1)
40
+ daemons (>= 1.0.9)
41
+ eventmachine (>= 0.12.6)
42
+ rack (>= 1.0.0)
43
+ tilt (1.3.3)
44
+
45
+ PLATFORMS
46
+ ruby
47
+
48
+ DEPENDENCIES
49
+ dolt!
50
+ em-minitest-spec (~> 1.1)
51
+ minitest (~> 2.0)
52
+ mocha
53
+ rake (~> 0.9)
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "rake/testtask"
2
+ require "bundler/gem_tasks"
3
+
4
+ Rake::TestTask.new("test") do |test|
5
+ test.libs << "test"
6
+ test.pattern = "test/**/*_test.rb"
7
+ test.verbose = true
8
+ end
9
+
10
+ task :default => :test
data/Readme.md ADDED
@@ -0,0 +1,25 @@
1
+ # Dolt - The Git project browser
2
+
3
+ Dolt is a stand-alone server that allows you to browse git repositories in your
4
+ browser. It uses Pygments to syntax highlight code, and displays blame as well
5
+ as git history for individual files.
6
+
7
+ Dolt can also be used as a library to serve git trees from e.g. a Rails app. It
8
+ is the blob viewer implementation that will be used in the Gitorious application
9
+ (gitorious.org) when it is ready.
10
+
11
+ ## Blobs
12
+
13
+ Dolt currenly only serves blobs. The sample Rack application that comes with
14
+ Dolt allows you to surf repos locally on your disk:
15
+
16
+ env REPO_ROOT=/where/git/repos/reside rackup -Ilib
17
+
18
+ That command will start the server, and allow you to view blobs in repos
19
+ available in the `/where/git/repos/reside` directory. For example, on my machine,
20
+ when I issue:
21
+
22
+ env REPO_ROOT=/home/christian/projects rackup -Ilib
23
+
24
+ I can go to [http://localhost:9292/gitorious/blob/master:app/models/repository.rb](http://localhost:9292/gitorious/blob/master:app/models/repository.rb)
25
+ to view Gitorious blobs.
data/bin/dolt ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+ require "thin"
3
+ require "sinatra/base"
4
+ require "dolt/repo_actions"
5
+ require "dolt/template_renderer"
6
+ require "dolt/view"
7
+ require "dolt/git/file_system_repository_resolver"
8
+
9
+ if ARGV.length == 0
10
+ puts("Dolt should be run with a directory as its sole argument")
11
+ puts("The directory should either be a Git repository or a directory")
12
+ puts("that holds Git repositories.")
13
+ exit(1)
14
+ end
15
+
16
+ ### TODO: Extract this into a testable API
17
+
18
+ def is_git_repo?(dir)
19
+ File.exists?(File.join(dir, ".git"))
20
+ end
21
+
22
+ def create_app(dir, view)
23
+ if is_git_repo?(dir)
24
+ require "dolt/sinatra/single_repo_browser"
25
+ dir = File.expand_path(dir)
26
+ resolver = Dolt::DiskRepoResolver.new(File.dirname(dir))
27
+ actions = Dolt::RepoActions.new(resolver)
28
+ Dolt::Sinatra::SingleRepoBrowser.new(File.basename(dir), actions, view)
29
+ else
30
+ resolver = Dolt::DiskRepoResolver.new(dir)
31
+ actions = Dolt::RepoActions.new(resolver)
32
+ require "dolt/sinatra/multi_repo_browser"
33
+ Dolt::Sinatra::MultiRepoBrowser.new(actions, view)
34
+ end
35
+ end
36
+
37
+ base = File.join(File.dirname(__FILE__), "..")
38
+
39
+ template_root = File.join(base, "views")
40
+ options = { :cache => false, :layout => "layout" }
41
+ view = Dolt::TemplateRenderer.new(template_root, options)
42
+ view.helper(Dolt::View)
43
+
44
+ Sinatra::Base.set(:public_folder, File.join(base, "vendor/ui"))
45
+ server = create_app(ARGV[0], view)
46
+ Thin::Server.start("0.0.0.0", 3000, server)
data/dolt.gemspec ADDED
@@ -0,0 +1,39 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.join("lib/dolt/version")
3
+
4
+ module GemSpecHelper
5
+ def self.files(path)
6
+ `cd #{path} && git ls-files`.split("\n").map do |p|
7
+ File.join(path, p)
8
+ end
9
+ end
10
+ end
11
+
12
+ Gem::Specification.new do |s|
13
+ s.name = "dolt"
14
+ s.version = Dolt::VERSION
15
+ s.authors = ["Christian Johansen"]
16
+ s.email = ["christian@gitorious.org"]
17
+ s.homepage = "http://gitorious.org/gitorious/dolt"
18
+ s.summary = %q{Dolt serves git trees and syntax highlighted blobs}
19
+ s.description = %q{Dolt serves git trees and syntax highlighted blobs}
20
+
21
+ s.rubyforge_project = "dolt"
22
+
23
+ s.add_dependency "eventmachine", "~>0.12"
24
+ s.add_dependency "thin", "~>1.4"
25
+ s.add_dependency "sinatra", "~>1.3"
26
+ s.add_dependency "async_sinatra", "~>1.0"
27
+ s.add_dependency "tilt", "~>1.3"
28
+ s.add_dependency "pygments.rb", "~>0.2"
29
+
30
+ s.add_development_dependency "minitest", "~> 2.0"
31
+ s.add_development_dependency "em-minitest-spec", "~> 1.1"
32
+ s.add_development_dependency "rake", "~> 0.9"
33
+ s.add_development_dependency "mocha"
34
+
35
+ s.files = GemSpecHelper.files(".") + GemSpecHelper.files("vendor/ui")
36
+ s.test_files = `git ls-files -- {test}/*`.split("\n")
37
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
38
+ s.require_paths = ["lib"]
39
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ #--
3
+ # Copyright (C) 2012 Gitorious AS
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #++
18
+ require "eventmachine"
19
+
20
+ module Dolt
21
+ # A deferrable child process implementation that actually considers
22
+ # the not uncommon situation where the command fails.
23
+ #
24
+ class DeferrableChildProcess < EventMachine::Connection
25
+ include EventMachine::Deferrable
26
+
27
+ def initialize
28
+ super
29
+ @data = []
30
+ end
31
+
32
+ def self.open cmd
33
+ EventMachine.popen(cmd, DeferrableChildProcess)
34
+ end
35
+
36
+ def receive_data data
37
+ @data << data
38
+ end
39
+
40
+ def unbind
41
+ status = get_status
42
+ if status.exitstatus != 0
43
+ fail(status)
44
+ else
45
+ succeed(@data.join, status)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,87 @@
1
+ require "eventmachine"
2
+
3
+ module When
4
+ class Promise
5
+ def initialize(deferred = EM::DefaultDeferrable.new)
6
+ @deferred = deferred
7
+ end
8
+
9
+ def callback(&block)
10
+ @deferred.callback(&block)
11
+ self
12
+ end
13
+
14
+ def errback(&block)
15
+ @deferred.errback(&block)
16
+ self
17
+ end
18
+ end
19
+
20
+ class Resolver
21
+ def initialize(deferred = EM::DefaultDeferrable.new)
22
+ @deferred = deferred
23
+ @resolved = false
24
+ end
25
+
26
+ def resolve(*args)
27
+ mark_resolved
28
+ @deferred.succeed(*args)
29
+ end
30
+
31
+ def reject(*args)
32
+ mark_resolved
33
+ @deferred.fail(*args)
34
+ end
35
+
36
+ private
37
+ def mark_resolved
38
+ raise StandardError.new("Already resolved") if @resolved
39
+ @resolved = true
40
+ end
41
+ end
42
+
43
+ class Deferred
44
+ attr_reader :resolver, :promise
45
+
46
+ def initialize
47
+ deferred = EM::DefaultDeferrable.new
48
+ @resolver = Resolver.new(deferred)
49
+ @promise = Promise.new(deferred)
50
+ end
51
+
52
+ def resolve(*args)
53
+ @resolver.resolve(*args)
54
+ end
55
+
56
+ def reject(*args)
57
+ @resolver.reject(*args)
58
+ end
59
+
60
+ def callback(&block)
61
+ @promise.callback(&block)
62
+ end
63
+
64
+ def errback(&block)
65
+ @promise.errback(&block)
66
+ end
67
+
68
+ def self.resolved(value)
69
+ d = self.new
70
+ d.resolve(vaule)
71
+ d
72
+ end
73
+
74
+ def self.rejected(value)
75
+ d = self.new
76
+ d.reject(vaule)
77
+ d
78
+ end
79
+ end
80
+
81
+ module Functions
82
+ def deferred(val)
83
+ return val if val.respond_to?(:callback) && val.respond_to?(:errback)
84
+ Deferred.resolved(val).promise
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ #--
3
+ # Copyright (C) 2012 Gitorious AS
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #++
18
+ require "dolt/git/shell"
19
+ require "dolt/git/repository"
20
+
21
+ module Dolt
22
+ class DiskRepoResolver
23
+ def initialize(root)
24
+ @root = root
25
+ end
26
+
27
+ def resolve(repo)
28
+ git = Dolt::Git::Shell.new(File.join(root, repo))
29
+ Dolt::Git::Repository.new(repo, git)
30
+ end
31
+
32
+ def all
33
+ Dir.entries(root).reject do |e|
34
+ e =~ /^\.+$/ || File.file?(File.join(root, e))
35
+ end
36
+ end
37
+
38
+ private
39
+ def root; @root; end
40
+ end
41
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ #--
3
+ # Copyright (C) 2012 Gitorious AS
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #++
18
+ module Dolt
19
+ class Blob
20
+ attr_reader :path, :raw, :repo
21
+
22
+ def initialize(path, raw)
23
+ @path = path
24
+ @raw = raw
25
+ end
26
+
27
+ def lines
28
+ raw.split("\n")
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+ #--
3
+ # Copyright (C) 2012 Gitorious AS
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #++
18
+ require "dolt/async/when"
19
+ require "dolt/git/blob"
20
+
21
+ module Dolt
22
+ module Git
23
+ class Repository
24
+ attr_reader :name
25
+
26
+ def initialize(name, git = nil)
27
+ @name = name
28
+ @git = git
29
+ end
30
+
31
+ def blob(path, ref = "HEAD")
32
+ gitop = git.show(path, ref)
33
+ deferred = When::Deferred.new
34
+
35
+ gitop.callback do |data, status|
36
+ deferred.resolve(Dolt::Blob.new(path, data))
37
+ end
38
+
39
+ gitop.errback { |err| deferred.reject(err) }
40
+ deferred.promise
41
+ end
42
+
43
+ private
44
+ def git; @git; end
45
+ end
46
+ end
47
+ end