ginatra 3.0.1 → 4.0.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 (91) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -15
  3. data/.travis.yml +7 -6
  4. data/CONTRIBUTING.md +30 -0
  5. data/Gemfile +1 -9
  6. data/LICENSE.txt +30 -0
  7. data/README.md +63 -114
  8. data/Rakefile +10 -12
  9. data/bin/ginatra +79 -63
  10. data/config.ru +35 -3
  11. data/ginatra.gemspec +29 -18
  12. data/lib/ginatra.rb +161 -148
  13. data/lib/ginatra/config.rb +18 -121
  14. data/lib/ginatra/errors.rb +10 -0
  15. data/lib/ginatra/helpers.rb +154 -139
  16. data/lib/ginatra/repo.rb +67 -82
  17. data/lib/ginatra/repo_list.rb +25 -18
  18. data/lib/ginatra/repo_stats.rb +93 -0
  19. data/lib/ginatra/version.rb +4 -0
  20. data/lib/git/webby.rb +292 -0
  21. data/lib/git/webby/extensions.rb +10 -0
  22. data/lib/git/webby/http_backend.rb +177 -0
  23. data/lib/sinatra/partials.rb +1 -1
  24. data/public/css/application.css +6 -0
  25. data/public/css/custom.css +57 -0
  26. data/public/css/lib/bootstrap-responsive.min.css +9 -0
  27. data/public/css/lib/bootstrap.min.css +9 -0
  28. data/public/css/lib/highlight.css +209 -0
  29. data/public/img/glyphicons-halflings-white.png +0 -0
  30. data/public/img/glyphicons-halflings.png +0 -0
  31. data/public/img/spin.gif +0 -0
  32. data/public/js/application.js +5 -0
  33. data/public/js/custom.js +51 -0
  34. data/public/js/lib/bootstrap.min.js +6 -0
  35. data/public/js/lib/jquery.lazyload.min.js +2 -0
  36. data/public/js/lib/jquery.min.js +2 -0
  37. data/public/js/lib/jquery.pjax.js +739 -0
  38. data/repos/README.md +21 -8
  39. data/spec/ginatra/helpers_spec.rb +95 -0
  40. data/spec/ginatra/repo_list_spec.rb +66 -0
  41. data/spec/ginatra/repo_spec.rb +78 -0
  42. data/spec/ginatra/repo_stats_spec.rb +27 -0
  43. data/spec/ginatra_spec.rb +121 -0
  44. data/spec/spec_helper.rb +8 -17
  45. data/views/404.erb +18 -0
  46. data/views/500.erb +18 -0
  47. data/views/_footer.erb +7 -0
  48. data/views/_header.erb +12 -6
  49. data/views/_tree_nav.erb +53 -0
  50. data/views/atom.erb +32 -0
  51. data/views/blob.erb +27 -8
  52. data/views/commit.erb +95 -17
  53. data/views/empty_repo.erb +10 -0
  54. data/views/index.erb +27 -11
  55. data/views/layout.erb +16 -20
  56. data/views/log.erb +74 -54
  57. data/views/stats.erb +89 -0
  58. data/views/tree.erb +32 -20
  59. metadata +168 -94
  60. data/bin/ginatra-daemon +0 -87
  61. data/bin/ginatra-directory +0 -55
  62. data/bin/ginatra-server +0 -27
  63. data/bin/ginatra-setup +0 -28
  64. data/lib/ginatra/graph_commit.rb +0 -77
  65. data/public/img/add.png +0 -0
  66. data/public/img/diff.png +0 -0
  67. data/public/img/doc.png +0 -0
  68. data/public/img/rm.png +0 -0
  69. data/public/img/tree.png +0 -0
  70. data/public/src/branch-graph.js +0 -170
  71. data/public/src/colour.css +0 -86
  72. data/public/src/commit.css +0 -211
  73. data/public/src/ginatra.js +0 -7
  74. data/public/src/github.css +0 -129
  75. data/public/src/graph.css +0 -9
  76. data/public/src/highlight.pack.js +0 -1
  77. data/public/src/index.css +0 -92
  78. data/public/src/lists.css +0 -25
  79. data/public/src/raphael.js +0 -7
  80. data/public/src/reset.css +0 -49
  81. data/public/src/table.css +0 -33
  82. data/public/src/type.css +0 -30
  83. data/rackup.ru +0 -5
  84. data/spec/graph_commit_spec.rb +0 -54
  85. data/spec/repo_list_spec.rb +0 -84
  86. data/spec/repo_spec.rb +0 -61
  87. data/views/_actor_box.erb +0 -13
  88. data/views/_commit_info_box.erb +0 -27
  89. data/views/_tree_part.erb +0 -11
  90. data/views/atom.builder +0 -32
  91. data/views/graph.erb +0 -15
