gitoe 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.gitmodules +3 -0
  4. data/Gemfile +7 -0
  5. data/Gemfile.lock +91 -0
  6. data/Guardfile +8 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +30 -0
  9. data/Rakefile +35 -0
  10. data/Rules +47 -0
  11. data/bin/gitoe +36 -0
  12. data/content/gitoe-draw.coffee +342 -0
  13. data/content/gitoe-repo.coffee +546 -0
  14. data/content/gitoe.coffee +182 -0
  15. data/content/index.haml +71 -0
  16. data/content/jquery/jquery-1.9.1.min.js +5 -0
  17. data/content/jquery/jquery.scrollTo.min.js +7 -0
  18. data/content/raphael-min.js +10 -0
  19. data/content/reset.sass +46 -0
  20. data/content/style.sass +109 -0
  21. data/gitoe.gemspec +34 -0
  22. data/lib/gitoe.rb +16 -0
  23. data/lib/gitoe/httpserver/public/gitoe-draw.js +399 -0
  24. data/lib/gitoe/httpserver/public/gitoe-repo.js +618 -0
  25. data/lib/gitoe/httpserver/public/gitoe.js +249 -0
  26. data/lib/gitoe/httpserver/public/index.html +49 -0
  27. data/lib/gitoe/httpserver/public/jquery/jquery-1.9.1.min.js +5 -0
  28. data/lib/gitoe/httpserver/public/jquery/jquery.scrollTo.min.js +7 -0
  29. data/lib/gitoe/httpserver/public/raphael-min.js +10 -0
  30. data/lib/gitoe/httpserver/public/reset.css +45 -0
  31. data/lib/gitoe/httpserver/public/style.css +106 -0
  32. data/lib/gitoe/httpserver/repos.rb +71 -0
  33. data/lib/gitoe/httpserver/static.rb +17 -0
  34. data/lib/gitoe/repo/repo.rb +174 -0
  35. data/lib/gitoe/repo/rugged.rb +121 -0
  36. data/lib/gitoe/version.rb +3 -0
  37. data/nanoc.yaml +77 -0
  38. data/test/test.rb +9 -0
  39. data/todo.markdown +16 -0
  40. data/vendor/jquery-1.9.1.min.js +5 -0
  41. data/vendor/raphael-min.js +10 -0
  42. metadata +239 -0
