lib/kameleon/cli.rb in kameleon-builder-2.1.3 vs lib/kameleon/cli.rb in kameleon-builder-2.2.0

- old
+ new

@@ -2,93 +2,106 @@ require 'kameleon/recipe' require 'kameleon/utils' module Kameleon class CLI < Thor + include Thor::Actions - class_option :color, :type => :boolean, :default => true, :desc => "Enable colorization in output" class_option :debug, :type => :boolean, :default => false, :desc => "Enable debug output" + class_option :script, :type => :boolean, :default => false, + :desc => "never prompts for user intervention", + :aliases => "-s" map %w(-h --help) => :help - no_commands do - def logger - @logger ||= Log4r::Logger.new("kameleon::[kameleon]") - end - end - - method_option :force,:type => :boolean, - :default => false, :aliases => "-f", - :desc => "Overwrite all existing files" desc "import [TEMPLATE_NAME]", "Imports the given template" def import(template_name) templates_path = Kameleon.env.templates_path template_path = File.join(templates_path, template_name) + '.yaml' begin - template_recipe = RecipeTemplate.new(template_path, :strict => false) + tpl = RecipeTemplate.new(template_path) rescue raise TemplateNotFound, "Template '#{template_name}' not found. " \ "To see all templates, run the command "\ "`kameleon templates`" else - logger.notice("Importing template '#{template_name}'...") - template_recipe.copy_template(options[:force]) - logger.notice("done") + files2copy = tpl.base_recipes_files + tpl.files + files2copy.each do |path| + relative_path = path.relative_path_from(Kameleon.env.templates_path) + dst = File.join(Kameleon.env.workspace, relative_path) + copy_file(path, dst) + end end end - method_option :force,:type => :boolean, - :default => false, :aliases => "-f", - :desc => "Overwrite all existing files" desc "new [RECIPE_NAME] [TEMPLATE_NAME]", "Creates a new recipe" def new(recipe_name, template_name) if recipe_name == template_name fail RecipeError, "Recipe name should be different from template name" end templates_path = Kameleon.env.templates_path template_path = File.join(templates_path, template_name) + '.yaml' begin - template_recipe = RecipeTemplate.new(template_path, :strict => false) + tpl = RecipeTemplate.new(template_path) rescue raise TemplateNotFound, "Template '#{template_name}' not found. " \ "To see all templates, run the command "\ "`kameleon templates`" else - logger.notice("Cloning template '#{template_name}'...") - template_recipe.copy_template(options[:force]) - logger.notice("Creating extended recipe from template '#{template_name}'...") - template_recipe.copy_extended_recipe(recipe_name, options[:force]) - logger.notice("done") + files2copy = tpl.base_recipes_files + tpl.files + files2copy.each do |path| + relative_path = path.relative_path_from(Kameleon.env.templates_path) + dst = File.join(Kameleon.env.workspace, relative_path) + copy_file(path, dst) + end + Dir::mktmpdir do |tmp_dir| + recipe_path = File.join(tmp_dir, recipe_name + '.yaml') + ## copying recipe + File.open(recipe_path, 'w+') do |file| + extend_erb_tpl = File.join(Kameleon.env.templates_path, "extend.erb") + erb = ERB.new(File.open(extend_erb_tpl, 'rb') { |f| f.read }) + result = erb.result(binding) + file.write(result) + end + recipe_dst = File.join(Kameleon.env.workspace, recipe_name + '.yaml') + copy_file(recipe_path, Pathname.new(recipe_dst)) + end end end desc "templates", "Lists all defined templates" def templates - Log4r::Outputter['console'].level = Log4r::ERROR unless Kameleon.env.debug puts "The following templates are available in " \ "#{ Kameleon.templates_path }:" templates_hash = [] - Kameleon.templates_files.each do |f| + templates_path = File.join(Kameleon.env.templates_path, "/") + all_yaml_files = Dir["#{templates_path}**/*.yaml"] + steps_files = Dir["#{templates_path}steps/**/*.yaml"] + templates_files = all_yaml_files - steps_files + templates_files.each do |f| begin - recipe = RecipeTemplate.new(f, :strict => false) + recipe = RecipeTemplate.new(f) templates_hash.push({ - "name" => recipe.name, + "name" => f.gsub(templates_path, "").chomp(".yaml"), "description" => recipe.metainfo['description'], }) rescue => e raise e if Kameleon.env.debug end end templates_hash = templates_hash.sort_by{ |k| k["name"] } - tp templates_hash, {"name" => {:width => 30}}, { "description" => {:width => 60}} + name_width = templates_hash.map { |k| k['name'].size }.max + desc_width = Kameleon.ui.shell.terminal_width - name_width - 3 + tp(templates_hash, + {"name" => {:width => name_width}}, + { "description" => {:width => desc_width}}) end desc "version", "Prints the Kameleon's version information" def version - Log4r::Outputter['console'].level = Log4r::OFF unless Kameleon.env.debug puts "Kameleon version #{Kameleon::VERSION}" end map %w(-v --version) => :version desc "build [RECIPE_PATH]", "Builds the appliance from the given recipe" @@ -101,130 +114,104 @@ method_option :from_checkpoint, :type => :string , :default => nil, :desc => "Using specific checkpoint to build the image. " \ "Default value is the last checkpoint." method_option :checkpoint, :type => :boolean , - :default => true, - :desc => "Do not use checkpoints" + :default => false, + :desc => "Enable checkpoint" method_option :cache, :type => :boolean, :default => false, :desc => "Generate a persistent cache for the appliance." + method_option :cache_path, :type => :string , + :default => nil, + :desc => "Set the cache directory path" method_option :from_cache, :type => :string , :default => nil, :desc => "Using a persistent cache tar file to build the image." method_option :proxy_path, :type => :string , :default => nil, :desc => "Full path of the proxy binary to use for the persistent cache." - def build(recipe_path) + def build(recipe_path=nil) + if recipe_path.nil? && !options[:from_cache].nil? + Kameleon.ui.info("Using the cached recipe") + @cache = Kameleon::Persistent_cache.instance + @cache.cache_path = options[:from_cache] + recipe_path = @cache.get_recipe + end + raise BuildError, "A recipe file or a persistent cache archive " \ + "is required to run this command." if recipe_path.nil? clean(recipe_path) if options[:clean] engine = Kameleon::Engine.new(Recipe.new(recipe_path), options) - logger.notice("Starting build recipe '#{recipe_path}'") + Kameleon.ui.info("Starting build recipe '#{recipe_path}'") start_time = Time.now.to_i engine.build total_time = Time.now.to_i - start_time - logger.notice("") - logger.notice("Build recipe '#{recipe_path}' is completed !") - logger.notice("Build total duration : #{total_time} secs") - logger.notice("Build directory : #{engine.cwd}") - logger.notice("Build recipe file : #{engine.build_recipe_path}") - logger.notice("Log file : #{Kameleon.env.log_file}") + Kameleon.ui.info("") + Kameleon.ui.info("Successfully built '#{recipe_path}'") + Kameleon.ui.info("Total duration : #{total_time} secs") end desc "checkpoints [RECIPE_PATH]", "Lists all availables checkpoints" method_option :build_path, :type => :string , :default => nil, :aliases => "-b", :desc => "Set the build directory path" def checkpoints(recipe_path) - Log4r::Outputter['console'].level = Log4r::ERROR unless Kameleon.env.debug + Kameleon.ui.level = "error" engine = Kameleon::Engine.new(Recipe.new(recipe_path), options) engine.pretty_checkpoints_list end - desc "clean [RECIPE_PATH]", "Cleaning 'out' and 'local' contexts and removing all checkpoints" + desc "clean [RECIPE_PATH]", "Cleaning all contexts and removing the checkpoints" method_option :build_path, :type => :string , :default => nil, :aliases => "-b", :desc => "Set the build directory path" def clean(recipe_path) - Log4r::Outputter['console'].level = Log4r::INFO - engine = Kameleon::Engine.new(Recipe.new(recipe_path), options) - engine.clear + opts = Hash.new.merge options + opts[:lazyload] = false + opts[:fail_silently] = true + engine = Kameleon::Engine.new(Recipe.new(recipe_path), opts) + engine.clean(:with_checkpoint => true) end map %w(clear) => :clean desc "commands", "Lists all available commands", :hide => true def commands - puts CLI.all_commands.keys - ["commands", "completions"] + Kameleon.ui.info CLI.all_commands.keys - ["commands", "completions"] end desc "source_root", "Prints the kameleon directory path", :hide => true def source_root puts Kameleon.source_root end - # Hack Thor to init Kameleon env soon - def self.init(base_config) - env_options = Hash.new - env_options.merge! base_config[:shell].base.options.clone - # configure logger - env_options["debug"] = true if ENV["KAMELEON_LOG"] == "debug" - ENV["KAMELEON_LOG"] = "debug" if env_options["debug"] - if ENV["KAMELEON_LOG"] && ENV["KAMELEON_LOG"] != "" - level_name = ENV["KAMELEON_LOG"] - else - level_name = "info" + def initialize(*args) + super + self.options ||= {} + Kameleon.env = Kameleon::Environment.new(self.options) + if !$stdout.tty? or !options["color"] + Thor::Base.shell = Thor::Shell::Basic end - # Require Log4r and define the levels we'll be using - require 'log4r-color/config' - Log4r.define_levels(*Log4r::Log4rConfig::LogLevels) - - begin - level = Log4r.const_get(level_name.upcase) - rescue NameError - level = Log4r.const_get("INFO") - $stderr << "Invalid KAMELEON_LOG level is set: #{level_name}.\n" \ - "Please use one of the standard log levels: debug," \ - " info, warn, or error\n" - raise KameleonError + Kameleon.ui = Kameleon::UI::Shell.new(self.options) + Kameleon.ui.level = "debug" if self.options["debug"] + opts = args[1] + cmd_name = args[2][:current_command].name + if opts.include? "--help" + CLI.command_help(Kameleon.ui.shell, cmd_name) + raise Kameleon::Exit end - format = ConsoleFormatter.new - # format = Log4r::PatternFormatter.new(:pattern => '%11c: %M') - if !$stdout.tty? or !env_options["color"] - console_output = Log4r::StdoutOutputter.new('console', - :formatter => format) - Diffy::Diff.default_format = :text - else - console_output = Log4r::ColorOutputter.new 'console', { - :colors => { :debug => :light_black, - :info => :green, - :progress_info => :green, - :notice => :light_blue, - :progress_notice => :light_blue, - :warn => :yellow, - :error => :red, - :progress_error => :red, - :fatal => :red, - }, - :formatter => format, - } - Diffy::Diff.default_format = :color - end - logger = Log4r::Logger.new('kameleon') - logger.level = level - logger.outputters << console_output - format_file = FileFormatter.new - Kameleon.logger.debug("`kameleon` invoked: #{ARGV.inspect}") - Kameleon.env = Kameleon::Environment.new(env_options) - filelog = Log4r::FileOutputter.new('logfile', - :trunc=>false, - :filename => Kameleon.env.log_file.to_s, - :formatter => format_file) - logger.outputters << filelog - logger = nil end - def self.start(given_args=ARGV, config={}) - config[:shell] ||= Thor::Base.shell.new - dispatch(nil, given_args.dup, nil, config) { init(config) } + def self.start(*) + super + rescue Exception => e + Kameleon.ui = Kameleon::UI::Shell.new + raise e end + + def self.source_root + Kameleon.source_root + end + end + end