followed one path, but now I think I'm going to back out
[rubygit.git] / camping / gitweb.rb
blob0e0f2c4ab25d1a37bb5b344f06022d6e4aec1e3f
1 require 'rubygems'
2 require 'camping'
3 require 'git'
5 begin
6   require 'syntax/convertors/html'
7 rescue LoadError
8 end
10 # this is meant to be a git-less web head to your git repo
12 # install dependencies
13 #   sudo gem install camping-omnibus --source http://code.whytheluckystiff.net
15 # author : scott chacon
16 # thanks to dr. nic for his syntax code highlighting deal
18 # /usr/local/lib/ruby/gems/1.8/gems/camping-1.5.180/examples/
20 Camping.goes :GitWeb
22 module GitWeb::Models
23   class Repository < Base; end
24   
25   class CreateGitWeb < V 0.1
26     def self.up
27       create_table :gitweb_repositories, :force => true do |t|
28         t.column :name,  :string 
29         t.column :path,  :string 
30         t.column :bare,  :boolean 
31       end
32     end
33   end
34 end
36 module GitWeb::Controllers
37   class Index < R '/'
38     def get
39       @repos = Repository.find :all
40       render :index
41     end
42   end
43   
44   class Stylesheet < R '/css/highlight.css'
45     def get
46       @headers['Content-Type'] = 'text/css'
47       ending = File.read(__FILE__).gsub(/.*__END__/m, '')
48       ending.gsub(/__END__.*/m, '')
49     end
50   end
51   
52   class JsHighlight < R '/js/highlight.js'
53     def get
54       @headers['Content-Type'] = 'text/css'
55       File.read(__FILE__).gsub(/.*__JS__/m, '')
56     end
57   end
58   
59   class View < R '/view/(\d+)'
60     def get repo_id
61       @repo = Repository.find repo_id
62       @git = Git.bare(@repo.path)      
63       render :view
64     end
65   end
66   
67   class Fetch < R '/git/(\d+)'
68     def get repo_id
69       @repo = Repository.find repo_id
70       @git = Git.bare(@repo.path)
71     end
72   end
73   
74   class Add < R '/add'
75     def get
76       @repo = Repository.new
77       render :add
78     end
79     def post
80       if Git.bare(input.repository_path)
81         repo = Repository.create :name => input.repo_name, :path => input.repo_path, :bare => input.repo_bare
82         redirect View, repo
83       else
84         redirect Index
85       end
86     end
87   end
89   class Commit < R '/commit/(\d+)/(\w+)'
90     def get repo_id, sha
91       @repo = Repository.find repo_id
92       @git = Git.bare(@repo.path)      
93       @commit = @git.gcommit(sha)
94       render :commit
95     end
96   end
97   
98   class Tree < R '/tree/(\d+)/(\w+)'
99     def get repo_id, sha
100       @repo = Repository.find repo_id
101       @git = Git.bare(@repo.path)      
102       @tree = @git.gtree(sha)
103       render :tree
104     end
105   end
106   
107   class Blob < R '/blob/(\d+)/(.*?)/(\w+)'
108     def get repo_id, file, sha
109       @repo = Repository.find repo_id
110       @git = Git.bare(@repo.path)      
111       @blob = @git.gblob(sha)
112       @file = file
113       render :blob
114     end
115   end  
116   
117   class BlobRaw < R '/blob/(\d+)/(\w+)'
118      def get repo_id, sha
119        @repo = Repository.find repo_id
120        @git = Git.bare(@repo.path)      
121        @blob = @git.gblob(sha)
122        @blob.contents
123      end
124   end
125   
126   class Archive < R '/archive/(\d+)/(\w+)'
127     def get repo_id, sha
128       @repo = Repository.find repo_id
129       @git = Git.bare(@repo.path)
130       
131       file = @git.gtree(sha).archive
132       @headers['Content-Type'] = 'application/zip'
133       @headers["Content-Disposition"] = "attachment; filename=archive.zip"
134       File.new(file).read
135     end
136   end
137   
138   class Diff < R '/diff/(\d+)/(\w+)/(\w+)'
139     def get repo_id, tree1, tree2
140       @repo = Repository.find repo_id
141       @git = Git.bare(@repo.path)
142       @tree1 = tree1
143       @tree2 = tree2
144       @diff = @git.diff(tree1, tree2)
145       render :diff
146     end
147   end
148   
149   class Patch < R '/patch/(\d+)/(\w+)/(\w+)'
150     def get repo_id, tree1, tree2
151       @repo = Repository.find repo_id
152       @git = Git.bare(@repo.path)
153       @diff = @git.diff(tree1, tree2).patch
154     end
155   end
156   
159 module GitWeb::Views
160   def layout
161     html do
162       head do
163         title 'gitweb'
164         #link :href=>R(Stylesheet), :rel=>'stylesheet', :type=>'text/css'
165         #script :type => "text/javascript", :language => "JavaScript", :src => R(JsHighlight)
166       end
167       style <<-END, :type => 'text/css'
168         body { color: #333; }
169         h1 { background: #cce; padding: 10px; margin: 3px; }
170         h3 { background: #aea; padding: 5px; margin: 3px; }
171         .options { float: right; margin: 10px; }
172         p { padding: 5px; }
173         .odd { background: #eee; }
174         .tag { margin: 5px; padding: 1px 3px; border: 1px solid #8a8; background: #afa;}
175         .indent { padding: 0px 15px;}
176         .tip { border-top: 1px solid #aaa; color: #666; padding: 10px; }
177       END
178       body do
179         self << yield
180       end
181     end
182   end
184   def view
185     h1 @repo.name
186     h2 @repo.path
188     @tags = {}
189     @git.tags.each { |tag| @tags[tag.sha] ||= []; @tags[tag.sha] << tag.name }
190         
191     url = 'http:' + URL(Fetch, @repo.id).to_s
193     h3 'info'
194     table.info do
195       tr { td 'owner: '; td @git.config('user.name') }
196       tr { td 'email: '; td @git.config('user.email') }
197       tr { td 'url: '; td { a url, :href => url } }
198     end
199     
200     h3 'shortlog'
201     table.shortlog do
202       @git.log.each do |log|
203         tr do
204           td log.date.strftime("%Y-%m-%d")
205           td log.sha[0, 8]
206           td { em log.author.name }
207           td do
208             span.message log.message[0, 60]
209             @tags[log.sha].each do |t|
210               span.space ' '
211               span.tag { code t }
212             end if @tags[log.sha]
213           end
214           td { a 'commit', :href => R(Commit, @repo, log.sha) }
215           td { a 'commit-diff', :href => R(Diff, @repo, log.sha, log.parent.sha) }
216           td { a 'tree', :href => R(Tree, @repo, log.gtree.sha) }
217           td { a 'archive', :href => R(Archive, @repo, log.gtree.sha) }
218         end
219       end
220     end
221     
222     h3 'branches'
223     @git.branches.each do |branch|
224       li { a branch.full, :href => R(Commit, @repo, branch.gcommit.sha) }
225     end
226     
227     h3 'tags'
228     @git.tags.each do |tag|
229       li { a tag.name, :href => R(Commit, @repo, tag.sha) }
230     end
231     
232   end
233   
234   def commit
235     a.options 'repo', :href => R(View, @repo)
236     h1 @commit.name
237     h3 'info'
238     table.info do
239       tr { td 'author: '; td @commit.author.name + ' <' + @commit.author.email + '>'}
240       tr { td ''; td { code @commit.author.date } }
241       tr { td 'committer: '; td @commit.committer.name + ' <' + @commit.committer.email + '>'}
242       tr { td ''; td { code @commit.committer.date } }
243       tr { td 'commit sha: '; td { code @commit.sha } }
244       tr do
245         td 'tree sha: '
246         td do 
247           code { a @commit.gtree.sha, :href => R(Tree, @repo, @commit.gtree.sha) }
248           span.space ' '
249           a 'archive', :href => R(Archive, @repo, @commit.gtree.sha)
250         end
251       end
252       tr do
253         td 'parents: '
254         td do
255           @commit.parents.each do |p|
256             code { a p.sha, :href => R(Commit, @repo, p.sha) }
257             span.space ' '
258             a 'diff', :href => R(DiffTwo, @repo, p.sha, @commit.sha)
259             span.space ' '
260             a 'archive', :href => R(Archive, @repo, p.gtree.sha)            
261             br
262           end
263         end
264       end
265     end
266     h3 'commit message'
267     p @commit.message
268   end
269   
270   def tree
271     a.options 'repo', :href => R(View, @repo)
272     h3 'tree : ' + @tree.sha
273     p { a 'archive tree', :href => R(Archive, @repo, @tree.sha) }; 
274     table do
275       @tree.children.each do |file, node|
276         tr :class => cycle('odd','even') do
277           td { code node.sha[0, 8] }
278           td node.mode
279           td file
280           if node.type == 'tree'
281             td { a node.type, :href => R(Tree, @repo, node.sha) }
282             td { a 'archive', :href => R(Archive, @repo, node.sha) }
283           else
284             td { a node.type, :href => R(Blob, @repo, file, node.sha) }
285             td { a 'raw', :href => R(BlobRaw, @repo, node.sha) }
286           end
287         end
288       end
289     end 
290   end
292   def blob
293     link :rel => "stylesheet", :type => "text/css",  
294           :href => "http://drnicwilliams.com/external/CodeHighlighter/styles.css"
295     script :src => "http://drnicwilliams.com/external/CodeHighlighter/clean_tumblr_pre.js"
296     
297     ext = File.extname(@file).gsub('.', '')
298     ext = 'ruby' if ext == 'rb'
299     
300     a.options 'repo', :href => R(View, @repo)
301     h3 'blob : ' + @blob.sha
302     h4 @file
303     pre { code @blob.contents, :class => ext }
304   end
305   
306   def diff
307     a.options 'repo', :href => R(View, @repo)    
308     h1 "diff"
310     p { a 'download patch file', :href => R(Patch, @repo, @tree1, @tree2) }
312     p do
313       a @tree1, :href => R(Tree, @repo, @tree1)
314       span.space ' : '
315       a @tree2, :href => R(Tree, @repo, @tree2)
316     end
317   
318     @diff.each do |file|
319       h3 file.path
320       begin
321         convertor = Syntax::Convertors::HTML.for_syntax "diff"
322         self << convertor.convert( file.patch )
323       rescue
324         div.indent { pre file.patch }
325         div.tip 'tip: if you run "gem install syntax", this will be highlighted'
326       end
327     end
328     
329   end
330   
331   
332   def cycle(v1, v2)
333     (@value == v1) ? @value = v2 : @value = v1
334     @value
335   end
336   
337   def add
338     _form(@repo)
339   end
340   
341   def _form(repo)
342     form(:method => 'post') do
343       label 'Path', :for => 'repo_path'; br
344       input :name => 'repo_path', :type => 'text', :value => repo.path; br
346       label 'Name', :for => 'repo_name'; br
347       input :name => 'repo_name', :type => 'text', :value => repo.name; br
349       label 'Bare', :for => 'repo_bare'; br
350       input :type => 'checkbox', :name => 'repo_bare', :value => repo.bare; br
352       input :type => 'hidden', :name => 'repo_id', :value => repo.id
353       input :type => 'submit'
354     end
355   end
356   
357   def index
358     @repos.each do | repo |
359       h1 repo.name
360       a repo.path, :href => R(View, repo.id)
361     end
362     br
363     br
364     a 'add new repo', :href => R(Add)
365   end
368 def GitWeb.create
369   GitWeb::Models.create_schema