lib/liquidoc.rb in liquidoc-0.9.5 vs lib/liquidoc.rb in liquidoc-0.10.0
- old
+ new
@@ -8,10 +8,12 @@
require 'logger'
require 'csv'
require 'crack/xml'
require 'fileutils'
require 'jekyll'
+require 'open3'
+require 'highline'
# ===
# Table of Contents
# ===
#
@@ -51,10 +53,11 @@
@verbose = false
@quiet = false
@explicit = false
@search_index = false
@search_index_dry = ''
+@safemode = true
# Instantiate the main Logger object, which is always running
@logger = Logger.new(STDOUT)
@logger.formatter = proc do |severity, datetime, progname, msg|
"#{severity}: #{msg}\n"
@@ -93,10 +96,24 @@
@logger.error "Problem loading config file #{config_file}. #{ex} Exiting."
end
raise "ConfigFileError"
end
cfg = BuildConfig.new(config) # convert the config file to a new object called 'cfg'
+ if @safemode
+ commands = ""
+ cfg.steps.each do |step|
+ if step['action'] == "execute"
+ commands = commands + "> " + step['command'] + "\n"
+ end
+ end
+ unless commands.to_s.strip.empty?
+ puts "\nWARNING: This routine will execute the following shell commands:\n\n#{commands}"
+ ui = HighLine.new
+ answer = ui.ask("\nDo you approve? (YES/no): ")
+ raise "CommandExecutionsNotAuthorized" unless answer.strip == "YES"
+ end
+ end
iterate_build(cfg)
end
def iterate_build cfg
stepcount = 0
@@ -142,10 +159,13 @@
render_doc(doc, build) # perform the render operation
end
when "deploy"
@logger.warn "Deploy actions are limited and experimental."
jekyll_serve(build)
+ when "execute"
+ @logger.info "Executing shell command: #{step.command}"
+ execute_command(step)
else
@logger.warn "The action `#{type}` is not valid."
end
end
end
@@ -211,10 +231,27 @@
"#{msg}\n"
end
end
end
+def generate_file content, target
+ base_path = File.dirname(target)
+ begin
+ FileUtils::mkdir_p(base_path) unless File.exists?(base_path)
+ File.open(target, 'w') { |file| file.write(content) } # saves file
+ rescue Exception => ex
+ @logger.error "Failed to save output.\n#{ex.class} #{ex.message}"
+ raise "FileNotBuilt"
+ end
+ if File.exists?(target)
+ @logger.info "File built: #{target}"
+ else
+ @logger.error "Hrmp! File not built."
+ raise "FileNotBuilt"
+ end
+end
+
# ===
# Core classes
# ===
# For now BuildConfig is mostly to objectify the primary build 'action' steps
@@ -278,10 +315,14 @@
def options
return @step['options']
end
+ def command
+ return @step['command']
+ end
+
def stage
return @step['stage']
end
def builds
@@ -343,10 +384,12 @@
reqs = ["data,builds"]
when "migrate"
reqs = ["source,target"]
when "render"
reqs = ["builds"]
+ when "execute"
+ reqs = ["command"]
end
for req in reqs
if (defined?(@step[req])).nil?
@logger.error "Every #{@step['action']}-type in the configuration file needs a '#{req}' declaration."
raise "ConfigStructError"
@@ -743,24 +786,11 @@
@logger.error message
raise message
end
unless output.downcase == "stdout"
output_file = output
- base_path = File.dirname(output)
- begin
- FileUtils::mkdir_p(base_path) unless File.exists?(base_path)
- File.open(output_file, 'w') { |file| file.write(rendered) } # saves file
- rescue Exception => ex
- @logger.error "Failed to save output.\n#{ex.class} #{ex.message}"
- raise "FileNotBuilt"
- end
- if File.exists?(output_file)
- @logger.info "File built: #{output_file}"
- else
- @logger.error "Hrmp! File not built."
- raise "FileNotBuilt"
- end
+ generate_file(rendered, output_file)
else # if stdout
puts "========\nOUTPUT: Rendered with template #{template_file}:\n\n#{rendered}\n"
end
end
@@ -922,13 +952,10 @@
@logger.debug "Final pre-Asciidoctor attributes: #{attrs.to_yaml}"
# Perform the aciidoctor convert
if build.backend == "pdf"
@logger.info "Generating PDF. This can take some time..."
end
-
-
-
Asciidoctor.convert_file(
doc.index,
to_file: to_file,
attributes: attrs,
require: "pdf",
@@ -1017,10 +1044,42 @@
end
end
end
# ===
+# Execute
+# ===
+
+def execute_command cmd
+ stdout, stderr, status = Open3.capture3(cmd.command)
+ failed = true if status.to_s.include?("exit 1")
+ unless cmd.options
+ puts stdout
+ puts stderr if failed
+ else
+ if failed && cmd.options['error']
+ @logger.warn cmd.options['error']['message'] if cmd.options['error']['message']
+ if cmd.options['error']['response'] == "exit"
+ @logger.error "Command failure: #{stderr}"
+ raise "CommandExecutionException"
+ end
+ end
+ if cmd.options['outfile']
+ contents = stdout
+ if cmd.options['outfile']
+ contents = "#{cmd.options['outfile']['prepend']}\n#{stdout}" if cmd.options['outfile']['prepend']
+ contents = "#{stdout}/n#{cmd.options['outfile']['append']}" if cmd.options['outfile']['append']
+ generate_file(contents, cmd.options['outfile']['path'])
+ end
+ if cmd.options['stdout']
+ puts stdout
+ end
+ end
+ end
+end
+
+# ===
# Text manipulation Classes, Modules, procs, etc
# ===
module HashMash
@@ -1220,9 +1279,13 @@
@passed_vars.merge!pair
end
opts.on("--parse-config", "Preprocess the designated configuration file as a Liquid template. Superfluous when passing -v/--var arguments.") do
@parseconfig = true
+ end
+
+ opts.on("--unsafe", "Enable shell command executions without interactive check.") do
+ @safemode = false
end
opts.on("-h", "--help", "Returns help.") do
puts opts
exit