ascii_binder 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,10 +4,20 @@ require 'ascii_binder/helpers'
4
4
  require 'pathname'
5
5
  require 'trollop'
6
6
 
7
-
8
7
  include AsciiBinder::Helpers
9
8
 
10
- SUB_COMMANDS = %w{help build watch package clean}
9
+ def call_generate(distro,page=nil)
10
+ if page == ''
11
+ page = nil
12
+ end
13
+ begin
14
+ generate_docs(distro,page)
15
+ rescue Exception => e
16
+ Trollop::die "Could not generate docs: #{e.message}"
17
+ end
18
+ end
19
+
20
+ SUB_COMMANDS = %w{help build watch package clean create}
11
21
  Trollop::options do
12
22
  banner <<-EOF
13
23
  Usage:
@@ -16,6 +26,8 @@ Usage:
16
26
  Commands:
17
27
  build (default action)
18
28
  Builds the HTML docs in the indicated repo dir
29
+ create
30
+ Generates a new AsciiBinder repo at the indicated dir
19
31
  watch
20
32
  Starts Guard, which automatically regenerates changed HTML
21
33
  files on the working branch in the repo dir
@@ -24,7 +36,7 @@ Commands:
24
36
  defined in the _distro_config.yml file
25
37
  clean
26
38
  Remove _preview, _publish and _package dirs created by
27
- other asciibinder operations.
39
+ other AsciiBinder operations.
28
40
 
29
41
  Options:
30
42
  EOF
@@ -38,7 +50,7 @@ if cmd.nil?
38
50
  cmd = "build"
39
51
  elsif not SUB_COMMANDS.include?(cmd)
40
52
  if not ARGV.empty?
41
- Trollop::die "'#{cmd}' is not a valid asciibinder command. Legal values are '#{SUB_COMMANDS.join('\', \'')}'."
53
+ Trollop::die "'#{cmd}' is not a valid asciibinder subcommand. Legal values are '#{SUB_COMMANDS.join('\', \'')}'."
42
54
  else
43
55
  repo_dir = Pathname.new(cmd)
44
56
  cmd = "build"
@@ -54,22 +66,44 @@ Usage:
54
66
 
55
67
  Description:
56
68
  This is the default behavior for the asciibinder utility. When run,
57
- asciibinder reads the _distro_config.yml file out of the working
69
+ AsciiBinder reads the _distro_config.yml file out of the working
58
70
  branch of the indicated repo directory and based on that, proceeds to
59
71
  build the working branch version of the documentation for each distro.
60
72
 
61
- Once the working branch version is built, asciibinder cycles through
73
+ Once the working branch version is built, AsciiBinder cycles through
62
74
  the other branches named in the _distro_config.yml file until all of
63
75
  the permutations have been built.
64
76
 
77
+ The available options enable you to limit the scope of the build work,
78
+ as described by the options themselves. Note that the format for the
79
+ "--page" option is:
80
+
81
+ <topic_group>:<topic_file>
82
+
83
+ or for subtopics:
84
+
85
+ <topic_group>/<subtopic_group>:<topic_file>
86
+
87
+ However, if you want to use the --page option extensively, then be
88
+ aware of the `asciibinder watch` function, which does this for you
89
+ automatically as you change .adoc files in your working branch.
90
+
65
91
  Options:
66
92
  EOF
67
93
  opt :distro, "Instead of building all distros, build branches only for the specified distro.", :default => ''
94
+ opt :page, "Build only the specified page for all distros and only the current working branch.", :default => ''
95
+ conflicts :distro, :page
96
+ end
97
+ when "create"
98
+ Trollop::options do
99
+ banner <<-EOF
100
+ Usage:
101
+ #$0 create <new_repo_dir>
102
+
103
+ Description:
104
+ Creates a new, bare AsciiBinder repo in the specified directory.
105
+ EOF
68
106
  end
69
- #when "new"
70
- # Trollop::options do
71
- # opt :initialize, "Create a new AsciiBinder-ready git repo in the target directory.", :default => true
72
- # end
73
107
  when "watch"
74
108
  Trollop::options do
75
109
  banner <<-EOF
@@ -77,16 +111,23 @@ Usage:
77
111
  #$0 watch <repo_dir>
78
112
 
79
113
  Description:
80
- In watch mode, asciibinder starts a Guard process in the foreground.
114
+ In watch mode, AsciiBinder starts a Guard process in the foreground.
81
115
  This process watches the repo_dir for changes to the AsciiDoc (.adoc)
82
- files. When a change occurs, asciibinder regenerates the specific
116
+ files. When a change occurs, AsciiBinder regenerates the specific
83
117
  HTML output of the file that was changed, for the working branch only.
84
118
 
119
+ This is the equivalent of running:
120
+
121
+ $ asciibinder build --page='<topic_group>:<affected_file>'
122
+
123
+ ...except that the Guardfile automatically detects and runs this as
124
+ you work.
125
+
85
126
  This is meant to be used in conjunction with a web browser that is
86
127
  running a LiveReload plugin. If you are viewing the output HTML page
87
128
  in a browser where LiveReload is active, then every time you save a
88
129
  new version of the .adoc file, the new HTML is automatically
89
- regenrated and your page view is automatically refreshed.
130
+ regenerated and your page view is automatically refreshed.
90
131
  EOF
91
132
  end
92
133
  when "package"
@@ -116,40 +157,70 @@ elsif repo_dir.nil?
116
157
  if ARGV.length == 1
117
158
  repo_dir = Pathname.new(ARGV.shift)
118
159
  else
119
- repo_dir = Pathname.pwd
160
+ if not cmd == 'create'
161
+ repo_dir = Pathname.pwd
162
+ else
163
+ Trollop::die "Specify a name for the new repo directory."
164
+ end
120
165
  end
121
166
  end
122
167
 
123
168
  # Validate the repo_dir path
124
- if not repo_dir.exist?
125
- Trollop::die "The specified repo directory '#{repo_dir}' does not exist."
126
- elsif not repo_dir.directory?
127
- Trollop::die "The specified repo directory path '#{repo_dir}' is not a directory."
128
- elsif not repo_dir.readable?
129
- Trollop::die "The specified repo directory '#{repo_dir}' is not readable."
130
- elsif not repo_dir.writable?
131
- Trollop::die "The specified repo directory '#{repo_dir}' cannot be written to."
169
+ if cmd == 'create'
170
+ if repo_dir.exist?
171
+ Trollop::die "The specified new repo directory '#{repo_dir}' already exists."
172
+ end
173
+ else
174
+ if not repo_dir.exist?
175
+ Trollop::die "The specified repo directory '#{repo_dir}' does not exist."
176
+ elsif not repo_dir.directory?
177
+ Trollop::die "The specified repo directory path '#{repo_dir}' is not a directory."
178
+ elsif not repo_dir.readable?
179
+ Trollop::die "The specified repo directory '#{repo_dir}' is not readable."
180
+ elsif not repo_dir.writable?
181
+ Trollop::die "The specified repo directory '#{repo_dir}' cannot be written to."
182
+ else
183
+ ['.git','_build_cfg.yml','_distro_map.yml','_templates'].each do |file|
184
+ if not File.exist?(File.join(repo_dir, file))
185
+ Trollop::die "The specified repo directory '#{repo_dir}' does not appear to be an AsciiBinder repo."
186
+ end
187
+ end
188
+ end
132
189
  end
133
190
 
134
191
  # Set the repo root
135
192
  set_source_dir(File.expand_path(repo_dir))
136
193
 
194
+ # Change to the repo dir. This is necessary in order for
195
+ # AsciiDoctor to work properly.
196
+ if not cmd == 'create'
197
+ Dir.chdir source_dir
198
+ end
199
+
137
200
  # Do the things with the stuff
138
201
  case cmd
139
202
  when "build"
140
203
  build_distro = cmd_opts[:build] || ''
141
- generate_docs(build_distro)
204
+ refresh_page = cmd_opts[:page] || ''
205
+ call_generate(build_distro,refresh_page)
142
206
  when "package"
143
207
  clean_up
144
- generate_docs('')
208
+ call_generate('')
145
209
  package_site = cmd_opts[:site] || ''
146
210
  package_docs(package_site)
147
211
  when "watch"