@@ -0,0 +1,71 @@
1
+ # rack app for repos
2
+ require "gitoe"
3
+ require "gitoe/repo/rugged"
4
+ require "sinatra"
5
+ require "active_support"
6
+
7
+ module Gitoe::HTTPServer
8
+ class Repos < ::Sinatra::Base
9
+
10
+ Repo = ::Gitoe::Repo::RestfulRugged
11
+
12
+ set :environment, :production
13
+
14
+ def json reply
15
+ content_type 'application/json'
16
+ ::ActiveSupport::JSON.encode(reply)
17
+ end
18
+
19
+ error do
20
+ json \
21
+ :error_message => env['sinatra.error'],
22
+ :backtrace => env['sinatra.error'].backtrace
23
+ end
24
+
25
+ # index
26
+ get "/" do
27
+ json Repo.instances[:by_arg]
28
+ end
29
+
30
+ # create
31
+ post "/new" do
32
+ # create instance if not existing
33
+ # and return id
34
+ path = params["path"] or raise "path not specified"
35
+ repo_id = Repo.id_for(path)
36
+ repo = Repo.find repo_id
37
+ json \
38
+ :id => repo_id ,
39
+ :path => repo.path
40
+ end
41
+
42
+ # show
43
+ get "/:repo_id/?" do
44
+ repo = Repo.find params["repo_id"]
45
+ json repo.status
46
+ end
47
+
48
+ # namespace under /:repo_id/:resource
49
+ Resources = Set[ 'commits', 'commit' ].freeze
50
+ get "/:repo_id/**" do
51
+
52
+ repo = Repo.find( params["repo_id"] )
53
+
54
+ sub_str = params[:splat].last # "**" part
55
+
56
+ resource, url = sub_str.split('/',2)
57
+ raise "invalid resource '#{resource}'" unless Resources.include? resource
58
+ query_hash = env['rack.request.query_hash']
59
+ # /1/commits/aaaaaaa/b/c/d ? a=1 & b=1
60
+ # => {
61
+ # repo_id: "1",
62
+ # resource: "commits"
63
+ # arg: "aaaaaaa/b/c/d"
64
+ # query_hash:
65
+ # }
66
+ # json resource => repo.send(resource.to_sym, arg, env[])
67
+ json repo.send(resource, url, query_hash )
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,17 @@
1
+ # rack app for static files
2
+ require "gitoe"
3
+ require "sinatra"
4
+
5
+ module Gitoe::HTTPServer
6
+ class Static < ::Sinatra::Base
7
+
8
+ set :app_file, __FILE__
9
+ set :environment, :production
10
+ set :static_cache_control, [:public, max_age: 3600]
11
+
12
+ get "/" do
13
+ send_file File.join( settings.public_folder, "index.html" )
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,174 @@
1
+ require "gitoe"
2
+
3
+ module Gitoe::Repo
4
+
5
+ # instance methods, enable querying of instances
6
+ module Query
7
+
8
+ def instances
9
+ @instances ||= {
10
+ :by_arg => {}, # arg => id
11
+ :by_id => {}, # id => instance
12
+ }
13
+ end
14
+
15
+ def create arg
16
+ id = instances[:by_id].size
17
+ instances[:by_id][id] = self.new arg
18
+ instances[:by_arg][arg] = id
19
+ end
20
+
21
+ def destroy id
22
+ raise NotImplementedError # TODO
23
+ end
24
+
25
+ def find id
26
+ id = Integer(id) unless id.is_a? Integer
27
+ instances[:by_id][id] or raise "repo not found"
28
+ end
29
+
30
+ def id_for arg
31
+ existing = instances[:by_arg][arg]
32
+ if existing
33
+ existing
34
+ else
35
+ create arg
36
+ end
37
+ end
38
+ end
39
+
40
+ module RestfulRepo
41
+ # public methods( 'resources' ):
42
+ # #status
43
+ # #commits
44
+
45
+ def status
46
+ {
47
+ :refs => refs ,
48
+ :path => path ,
49
+ :cached_commits => size_of_cache,
50
+ }
51
+ end
52
+
53
+ def commits start, options={}
54
+ # start :
55
+ # commits to start at,
56
+ # possible multiple, ','
57
+ # options :
58
+ # limit
59
+ limit = (options['limit'] || 1000).to_i
60
+
61
+ to_query = start.split ','
62
+ queried = {}
63
+
64
+ while to_query.size > 0 and queried.size < limit
65
+
66
+ another = to_query.shift
67
+ next if queried.has_key?(another)
68
+
69
+ parent = commit another
70
+ queried[ parent[:sha1] ] ||= parent
71
+ parent[:parents].each do |p|
72
+ next if queried.has_key? p
73
+ to_query.push p
74
+ end
75
+ end
76
+ $gitoe_log[ "gathered #{queried.size} from #{start}" ]
77
+
78
+ queried
79
+ end
80
+
81
+ end
82
+
83
+ module Cache
84
+ def initialize *args
85
+ init_cache
86
+ super
87
+ end
88
+
89
+ private
90
+
91
+ def ref name
92
+ follow_ref super
93
+ end
94
+
95
+ def follow_ref ref_hash
96
+ ref_hash
97
+ end
98
+
99
+ def commit sha1, options={}
100
+ # if in_cache?
101
+ # just take from cache
102
+ # else
103
+ # add sha1 and all its ancestors to cache, in topological order
104
+ if in_cache? sha1
105
+ return from_cache sha1
106
+ end
107
+ this = super(sha1).freeze
108
+ if not in_cache? this[:sha1]
109
+ add_to_cache this[:sha1], this
110
+ end
111
+ this
112
+ end
113
+
114
+ private
115
+
116
+ def add_to_cache sha1, content
117
+ if $gitoe_debug and in_cache?(sha1)
118
+ raise "#{sha1} already in cache"
119
+ end
120
+ $gitoe_log[ "add #{sha1} to cache" ]
121
+ @cached_commits[sha1] = content
122
+ end
123
+
124
+ def init_cache
125
+ @cached_commits = {} # { sha1:content, order:content }
126
+ end
127
+
128
+ def size_of_cache
129
+ @cached_commits.size
130
+ end
131
+
132
+ def from_cache sha1
133
+ @cached_commits[sha1] or raise "not in cache"
134
+ end
135
+
136
+ def in_cache? key
137
+ @cached_commits.has_key? key
138
+ end
139
+
140
+ def sort_topo queried
141
+
142
+ sorted = []
143
+
144
+ in_degree = Hash.new{|h,k| h[k] = 0 }
145
+ children = Hash.new{|h,k| h[k] = [] }
146
+
147
+ queried.each do |sha1,content|
148
+ in_degree[sha1]
149
+ content[:parents].each do |p|
150
+ in_degree[p]
151
+ in_degree[sha1] += 1
152
+ children[p] << sha1
153
+ end
154
+ end
155
+
156
+ to_remove = in_degree.keys.select{|k| in_degree[k] == 0 }
157
+ while to_remove.size > 0
158
+ # $gitoe_log[ "topo-sorting : remaining #{in_degree.size}" ]
159
+
160
+ n = to_remove.shift
161
+ sorted.push n
162
+ in_degree.delete n
163
+
164
+ children[n].each do |c|
165
+ new_in_degree = in_degree[c] -= 1
166
+ to_remove.push c if new_in_degree == 0
167
+ end
168
+ end
169
+
170
+ $gitoe_log[ "topo-sorting DONE" ]
171
+ return sorted.select{|s| queried.has_key? s }
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,121 @@
1
+ # repo using rugged ( https://github.com/libgit2/rugged )
2
+ require "gitoe/repo/repo"
3
+ require "rugged"
4
+
5
+ module Gitoe::Repo
6
+ class Rugged_backend
7
+
8
+ # implements
9
+ # path :: -> String
10
+ # commit :: sha1::String -> { prop:val }
11
+ # refs :: -> { ref_name : reflogs }
12
+ # ref :: String -> reflogs
13
+
14
+ # private
15
+ # ref_names :: -> [ String ]
16
+ # reflog :: String -> [ {} ]
17
+
18
+ include ::Rugged
19
+
20
+ def initialize path
21
+ @rugged = Repository.new path
22
+ end
23
+
24
+ def path
25
+ @rugged.path
26
+ end
27
+
28
+ def commit sha1
29
+ # $gitoe_log[ "query #{sha1}" ]
30
+ obj = @rugged.lookup(sha1)
31
+ case obj
32
+ when Commit
33
+ commit_to_hash obj
34
+ else
35
+ raise "#{obj} is not commit"
36
+ end
37
+ end
38
+
39
+ def refs
40
+ Hash[
41
+ ref_names.map do |ref_name|
42
+ [ ref_name, ref(ref_name) ]
43
+ end
44
+ ]
45
+ end
46
+
47
+ def ref(name)
48
+ resolved = Reference.lookup(@rugged, name)
49
+ basic = {
50
+ :name => resolved.name ,
51
+ :target => resolved.target ,
52
+ :type => resolved.type ,
53
+ :log => reflog( resolved ),
54
+ }
55
+ case name
56
+ when %r{^refs/remotes/}, %r{^refs/heads/}, 'HEAD'
57
+ extra = {}
58
+ when %r{^refs/tags/}
59
+ extra = deref_tag(resolved)
60
+ else
61
+ raise "error parsing ref <ref>"
62
+ end
63
+ basic.merge(extra).freeze
64
+ end
65
+
66
+ private
67
+
68
+ def ref_names
69
+ @rugged.refs.to_a.each do |ref_name|
70
+ ref_name.sub! %r{^/} , ""
71
+ end << "HEAD"
72
+ end
73
+
74
+ def deref_tag tag
75
+ target = @rugged.lookup(tag.target)
76
+ case target
77
+ when Tag
78
+ {
79
+ tag_type: 'annotated',
80
+ real_target: target.target.oid
81
+ }
82
+ when Commit
83
+ {
84
+ tag_type: 'lightweight'
85
+ }
86
+ else
87
+ raise "don't know #{tag}"
88
+ end
89
+ end
90
+
91
+ def reflog ref
92
+ raise "demand Reference" unless ref.is_a? Reference
93
+ log =
94
+ begin
95
+ ref.log
96
+ rescue
97
+ []
98
+ end
99
+ log.each do |change|
100
+ change[:committer][:time] = change[:committer][:time].to_i # seconds from epoch
101
+ end
102
+ end
103
+
104
+ def commit_to_hash commit_obj
105
+ {
106
+ :sha1 => commit_obj.oid,
107
+ :parents => commit_obj.parents.map(&:oid),
108
+ # :type => :commit,
109
+ :author => commit_obj.author,
110
+ :committer => commit_obj.committer
111
+ }.freeze
112
+ end
113
+ end
114
+
115
+ class RestfulRugged < Rugged_backend
116
+ extend Query
117
+ include Cache
118
+ include RestfulRepo
119
+ # ancestors: [RestfulRugged, RestfulRepo, Cache, Rugged_backend]
120
+ end
121
+ end
@@ -0,0 +1,3 @@
1
+ module Gitoe
2
+ VERSION = "0.1.0"
3
+ end
data/nanoc.yaml ADDED
@@ -0,0 +1,77 @@
1
+ # A list of file extensions that nanoc will consider to be textual rather than
2
+ # binary. If an item with an extension not in this list is found, the file
3
+ # will be considered as binary.
4
+ text_extensions: [ 'coffee', 'haml', 'sass' ]
5
+
6
+ # The path to the directory where all generated files will be written to. This
7
+ # can be an absolute path starting with a slash, but it can also be path
8
+ # relative to the site directory.
9
+ output_dir: lib/gitoe/httpserver/public/
10
+
11
+ # A list of index filenames, i.e. names of files that will be served by a web
12
+ # server when a directory is requested. Usually, index files are named
13
+ # “index.html”, but depending on the web server, this may be something else,
14
+ # such as “default.htm”. This list is used by nanoc to generate pretty URLs.
15
+ index_filenames: [ 'index.html' ]
16
+
17
+ # Whether or not to generate a diff of the compiled content when compiling a
18
+ # site. The diff will contain the differences between the compiled content
19
+ # before and after the last site compilation.
20
+ enable_output_diff: false
21
+
22
+ prune:
23
+ # Whether to automatically remove files not managed by nanoc from the output
24
+ # directory. For safety reasons, this is turned off by default.
25
+ auto_prune: true
26
+
27
+ # Which files and directories you want to exclude from pruning. If you version
28
+ # your output directory, you should probably exclude VCS directories such as
29
+ # .git, .svn etc.
30
+ exclude: [ '.git', '.hg', '.svn', 'CVS' ]
31
+
32
+ # The data sources where nanoc loads its data from. This is an array of
33
+ # hashes; each array element represents a single data source. By default,
34
+ # there is only a single data source that reads data from the “content/” and
35
+ # “layout/” directories in the site directory.
36
+ data_sources:
37
+ -
38
+ # The type is the identifier of the data source. By default, this will be
39
+ # `filesystem_unified`.
40
+ type: filesystem_unified
41
+
42
+ # The path where items should be mounted (comparable to mount points in
43
+ # Unix-like systems). This is “/” by default, meaning that items will have
44
+ # “/” prefixed to their identifiers. If the items root were “/en/”
45
+ # instead, an item at content/about.html would have an identifier of
46
+ # “/en/about/” instead of just “/about/”.
47
+ items_root: /
48
+
49
+ # The path where layouts should be mounted. The layouts root behaves the
50
+ # same as the items root, but applies to layouts rather than items.
51
+ layouts_root: /
52
+
53
+ # Whether to allow periods in identifiers. When turned off, everything
54
+ # past the first period is considered to be the extension, and when
55
+ # turned on, only the characters past the last period are considered to
56
+ # be the extension. For example, a file named “content/about.html.erb”
57
+ # will have the identifier “/about/” when turned off, but when turned on
58
+ # it will become “/about.html/” instead.
59
+ allow_periods_in_identifiers: true
60
+
61
+ # Configuration for the “watch” command, which watches a site for changes and
62
+ # recompiles if necessary.
63
+ watcher:
64
+ # A list of directories to watch for changes. When editing this, make sure
65
+ # that the “output/” and “tmp/” directories are _not_ included in this list,
66
+ # because recompiling the site will cause these directories to change, which
67
+ # will cause the site to be recompiled, which will cause these directories
68
+ # to change, which will cause the site to be recompiled again, and so on.
69
+ dirs_to_watch: [ 'content' ]
70
+
71
+ # A list of single files to watch for changes. As mentioned above, don’t put
72
+ # any files from the “output/” or “tmp/” directories in here.
73
+ files_to_watch: [ 'nanoc.yaml', 'Rules' ]
74
+
75
+ # When to send notifications (using Growl or notify-send).
76
+ notify_on_compilation_success: true
77
+ notify_on_compilation_failure: true