data/config.ru CHANGED
@@ -1,5 +1,37 @@
1
- require "ginatra"
1
+ require 'ginatra'
2
+ require 'sprockets'
2
3
 
3
- map '/' do
4
- run Ginatra::App
4
+ map '/assets' do
5
+ environment = Sprockets::Environment.new
6
+ root_path = File.dirname __FILE__
7
+ environment.append_path "#{root_path}/public/js"
8
+ environment.append_path "#{root_path}/public/css"
9
+ run environment
10
+ end
11
+
12
+ if Ginatra.config.git_clone_enabled?
13
+ require 'mkmf'
14
+ require 'git/webby'
15
+
16
+ # Make the MakeMakefile logger write file output to null
17
+ module MakeMakefile::Logging; @logfile = File::NULL; end
18
+
19
+ git_executable = find_executable 'git'
20
+ raise 'Git executable not found in PATH' if git_executable.nil?
21
+ root_path = File.dirname __FILE__
22
+
23
+ Git::Webby::HttpBackend.configure do |server|
24
+ server.project_root = "#{root_path}/repos"
25
+ server.git_path = git_executable
26
+ server.get_any_file = true
27
+ server.upload_pack = false
28
+ server.receive_pack = false
29
+ server.authenticate = false
30
+ end
31
+
32
+ run Rack::Cascade.new [Git::Webby::HttpBackend, Ginatra::App]
33
+ else
34
+ map '/' do
35
+ run Ginatra::App
36
+ end
5
37
  end
data/ginatra.gemspec CHANGED
@@ -1,21 +1,32 @@
1
- Gem::Specification.new do |s|
2
- s.name = "ginatra"
3
- s.version = "3.0.1"
4
- s.summary = "A Gitweb Clone in Sinatra and Grit"
5
- s.description = "Host your own git repository browser through the power of Sinatra and Grit"
6
- s.email = "sam@lenary.co.uk"
7
- s.homepage = "http://lenary.co.uk/ginatra"
8
- s.authors = ["Sam Elliott", "Ryan Bigg"]
9
- s.add_dependency('bundler', '~> 1.0.15')
10
- s.add_dependency('sinatra', '~> 1.2.6')
11
- s.add_dependency('grit', '~> 2.4.1')
12
- s.add_dependency('vegas', '~> 0.1.8')
13
- s.add_dependency('builder', '~> 3.0.0')
14
- s.add_dependency('erubis', '~> 2.7.0')
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'ginatra/version'
15
4
 
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "ginatra"
7
+ gem.version = Ginatra::VERSION
8
+ gem.summary = "Web interface for git repositories"
9
+ gem.description = "Git repository viewer with a rocking good web interface"
10
+ gem.homepage = "https://github.com/narkoz/ginatra"
11
+ gem.email = ["mail@narkoz.me"]
12
+ gem.authors = ["Nihad Abbasov", "Sam Elliott", "Ryan Bigg"]
16
13
 