148
- guardfile_path = File.join(Gem::Specification.find_by_name("ascii_binder").full_gem_path, 'Guardfile')
149
- exec("guard -G #{guardfile_path}")
212
+ if not dir_empty?(preview_dir)
213
+ guardfile_path = File.join(Gem::Specification.find_by_name("ascii_binder").full_gem_path, 'Guardfile')
214
+ exec("guard -G #{guardfile_path}")
215
+ else
216
+ Trollop::die "Run 'asciibinder build' at least once before running 'asciibinder watch'."
217
+ end
150
218
  when "clean"
151
219
  clean_up
152
220
  puts "Cleaned up #{repo_dir}."
221
+ when "create"
222
+ create_new_repo
223
+ puts "Created new repo in #{repo_dir}."
153
224
  end
154
225
 
155
226
  exit
@@ -2,6 +2,7 @@ require 'ascii_binder/template_renderer'
2
2
  require 'asciidoctor'
3
3
  require 'asciidoctor/cli'
4
4
  require 'asciidoctor-diagram'
5
+ require 'fileutils'
5
6
  require 'find'
6
7
  require 'git'
7
8
  require 'logger'
@@ -19,10 +20,18 @@ module AsciiBinder
19
20
  @source_dir ||= `git rev-parse --show-toplevel`.chomp
20
21
  end
21
22
 
23
+ def self.gem_root_dir
24
+ @gem_root_dir ||= File.expand_path("../../../", __FILE__)
25
+ end
26
+
22
27
  def self.set_source_dir(source_dir)
23
28
  @source_dir = source_dir
24
29
  end
25
30
 
31
+ def template_renderer
32
+ @template_renderer ||= TemplateRenderer.new(source_dir, template_dir)
33
+ end
34
+
26
35
  def self.template_dir
27
36
  @template_dir ||= File.join(source_dir,'_templates')
28
37
  end
@@ -47,13 +56,28 @@ module AsciiBinder
47
56
  end
48
57
  end
49
58
 
50
- def_delegators self, :source_dir, :set_source_dir, :template_dir, :preview_dir, :package_dir
59
+ def self.stylesheet_dir
60
+ @stylesheet_dir ||= File.join(source_dir,STYLESHEET_DIRNAME)
61
+ end
62
+
63
+ def self.javascript_dir
64
+ @javascript_dir ||= File.join(source_dir,JAVASCRIPT_DIRNAME)
65
+ end
66
+
67
+ def self.image_dir
68
+ @image_dir ||= File.join(source_dir,IMAGE_DIRNAME)
69
+ end
70
+
71
+ def_delegators self, :source_dir, :set_source_dir, :template_dir, :preview_dir, :package_dir, :gem_root_dir, :stylesheet_dir, :javascript_dir, :image_dir
51
72
 
52
73
  BUILD_FILENAME = '_build_cfg.yml'
53
74
  DISTRO_MAP_FILENAME = '_distro_map.yml'
54
75
  BUILDER_DIRNAME = '_build_system'
55
76
  PREVIEW_DIRNAME = '_preview'
56
77
  PACKAGE_DIRNAME = '_package'
78
+ STYLESHEET_DIRNAME = '_stylesheets'
79
+ JAVASCRIPT_DIRNAME = '_javascripts'
80
+ IMAGE_DIRNAME = '_images'
57
81
  BLANK_STRING_RE = Regexp.new('^\s*$')
58
82
 
59
83
  def build_date
@@ -95,8 +119,10 @@ module AsciiBinder
95
119
  def local_branches
96
120
  @local_branches ||= begin
97
121
  branches = []
98
- branches << git.branches.local.select{ |b| b.current }[0].name
99
- branches << git.branches.local.select{ |b| not b.current }.map{ |b| b.name }
122
+ if not git.branches.local.empty?
123
+ branches << git.branches.local.select{ |b| b.current }[0].name
124
+ branches << git.branches.local.select{ |b| not b.current }.map{ |b| b.name }
125
+ end
100
126
  branches.flatten
101
127
  end
102
128
  end
@@ -113,13 +139,54 @@ module AsciiBinder
113
139
  @distro_map_file ||= File.join(source_dir, DISTRO_MAP_FILENAME)
114
140
  end
115
141
 
142
+ def dir_empty?(dir)
143
+ Dir.entries(dir).select{ |f| not f.start_with?('.') }.empty?
144
+ end
145
+
116
146
  # Protip: Don't cache this! It needs to be reread every time we change branches.
