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/bin/ginatra-daemon DELETED
@@ -1,87 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "ginatra"
4
-
5
- module Ginatra::Daemon
6
-
7
- SYMLINK_DIR = File.expand_path('~/.ginatra/symlinks')
8
- PID_FILE = File.expand_path('~/.ginatra/daemon.pid')
9
- HELP = <<HELP
10
- Usage: ginatra-daemon [ start | stop | restart | status ]
11
-
12
- Commands:
13
- start - Starts the Git Daemon servimg Ginatra's Repositories
14
- stop - Stops the Git Daemon
15
- restart - Restarts the Git Daemon
16
- status - Is the Git Daemon on or off?
17
-
18
- HELP
19
-
20
- def self.start
21
- # Create Symlinks
22
- FileUtils.mkdir_p(SYMLINK_DIR)
23
- logger.info "Creating Symlinks"
24
- dirs = Ginatra::Config.git_dirs.map{|path| Dir.glob(path)}.flatten
25
- FileUtils.ln_sf(dirs, SYMLINK_DIR)
26
- # Start Process
27
- if File.exists?(PID_FILE)
28
- logger.warn "Ginatra Daemon running at pid:#{File.new(PID_FILE).read}"
29
- else
30
- logger.info "Starting ginatra-daemon"
31
- Kernel.fork do
32
- system "git daemon --reuseaddr --base-path=#{SYMLINK_DIR} --pid-file=#{PID_FILE} #{SYMLINK_DIR}/*"
33
- end
34
- end
35
- end
36
-
37
- def self.stop
38
- # Stop Process
39
- pid = File.new(PID_FILE).read.to_i
40
- logger.warn "Sending INT to #{pid}"
41
- FileUtils.rm(PID_FILE)
42
- Process.kill(:INT, pid)
43
- # Remove Symlinks
44
- links = Dir.glob("#{SYMLINK_DIR}/*")
45
- logger.warn "Removing Symlinks"
46
- FileUtils.rm(links)
47
- end
48
-
49
- def self.restart
50
- self.stop
51
- self.start
52
- end
53
-
54
- def self.status
55
- logger.level = Logger::INFO
56
- if File.exists?(PID_FILE)
57
- logger.info "Ginatra Daemon running at pid:#{File.new(PID_FILE).read}"
58
- else
59
- logger.info "Ginatra Daemon not running"
60
- end
61
- end
62
-
63
- def self.logger
64
- Ginatra::Config.logger
65
- end
66
-
67
- def self.execute(command)
68
- case command
69
- when "start"
70
- start
71
- when "stop"
72
- stop
73
- when "restart"
74
- restart
75
- when "status"
76
- status
77
- else
78
- puts Ginatra::Daemon::HELP
79
- end
80
- end
81
-
82
- end
83
-
84
- Ginatra::Daemon.execute ARGV[0]
85
-
86
-
87
-
@@ -1,55 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "ginatra"
4
-
5
- module Ginatra::Directory
6
-
7
- HELP = <<HELP
8
- Usage: ginatra-directory [ list | add <globs> | remove <globs> ]
9
-
10
- Commands:
11
- add - Adds the <globs> to the array of dirs that Ginatra
12
- looks in for repositories.
13
- remove - Removes the <globs> from the aforementioned array.
14
- list - Lists the globs Ginatra looks in for repositories
15
-
16
- HELP
17
-
18
- def self.add(globs)
19
- Ginatra::Config.load!
20
- Ginatra::Config[:git_dirs] += globs
21
- Ginatra::Config.logger.info "Added #{globs.join(" ")} to your config"
22
- Ginatra::Config.dump!
23
- end
24
-
25
- def self.remove(globs)
26
- Ginatra::Config.load!
27
- globs.each do |glob|
28
- Ginatra::Config[:git_dirs].delete(glob)
29
- end
30
- Ginatra::Config.logger.info "Removed #{globs.join(" ")} from your config"
31
- Ginatra::Config.dump!
32
- end
33
-
34
- def self.list
35
- Ginatra::Config.load!
36
- puts "Directories Ginatra will look for repos in:"
37
- puts Ginatra::Config[:git_dirs].map{|r| " - #{r}"}.join("\n")
38
- puts ""
39
- end
40
-
41
- def self.execute(command, args)
42
- case command
43
- when "add"
44
- add(args)
45
- when "remove"
46
- remove(args)
47
- when "list"
48
- list
49
- else
50
- puts Ginatra::Directory::HELP
51
- end
52
- end
53
- end
54
-
55
- Ginatra::Directory.execute ARGV[0], ARGV[1..-1]
data/bin/ginatra-server DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "ginatra"
4
- require "vegas"
5
-
6
- Vegas::Runner.new(Ginatra::App, 'ginatra-server', {:port => Ginatra::Config.port, :host => Ginatra::Config.host}) do |runner, opts, app|
7
-
8
- opts.banner = "Usage: ginatra-server [[options] start | stop | status]"
9
-
10
- opts.separator " start - Start the Ginatra HTTP Server"
11
- opts.separator " stop - Stop the Ginatra Server"
12
- opts.separator " status - How's your Ginatra Server holding up?"
13
-
14
- if ARGV[-1] == "start"
15
- elsif ARGV[-1] == "stop"
16
- runner.kill!
17
- exit
18
- elsif ARGV[-1] == "status"
19
- runner.status
20
- exit!
21
- elsif ARGV.length == 0 || ARGV[-1] !~ /^(start|stop|status)$/
22
- runner.options[:start] = false
23
- at_exit { puts opts }
24
- end
25
-
26
- end
27
-
data/bin/ginatra-setup DELETED
@@ -1,28 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "ginatra/config"
4
- require "rbconfig"
5
-
6
- unless ENV['TRAVIS']
7
- if RbConfig::CONFIG["ruby_version"] < "1.9"
8
- $stderr.puts "You need Ruby 1.9.2 to run ginatra"
9
- exit(1)
10
- end
11
-
12
- if `which pygmentize` !~ /pygmentize/
13
- $stderr.puts "You need Pygmentize to run ginatra"
14
- exit(1)
15
- end
16
-
17
- if `git --version` < "git version 1.6.3"
18
- $stderr.puts "You need at least git version 1.6.3 to run ginatra"
19
- exit(1)
20
- end
21
-
22
- puts "checked deps"
23
- end
24
-
25
- Ginatra::Config.safe_setup
26
- puts "installed config"
27
-
28
- exit(0)
@@ -1,77 +0,0 @@
1
- require "grit"
2
-
3
- module Ginatra
4
-
5
- class GraphCommit
6
- attr_accessor :time, :space
7
- def initialize(commit)
8
- @_commit = commit
9
- @time = -1
10
- @space = 0
11
- end
12
-
13
- def method_missing(m, *args, &block)
14
- @_commit.send(m, *args, &block)
15
- end
16
-
17
- # Method is adding time and space on the
18
- # list of commits. As well as returns date list
19
- # corelated with time set on commits.
20
- #
21
- # @param [Array<GraphCommit>] comits to index
22
- #
23
- # @return [Array<TimeDate>] list of commit dates corelated with time on commits
24
- def self.index_commits(commits)
25
- days, heads = [], []
26
- map = {}
27
-
28
- commits.reverse.each_with_index do |c,i|
29
- c.time = i
30
- days[i]=c.committed_date
31
- map[c.id] = c
32
- heads += c.refs unless c.refs.nil?
33
- end
34
-
35
- heads.select!{|h|h.is_a? Grit::Head or h.is_a? Grit::Remote}
36
- # sort heads so the master is top and current branches are closer
37
- heads.sort! do |a,b|
38
- if a.name == "master"
39
- -1
40
- elsif b.name == "master"
41
- 1
42
- else
43
- b.commit.committed_date <=> a.commit.committed_date
44
- end
45
- end
46
-
47
- j=0
48
- heads.each do |h|
49
- if map.include? h.commit.id then
50
- j = mark_chain(j+=1,map[h.commit.id], map)
51
- end
52
- end
53
- return days
54
- end
55
-
56
- # Add space mark on commit and its parents
57
- #
58
- # @param [Fixnum] space (row on the graph) to be set
59
- # @param [GraphCommit] the commit object.
60
- # @param [Hash<String,GraphCommit>] map of commits
61
- #
62
- # @return [Fixnum] max space used.
63
- def self.mark_chain(mark, commit, map)
64
- commit.space = mark if commit.space == 0
65
- m1 = mark-1
66
- marks = commit.parents.collect do |p|
67
- if map.include? p.id and map[p.id].space == 0 then
68
- mark_chain(m1+=1, map[p.id],map)
69
- else
70
- m1+1
71
- end
72
- end
73
- marks << mark
74
- return marks.compact.max
75
- end
76
- end
77
- end
data/public/img/add.png DELETED
Binary file
data/public/img/diff.png DELETED
Binary file
data/public/img/doc.png DELETED
Binary file
data/public/img/rm.png DELETED
Binary file
data/public/img/tree.png DELETED
Binary file
@@ -1,170 +0,0 @@
1
- var commits = chunk1.commits,
2
- comms = {},
3
- pixelsX = [],
4
- pixelsY = [],
5
- mmax = Math.max,
6
- mtime = 0,
7
- mspace = 0,
8
- parents = {};
9
- for (var i = 0, ii = commits.length; i < ii; i++) {
10
- for (var j = 0, jj = commits[i].parents.length; j < jj; j++) {
11
- parents[commits[i].parents[j][0]] = true;
12
- }
13
- mtime = Math.max(mtime, commits[i].time);
14
- mspace = Math.max(mspace, commits[i].space);
15
- }
16
- mtime = mtime + 4;
17
- mspace = mspace + 10;
18
- for (i = 0; i < ii; i++) {
19
- if (commits[i].id in parents) {
20
- commits[i].isParent = true;
21
- }
22
- comms[commits[i].id] = commits[i];
23
- }
24
- var colors = ["#000"];
25
- for (var k = 0; k < mspace; k++) {
26
- colors.push(Raphael.getColor());
27
- }
28
- function branchGraph(holder) {
29
- var ch = mspace * 20 + 20, cw = mtime * 20 + 20,
30
- r = Raphael("holder", cw, ch),
31
- top = r.set();
32
- var cuday = 0, cumonth = "";
33
- r.rect(0,0,days.length*20+20,40).attr({fill: "#999"});
34
-
35
- for (mm = 0; mm < days.length; mm++) {
36
- if(days[mm] != null){
37
- if(cuday != days[mm][0]){
38
- r.text(10+mm*20,30,days[mm][0]).attr({font: "12px Fontin-Sans, Arial", fill: "#444"});
39
- cuday = days[mm][0]
40
- }
41
- if(cumonth != days[mm][1]){
42
- r.text(10+mm*20,10,days[mm][1]).attr({font: "12px Fontin-Sans, Arial", fill: "#444"});
43
- cumonth = days[mm][1]
44
- }
45
-
46
- }
47
- }
48
- for (i = 0; i < ii; i++) {
49
- var x = 10 + 20 * commits[i].time,
50
- y = 70 + 20 * commits[i].space;
51
- r.circle(x, y, 3).attr({fill: colors[commits[i].space], stroke: "none"});
52
- if (commits[i].refs != null && commits[i].refs != "") {
53
- var longrefs = commits[i].refs
54
- var shortrefs = commits[i].refs;
55
- if (shortrefs.length > 15){
56
- shortrefs = shortrefs.substr(0,13) + "...";
57
- }
58
- var t = r.text(x+5,y+5,shortrefs).attr({font: "12px Fontin-Sans, Arial", fill: "#666",
59
- title: longrefs, cursor: "pointer", rotation: "90"});
60
-
61
- var textbox = t.getBBox();
62
- t.translate(textbox.height/-4,textbox.width/2);
63
- }
64
- for (var j = 0, jj = commits[i].parents.length; j < jj; j++) {
65
- var c = comms[commits[i].parents[j][0]];
66
- if (c) {
67
- var cx = 10 + 20 * c.time,
68
- cy = 70 + 20 * c.space;
69
- if (c.space == commits[i].space) {
70
- r.path("M" + (x - 5) + "," + (y + .0001) + "L" + (15 + 20 * c.time) + "," + (y + .0001))
71
- .attr({stroke: colors[c.space], "stroke-width": 2});
72
-
73
- } else if (c.space < commits[i].space) {
74
- r.path(["M", x - 5, y + .0001, "l-5-2,0,4,5,-2C",x-5,y,x -17, y+2, x -20, y-10,"L", cx,y-10,cx , cy])
75
- .attr({stroke: colors[commits[i].space], "stroke-width": 2});
76
- } else {
77
- r.path(["M", x-5, y, "l-5-2,0,4,5,-2C",x-5,y,x -17, y-2, x -20, y+10,"L", cx,y+10,cx , cy])
78
- .attr({stroke: colors[commits[i].space], "stroke-width": 2});
79
- }
80
- }
81
- }
82
- (function (c, x, y) {
83
- top.push(r.circle(x, y, 10).attr({fill: "#000", opacity: 0, cursor: "pointer"})
84
- .hover(function () {
85
- var s = r.text(100, 100,c.author + "\n \n" +c.id + "\n \n" + c.message).attr({fill: "#fff"});
86
- this.popup = r.popupit(x, y + 5, s, 0);
87
- top.push(this.popup.insertBefore(this));
88
- }, function () {
89
- this.popup && this.popup.remove() && delete this.popup;
90
- }));
91
- }(commits[i], x, y));
92
- }
93
- top.toFront();
94
- var hw = holder.offsetWidth,
95
- hh = holder.offsetHeight,
96
- v = r.rect(hw - 8, 0, 4, Math.pow(hh, 2) / ch, 2).attr({fill: "#000", opacity: 0}),
97
- h = r.rect(0, hh - 8, Math.pow(hw, 2) / cw, 4, 2).attr({fill: "#000", opacity: 0}),
98
- bars = r.set(v, h),
99
- drag,
100
- dragger = function (e) {
101
- if (drag) {
102
- e = e || window.event;
103
- holder.scrollLeft = drag.sl - (e.clientX - drag.x);
104
- holder.scrollTop = drag.st - (e.clientY - drag.y);
105
- }
106
- };
107
- holder.onmousedown = function (e) {
108
- e = e || window.event;
109
- drag = {x: e.clientX, y: e.clientY, st: holder.scrollTop, sl: holder.scrollLeft};
110
- document.onmousemove = dragger;
111
- bars.animate({opacity: .5}, 300);
112
- };
113
- document.onmouseup = function () {
114
- drag = false;
115
- document.onmousemove = null;
116
- bars.animate({opacity: 0}, 300);
117
- };
118
- holder.scrollLeft = cw;
119
- };
120
- Raphael.fn.popupit = function (x, y, set, dir, size) {
121
- dir = dir == null ? 2 : dir;
122
- size = size || 5;
123
- x = Math.round(x);
124
- y = Math.round(y);
125
- var bb = set.getBBox(),
126
- w = Math.round(bb.width / 2),
127
- h = Math.round(bb.height / 2),
128
- dx = [0, w + size * 2, 0, -w - size * 2],
129
- dy = [-h * 2 - size * 3, -h - size, 0, -h - size],
130
- p = ["M", x - dx[dir], y - dy[dir], "l", -size, (dir == 2) * -size, -mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size,
131
- "l", 0, -mmax(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -mmax(h - size, 0), "a", size, size, 0, 0, 1, size, -size,
132
- "l", mmax(w - size, 0), 0, size, !dir * -size, size, !dir * size, mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, size, size,
133
- "l", 0, mmax(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, mmax(h - size, 0), "a", size, size, 0, 0, 1, -size, size,
134
- "l", -mmax(w - size, 0), 0, "z"].join(","),
135
- xy = [{x: x, y: y + size * 2 + h}, {x: x - size * 2 - w, y: y}, {x: x, y: y - size * 2 - h}, {x: x + size * 2 + w, y: y}][dir];
136
- set.translate(xy.x - w - bb.x, xy.y - h - bb.y);
137
- return this.set(this.path(p).attr({fill: "#234", stroke: "none"}).insertBefore(set.node ? set : set[0]), set);
138
- };
139
- Raphael.fn.popup = function (x, y, text, dir, size) {
140
- dir = dir == null ? 2 : dir > 3 ? 3 : dir;
141
- size = size || 5;
142
- text = text || "$9.99";
143
- var res = this.set(),
144
- d = 3;
145
- res.push(this.path().attr({fill: "#000", stroke: "#000"}));
146
- res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff", "font-family": "Helvetica, Arial"}));
147
- res.update = function (X, Y, withAnimation) {
148
- X = X || x;
149
- Y = Y || y;
150
- var bb = this[1].getBBox(),
151
- w = bb.width / 2,
152
- h = bb.height / 2,
153
- dx = [0, w + size * 2, 0, -w - size * 2],
154
- dy = [-h * 2 - size * 3, -h - size, 0, -h - size],
155
- p = ["M", X - dx[dir], Y - dy[dir], "l", -size, (dir == 2) * -size, -mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size,
156
- "l", 0, -mmax(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -mmax(h - size, 0), "a", size, size, 0, 0, 1, size, -size,
157
- "l", mmax(w - size, 0), 0, size, !dir * -size, size, !dir * size, mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, size, size,
158
- "l", 0, mmax(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, mmax(h - size, 0), "a", size, size, 0, 0, 1, -size, size,
159
- "l", -mmax(w - size, 0), 0, "z"].join(","),
160
- xy = [{x: X, y: Y + size * 2 + h}, {x: X - size * 2 - w, y: Y}, {x: X, y: Y - size * 2 - h}, {x: X + size * 2 + w, y: Y}][dir];
161
- xy.path = p;
162
- if (withAnimation) {
163
- this.animate(xy, 500, ">");
164
- } else {
165
- this.attr(xy);
166
- }
167
- return this;
168
- };
169
- return res.update(x, y);
170
- };