lib/cide/cli.rb in cide-0.2.0 vs lib/cide/cli.rb in cide-0.4.0
- old
+ new
@@ -3,10 +3,11 @@
require 'cide/build'
require 'thor'
require 'json'
+require 'securerandom'
require 'time'
module CIDE
# Command-line option-parsing and execution for cide
class CLI < Thor
@@ -33,13 +34,19 @@
aliases: %w(o host_export_dir),
default: nil
method_option 'run',
desc: 'Override the script to run',
+ type: :array,
aliases: ['r'],
- default: nil
+ default: []
+ method_option 'pull',
+ desc: 'Whenever to pull for new images on build',
+ type: :boolean,
+ default: true
+
method_option 'ssh_key',
desc: 'Path to a ssh key to import into the docker image',
aliases: ['s'],
default: '~/.ssh/id_rsa'
@@ -50,28 +57,33 @@
## Config ##
banner 'Config'
build = Build::Config.load_file CONFIG_FILE
exit 1 if build.nil?
- export_dir = options.export_dir || File.dirname(build.export_dir)
- build.run = options.run if options.run
+ export_dir = options.export_dir
+ export_dir ||= File.dirname(build.export_dir) if build.export_dir
+ ssh_key = File.expand_path(options.ssh_key)
+ build.run = options.run unless options.run.empty?
name = CIDE::Docker.id options.name
tag = "cide/#{name}"
say_status :config, build.inspect
## Build ##
banner 'Build'
if build.use_ssh
- unless File.exist?(options.ssh_key)
- fail ArgumentError, "SSH key #{options.ssh_key} not found"
+ unless File.exist?(ssh_key)
+ fail ArgumentError, "SSH key #{ssh_key} not found"
end
-
- create_tmp_file SSH_CONFIG_FILE, File.read(SSH_CONFIG_PATH)
- create_tmp_file TEMP_SSH_KEY, File.read(build.ssh_key)
+ create_tmp_file TEMP_SSH_KEY, File.read(ssh_key)
end
create_tmp_file DOCKERFILE, build.to_dockerfile
- docker :build, '--force-rm', '--pull', '-f', DOCKERFILE, '-t', tag, '.'
+ build_options = ['--force-rm']
+ build_options << '--pull' if options.pull
+ build_options.push '-f', DOCKERFILE
+ build_options.push '-t', tag
+ build_options << '.'
+ docker :build, *build_options
## CI ##
banner 'Run'
build.links.each do |link|
args = ['--detach']
@@ -84,44 +96,131 @@
containers << link.id
end
run_options = ['--detach']
- build.forward_env.each do |env|
- run_options.push '--env', [env, ENV[env]].join('=')
+ build.env.each_pair do |key, value|
+ run_options.push '--env', [key, value].join('=')
end
build.links.each do |link|
run_options.push '--link', [link.id, link.name].join(':')
end
+ id = SecureRandom.hex
+ run_options.push '--name', id
+
run_options.push tag
- run_options.push build.run
+ run_options.push(*build.run)
- id = docker(:run, *run_options, capture: true).strip
containers << id
+ docker(:run, *run_options, capture: true).strip
docker(:attach, id)
+ say_status :status, 'SUCCESS', :green
+
## Export ##
return unless options.export
banner 'Export'
fail 'export flag set but no export_dir given' if build.export_dir.nil?
guest_export_dir = File.expand_path(build.export_dir, CIDE_SRC_DIR)
host_export_dir = File.expand_path(export_dir, Dir.pwd)
docker :cp, [id, guest_export_dir].join(':'), host_export_dir
rescue Docker::Error => ex
+ say_status :status, 'ERROR', :red
exit ex.exitstatus
ensure
+ linked_containers = containers - [id]
+ unless linked_containers.empty?
+ infos = docker(
+ :inspect,
+ *linked_containers,
+ capture: true,
+ verbose: false,
+ )
+ JSON.parse(infos).each do |info|
+ config = info['Config']
+ state = info['State']
+
+ next unless state['Dead'] || state['ExitCode'] > 0
+
+ $stderr.puts "=== Failed linked container #{info['Id']} ==="
+ $stderr.puts "Image: #{config['Image']}"
+ $stderr.puts "State: #{state.inspect}"
+ docker(:logs, '--tail', 20, info['Id'])
+ end
+ end
# Shutdown old containers
unless containers.empty?
docker :rm, '--force', *containers.reverse,
verbose: false,
capture: true
end
end
+ desc 'debug', 'Opens a debug console in the last project image'
+ method_option 'name',
+ desc: 'Name of the build',
+ aliases: %w(n t),
+ default: File.basename(Dir.pwd)
+ method_option 'user',
+ desc: 'User to run under',
+ default: 'cide'
+ def debug
+ containers = []
+
+ setup_docker
+
+ ## Config ##
+ banner 'Config'
+ build = Build::Config.load_file CONFIG_FILE
+ exit 1 if build.nil?
+ name = CIDE::Docker.id options.name
+ tag = "cide/#{name}"
+ say_status :config, build.inspect
+
+ ## CI ##
+ banner 'Run'
+ build.links.each do |link|
+ args = ['--detach']
+ link.env.each_pair do |key, value|
+ args.push('--env', [key, value].join('='))
+ end
+ args << link.image
+ args << link.run if link.run
+ link.id = docker(:run, *args, capture: true).strip
+ containers << link.id
+ end
+
+ run_options = ['--rm', '-t', '-i']
+
+ run_options.push '--user', options.user
+
+ build.env.each_pair do |key, value|
+ run_options.push '--env', [key, value].join('=')
+ end
+
+ build.links.each do |link|
+ run_options.push '--link', [link.id, link.name].join(':')
+ end
+
+ run_options.push tag
+ run_options.push 'bash'
+
+ docker(:run, *run_options)
+ rescue Docker::Error => ex
+ exit ex.exitstatus
+ ensure
+ # Shutdown old containers
+ unless containers.empty?
+ docker :rm, '--force', *containers.reverse,
+ verbose: false,
+ capture: true
+ end
+ end
+
desc 'clean', 'Removes old containers'
method_option 'days',
desc: 'Number of days to keep the images',
default: 7,
type: :numeric
@@ -166,11 +265,11 @@
if old_cide_images.empty?
puts 'No images found to be cleaned'
return
end
- docker('rmi', *old_cide_images)
+ docker('rmi', '--force', *old_cide_images)
end
desc 'init', "Creates a blank #{CONFIG_FILE} into the project"
def init
puts "Creating #{CONFIG_FILE} with default values"
@@ -179,9 +278,11 @@
private
def create_tmp_file(destination, *args, &block)
create_file(destination, *args, &block)
+ # Dockerfile ADD compares content and mtime, we don't want that
+ File.utime(1_286_701_800, 1_286_701_800, destination)
at_exit do
remove_file(destination, verbose: false)
end
end