#!/usr/bin/env ruby RAILS_ENV = 'builder' CCRB_THIS_PROCESS_IS_BUILDER = true require File.dirname(__FILE__) + '/../config/boot' require 'optparse' CRUISE_OPTIONS = { :verbose => false } ARGV.options do |opts| opts.banner = "Usage: cruise builder []options]" opts.separator "" opts.on("-t", "--trace", "Trace-level (verbose) logging") { CRUISE_OPTIONS[:verbose] = true } opts.on("-h", "--help", "Show this help message.") { puts opts; exit } args = opts.parse! unless args.length == 1 STDERR.puts "Project name not specified" STDERR.puts puts opts exit(-1) end CRUISE_OPTIONS[:project_name] = args[0] CRUISE_OPTIONS[:log_file_name] = "log/#{CRUISE_OPTIONS[:project_name]}_builder.log" end require RAILS_ROOT + "/config/environment" require 'site_config' if File.exists?("#{RAILS_ROOT}/config/site_config.rb") CruiseControl::Log.verbose = CRUISE_OPTIONS[:verbose] project_path = File.expand_path(File.join(Configuration.projects_directory, CRUISE_OPTIONS[:project_name])) unless File.directory? project_path STDERR.puts "Project '#{CRUISE_OPTIONS[:project_name]}' not found in '#{Configuration.projects_directory}'" exit(-1) end def write_to_log_and_console(message, severity = :info) CruiseControl::Log.event(message, severity) rescue nil (puts message unless CRUISE_OPTIONS[:verbose]) rescue nil end def cleanup(project) write_to_log_and_console "Builder for project '#{CRUISE_OPTIONS[:project_name]}' exited" if project ProjectBlocker.release(project) rescue nil end end def load_project(path) begin Project.read(path) rescue Exception => e write_to_log_and_console("Failed to load the new project configuration. The builder will stop.", :fatal) raise end end project = nil begin begin project = load_project(project_path) # this will create builder.pid file in project's CC directory and grab an exclusive lock on it, or else # blow up saying that something else is already locking it ProjectBlocker.block(project) write_to_log_and_console "Builder for project '#{project.name}' started" puts "Logging to: #{File.expand_path(CRUISE_OPTIONS[:log_file_name])}" while (true) do catch(:reload_project) do project.scheduler.run end project = load_project(project_path) # this will cause the next call to scheduler to run the build immediately project.request_build rescue nil end rescue Interrupt # this is okay, we're just control-c'ing the app rescue Exception => e begin CruiseControl::Log.fatal(e) rescue => logging_error STDERR.puts e.message STDERR.puts e.backtrace STDERR.puts "Attempt to log the above error failed with this:" STDERR.puts logging_error.message STDERR.puts logging_error.backtrace end CRUISE_OPTIONS[:verbose] ? raise : exit(1) ensure cleanup(project) end end