class Crew::Home

Constants

CREW_CONF_FILE

Attributes

callbacks[R]
context[R]
data_path[R]
default_context_name[RW]
default_test_name[RW]
home_path[R]
in_setup[R]
logger[R]
setup_mode[RW]
task_path[R]

Public Class Methods

init(*args) click to toggle source
# File lib/crew/home.rb, line 14
def self.init(*args)
  opts = args.last.is_a?(Hash) ? args.pop : {}
  path = args.size == 1 ? args.shift : Dir.pwd
  path = File.join(path, ".crew")
  crew_config_path = File.join(path, CREW_CONF_FILE)
  raise "#{crew_config_path} file is in the way" if File.exist?(crew_config_path) && !opts[:force]
  FileUtils.mkdir_p(path)
  template = File.read(File.expand_path("../template/config.erb", __FILE__))
  out = ERB.new(template).result
  puts "Writing #{CREW_CONF_FILE} file"
  File.open(crew_config_path, "w") do |f|
    f << out
  end
  new(path)
end
new(path) click to toggle source
# File lib/crew/home.rb, line 33
def initialize(path)
  @home_path = File.expand_path(path)
  @task_path = File.join(@home_path, "tasks")
  @data_path = File.join(@home_path, "data")
  @config_path = File.join(@home_path, "config")
  @contexts_path = File.join(@home_path, "contexts")
  @sources = [File.expand_path("../../../.crew/tasks", __FILE__)]
  @callbacks = {before: [], after: []}
  @contexts = {}
  @testers = {}
  @logger = Logger.new
  load!
end

Public Instance Methods

add_callback(type, &cb) click to toggle source
# File lib/crew/home.rb, line 238
def add_callback(type, &cb)
  @callbacks[type] << cb
end
add_context(name, file = nil, &blk) click to toggle source
# File lib/crew/home.rb, line 249
def add_context(name, file = nil, &blk)
  @contexts[name] = Context.new(self, name, file, &blk)
end
add_tester(context_name, &blk) click to toggle source
# File lib/crew/home.rb, line 157
def add_tester(context_name, &blk)
  @testers[context_name] = Tester.new(self, context_name, &blk)
end
context_new(name) click to toggle source
# File lib/crew/home.rb, line 64
def context_new(name)
  load_contexts!
  if @contexts[name]
    raise "Cannot create #{name}, context already in the way"
  else
    template = File.read(File.expand_path("../template/context.rb.erb", __FILE__))
    path = "#{name}.rb"
    out = ERB.new(template).result
    puts "Writing #{path} file"
    out_path = File.join(@contexts_path, path)
    FileUtils.mkdir_p(File.dirname(out_path))
    File.open(out_path, "w") do |f|
      f << out
    end
  end
end
contexts() { |name, context| ... } click to toggle source
# File lib/crew/home.rb, line 81
def contexts
  @contexts.each do |name, context|
    yield name, context
  end
end
docs() click to toggle source
# File lib/crew/home.rb, line 123
def docs
  path = Docs.new(self).generate
  puts "Docs generated at #{path}"
  path
end
each_task() { |task| ... } click to toggle source
# File lib/crew/home.rb, line 267
def each_task
  Dir[File.join(@task_path, "**/*.crew")].each do |file|
    name = path_to_name(@task_path, file)
    yield Task.new(self, name, file)
  end
end
each_task_for_source(source) { |task| ... } click to toggle source
# File lib/crew/home.rb, line 274
def each_task_for_source(source)
  Dir[File.join(source, "**/*.crew")].each do |file|
    name = path_to_name(source, file)
    yield Task.new(self, name, file)
  end
end
find_and_add_task(name) click to toggle source
# File lib/crew/home.rb, line 257
def find_and_add_task(name)
  if parts = find_task(name)
    add_task(*parts)
    task_path = File.join(*parts)
    Task.new(self, name, task_path)
  else
    raise "no such task `#{name}'"
  end
end
find_task(name) click to toggle source
# File lib/crew/home.rb, line 253
def find_task(name)
  find_task_in_paths(name, [@task_path] + @sources)
