Class: DamageControl::Project

Inherits:
Object
  • Object
show all
Includes:
Web::Configuration
Defined in:
lib/damagecontrol/project.rb,
lib/damagecontrol/project_dependencies.rb,
app/controllers/application.rb

Overview

Represents a project with associated SCM, Tracker and SCMWeb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Web::Configuration

#selected?, #short

Constructor Details

#initialize(name = nil) ⇒ Project

Returns a new instance of Project.



47
48
49
50
51
52
# File 'lib/damagecontrol/project.rb', line 47

def initialize(name=nil)
  @name = name
  @scm = nil
  @tracker = Tracker::Null.new
  @scm_web = SCMWeb::Null.new
end

Instance Attribute Details

#build_commandObject

Returns the value of attribute build_command.



29
30
31
# File 'lib/damagecontrol/project.rb', line 29

def build_command
  @build_command
end

#descriptionObject

Returns the value of attribute description.



19
20
21
# File 'lib/damagecontrol/project.rb', line 19

def description
  @description
end

#home_pageObject

Returns the value of attribute home_page.



20
21
22
# File 'lib/damagecontrol/project.rb', line 20

def home_page
  @home_page
end

#nameObject

Returns the value of attribute name.



18
19
20
# File 'lib/damagecontrol/project.rb', line 18

def name
  @name
end

#quiet_periodObject

How long to sleep between each changesets invocation for non-transactional SCMs



27
28
29
# File 'lib/damagecontrol/project.rb', line 27

def quiet_period
  @quiet_period
end

#scmObject

Returns the value of attribute scm.



22
23
24
# File 'lib/damagecontrol/project.rb', line 22

def scm
  @scm
end

#scm_webObject

Returns the value of attribute scm_web.



24
25
26
# File 'lib/damagecontrol/project.rb', line 24

def scm_web
  @scm_web
end

#trackerObject

Returns the value of attribute tracker.



23
24
25
# File 'lib/damagecontrol/project.rb', line 23

def tracker
  @tracker
end

Class Method Details

.find_allObject

Loads all projects



41
42
43
44
45
# File 'lib/damagecontrol/project.rb', line 41

def Project.find_all
  Directories.project_names.collect do |name|
    Project.load(name)
  end
end

.load(name) ⇒ Object

Loads the project with the given name.



32
33
34
35
36
37
38
# File 'lib/damagecontrol/project.rb', line 32

def Project.load(name)
  config_file = Directories.project_config_file(name)
  Log.info "Loading project from #{config_file}"
  File.open(config_file) do |io|
    YAML::load(io)
  end
end

Instance Method Details

#==(o) ⇒ Object



171
172
173
174
# File 'lib/damagecontrol/project.rb', line 171

def == (o)
  return false unless o.is_a?(Project)
  name == o.name
end

#add_dependency(project) ⇒ Object



5
6
# File 'lib/damagecontrol/project_dependencies.rb', line 5

def add_dependency(project)
end

#build(changeset_identifier) {|build| ... } ⇒ Object

Creates, persists and executes a build for the changeset with the given changeset_identifier. Should be called with a block of arity 1 that will receive the build.

Yields:



183
184
185
186
187
# File 'lib/damagecontrol/project.rb', line 183

def build(changeset_identifier)
  scm.checkout(checkout_dir, changeset_identifier)
  build = Build.new(name, changeset_identifier, Time.now.utc)
  yield build
end

#builds(changeset_identifier) ⇒ Object

Returns an array of existing builds for the given changeset.



190
191
192
193
194
195
# File 'lib/damagecontrol/project.rb', line 190

def builds(changeset_identifier)
  Directories.build_dirs(name, changeset_identifier).collect do |dir|
    # The dir's basename will always be a Time
    Build.new(name, changeset_identifier, File.basename(dir).to_identifier)
  end
end

#changeset_identifiersObject



159
160
161
# File 'lib/damagecontrol/project.rb', line 159

def changeset_identifiers
  changesets_persister.identifiers
end

#changesets(changeset_identifier, prior) ⇒ Object



155
156
157
# File 'lib/damagecontrol/project.rb', line 155

def changesets(changeset_identifier, prior)
  changesets_persister.load_upto(changeset_identifier, prior)
end

#changesets_dirObject



151
152
153
# File 'lib/damagecontrol/project.rb', line 151

def changesets_dir
  Directories.changesets_dir(name)
end

#changesets_persisterObject



176
177
178
# File 'lib/damagecontrol/project.rb', line 176

def changesets_persister
  DamageControl::Visitor::YamlPersister.new(changesets_dir)
end

#changesets_rss_exists?Boolean

Returns:

  • (Boolean)


147
148
149
# File 'lib/damagecontrol/project.rb', line 147

def changesets_rss_exists?
  File.exist?(changesets_rss_file)
end

#changesets_rss_fileObject

Where RSS is written.



123
124
125
# File 'lib/damagecontrol/project.rb', line 123