17
- s.files = `git ls-files`.split("\n")
18
- s.test_files = `git ls-files -- spec`.split("\n")
19
- s.executables = `git ls-files -- bin`.split("\n").map {|f| File.basename(f) }
20
- s.require_paths = ["lib"]
14
+ gem.files = `git ls-files`.split($/) - ['Gemfile.lock']
15
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
16
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.required_ruby_version = ">= 1.9"
20
+
21
+ gem.add_dependency 'sinatra', '~> 1.4.5'
22
+ gem.add_dependency 'rugged', '~> 0.21.3'
23
+ gem.add_dependency 'rouge', '~> 1.7.7'
24
+ gem.add_dependency 'sprockets', '~> 2.0'
25
+
26
+ gem.add_development_dependency 'rake'
27
+ gem.add_development_dependency 'rspec'
28
+ gem.add_development_dependency 'rack-test'
29
+ gem.add_development_dependency 'sinatra-contrib'
30
+ gem.add_development_dependency 'better_errors', '~> 1.1.0'
31
+ gem.add_development_dependency 'binding_of_caller'
21
32
  end
data/lib/ginatra.rb CHANGED
@@ -1,74 +1,59 @@
1
-
2
1
  require 'sinatra/base'
3
- require "sinatra/partials"
4
- require 'json'
2
+ require 'sinatra/partials'
3
+ require 'rouge'
4
+ require 'ginatra/config'
5
+ require 'ginatra/errors'
6
+ require 'ginatra/helpers'
7
+ require 'ginatra/repo'
8
+ require 'ginatra/repo_list'
9
+ require 'ginatra/repo_stats'
5
10
 
6
- # Written myself. i know, what the hell?!
7
11
  module Ginatra
12
+ # The main application class.
13
+ # Contains all the core application logic and mounted in +config.ru+ file.
14
+ class App < Sinatra::Base
15
+ helpers Helpers, Sinatra::Partials
8
16
 
9
- autoload :Config, "ginatra/config"
10
- autoload :Helpers, "ginatra/helpers"
11
- autoload :Repo, "ginatra/repo"
12
- autoload :RepoList, "ginatra/repo_list"
13
- autoload :GraphCommit, "ginatra/graph_commit"
17
+ configure do
18
+ set :host, Ginatra.config.host
19
+ set :port, Ginatra.config.port
20
+ set :public_folder, "#{settings.root}/../public"
21
+ set :views, "#{settings.root}/../views"
22
+ enable :dump_errors, :logging, :static
23
+ end
14
24
 
15
- # A standard error class for inheritance.
16
- class Error < StandardError; end
25
+ configure :development do
26
+ # Use better errors in development
27
+ require 'better_errors'
28
+ use BetterErrors::Middleware
29
+ BetterErrors.application_root = settings.root
17
30
 
18
- # An error related to a commit somewhere.
19
- class CommitsError < Error
20
- def initialize(repo)
21
- super("Something went wrong looking for the commits for #{repo}")
31
+ # Reload modified files in development
32
+ require 'sinatra/reloader'
33
+ register Sinatra::Reloader
34
+ Dir["#{settings.root}/ginatra/*.rb"].each { |file| also_reload file }
22
35
  end
23
- end
24
36
 
25
- # Error raised when commit ref passed in parameters
26
- # does not exist in repository
27
- class InvalidCommit < Error
28
- def initialize(id)
29
- super("Could not find a commit with the id of #{id}")
37
+ def cache(obj)
38
+ etag obj if settings.production?
30
39
  end
31
- end
32
-
33
- VERSION = "3.0.1"
34
-
35
- # The main application class.
36
- #
37
- # This class contains all the core application logic
38
- # and is what is mounted by the +rackup.ru+ files.
39
- class App < Sinatra::Base
40
40
 
41
- # logger that can be used with the Sinatra code
42
- def logger
43
- Ginatra::Config.logger
41
+ not_found do
42
+ erb :'404', layout: false
44
43
  end
45
44
 
