docurium 0.0.5 → 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.
data/bin/cm CHANGED
@@ -6,7 +6,7 @@ require 'gli'
6
6
  require 'docurium'
7
7
  require 'docurium/cli'
8
8
 
9
- include GLI
9
+ include GLI::App
10
10
 
11
11
  version Docurium::Version
12
12
 
@@ -38,4 +38,4 @@ on_error do |exception|
38
38
  puts exception.backtrace
39
39
  end
40
40
 
41
- exit GLI.run(ARGV)
41
+ exit run(ARGV)
data/docurium.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  $:.push File.expand_path("../lib", __FILE__)
3
- require 'docurium'
3
+ require 'docurium/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "docurium"
@@ -17,6 +17,9 @@ Gem::Specification.new do |s|
17
17
  s.add_dependency "version_sorter", "~>1.1.0"
18
18
  s.add_dependency "mustache", ">= 0.99.4"
19
19
  s.add_dependency "rocco", "= 0.7.0"
20
+ s.add_dependency "gli", "~>2.5"
21
+ s.add_dependency "rugged", "~>0.18.b1"
22
+ s.add_dependency "redcarpet", "~>2.2.2"
20
23
  s.add_development_dependency "bundler", "~>1.0"
21
24
 
22
25
  s.files = `git ls-files`.split("\n")
data/lib/docurium.rb CHANGED
@@ -2,12 +2,14 @@ require 'json'
2
2
  require 'tempfile'
3
3
  require 'version_sorter'
4
4
  require 'rocco'
5
+ require 'docurium/version'
5
6
  require 'docurium/layout'
7
+ require 'docurium/cparser'
6
8
  require 'pp'
9
+ require 'rugged'
10
+ require 'redcarpet'
7
11
 
8
12
  class Docurium
9
- Version = VERSION = '0.0.5'
10
-
11
13
  attr_accessor :branch, :output_dir, :data
12
14
 
13
15
  def initialize(config_file)
@@ -15,6 +17,8 @@ class Docurium
15
17
  raise "You need to specify a valid config file" if !valid_config(config_file)
16
18
  @sigs = {}
17
19
  @groups = {}
20
+ repo_path = Rugged::Repository.discover('.')
21
+ @repo = Rugged::Repository.new(repo_path)
18
22
  clear_data
19
23
  end
20
24
 
@@ -38,73 +42,68 @@ class Docurium
38
42
 
39
43
  def generate_docs
40
44
  out "* generating docs"
41
- outdir = mkdir_temp
42
- copy_site(outdir)
45
+ output_index = Rugged::Index.new
46
+ write_site(output_index)
43
47
  versions = get_versions
44
48
  versions << 'HEAD'
45
49
  versions.each do |version|
46
50
  out " - processing version #{version}"
47
- workdir = mkdir_temp
48
- Dir.chdir(workdir) do
49
- clear_data(version)
50
- checkout(version, workdir)
51
- parse_headers
52
- tally_sigs(version)
53
- end
51
+ index = @repo.index
52
+ index.clear
53
+ clear_data(version)
54
+ read_subtree(index, version, @data[:prefix])
55
+ parse_headers(index)
56
+ tally_sigs(version)
54
57
 
55
58
  tf = File.expand_path(File.join(File.dirname(__FILE__), 'docurium', 'layout.mustache'))
56
59
  if ex = option_version(version, 'examples')