def changesets_rss_file
  Directories.changesets_rss_file(name)
end

#checked_out?Boolean

Returns:

  • (Boolean)


127
128
129
# File 'lib/damagecontrol/project.rb', line 127

def checked_out?
  @scm.checked_out?(checkout_dir)
end

#checkout(changeset_identifier) ⇒ Object

Checks out files to project’s checkout directory. Writes the checked out files to checkout_list_file. The changeset_identifier parameter is a String or a Time representing a changeset.



74
75
76
77
78
79
80
81
# File 'lib/damagecontrol/project.rb', line 74

def checkout(changeset_identifier)
  File.open(checkout_list_file, "w") do |f|
    scm.checkout(checkout_dir, changeset_identifier) do |file_name|
      f << file_name << "\n"
      f.flush
    end
  end
end

#checkout_dirObject



139
140
141
# File 'lib/damagecontrol/project.rb', line 139

def checkout_dir
  Directories.checkout_dir(name)
end

#checkout_list_fileObject

Path to file containing pathnames of latest checked out files.



66
67
68
# File 'lib/damagecontrol/project.rb', line 66

def checkout_list_file
  Directories.checkout_list_file(name)
end

#deleteObject



167
168
169
# File 'lib/damagecontrol/project.rb', line 167

def delete
  File.delete(Directories.project_dir(name))
end

#delete_working_copyObject



143
144
145
# File 'lib/damagecontrol/project.rb', line 143

def delete_working_copy
  File.delete(checkout_dir)
end

#exists?Boolean

Returns:

  • (Boolean)


131
132
133
# File 'lib/damagecontrol/project.rb', line 131

def exists?
  File.exists?(project_config_file)
end

#latest_buildObject

Returns the latest build.



198
199
200
201
202
203
204
# File 'lib/damagecontrol/project.rb', line 198

def latest_build
  changeset_identifiers.reverse.each do |changeset_identifier|
    builds = builds(changeset_identifier)
    return builds[-1] unless builds.empty?
  end
  nil
end

#latest_changeset_identifierObject



163
164
165
# File 'lib/damagecontrol/project.rb', line 163

def latest_changeset_identifier
  changesets_persister.latest_identifier
end

#next_changeset_identifier(d = changesets_dir) ⇒ Object

Returns the identifier (int label or time) that should be used to get the next (unrecorded) changeset. This is the identifier following the latest recorded changeset. This identifier is determined by looking at the directory names under changesets_dir. If there are none, this method returns nil.



116
117
118
119
120
# File 'lib/damagecontrol/project.rb', line 116

def next_changeset_identifier(d=changesets_dir)
  # See String extension at top of this file.
  latest_identifier = DamageControl::Visitor::YamlPersister.new(d).latest_identifier
  latest_identifier ? latest_identifier + 1 : nil
end

#poll(from_if_first_poll = Time.epoch) {|changesets| ... } ⇒ Object

Polls SCM for new changesets and yields them to the given block.

Yields:



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/damagecontrol/project.rb', line 84

def poll(from_if_first_poll=Time.epoch)
  start = Time.now
  from = next_changeset_identifier || from_if_first_poll
  
  Log.info "Getting changesets for #{name} from #{from} (retrieved from #{checkout_dir})"
  changesets = @scm.changesets(checkout_dir, from)
  if(!changesets.empty? && !@scm.transactional?)
    # We're dealing with a non-transactional SCM (like CVS/StarTeam/ClearCase,
    # unlike Subversion/Monotone). Sleep a little, get the changesets again.
    # When the changesets are not changing, we can consider the last commit done
    # and the quiet period elapsed. This is not 100% failsafe, but will work
    # under most circumstances. In the worst case, we'll miss some files in
    # the changesets, but they will be part of the next changeset (on next poll).
    commit_in_progress = true
    while(commit_in_progress)
      @quiet_period ||= 5
      Log.info "Sleeping for #{@quiet_period} seconds since #{name}'s SCM (#{@scm.name}) is not transactional."
      sleep @quiet_period
      next_changesets = @scm.changesets(checkout_dir, from)
      commit_in_progress = changesets != next_changesets
      changesets = next_changesets
    end
    Log.info "Quiet period elapsed for #{name}"
  end
  Log.info "Got changesets for #{@name} in #{Time.now.difference_as_text(start)}"
  yield changesets
end

#saveObject

Saves the state of this project to persistent store (YAML)



55
56
57
58
59
60
61
62
63
# File 'lib/damagecontrol/project.rb', line 55

def save
  f = project_config_file
  FileUtils.mkdir_p(File.dirname(f))
  File.open(f, "w") do |io|
    YAML::dump(self, io)
  end
  
  REGISTRY.poller.add_project(self) if REGISTRY
end

#scm_exists?Boolean

Returns:

  • (Boolean)


135
136
137
# File 'lib/damagecontrol/project.rb', line 135

def scm_exists?
  scm.exists?
end