require 'dandelion' require 'dandelion/backend' require 'dandelion/deployment' require 'dandelion/git' require 'dandelion/version' require 'optparse' require 'yaml' module Dandelion module Command class InvalidCommandError < StandardError; end class Base class << self @@commands = {} def command(name) @@commands[name] = self end def create(name) require_commands raise InvalidCommandError unless @@commands.include?(name) @@commands[name] end def commands @@commands.keys end def require_commands Dir.glob(File.join(File.dirname(__FILE__), 'command', '*.rb')) { |file| require file } end def parser(options) OptionParser.new do |opts| opts.banner = 'Usage: dandelion [options] []' opts.on('-v', '--version', 'Display the current version') do puts "Dandelion #{Dandelion::VERSION}" exit end opts.on('-h', '--help', 'Display this screen') do require_commands puts opts puts "\nAvailable commands:" puts commands.map { |name| " #{name}" }.join("\n") exit end opts.on('--log=[level]', 'Use the given log level (fatal, error, warn, info, debug)') do |level| levels = { :fatal => Logger::FATAL, :error => Logger::ERROR, :warn => Logger::WARN, :info => Logger::INFO, :debug => Logger::DEBUG } Dandelion.logger.level = levels[level.to_sym] end options[:repo] = closest_repo(File.expand_path('.')) opts.on('--repo=[REPO]', 'Use the given repository') do |repo| options[:repo] = File.expand_path(repo) end options[:config] = nil opts.on('--config=[CONFIG]', 'Use the given configuration file') do |config| options[:config] = File.expand_path(config) end end end private def closest_repo(dir) if File.exists?(File.join(dir, '.git')) dir else File.dirname(dir) != dir && closest_repo(File.dirname(dir)) || File.expand_path('.') end end end def initialize(options) @options = options @config = YAML.load_file(@options[:config]) @repo = Git::Repo.new(@options[:repo]) yield(self) if block_given? end protected def log Dandelion.logger end def backend begin backend = Backend::Base.create(@config) log.info("Connecting to #{backend}") backend rescue Backend::MissingDependencyError => e log.fatal("The '#{@config['scheme']}' scheme requires additional gems:") log.fatal(e.gems.map { |name| " #{name}" }.join("\n")) log.fatal("Please install the gems: gem install #{e.gems.join(' ')}") exit 1 rescue Backend::UnsupportedSchemeError log.fatal("Unsupported scheme: #{@config['scheme']}") exit 1 end end def deployment(revision, backend = nil) begin backend ||= backend() revision_file = @config['revision_file'].nil? ? '.revision' : @config['revision_file'] local_path = @config['local_path'].nil? ? '' : @config['local_path'] options = { :dry => @options[:dry], :exclude => @config['exclude'], :additional => @config['additional'], :revision => revision, :revision_file => revision_file, :local_path => local_path } Deployment::Deployment.create(@repo, backend, options) rescue Git::DiffError log.fatal('Error: could not generate diff') log.fatal('Try merging remote changes before running dandelion again') exit 1 end end end end end