dolt 0.1.0

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