lib/cide.rb in cide-0.1.1 vs lib/cide.rb in cide-0.2.0

- old
+ new

@@ -1,229 +1,7 @@ -require 'erb' -require 'json' -require 'optparse' -require 'time' -require 'yaml' - -require 'thor' - -require 'cide/docker' - # CIDE is a Continuous Integration Docker Environment runner # # The juicy bits are defined in CIDE::CLI module CIDE - DIR = File.expand_path('..', __FILE__) - DOCKERFILE = 'Dockerfile' - TEMP_SSH_KEY = 'id_rsa.tmp' - DOCKERFILE_TEMPLATE = File.join(DIR, 'cide_template.erb') - SSH_CONFIG_FILE = 'ssh_config' - SSH_CONFIG_PATH = File.join(DIR, SSH_CONFIG_FILE) - CONFIG_FILE = '.cide.yml' - - CIDE_DIR = '/cide' - CIDE_SRC_DIR = File.join(CIDE_DIR, '/src') - CIDE_SSH_DIR = File.join(CIDE_DIR, '/.ssh') - - def self.struct(opts = {}, &block) - Class.new(Struct.new(*opts.keys), &block).new(*opts.values) - end - - DefaultConfig = struct( - name: nil, - from: 'ubuntu', - as_root: [], - forward_env: [], - before: {}, - export: false, - export_dir: './artifacts', - host_export_dir: nil, - run: 'script/ci', - use_ssh: false, - ssh_key: '~/.ssh/id_rsa', - ) do - - alias_method :image=, :from= - alias_method :command=, :run= - - def name=(str) - super CIDE::Docker.id(str) - end - - def ssh_key_path - File.expand_path(ssh_key) - end - - def to_dockerfile - ERB.new(File.read(DOCKERFILE_TEMPLATE), nil, '<>-').result(binding) - end - - def merge!(opts = {}) - opts.each_pair { |k, v| public_send("#{k}=", v) } - self - end - - def merge(opts = {}) - dup.merge!(opts) - end - - def to_yaml - members.each_with_object({}) do |k, obj| - v = self[k] - obj[k.to_s] = v unless v.nil? - end.to_yaml - end - end - - # Command-line option-parsing and execution for cide - class CLI < Thor - include CIDE::Docker - include Thor::Actions - add_runtime_options! - - default_command 'build' - - desc 'build', 'Builds an image and executes the run script' - - method_option 'name', - desc: 'Name of the build', - aliases: %w(n t), - default: nil - - method_option 'host_export_dir', - desc: 'Output directory on host to put build artefacts in', - aliases: ['o'], - default: nil - - method_option 'export', - desc: 'Are we expecting to export artifacts', - type: :boolean, - default: nil - - method_option 'run', - desc: 'The script to run', - aliases: ['r'], - default: nil - - method_option 'ssh_key', - desc: 'Path to a ssh key to import into the docker image', - aliases: ['s'], - default: '~/.ssh/id_rsa' - - def build - setup_docker - - config = DefaultConfig.merge YAML.load_file(CONFIG_FILE) - options.each_pair do |k, v| - config[k] = v unless v.nil? - end - config.name ||= File.basename(Dir.pwd) - config.host_export_dir ||= config.export_dir - - tag = "cide/#{config.name}" - - if config.use_ssh - unless File.exist?(config.ssh_key_path) - fail MalformattedArgumentError, "SSH key #{config.ssh_key} not found" - end - - create_tmp_file SSH_CONFIG_FILE, File.read(SSH_CONFIG_PATH) - create_tmp_file TEMP_SSH_KEY, File.read(config.ssh_key_path) - end - - say_status :config, config.to_h - - create_tmp_file DOCKERFILE, config.to_dockerfile - - docker :build, '--force-rm', '-t', tag, '.' - - return unless config.export - - unless config.export_dir - fail 'Fail: export flag set but no export dir given' - end - - id = docker(:run, '-d', tag, true, capture: true).strip - begin - guest_export_dir = File.expand_path(config.export_dir, CIDE_SRC_DIR) - - host_export_dir = File.expand_path( - config.host_export_dir || config.export_dir, - Dir.pwd, - ) - - docker :cp, [id, guest_export_dir].join(':'), host_export_dir - - ensure - docker :rm, '-f', id - end - rescue Docker::Error => ex - exit ex.exitstatus - end - - desc 'clean', 'Removes old containers' - method_option 'days', - desc: 'Number of days to keep the images', - default: 7, - type: :numeric - method_option 'count', - desc: 'Maximum number of images to keep', - default: 10, - type: :numeric - def clean - setup_docker - - days_to_keep = options[:days] - max_images = options[:count] - - x = docker('images', '--no-trunc', capture: true) - iter = x.lines.each - iter.next - cide_image_ids = iter - .map { |line| line.split(/\s+/) } - .select { |line| line[0] =~ /^cide\// || line[0] == '<none>' } - .map { |line| line[2] } - - if cide_image_ids.empty? - puts 'No images found to be cleaned' - return - end - - x = docker('inspect', *cide_image_ids, capture: true) - cide_images = JSON.parse(x.strip) - .each { |image| image['Created'] = Time.iso8601(image['Created']) } - .sort { |a, b| a['Created'] <=> b['Created'] } - - if cide_images.size > max_images - old_cide_images = cide_images[0..-max_images] - .map { |image| image['Id'] } - else - old_times = Time.now - (days_to_keep * 24 * 60 * 60) - old_cide_images = cide_images - .select { |image| image['Created'] < old_times } - .map { |image| image['Id'] } - end - - if old_cide_images.empty? - puts 'No images found to be cleaned' - return - end - - docker('rmi', *old_cide_images) - end - - desc 'init', "Creates a blank #{CONFIG_FILE} into the project" - def init - puts "Creating #{CONFIG_FILE} with default values" - create_file CONFIG_FILE, DefaultConfig.to_yaml - end - - private - - def create_tmp_file(destination, *args, &block) - create_file(destination, *args, &block) - at_exit do - remove_file(destination, verbose: false) - end - end - end end + +require 'cide/cli'