end
in_context(context_or_name, opts = {}) { || ... } click to toggle source
# File lib/crew/home.rb, line 287
def in_context(context_or_name, opts = {})
  previous_context = @context
  @context = case context_or_name
  when Context
    context_or_name
  when Module
    Context.new(self, context_or_name.to_s) do
      adapter(context_or_name, opts)
    end
  when String
    context_name = context_or_name
    @contexts.key?(context_name) ?
      @contexts[context_name] : raise(UnknownContextError.new(context_name))
  end
  begin
    raise UnknownContextError.new(context_or_name) if @context.nil?
    yield
  ensure
    @context = previous_context
  end
end
perform_setup() { || ... } click to toggle source
# File lib/crew/home.rb, line 87
def perform_setup
  @in_setup = true
  yield
ensure
  @in_setup = false
end
run(context_name, name, *args) click to toggle source
# File lib/crew/home.rb, line 242
def run(context_name, name, *args)
  context_name ||= @default_context_name
  in_context(context_name) do
    @context.task(name).run!(*args)
  end
end
run_in_context(context_or_name, label, opts = {}, &blk) click to toggle source
# File lib/crew/home.rb, line 281
def run_in_context(context_or_name, label, opts = {}, &blk)
  in_context(context_or_name, opts) do
    @context.run(label, &blk)
  end
end
shell(context_name) click to toggle source
# File lib/crew/home.rb, line 114
def shell(context_name)
  context_name ||= @default_context_name
  in_context(context_name) do
    @context.run "shell" do
      pry
    end
  end
end
task_available() { |task, include?(name)| ... } click to toggle source
# File lib/crew/home.rb, line 100
def task_available
  names = Set.new
  list do |task|
    names << task.name
  end

  @sources.each do |source|
    each_task_for_source(source) do |task|
      task.from_source = source
      yield task, names.include?(task.name)
    end
  end
end
task_diff() click to toggle source
# File lib/crew/home.rb, line 173
def task_diff
  only_local = []
  different = []
  each_task do |task|
    source_path = find_task_in_paths(task.name, @sources)
    if source_path.nil?
      only_local << task.path
    elsif File.read(File.join(*source_path)) != File.read(task.path)
      different << [task.path, File.join(*source_path)]
    end
  end
  puts "Diff -- #{only_local.size} tasks only present locally, #{different.size} tasks different"
  unless only_local.empty?
    only_local.each do |dest|
      puts "Only present #{dest}"
    end
  end
  unless different.empty?
    different.each do |(dest, src)|
      puts "Comparing #{dest} with #{src}"
      puts `diff #{dest} #{src}`
    end
  end
end
task_edit(name) click to toggle source
# File lib/crew/home.rb, line 129
def task_edit(name)
  raise "$EDITOR not defined" unless ENV.key?('EDITOR')
  if source_path = find_task_in_paths(name, @task_path)
    puts "Editing #{source_path[1]} into #{source_path[0]}"
    exec "#{ENV['EDITOR']} #{File.join(source_path)}"
  else
    raise "unable to find task #{name} to install"
  end
end
task_info(name) click to toggle source
# File lib/crew/home.rb, line 139
def task_info(name)
  if source_path = find_task_in_paths(name, @task_path)
    puts "Task installed, located at #{File.join(*source_path)}"
  else
    puts "Task #{name} is not installed"
    puts
    @sources.each do |source|
      path = name_to_path(name)
      task_name = File.join(source, path)
      if File.exist?(task_name)
        puts "Task available in #{@source} at #{task_name}"
      else
        puts "Not found in #{@source}"
      end
    end
  end
end
task_install(name) click to toggle source
# File lib/crew/home.rb, line 206
def task_install(name)
  if source_path = find_task_in_paths(name, @sources)
    puts "Installing #{source_path[1]} into #{source_path[0]}"
    if add_task(source_path[0], source_path[1])
      puts "Task installed!"
    else
      puts "Nothing done, aready installed"
    end
  else
    raise "unable to find task #{name} to install"
  end
end
task_install_all() click to toggle source
# File lib/crew/home.rb, line 219
def task_install_all
  @sources.each do |source|
    each_task_for_source(source) do |task|
      task.from_source = source
      install task.name
    end
  end
end
task_list() { |task| ... } click to toggle source
# File lib/crew/home.rb, line 94
def task_list
  each_task_for_source(@task_path) do |task|
    yield task
  end