117
147
  def build_config
118
148
  validate_config(YAML.load_stream(open(build_config_file)))
119
149
  end
120
150
 
151
+ def create_new_repo
152
+ gem_template_dir = File.join(gem_root_dir,"templates")
153
+
154
+ # Create the new repo dir
155
+ begin
156
+ Dir.mkdir(source_dir)
157
+ rescue Exception => e
158
+ raise "Could not create directory '#{source_dir}': #{e.message}"
159
+ end
160
+
161
+ # Copy the basic repo content into the new repo dir
162
+ Find.find(gem_template_dir).each do |path|
163
+ next if path == gem_template_dir
164
+ src_path = Pathname.new(path)
165
+ tgt_path = src_path.sub(gem_template_dir,source_dir)
166
+ if src_path.directory?
167
+ FileUtils.mkdir_p(tgt_path.to_s)
168
+ else
169
+ FileUtils.cp src_path.to_s, tgt_path.to_s
170
+ end
171
+ end
172
+
173
+ # Initialize the git repo and check everything in
174
+ g = nil
175
+ begin
176
+ g = Git.init(source_dir)
177
+ rescue Exception => e
178
+ raise "Could not initialize git repo in '#{source_dir}': #{e.message}"
179
+ end
180
+ end
181
+
121
182
  def find_topic_files
122
- file_list = Find.find('.').select{ |path| not path.nil? and path =~ /.*\.adoc$/ and not path =~ /README/ and not path =~ /\/old\// and not path.split('/').length < 3 }
183
+ file_list = []
184
+ Find.find(source_dir).each do |path|
185
+ next if path.nil? or not path =~ /.*\.adoc/ or path =~ /README/ or path =~ /\/old\//
186
+ src_path = Pathname.new(path).sub(source_dir,'').to_s
187
+ next if src_path.split('/').length < 3
188
+ file_list << src_path
189
+ end
123
190
  file_list.map{ |path|
124
191
  parts = path.split('/').slice(1..-1);
125
192
  parts.slice(0..-2).join('/') + '/' + parts[-1].split('.')[0]
@@ -187,7 +254,8 @@ module AsciiBinder
187
254
  args[:subtopic_shim] = '../'
188
255
  end
189
256
 
190
- TemplateRenderer.new.render(File.expand_path("#{source_dir}/_templates/page.html.erb"), args)
257
+ template_path = File.expand_path("#{source_dir}/_templates/page.html.erb")
258
+ template_renderer.render(template_path, args)
191
259
  end
192
260
 
193
261
  def extract_breadcrumbs(args)
@@ -390,6 +458,12 @@ module AsciiBinder
390
458
  end
391
459
 
392
460
  def generate_docs(build_distro,single_page=nil)
461
+ # First, test to see if the docs repo has any commits. If the user has just
462
+ # run `asciibinder create`, there will be no commits to work from, yet.
463
+ if local_branches.empty?
464
+ raise "Before you can build the docs, you need at least one commit in your docs repo."
465
+ end
466
+
393
467
  single_page_dir = []
394
468
  single_page_file = nil
395
469
  if not single_page.nil?
@@ -408,9 +482,6 @@ module AsciiBinder
408
482
  puts "Building all distributions."
409
483
  end
410
484
 
411
- # Cache the page templates
412
- TemplateRenderer.initialize_cache(template_dir)
413
-
414
485
  # First, notify the user of missing local branches
415
486
  missing_branches = []
416
487
  distro_branches(build_distro).sort.each do |dbranch|
@@ -480,19 +551,23 @@ module AsciiBinder
480
551
  end
481
552
 
482
553
  # Create the target dir
483
- branch_path = File.join(preview_dir,distro,branch_config["dir"])
484
- system("mkdir -p #{branch_path}/stylesheets")
485
- system("mkdir -p #{branch_path}/javascripts")
486
- system("mkdir -p #{branch_path}/images")
487
-
488
- # Copy stylesheets into preview area
489
- system("cp -r #{source_dir}/_stylesheets/*css #{branch_path}/stylesheets")
490
-
491
- # Copy javascripts into preview area
492
- system("cp -r #{source_dir}/_javascripts/*js #{branch_path}/javascripts")
493
-
494
- # Copy images into preview area
495
- system("cp -r #{source_dir}/_images/* #{branch_path}/images")
554
+ branch_path = File.join(preview_dir,distro,branch_config["dir"])
555
+ branch_stylesheet_dir = File.join(branch_path,STYLESHEET_DIRNAME)
556
+ branch_javascript_dir = File.join(branch_path,JAVASCRIPT_DIRNAME)
557
+ branch_image_dir = File.join(branch_path,IMAGE_DIRNAME)
558
+
559
+ # Copy files into the preview area.
560
+ [[stylesheet_dir, '*css', branch_stylesheet_dir],
561
+ [javascript_dir, '*js', branch_javascript_dir],
562
+ [image_dir, '*', branch_image_dir]].each do |dgroup|
563
+ src_dir = dgroup[0]
564
+ glob = dgroup[1]
565
+ tgt_dir = dgroup[2]
566
+ if Dir.exist?(src_dir) and not dir_empty?(src_dir)
567
+ FileUtils.mkdir_p tgt_dir
568
+ FileUtils.cp_r Dir.glob(File.join(src_dir,glob)), tgt_dir
569
+ end
570
+ end
496
571
 
497
572
  # Build the landing page
498
573
  navigation = nav_tree(distro,branch_build_config)
@@ -665,12 +740,11 @@ module AsciiBinder
665
740
  :group_id => topic_group['ID'],
666
741
  :subgroup_id => topic_subgroup && topic_subgroup['ID'],
667
742
  :topic_id => topic['ID'],
668
- :css_path => "../../#{dir_depth}#{branch_config["dir"]}/stylesheets/",
669
- :javascripts_path => "../../#{dir_depth}#{branch_config["dir"]}/javascripts/",
670
- :images_path => "../../#{dir_depth}#{branch_config["dir"]}/images/",
743
+ :css_path => "../../#{dir_depth}#{branch_config["dir"]}/#{STYLESHEET_DIRNAME}/",
744
+ :javascripts_path => "../../#{dir_depth}#{branch_config["dir"]}/#{JAVASCRIPT_DIRNAME}/",
745
+ :images_path => "../../#{dir_depth}#{branch_config["dir"]}/#{IMAGE_DIRNAME}/",
671
746
  :site_home_path => "../../#{dir_depth}index.html",
672
- :css => ['docs.css'],
673
- :template_dir => template_dir,
747
+ :template_path => template_dir,
674
748
  }
675
749
  full_file_text = page(page_args)
676
750
  File.write(tgt_file_path,full_file_text)
@@ -4,7 +4,7 @@ guard 'shell' do
4
4
  full_path = m[0].split('/')
5
5
  src_group_path = full_path.length == 1 ? '' : full_path[0..-2].join('/')
6
6
  filename = full_path[-1][0..-6]
7
- system("bundle exec rake refresh_page['#{src_group_path}:#{filename}']")
7
+ system("asciibinder build --page='#{src_group_path}:#{filename}'")
8
8
  end
9
9
  }