57
- workdir = mkdir_temp
58
- Dir.chdir(workdir) do
59
- with_git_env(workdir) do
60
- `git rev-parse #{version}:#{ex} 2>&1` # check that it exists
61
- if $?.exitstatus == 0
62
- out " - processing examples for #{version}"
63
- `git read-tree #{version}:#{ex}`
64
- `git checkout-index -a`
65
-
66
- files = []
67
- Dir.glob("**/*.c") do |file|
68
- next if !File.file?(file)
69
- files << file
70
- end
71
- files.each do |file|
72
- out " # #{file}"
73
-
74
- # highlight, roccoize and link
75
- rocco = Rocco.new(file, files, {:language => 'c'})
76
- rocco_layout = Rocco::Layout.new(rocco, tf)
77
- rocco_layout.version = version
78
- rf = rocco_layout.render
79
-
80
- rf_path = File.basename(file).split('.')[0..-2].join('.') + '.html'
81
- rel_path = "ex/#{version}/#{rf_path}"
82
- rf_path = File.join(outdir, rel_path)
83
-
84
- # look for function names in the examples and link
85
- id_num = 0
86
- @data[:functions].each do |f, fdata|
87
- rf.gsub!(/#{f}([^\w])/) do |fmatch|
88
- extra = $1
89
- id_num += 1
90
- name = f + '-' + id_num.to_s
91
- # save data for cross-link
92
- @data[:functions][f][:examples] ||= {}
93
- @data[:functions][f][:examples][file] ||= []
94
- @data[:functions][f][:examples][file] << rel_path + '#' + name
95
- "<a name=\"#{name}\" href=\"../../##{version}/group/#{fdata[:group]}/#{f}\">#{f}</a>#{extra}"
96
- end
97
- end
98
-
99
- # write example to docs directory
100
- FileUtils.mkdir_p(File.dirname(rf_path))
101
- File.open(rf_path, 'w+') do |f|
102
- @data[:examples] ||= []
103
- @data[:examples] << [file, rel_path]
104
- f.write(rf)
105
- end
60
+ if subtree = find_subtree(version, ex) # check that it exists
61
+ index.read_tree(subtree)
62
+ out " - processing examples for #{version}"
63
+
64
+ files = []
65
+ index.each do |entry|
66
+ next unless entry[:path].match(/\.c$/)
67
+ files << entry[:path]
68
+ end
69
+
70
+ files.each do |file|
71
+ out " # #{file}"
72
+
73
+ # highlight, roccoize and link
74
+ rocco = Rocco.new(file, files, {:language => 'c'}) do
75
+ ientry = index[file]
76
+ blob = @repo.lookup(ientry[:oid])
77
+ blob.content
78
+ end
79
+ rocco_layout = Rocco::Layout.new(rocco, tf)
80
+ rocco_layout.version = version
81
+ rf = rocco_layout.render
82
+
83
+ rf_path = File.basename(file).split('.')[0..-2].join('.') + '.html'
84
+ rel_path = "ex/#{version}/#{rf_path}"
85
+
86
+ # look for function names in the examples and link
87
+ id_num = 0
88
+ @data[:functions].each do |f, fdata|
89
+ rf.gsub!(/#{f}([^\w])/) do |fmatch|
90
+ extra = $1
91
+ id_num += 1
92
+ name = f + '-' + id_num.to_s
93
+ # save data for cross-link
94
+ @data[:functions][f][:examples] ||= {}
95
+ @data[:functions][f][:examples][file] ||= []
96
+ @data[:functions][f][:examples][file] << rel_path + '#' + name
97
+ "<a name=\"#{name}\" class=\"fnlink\" href=\"../../##{version}/group/#{fdata[:group]}/#{f}\">#{f}</a>#{extra}"
106
98
  end
107
99
  end
100
+
101
+ # write example to the repo
102
+ sha = @repo.write(rf, :blob)
103
+ output_index.add(:path => rel_path, :oid => sha, :mode => 0100644)
104
+
105
+ @data[:examples] ||= []
106
+ @data[:examples] << [file, rel_path]
108
107
  end
109
108
  end
110
109
 
@@ -113,49 +112,37 @@ class Docurium
113
112
  end
114
113
  end
115
114
 
116
- File.open(File.join(outdir, "#{version}.json"), 'w+') do |f|
117
- f.write(@data.to_json)
118
- end
119
- end
120
-
121
- Dir.chdir(outdir) do
122
- project = {
123
- :versions => versions.reverse,
124
- :github => @options['github'],
125
- :name => @options['name'],
126
- :signatures => @sigs,
127
- :groups => @groups
128
- }
129
- File.open("project.json", 'w+') do |f|
130
- f.write(project.to_json)
131
- end
115
+ sha = @repo.write(@data.to_json, :blob)
116
+ output_index.add(:path => "#{version}.json", :oid => sha, :mode => 0100644)
132
117
  end
133
118
 
134
- if br = @options['branch']
135
- out "* writing to branch #{br}"
136
- ref = "refs/heads/#{br}"
137
- with_git_env(outdir) do
138
- psha = `git rev-parse #{ref}`.chomp
139
- `git add -A`
140
- tsha = `git write-tree`.chomp
141
- puts "\twrote tree #{tsha}"
142
- if(psha == ref)
143
- csha = `echo 'generated docs' | git commit-tree #{tsha}`.chomp
144
- else
145
- csha = `echo 'generated docs' | git commit-tree #{tsha} -p #{psha}`.chomp
146
- end
147
- puts "\twrote commit #{csha}"
148
- `git update-ref -m 'generated docs' #{ref} #{csha}`
149
- puts "\tupdated #{br}"
150
- end
151
- else
152
- final_dir = File.join(@project_dir, @options['output'] || 'docs')
153
- out "* output html in #{final_dir}"
154
- FileUtils.mkdir_p(final_dir)
155
- Dir.chdir(final_dir) do
156
- FileUtils.cp_r(File.join(outdir, '.'), '.')
157
- end
158
- end
119
+ project = {
120
+ :versions => versions.reverse,
121
+ :github => @options['github'],
122
+ :name => @options['name'],
123
+ :signatures => @sigs,
124
+ :groups => @groups
125
+ }
126
+ sha = @repo.write(project.to_json, :blob)
127
+ output_index.add(:path => "project.json", :oid => sha, :mode => 0100644)
128
+
129
+ br = @options['branch']
130
+ out "* writing to branch #{br}"
131
+ refname = "refs/heads/#{br}"
132
+ tsha = output_index.write_tree(@repo)
133
+ puts "\twrote tree #{tsha}"
134
+ ref = Rugged::Reference.lookup(@repo, refname)
135
+ user = { :name => @repo.config['user.name'], :email => @repo.config['user.email'], :time => Time.now }
136
+ options = {}
137
+ options[:tree] = tsha
138
+ options[:author] = user
139
+ options[:committer] = user
140
+ options[:message] = 'generated docs'
141
+ options[:parents] = ref ? [ref.target] : []
142
+ options[:update_ref] = refname
143
+ csha = Rugged::Commit.create(@repo, options)
144
+ puts "\twrote commit #{csha}"
145
+ puts "\tupdated #{br}"
159
146
  end
160
147
 
161
148
  def show_warnings
@@ -185,13 +172,17 @@ class Docurium
185
172
  end
186
173
 
187
174
  def get_versions
188
- VersionSorter.sort(git('tag').split("\n"))
175
+ tags = []
176
+ @repo.tags.each { |tag| tags << tag.gsub(%r(^refs/tags/), '') }
177
+ VersionSorter.sort(tags)
189
178
  end
190
179
 
191
- def parse_headers
192
- headers.each do |header|
193
- parse_header(header)
180
+ def parse_headers(index)
181
+ headers(index).each do |header|
182
+ records = parse_header(index, header)
183
+ update_globals(records)
194
184
  end
185
+
195
186
  @data[:groups] = group_functions
196
187
  @data[:types] = @data[:types].sort # make it an assoc array
197
188
  find_type_usage
@@ -214,29 +205,30 @@ class Docurium
214
205
  end
215
206
  end
216
207
 
217
- def git(command)
218
- out = ''
219
- Dir.chdir(@project_dir) do
220
- out = `git #{command}`
208
+ def find_subtree(version, path)
209
+ tree = nil
210
+ if version == 'HEAD'
211
+ tree = @repo.lookup(@repo.head.target).tree
212
+ else
213
+ trg = @repo.lookup(Rugged::Reference.lookup(@repo, "refs/tags/#{version}").target)
214
+ if(trg.class == Rugged::Tag)
215
+ trg = trg.target
216
+ end
217
+
218
+ tree = trg.tree
221
219
  end
222
- out.strip
223
- end
224
220
 
225
- def checkout(version, workdir)
226
- with_git_env(workdir) do
227
- `git read-tree #{version}:#{@data[:prefix]}`
228
- `git checkout-index -a`
221
+ begin
222
+ tree_entry = tree.path(path)
223
+ @repo.lookup(tree_entry[:oid])
224
+ rescue Rugged::TreeError
225
+ nil
229
226
  end
230
227
  end
231
228
 
232
- def with_git_env(workdir)
233
- ENV['GIT_INDEX_FILE'] = mkfile_temp
234
- ENV['GIT_WORK_TREE'] = workdir
235
- ENV['GIT_DIR'] = File.join(@project_dir, '.git')
236
- yield
237
- ENV.delete('GIT_INDEX_FILE')
238
- ENV.delete('GIT_WORK_TREE')
239
- ENV.delete('GIT_DIR')
229
+ def read_subtree(index, version, path)
230
+ tree = find_subtree(version, path)
231
+ index.read_tree(tree)
240
232
  end
241
233
 
242
234
  def valid_config(file)
@@ -245,7 +237,7 @@ class Docurium
245
237
  @project_dir = File.dirname(fpath)
246
238
  @config_file = File.basename(fpath)
247
239
  @options = JSON.parse(File.read(fpath))
248
- true
240
+ !!@options['branch']
249
241
  end
250
242
 
251
243
  def group_functions
@@ -271,11 +263,11 @@ class Docurium
271
263
  func.to_a.sort
272
264
  end
273
265
 
274
- def headers
266
+ def headers(index = nil)
275
267
  h = []
276
- Dir.glob(File.join('**/*.h')).each do |header|
277
- next if !File.file?(header)
278
- h << header
268
+ index.each do |entry|
269
+ next unless entry[:path].match(/\.h$/)
270
+ h << entry[:path]
279
271
  end
280
272
  h
281
273
  end
@@ -299,248 +291,123 @@ class Docurium
299
291
  end
300
292
  end
301
293
 
302
- def header_content(header_path)
303
- File.readlines(header_path)
294
+ def parse_header(index, path)
295
+ id = index[path][:oid]
296
+ blob = @repo.lookup(id)
297
+ parser = Docurium::CParser.new
298
+ parser.parse_text(path, blob.content)
304
299
  end
305
300
 
306
- def parse_header(filepath)
307
- lineno = 0
308
- content = header_content(filepath)
309
-
310
- # look for structs and enums
311
- in_block = false
312
- block = ''
313
- linestart = 0
314
- tdef, type, name = nil
315
- content.each do |line|
316
- lineno += 1
317
- line = line.strip
318
-
319
- if line[0, 1] == '#' #preprocessor
320
- if m = /\#define (.*?) (.*)/.match(line)
321
- @data[:globals][m[1]] = {:value => m[2].strip, :file => filepath, :line => lineno}
322
- else
323
- next
324
- end
325
- end
301
+ def update_globals(recs)
302
+ wanted = {
303
+ :functions => %W/type value file line lineto args argline sig return group description comments/.map(&:to_sym),
304
+ :types => %W/type value file line lineto block tdef comments/.map(&:to_sym),
305
+ :globals => %W/value file line comments/.map(&:to_sym),
306
+ :meta => %W/brief defgroup ingroup comments/.map(&:to_sym),
307
+ }
326
308
 
327
- if m = /^(typedef )*(struct|enum) (.*?)(\{|(\w*?);)/.match(line)
328
- tdef = m[1] # typdef or nil
329
- type = m[2] # struct or enum
330
- name = m[3] # name or nil
331
- linestart = lineno
332
- name.strip! if name
333
- tdef.strip! if tdef
334
- if m[4] == '{'
335
- # struct or enum
336
- in_block = true
337
- else
338
- # single line, probably typedef
339
- val = m[4].gsub(';', '').strip
340
- if !name.empty?
341
- name = name.gsub('*', '').strip
342
- @data[:types][name] = {:tdef => tdef, :type => type, :value => val, :file => filepath, :line => lineno}
343
- end
344
- end
345
- elsif m = /\}(.*?);/.match(line)
346
- if !m[1].strip.empty?
347
- name = m[1].strip
348
- end
349
- name = name.gsub('*', '').strip
350
- @data[:types][name] = {:block => block, :tdef => tdef, :type => type, :value => val, :file => filepath, :line => linestart, :lineto => lineno}
351
- in_block = false
352
- block = ''
353
- elsif in_block
354
- block += line + "\n"
355
- end
356
- end
357
-
358
- in_comment = false
359
- in_block = false
360
- current = -1
361
- data = []
362
- lineno = 0
363
- # look for functions
364
- content.each do |line|
365
- lineno += 1
366
- line = line.strip
367
- next if line.size == 0
368
- next if line[0, 1] == '#'
369
- in_block = true if line =~ /\{/
370
- if m = /(.*?)\/\*(.*?)\*\//.match(line)
371
- code = m[1]
372
- comment = m[2]
373
- current += 1
374
- data[current] ||= {:comments => clean_comment(comment), :code => [code], :line => lineno}
375
- elsif m = /(.*?)\/\/(.*?)/.match(line)
376
- code = m[1]
377
- comment = m[2]
378
- current += 1
379
- data[current] ||= {:comments => clean_comment(comment), :code => [code], :line => lineno}
380
- else
381
- if line =~ /\/\*/
382
- in_comment = true
383
- current += 1
384
- elsif current == -1
385
- current += 1
386
- end
387
- data[current] ||= {:comments => '', :code => [], :line => lineno}
388
- data[current][:lineto] = lineno
389
- if in_comment
390
- data[current][:comments] += clean_comment(line) + "\n"
391
- else
392
- data[current][:code] << line
393
- end
394
- if (m = /(.*?);$/.match(line)) && (data[current][:code].size > 0) && !in_block
395
- current += 1
396
- end
397
- in_comment = false if line =~ /\*\//
398
- in_block = false if line =~ /\}/
399
- end
400
- end
401
- data.compact!
402
- meta = extract_meta(data)
403
- funcs = extract_functions(filepath, data)
404
- @data[:files] << {:file => filepath, :meta => meta, :functions => funcs, :lines => lineno}
405
- end
309
+ file_map = {}
406
310
 
407
- def clean_comment(comment)
408
- comment = comment.gsub(/^\/\//, '')
409
- comment = comment.gsub(/^\/\**/, '')
410
- comment = comment.gsub(/^\**/, '')
411
- comment = comment.gsub(/^[\w\*]*\//, '')
412
- comment
413
- end
311
+ md = Redcarpet::Markdown.new Redcarpet::Render::HTML, :no_intra_emphasis => true
312
+ recs.each do |r|
414
313
 
415
- # go through all the comment blocks and extract:
416
- # @file, @brief, @defgroup and @ingroup
417
- def extract_meta(data)
418
- file, brief, defgroup, ingroup = nil
419
- data.each do |block|
420
- block[:comments].each do |comment|
421
- m = []
422
- file = m[1] if m = /@file (.*?)$/.match(comment)
423
- brief = m[1] if m = /@brief (.*?)$/.match(comment)
424
- defgroup = m[1] if m = /@defgroup (.*?)$/.match(comment)
425
- ingroup = m[1] if m = /@ingroup (.*?)$/.match(comment)
314
+ # initialize filemap for this file
315
+ file_map[r[:file]] ||= {
316
+ :file => r[:file], :functions => [], :meta => {}, :lines => 0
317
+ }
318
+ if file_map[r[:file]][:lines] < r[:lineto]
319
+ file_map[r[:file]][:lines] = r[:lineto]
426
320
  end
427
- end
428
- {:file => file, :brief => brief, :defgroup => defgroup, :ingroup => ingroup}
429
- end
430
321
 
431
- def extract_functions(file, data)
432
- @data[:functions]
433
- funcs = []
434
- data.each do |block|
435
- ignore = false
436
- code = block[:code].join(" ")
437
- code = code.gsub(/\{(.*)\}/, '') # strip inline code
438
- rawComments = block[:comments]
439
- comments = block[:comments]
440
-
441
- if m = /^(.*?) ([a-z_]+)\((.*)\)/.match(code)
442
- ret = m[1].strip
443
- if r = /\((.*)\)/.match(ret) # strip macro
444
- ret = r[1]
322
+ # process this type of record
323
+ case r[:type]
324
+ when :function
325
+ @data[:functions][r[:name]] ||= {}
326
+ wanted[:functions].each do |k|
327
+ next unless r.has_key? k
328
+ conents = nil
329
+ if k == :description || k == :comments
330
+ contents = md.render r[k]
331
+ else
332
+ contents = r[k]
333
+ end
334
+ @data[:functions][r[:name]][k] = contents
445
335
  end
446
- fun = m[2].strip
447
- origArgs = m[3].strip
448
-
449
- # replace ridiculous syntax
450
- args = origArgs.gsub(/(\w+) \(\*(.*?)\)\(([^\)]*)\)/) do |m|
451
- type, name = $1, $2
452
- cast = $3.gsub(',', '###')
453
- "#{type}(*)(#{cast}) #{name}"
336
+ file_map[r[:file]][:functions] << r[:name]
337
+
338
+ when :define, :macro
339
+ @data[:globals][r[:decl]] ||= {}
340
+ wanted[:globals].each do |k|
341
+ @data[:globals][r[:decl]][k] = r[k] if r.has_key?(k)
454
342
  end
455
343
 
456
- args = args.split(',').map do |arg|
457
- argarry = arg.split(' ')
458
- var = argarry.pop
459
- type = argarry.join(' ').gsub('###', ',') + ' '
344
+ when :file
345
+ wanted[:meta].each do |k|
346
+ file_map[r[:file]][:meta][k] = r[k] if r.has_key?(k)
347
+ end
460
348
 
461
- ## split pointers off end of type or beg of name
462
- var.gsub!('*') do |m|
463
- type += '*'
464
- ''
349
+ when :enum
350
+ if !r[:name]
351
+ # Explode unnamed enum into multiple global defines
352
+ r[:decl].each do |n|
353
+ @data[:globals][n] ||= {
354
+ :file => r[:file], :line => r[:line],
355
+ :value => "", :comments => r[:comments],
356
+ }
357
+ m = /#{Regexp.quote(n)}/.match(r[:body])
358
+ if m
359
+ @data[:globals][n][:line] += m.pre_match.scan("\n").length
360
+ if m.post_match =~ /\s*=\s*([^,\}]+)/
361
+ @data[:globals][n][:value] = $1
362
+ end
363
+ end
465
364
  end
466
- desc = ''
467
- comments = comments.gsub(/\@param #{Regexp.escape(var)} ([^@]*)/m) do |m|
468
- desc = $1.gsub("\n", ' ').gsub("\t", ' ').strip
469
- ''
365
+ else
366
+ @data[:types][r[:name]] ||= {}
367
+ wanted[:types].each do |k|
368
+ @data[:types][r[:name]][k] = r[k] if r.has_key?(k)
470
369
  end
471
- ## TODO: parse comments to extract data about args
472
- {:type => type.strip, :name => var, :comment => desc}
473
370
  end
474
371
 
475
- sig = args.map do |arg|
476
- arg[:type].to_s
477
- end.join('::')
478
-
479
- return_comment = ''
480
- comments.gsub!(/\@return ([^@]*)/m) do |m|
481
- return_comment = $1.gsub("\n", ' ').gsub("\t", ' ').strip
482
- ''
372
+ when :struct, :fnptr
373
+ @data[:types][r[:name]] ||= {}
374
+ r[:value] ||= r[:name]
375
+ wanted[:types].each do |k|
376
+ @data[:types][r[:name]][k] = r[k] if r.has_key?(k)
483
377
  end
484
-
485
- comments = strip_block(comments)
486
- comment_lines = comments.split("\n\n")
487
-
488
- desc = ''
489
- if comments.size > 0
490
- desc = comment_lines.shift.split("\n").map { |e| e.strip }.join(' ')
491
- comments = comment_lines.join("\n\n").strip
378
+ if r[:type] == :fnptr
379
+ @data[:types][r[:name]][:type] = "function pointer"
492
380
  end
493
381
 
494
- next if fun == 'defined'
495
- @data[:functions][fun] = {
496
- :description => desc,
497
- :return => {:type => ret, :comment => return_comment},
498
- :args => args,
499
- :argline => origArgs,
500
- :file => file,
501
- :line => block[:line],
502
- :lineto => block[:lineto],
503
- :comments => comments,
504
- :sig => sig,
505
- :rawComments => rawComments
506
- }
507
- funcs << fun
382
+ else
383
+ # Anything else we want to record?
508
384
  end
509
- end
510
- funcs
511
- end
512
385
 
513
- # TODO: rolled this back, want to strip the first few spaces, not everything
514
- def strip_block(block)
515
- block.strip
516
- end
517
-
518
- def mkdir_temp
519
- tf = Tempfile.new('docurium')
520
- tpath = tf.path
521
- tf.unlink
522
- FileUtils.mkdir_p(tpath)
523
- tpath
524
- end
386
+ end
525
387
 
526
- def mkfile_temp
527
- tf = Tempfile.new('docurium-index')
528
- tpath = tf.path
529
- tf.unlink
530
- tpath
388
+ @data[:files] << file_map.values[0]
531
389
  end
532
390
 
533
- def copy_site(outdir)
534
- here = File.expand_path(File.dirname(__FILE__))
535
- FileUtils.mkdir_p(outdir)
536
- Dir.chdir(outdir) do
537
- FileUtils.cp_r(File.join(here, '..', 'site', '.'), '.')
391
+ def add_dir_to_index(index, prefix, dir)
392
+ Dir.new(dir).each do |filename|
393
+ next if [".", ".."].include? filename
394
+ name = File.join(dir, filename)
395
+ if File.directory? name
396
+ add_dir_to_index(index, prefix, name)
397
+ else
398
+ rel_path = name.gsub(prefix, '')
399
+ content = File.read(name)
400
+ sha = @repo.write(content, :blob)
401
+ index.add(:path => rel_path, :oid => sha, :mode => 0100644)
402
+ end
538
403
  end
539
404
  end
540
405
 
541
- def write_dir
542
- out "Writing to directory #{output_dir}"
543
- out "Done!"
406
+ def write_site(index)
407
+ here = File.expand_path(File.dirname(__FILE__))
408
+ dirname = File.join(here, '..', 'site')
409
+ dirname = File.realpath(dirname)
410
+ add_dir_to_index(index, dirname + '/', dirname)
544
411
  end
545
412
 
546
413
  def out(text)