46
- configure do
47
- Config.load!
48
- set :host, Ginatra::Config[:host]
49
- set :port, Ginatra::Config[:port]
50
- set :raise_errors, Proc.new { test? }
51
- set :show_exceptions, Proc.new { development? }
52
- set :dump_errors, true
53
- set :logging, Proc.new { !test? }
54
- set :static, true
55
- current_path = File.expand_path(File.dirname(__FILE__))
56
- set :public, "#{current_path}/../public"
57
- set :views, "#{current_path}/../views"
45
+ error Ginatra::RepoNotFound, Ginatra::InvalidRef,
46
+ Rugged::OdbError, Rugged::ObjectError, Rugged::InvalidError do
47
+ halt 404, erb(:'404', layout: false)
58
48
  end
59
49
 
60
- helpers Helpers, Sinatra::Partials
61
-
62
- # Let's handle a CommitsError.
63
- #
64
- # @todo prettify
65
- error CommitsError do
66
- 'No commits were returned for ' + request.uri
50
+ error 500 do
51
+ erb :'500', layout: false
67
52
  end
68
53
 
69
54
  # The root route
70
- # This works by interacting with the Ginatra::Repolist singleton.
71
55
  get '/' do
56
+ @repositories = Ginatra::RepoList.list
72
57
  erb :index
73
58
  end
74
59
 
@@ -80,47 +65,34 @@ module Ginatra
80
65
  get '/:repo.atom' do
81
66
  @repo = RepoList.find(params[:repo])
82
67
  @commits = @repo.commits
83
- return "" if @commits.empty?
84
- etag(@commits.first.id) if Ginatra::App.production?
85
- builder :atom, :layout => nil
68
+
69
+ if @commits.empty?
70
+ return ''
71
+ else
72
+ cache "#{@commits.first.oid}/atom"
73
+ content_type 'application/xml'
74
+ erb :atom, layout: false
75
+ end
86
76
  end
87
77
 
88
78
  # The html page for a +repo+.
89
79
  #
90
- # Shows the most recent commits in a log format
80
+ # Shows the most recent commits in a log format.
91
81
  #
92
82
  # @param [String] repo the repository url-sanitised-name
93
- get '/:repo' do
83
+ get '/:repo/?' do
94
84
  @repo = RepoList.find(params[:repo])
95
- @commits = @repo.commits
96
- etag(@commits.first.id) if Ginatra::App.production?
97
- erb :log
98
- end
99
85
 
100
- get '/:repo/graph' do
101
- @repo = RepoList.find(params[:repo])
102
- max_count = 650
103
- max_count = params[:max_count].to_i unless params[:max_count].nil?
104
- commits = @repo.all_commits(max_count)
105
-
106
- days = GraphCommit.index_commits(commits)
107
- @days_json = days.compact.collect{|d|[d.day,d.strftime("%b")]}.to_json
108
- @commits_json = commits.collect do |c|
109
- h = {}
110
- h[:parents] = c.parents.collect do |p|
111
- [p.id,0,0]
112
- end
113
- h[:author] = c.author.name.force_encoding("UTF-8")
114
- h[:time] = c.time
115
- h[:space] = c.space
116
- h[:refs] = c.refs.collect{|r|r.name}.join(" ") unless c.refs.nil?
117
- h[:id] = c.sha
118
- h[:date] = c.date
119
- h[:message] = c.message.force_encoding("UTF-8")
120
- h[:login] = c.author.email
121
- h
122
- end.to_json
123
- erb :graph
86
+ if @repo.branches.none?
87
+ erb :empty_repo
88
+ else
89
+ params[:page] = 1
90
+ params[:ref] = @repo.branch_exists?('master') ? 'master' : @repo.branches.first.name
91
+ @commits = @repo.commits(params[:ref])
92
+ cache "#{@commits.first.oid}/log"
93
+ @next_commits = !@repo.commits(params[:ref], 10, 10).nil?
94
+ erb :log
95
+ end
124
96
  end
125
97
 