end
task_new(name) click to toggle source
# File lib/crew/home.rb, line 47
def task_new(name)
  dest, path = find_task_in_paths(name, @task_path)
  if path
    raise "Cannot create #{name}, task already in the way"
  else
    path = name_to_path(name)
    template = File.read(File.expand_path("../template/task.crew.erb", __FILE__))
    out = ERB.new(template).result
    puts "Writing #{path} file"
    out_path = File.join(@task_path, path)
    FileUtils.mkdir_p(File.dirname(out_path))
    File.open(out_path, "w") do |f|
      f << out
    end
  end
end
task_remove(name) click to toggle source
# File lib/crew/home.rb, line 228
def task_remove(name)
  if path = File.join(@task_path, name_to_path(name))
    if File.exist?(path)
      File.unlink(path)
    end
  else
    raise "unable to find task #{name} to install"
  end
end
task_update(name = nil) click to toggle source
# File lib/crew/home.rb, line 198
def task_update(name = nil)
  if name
    update_task(name)
  else
    update_all
  end
end
test(opts = {}) click to toggle source
# File lib/crew/home.rb, line 161
def test(opts = {})
  clean_tests
  @testers.each do |name, tester|
    puts "Running test suite #{name}..."
    tester.run(opts)
  end
end
test_path() click to toggle source
# File lib/crew/home.rb, line 169
def test_path
  File.join(data_path)
end

Private Instance Methods

add_task(source, path, force = false) click to toggle source
# File lib/crew/home.rb, line 350
def add_task(source, path, force = false)
  added = false
  source_path = File.join(source, path)
  target_path = File.join(@task_path, path)
  unless File.exist?(target_path) || force
    puts "Copying #{source_path} to #{target_path}"
    FileUtils.mkdir_p File.dirname(target_path)
    FileUtils.cp(source_path, target_path)
    added = true
  end
  raise unless File.exist?(target_path)
  added
end
clean_tests(opts = {}) click to toggle source
# File lib/crew/home.rb, line 310
def clean_tests(opts = {})
  digests = Set.new
  each_task do |task|
    digests << task.digest
  end
  Dir[File.join(data_path, "*", "*", "*", "*")].each do |path|
    target_hash = path[/#{Regexp.quote(test_path)}\/(.*)/, 1].gsub('/', '')
    unless digests.include?(target_hash)
      puts "Deleting #{path}..."
      FileUtils.rm_r(path)
    end
  end
end
crew_config_path() click to toggle source
# File lib/crew/home.rb, line 364
def crew_config_path
  File.join(@home, "config.rb")
end
find_task_in_paths(name, paths) click to toggle source
# File lib/crew/home.rb, line 342
def find_task_in_paths(name, paths)
  path = name_to_path(name)
  target_source = Array(paths).find do |source|
    File.exist?(File.join(source, path))
  end
  target_source && [target_source, path]
end
load!() click to toggle source
# File lib/crew/home.rb, line 378
def load!
  DSL.new(self).load(@config_path)
  load_contexts!
end
load_contexts!() click to toggle source
# File lib/crew/home.rb, line 383
def load_contexts!
  Dir[File.join(@contexts_path, "*.rb")].each do |context_file|
    name = File.basename(context_file)[/(.*)\.rb$/, 1]
    add_context(name, context_file)
  end
end
name_to_path(name) click to toggle source
# File lib/crew/home.rb, line 373
def name_to_path(name)
  path = File.join(*name.to_s.split("_")) + ".crew"
  path.gsub(/\?\.crew$/, '_.crew')
end
path_to_name(source, path) click to toggle source
# File lib/crew/home.rb, line 368
def path_to_name(source, path)
  local_path = path[/^#{Regexp.quote(source + "/")}(.*)/, 1]
  local_path.gsub(/\.crew$/, '').gsub(/_$/, '?').gsub('/', "_")
end
update_all() click to toggle source
# File lib/crew/home.rb, line 324
def update_all
  each_task do |task|
    update_task(task.name)
  end
end
update_task(name) click to toggle source
# File lib/crew/home.rb, line 330
def update_task(name)
  dest, path = find_task_in_paths(name, @task_path)
  raise "Unable to update task #{name}, not found" if dest.nil?

  if source = find_task_in_paths(name, @sources)
    source_path = File.join(*source)
    return if File.read(source_path) == File.read(File.join(dest, path))
    puts "Updating #{path} from #{source_path}"
    FileUtils.cp source_path, File.join(dest, path)
  end
end