Class: DamageControl::Build

Inherits:
Object
  • Object
show all
Defined in:
lib/damagecontrol/build.rb,
app/controllers/rscm_ext.rb,
lib/damagecontrol/publisher/execute.rb

Overview

Represents build-related data organised in the following file structure:

File structure:

.damagecontrol/
SomeProject/
  project.yaml
  checkout/
  changesets/
    2802/
      changeset.yaml         (serialised ChangeSet object)
      diffs/                 (serialised diff files)
      builds/                
        2005280271234500/    (timestamp of build start)
          stdout.log
          stderr.log
          artifacts/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_name, changeset_identifier, time, build_reason) ⇒ Build

Creates a new Build for a +project+'s changeset, created at time.



34
35
36
# File 'lib/damagecontrol/build.rb', line 34

def initialize(project_name, changeset_identifier, time, build_reason)
  @project_name, @changeset_identifier, @time, @build_reason = project_name, changeset_identifier, time, build_reason
end

Instance Attribute Details

#time ⇒ Object (readonly)

TODO: we want to store the following additional info for a build (time related)

  • Total Duration
  • Duration of checkpoints (compile, test, javadocs...) - should be configurable in project.


31
32
33
# File 'lib/damagecontrol/build.rb', line 31

def time
  @time
end

Instance Method Details

#changeset ⇒ Object

Our associated changeset



49
50
51
# File 'lib/damagecontrol/build.rb', line 49

def changeset
  project.changeset(@changeset_identifier)
end

#dir ⇒ Object

The directory of the build



124
125
126
# File 'lib/damagecontrol/build.rb', line 124

def dir
  Directories.build_dir(@project_name, @changeset_identifier, @time)
end

#execute(command, env = {}) ⇒ Object

Executes command with the environment variables env and persists the command for future reference. This will prevent the same build from being executed in the future.

Raises:



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/damagecontrol/build.rb', line 55

def execute(command, env={})
  command_file = Directories.build_command_file(@project_name, @changeset_identifier, @time)
  raise BuildException.new("This build has already been executed and cannot be re-executed. It was executed with '#{File.open(command_file).read}'") if File.exist?(command_file)
  FileUtils.mkdir_p(File.dirname(command_file))
  File.open(command_file, "w") do |io|
    io.write(command)
  end
  command_line = "#{command} > #{stdout} 2> #{stderr}"

  begin
    with_working_dir(checkout_dir) do
      env.each {|k,v| ENV[k]=v}
      Log.info "Executing '#{command_line}'"
      Log.info "Execution environment:"
      ENV.each {|k,v| Log.info("#{k}=#{v}")}
      IO.popen(command_line) do |io|
        File.open(pid_file, "w") do |pid_io|
          pid_io.write(pid)
        end
        
        # there is nothing to read, since we're redirecting to file,
        # but we still need to read in order to block until the process is done.
        # TODO: don't redirect stdout - we want to intercept checkpoints
        io.read
      end
    end
  ensure
    exit_code = $? >> 8
    File.open(exit_code_file, "w") do |io|
      io.write(exit_code)
    end
  end
end

#execute_publisher_dir ⇒ Object



16
17
18
# File 'lib/damagecontrol/publisher/execute.rb', line 16

def execute_publisher_dir
  File.expand_path("#{dir}/execute_publisher")
end

#execute_publisher_stderr ⇒ Object



12
13
14
# File 'lib/damagecontrol/publisher/execute.rb', line 12

def execute_publisher_stderr
  File.expand_path("#{execute_publisher_dir}/stderr.log")
end

#execute_publisher_stdout ⇒ Object



8
9
10
# File 'lib/damagecontrol/publisher/execute.rb', line 8

def execute_publisher_stdout
  File.expand_path("#{execute_publisher_dir}/stdout.log")
end

#exit_code ⇒ Object

Returns the exit code of the build process, or nil if the process was killed



90
91
92
93
94
95
96
# File 'lib/damagecontrol/build.rb', line 90

def exit_code
  if(File.exist?(exit_code_file))
    File.read(exit_code_file).to_i
  else
    nil
  end
end

#identifier ⇒ Object

Our unique id within the changeset



39
40
41
# File 'lib/damagecontrol/build.rb', line 39

def identifier
  time.ymdHMS
end

#kill ⇒ Object



111
112
113
# File 'lib/damagecontrol/build.rb', line 111

def kill
  Process.kill("SIGHUP", pid)
end

#pid ⇒ Object

Returns the pid of the build process



107
108
109
# File 'lib/damagecontrol/build.rb', line 107

def pid
  File.read(pid_file).to_i
end

#project ⇒ Object

Our associated project



44
45
46
# File 'lib/damagecontrol/build.rb', line 44

def project
  Project.load(@project_name)
end

#small_image ⇒ Object



7
8
9
# File 'app/controllers/rscm_ext.rb', line 7

def small_image
  exit_code == 0 ? "/images/green-16.gif" : "/images/red-16.gif"
end

#status_message ⇒ Object



102
103
104
# File 'lib/damagecontrol/build.rb', line 102

def status_message
  successful? ? "Successful" : "Failed"
end

#stderr ⇒ Object



119
120
121
# File 'lib/damagecontrol/build.rb', line 119

def stderr
  Directories.stderr(@project_name, @changeset_identifier, @time)
end

#stdout ⇒ Object



115
116
117
# File 'lib/damagecontrol/build.rb', line 115

def stdout
  Directories.stdout(@project_name, @changeset_identifier, @time)
end

#successful? ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
# File 'lib/damagecontrol/build.rb', line 98

def successful?
  exit_code == 0
end