126
98
  # The atom feed of recent commits to a certain branch of a +repo+.
@@ -130,33 +102,54 @@ module Ginatra
130
102
  get '/:repo/:ref.atom' do
131
103
  @repo = RepoList.find(params[:repo])
132
104
  @commits = @repo.commits(params[:ref])
133
- return "" if @commits.empty?
134
- etag(@commits.first.id) if Ginatra::App.production?
135
- builder :atom, :layout => nil
105
+
106
+ if @commits.empty?
107
+ return ''
108
+ else
109
+ cache "#{@commits.first.oid}/atom/ref"
110
+ content_type 'application/xml'
111
+ erb :atom, layout: false
112
+ end
136
113
  end
137
114
 
138
115
  # The html page for a given +ref+ of a +repo+.
139
116
  #
140
- # Shows the most recent commits in a log format
117
+ # Shows the most recent commits in a log format.
141
118
  #
142
119
  # @param [String] repo the repository url-sanitised-name
143
120
  # @param [String] ref the repository ref
144
121
  get '/:repo/:ref' do
145
- params[:page] = 1
146
122
  @repo = RepoList.find(params[:repo])
147
123
  @commits = @repo.commits(params[:ref])
148
- etag(@commits.first.id) if Ginatra::App.production?
124
+ cache "#{@commits.first.oid}/ref" if @commits.any?
125
+ params[:page] = 1
126
+ @next_commits = !@repo.commits(params[:ref], 10, 10).nil?
149
127
  erb :log
150
128
  end
151
129
 
130
+ # The html page for a +repo+ stats.
131
+ #
132
+ # Shows information about repository branch.
133
+ #
134
+ # @param [String] repo the repository url-sanitised-name
135
+ # @param [String] ref the repository ref
136
+ get '/:repo/stats/:ref' do
137
+ @repo = RepoList.find(params[:repo])
138
+ @stats = RepoStats.new(@repo, params[:ref])
139
+ erb :stats
140
+ end
141
+
152
142
  # The patch file for a given commit to a +repo+.
153
143
  #
154
144
  # @param [String] repo the repository url-sanitised-name
155
145
  # @param [String] commit the repository commit
156
146
  get '/:repo/commit/:commit.patch' do
157
- response['Content-Type'] = "text/plain"
158
- @repo = RepoList.find(params[:repo])
159
- @repo.git.format_patch({}, "--stdout", "-1", params[:commit])
147
+ content_type :txt
148
+ repo = RepoList.find(params[:repo])
149
+ commit = repo.commit(params[:commit])
150
+ cache "#{commit.oid}/patch"
151
+ diff = commit.parents.first.diff(commit)
152
+ diff.patch
160
153
  end
161
154
 
162
155
  # The html representation of a commit.
@@ -165,64 +158,58 @@ module Ginatra
165
158
  # @param [String] commit the repository commit
166
159
  get '/:repo/commit/:commit' do
167
160
  @repo = RepoList.find(params[:repo])
168
- @commit = @repo.commit(params[:commit]) # can also be a ref
169
- etag(@commit.id) if Ginatra::App.production?
170
- erb(:commit)
161
+ @commit = @repo.commit(params[:commit])
162
+ cache @commit.oid
163
+ erb :commit
171
164
  end
172
165
 
173
- # Download an archive of a given tree!
166
+ # The html representation of a tag.
174
167
  #
175
168
  # @param [String] repo the repository url-sanitised-name
176
- # @param [String] tree the repository tree
177
- get '/:repo/archive/:tree.tar.gz' do
178
- response['Content-Type'] = "application/x-tar-gz"
169
+ # @param [String] tag the repository tag
170
+ get '/:repo/tag/:tag' do
179
171
  @repo = RepoList.find(params[:repo])
180
- @repo.archive_tar_gz(params[:tree])
172
+ @commit = @repo.commit_by_tag(params[:tag])
173
+ cache "#{@commit.oid}/tag"
174
+ erb :commit
181
175
  end