10
10
  end
@@ -2,24 +2,28 @@ require 'tilt'
2
2
 
3
3
  module AsciiBinder
4
4
  class TemplateRenderer
5
- def self.template_cache
6
- @template_cache ||= {}
7
- end
5
+ attr_reader :source_dir, :template_cache
8
6
 
9
- def self.initialize_cache(directory)
10
- Dir.glob(File.join(directory, "**/*")).each do |file|
11
- template_cache[file] = Tilt.new(file, :trim => "-")
7
+ def initialize(source_dir,template_directory)
8
+ @source_dir = source_dir
9
+ @template_cache = {}
10
+ Dir.glob(File.join(template_directory, "**/*")).each do |file|
11
+ @template_cache[file] = Tilt.new(file, :trim => "-")
12
12
  end
13
13
  end
14
14
 
15
15
  def render(template, args = {})
16
+ # Inside erb files, template path is local to repo
17
+ if not template.start_with?(source_dir)
18
+ template = File.join(source_dir, template)
19
+ end
16
20
  renderer_for(template).render(self, args).chomp
17
21
  end
18
22
 
19
23
  private
20
24
 
21
25
  def renderer_for(template)
22
- self.class.template_cache.fetch(File.expand_path(template))
26
+ template_cache.fetch(File.expand_path(template))
23
27
  end
24
28
  end
25
29
  end