#!/usr/bin/env ruby require 'ascii_binder/distro_map' require 'ascii_binder/engine' require 'ascii_binder/helpers' require 'ascii_binder/version' require 'pathname' require 'trollop' include AsciiBinder::Engine include AsciiBinder::Helpers def call_generate(branch_group, distro, page) if page == '' page = nil end begin generate_docs(branch_group, distro, page) rescue => e message = "#{e.class.name}: #{e.message} at\n #{e.backtrace.join("\n ")}" Trollop::die "Could not generate docs:\n#{message}" end end def repo_check(docs_basedir) missing_files = false # These must all be present ['_distro_map.yml','_templates'].each do |file| unless File.exist?(File.join(docs_basedir, file)) missing_files = true end end # Either of these must be present # unless File.exist?(File.join("#{docs_basedir}/#{TOPIC_MAP_FOLDER}", '_topic_map.yml')) # missing_files = true # end if missing_files or not in_git_repo(docs_basedir) Trollop::die "The specified docs base directory '#{docs_basedir}' does not appear to be part of an AsciiBinder-compatible repo." end end def in_git_repo(dir) git_path = File.join(dir,'.git') return true if File.exist?(git_path) and File.directory?(git_path) return false if dir == '/' in_git_repo(File.expand_path('..',dir)) end SUB_COMMANDS = %w{help version build watch package clean create clone} Trollop::options do version AsciiBinder::VERSION banner <<-EOF Usage: #$0 Commands: build (default action) Builds the HTML docs within the indicated docs base directory create Generates a new AsciiBinder repo at the indicated dir clone Clones an existing AsciiBinder repo to the local filesystem watch Starts Guard, which automatically regenerates changed HTML files on the working branch in the docs base directory dir package Builds and packages the static HTML for all of the sites defined in the _distro_config.yml file clean Remove _preview, _publish and _package dirs created by other AsciiBinder operations. Options: EOF stop_on SUB_COMMANDS end cmd = ARGV.shift docs_basedir = nil if cmd.nil? cmd = "build" elsif !SUB_COMMANDS.include?(cmd) if ARGV.empty? docs_basedir = Pathname.new(cmd) cmd = "build" else Trollop::die "'#{cmd}' is not a valid asciibinder subcommand. Legal values are '#{SUB_COMMANDS.join('\', \'')}'." end end cmd_opts = case cmd when "build" Trollop::options do banner <<-EOF Usage: #$0 build Description: This is the default behavior for the asciibinder utility. When run, AsciiBinder reads the _distro_config.yml file out of the working branch of the indicated docs base directory and based on that, proceeds to build the working branch version of the documentation for each distro. If you use the --all_branches flag, AsciiBinder behaves as described above, and then once the working branch version is built, AsciiBinder cycles through the other branches named in the _distro_config.yml file until all of the permutations have been built. If you want to limit the scope of the build work for faster builds, you have two targeted options: --distro= - Only builds the specified distro and branches associated with this distro. --page= - Only builds the specified page for all distros. Note that the format for the "--page" option is: : or for subtopics: /: However, if you want to use the --page option extensively, then be aware of the `asciibinder watch` function, which does this for you automatically as you change any .adoc files in your working branch. Options: EOF opt :all_branches, "Instead of building only the current working branch, build all branches", :default => false opt :distro, "Instead of building all distros, build branches only for the specified distro.", :default => '' opt :page, "Build only the specified page for all distros and only the current working branch.", :default => '' opt :log_level, "Set the logging output level for this operation.", :default => 'warn' opt :toc_depth, "Maximum depth of topics allowed. Use 0 for infinite depth.", :default => 3 conflicts :distro, :page end when "create" Trollop::options do banner <<-EOF Usage: #$0 create Description: Creates a new, bare AsciiBinder repo in the specified directory. EOF end when "clone" Trollop::options do banner <<-EOF Usage: #$0 clone Description: Clones an existing AsciiBinder repo to the current directory. Under the default behavior, AsciiBinder will attempt to set up tracking branches based on the contents of _distro_map.yml, but this can be suppressed (see Options). Options: EOF opt :branches, "Create tracking branches after cloning.", :default => true opt :dir, "Specify the pathname of the local directory for cloning.", :default => '' opt :log_level, "Set the logging output level for this operation.", :default => 'warn' end when "watch" Trollop::options do banner <<-EOF Usage: #$0 watch Description: In watch mode, AsciiBinder starts a Guard process in the foreground. This process watches the docs_basedir for changes to the AsciiDoc (.adoc) files. When a change occurs, AsciiBinder regenerates the specific HTML output of the file that was changed, for the working branch only. This is the equivalent of running: $ asciibinder build --page=':' ...except that the Guardfile automatically detects and runs this as you work. This is meant to be used in conjunction with a web browser that is viewing the output HTML page. Every time you save a new version of the .adoc file, you can manually refresh your page to view the newly-generated HTML. EOF opt :log_level, "Set the logging output level for this operation.", :default => 'warn' end when "package" Trollop::options do banner <<-EOF Usage: #$0 package Description: Publish mode is similar to 'build' mode, but once all of the branches' of HTML are generated, 'publish' goes on to organize the branch / distro combinations that are described in _distro_config.yml into their "site" layouts. As a final step, the site layouts are tarred and gzipped for easy placement onto a production web server. Options: EOF opt :site, "Instead of packaging every docs site, package the specified site only.", :default => '' opt :log_level, "Set the logging output level for this operation.", :default => 'warn' opt :toc_depth, "Maximum depth of topics allowed. Use 0 for infinite depth.", :default => 3 end when "help" Trollop::educate when "version" puts AsciiBinder::VERSION exit 0 end if (not docs_basedir.nil? and not ARGV.empty?) or (docs_basedir.nil? and ARGV.length > 1) Trollop::die "Too many arguments provided to ascii_binder: '#{ARGV.join(' ')}'. Exiting." elsif docs_basedir.nil? if ARGV.length == 1 if cmd == 'clone' cmd_opts[:giturl] = ARGV.shift if cmd_opts[:dir] != '' docs_basedir = Pathname.new(cmd_opts[:dir]) else docs_basedir = Pathname.new(File.join(Pathname.pwd, cmd_opts[:giturl].split('/')[-1].split('.')[0])) end else docs_basedir = Pathname.new(ARGV.shift) end else if cmd != 'create' if cmd == 'clone' Trollop::die "Provide a git URL to clone from." else docs_basedir = Pathname.pwd end else Trollop::die "Specify a name for the new repo directory." end end end # Validate the docs_basedir path if cmd == 'create' or cmd == 'clone' if docs_basedir.exist? Trollop::die "The specified new repo directory '#{docs_basedir}' already exists." end else if !docs_basedir.exist? Trollop::die "The specified docs directory '#{docs_basedir}' does not exist." elsif !docs_basedir.directory? Trollop::die "The specified docs directory path '#{docs_basedir}' is not a directory." elsif !docs_basedir.readable? Trollop::die "The specified docs directory '#{docs_basedir}' is not readable." elsif !docs_basedir.writable? Trollop::die "The specified docs directory '#{docs_basedir}' cannot be written to." else repo_check(docs_basedir) end end # Set the repo root set_docs_root_dir(File.expand_path(docs_basedir)) # Set the log level user_log_level = :warn unless cmd_opts.nil? or cmd_opts[:log_level].nil? user_log_level = cmd_opts[:log_level].to_sym unless log_levels.has_key?(user_log_level) Trollop::die "log_level value '#{cmd_opts[:log_level]}' is not recognized. Legal values are " + log_levels.keys.map{ |lvl| "'#{lvl.to_s}'" }.join(', ') end end set_log_level(user_log_level) # Set the depth level user_depth = 3 unless cmd_opts.nil? or cmd_opts[:toc_depth].nil? user_depth = cmd_opts[:toc_depth].to_i end set_depth(user_depth) # Cloning? Time to try it. if cmd == 'clone' puts "Cloning #{cmd_opts[:giturl]} to #{docs_basedir}" system("git clone #{cmd_opts[:giturl]} #{docs_basedir}") Trollop::die "The git URL could not be cloned: #{err}" if $?.exitstatus != 0 # Make sure this cloned repo is legit. repo_check(docs_basedir) if cmd_opts[:branches] cloned_map = AsciiBinder::DistroMap.new(File.join(docs_basedir,DISTRO_MAP_FILENAME)) unless cloned_map.is_valid? error_info = cloned_map.errors.join("\n") Trollop::die "The distro map in the newly cloned repo is invalid, with the following errors:\n#{error_info}" end Dir.chdir(docs_basedir) puts "Tracking branch setup:" cloned_map.distro_branches.each do |doc_branch| next if doc_branch == 'main' puts "- #{doc_branch}" system("git branch #{doc_branch} origin/#{doc_branch}") end else puts "- Skipping tracking branch setup" end # Done and done. puts "Cloning complete." exit end # Change to the repo dir. This is necessary in order for # AsciiDoctor to work properly. if cmd != 'create' Dir.chdir docs_basedir end # Do the things with the stuff case cmd when "build" branch_group = cmd_opts[:all_branches] ? :all : :working_only build_distro = cmd_opts[:distro] || '' refresh_page = cmd_opts[:page] || nil call_generate(branch_group,build_distro,refresh_page) when "package" clean_up package_site = cmd_opts[:site] || '' branch_group = package_site == '' ? :publish : "publish_#{package_site}".to_sym call_generate(branch_group,'',nil) package_docs(package_site) when "watch" if !dir_empty?(preview_dir) guardfile_path = File.join(Gem::Specification.find_by_name("ascii_binder").full_gem_path, 'Guardfile') exec("guard -G #{guardfile_path}") else Trollop::die "Run 'asciibinder build' at least once before running 'asciibinder watch'." end when "clean" clean_up puts "Cleaned up #{docs_basedir}." when "create" create_new_repo puts "Created new repo in #{docs_basedir}." end exit