182
176
 
183
177
  # HTML page for a given tree in a given +repo+
184
178
  #
185
- # @todo cleanup!
186
179
  # @param [String] repo the repository url-sanitised-name
187
180
  # @param [String] tree the repository tree
188
181
  get '/:repo/tree/:tree' do
189
182
  @repo = RepoList.find(params[:repo])
183
+ @tree = @repo.find_tree(params[:tree])
184
+ cache @tree.oid
190
185
 
191
- if (tag = @repo.git.rev_parse({'--verify' => ''}, "#{params[:tree]}^{tree}")).empty?
192
- # we don't have a tree.
193
- not_found
194
- else
195
- etag(tag) if Ginatra::App.production?
196
- end
197
-
198
- @tree = @repo.tree(params[:tree]) # can also be a ref (i think)
199
- @path = {}
200
- @path[:tree] = "#{params[:repo]}/tree/#{params[:tree]}"
201
- @path[:blob] = "#{params[:repo]}/blob/#{params[:tree]}"
202
- erb(:tree)
186
+ @path = {
187
+ blob: "#{params[:repo]}/blob/#{params[:tree]}",
188
+ tree: "#{params[:repo]}/tree/#{params[:tree]}"
189
+ }
190
+ erb :tree, layout: !is_pjax?
203
191
  end
204
192
 
205
193
  # HTML page for a given tree in a given +repo+.
206
194
  #
207
- # This one supports a splat parameter so you can specify a path
195
+ # This one supports a splat parameter so you can specify a path.
208
196
  #
209
- # @todo cleanup!
210
197
  # @param [String] repo the repository url-sanitised-name
211
198
  # @param [String] tree the repository tree
212
- get '/:repo/tree/:tree/*' do # for when we specify a path
199
+ get '/:repo/tree/:tree/*' do
213
200
  @repo = RepoList.find(params[:repo])
214
- @tree = @repo.tree(params[:tree])/params[:splat].first # can also be a ref (i think)
215
- if @tree.is_a?(Grit::Blob)
216
- # we need @tree to be a tree. if it's a blob, send it to the blob page
217
- # this allows people to put in the remaining part of the path to the file, rather than endless clicks like you need in github
218
- redirect "#{params[:repo]}/blob/#{params[:tree]}/#{params[:splat].first}"
219
- else
220
- etag(@tree.id) if Ginatra::App.production?
221
- @path = {}
222
- @path[:tree] = "#{params[:repo]}/tree/#{params[:tree]}/#{params[:splat].first}"
223
- @path[:blob] = "#{params[:repo]}/blob/#{params[:tree]}/#{params[:splat].first}"
224
- erb(:tree)
201
+ @tree = @repo.find_tree(params[:tree])
202
+ cache "#{@tree.oid}/#{params[:splat].first}"
203
+
204
+ @tree.walk(:postorder) do |root, entry|
205
+ @tree = @repo.lookup entry[:oid] if "#{root}#{entry[:name]}" == params[:splat].first
225
206
  end
207
+
208
+ @path = {
209
+ blob: "#{params[:repo]}/blob/#{params[:tree]}/#{params[:splat].first}",
210
+ tree: "#{params[:repo]}/tree/#{params[:tree]}/#{params[:splat].first}"
211
+ }
212
+ erb :tree, layout: !is_pjax?
226
213
  end
227
214
 
228
215
  # HTML page for a given blob in a given +repo+
@@ -231,49 +218,75 @@ module Ginatra
231
218
  # @param [String] tree the repository tree
232
219
  get '/:repo/blob/:blob' do
233
220
  @repo = RepoList.find(params[:repo])
234
- @blob = @repo.blob(params[:blob])
235
- etag(@blob.id) if Ginatra::App.production?
236
- erb(:blob)
221
+ @tree = @repo.lookup(params[:tree])
222
+
223
+ @tree.walk(:postorder) do |root, entry|
224
+ @blob = entry if "#{root}#{entry[:name]}" == params[:splat].first
225
+ end
226
+
227
+ cache @blob[:oid]
228
+ erb :blob, layout: !is_pjax?
237
229
  end
238
230
 
239
231
  # HTML page for a given blob in a given repo.
240
232
  #
241
233
  # Uses a splat param to specify a blob path.
242
234
  #
243
- # @todo cleanup!
244
235
  # @param [String] repo the repository url-sanitised-name
245
236
  # @param [String] tree the repository tree
246
237
  get '/:repo/blob/:tree/*' do
247
238
  @repo = RepoList.find(params[:repo])
248
- @blob = @repo.tree(params[:tree])/params[:splat].first
249
- if @blob.is_a?(Grit::Tree)
250
- # as above, we need @blob to be a blob. if it's a tree, send it to the tree page
251
- # this allows people to put in the remaining part of the path to the folder, rather than endless clicks like you need in github
252
- redirect "/#{params[:repo]}/tree/#{params[:tree]}/#{params[:splat].first}"
239
+ @tree = @repo.find_tree(params[:tree])
240
+
241
+ @tree.walk(:postorder) do |root, entry|
242
+ @blob = entry if "#{root}#{entry[:name]}" == params[:splat].first
243
+ end
244
+
245
+ cache "#{@blob[:oid]}/#{@tree.oid}"
246
+ erb :blob, layout: !is_pjax?
247
+ end
248
+
249
+ # HTML page for a raw blob contents in a given repo.
250
+ #
251
+ # Uses a splat param to specify a blob path.
252
+ #
253
+ # @param [String] repo the repository url-sanitised-name
254
+ # @param [String] tree the repository tree
255
+ get '/:repo/raw/:tree/*' do
256
+ @repo = RepoList.find(params[:repo])
257
+ @tree = @repo.find_tree(params[:tree])
258
+
259
+ @tree.walk(:postorder) do |root, entry|
260
+ @blob = entry if "#{root}#{entry[:name]}" == params[:splat].first
261
+ end
262
+
263
+ cache "#{@blob[:oid]}/#{@tree.oid}/raw"
264
+ blob = @repo.find_blob @blob[:oid]
265
+ if blob.binary?
266
+ content_type 'application/octet-stream'
267
+ blob.text
253
268
  else
254
- etag(@blob.id) if Ginatra::App.production?
255
- erb(:blob)
269
+ content_type :txt
270
+ blob.text
256
271
  end
257
272
  end
258
273
 
259
- # pagination route for the commits to a given ref in a +repo+.
274
+ # Pagination route for the commits to a given ref in a +repo+.
260
275
  #
261
- # @todo cleanup!
262
276
  # @param [String] repo the repository url-sanitised-name
263
277
  # @param [String] ref the repository ref
264
- get '/:repo/:ref/:page' do
265
- pass unless params[:page] =~ /^(\d)+$/
278
+ get '/:repo/:ref/page/:page' do
279
+ pass unless params[:page] =~ /\A\d+\z/
266
280
  params[:page] = params[:page].to_i
267
281
  @repo = RepoList.find(params[:repo])
268
282
  @commits = @repo.commits(params[:ref], 10, (params[:page] - 1) * 10)
269
- @next_commits = !@repo.commits(params[:ref], 10, params[:page] * 10).empty?
283
+ cache "#{@commits.first.oid}/page/#{params[:page]}/ref/#{params[:ref]}" if @commits.any?
284
+ @next_commits = !@repo.commits(params[:ref], 10, params[:page] * 10).nil?
270
285
  if params[:page] - 1 > 0
271
286
  @previous_commits = !@repo.commits(params[:ref], 10, (params[:page] - 1) * 10).empty?
272
287
  end
273
- @separator = @next_commits && @previous_commits
274
288
  erb :log
275
289
  end
276
290
 
277
291
  end # App
278
-
279
292
  end # Ginatra