blob: 752b17d21353df578fa75a1090b83d66c0e8176e [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with this
# work for additional information regarding copyright ownership. The ASF
# licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
module Buildr #:nodoc:
class CCTask < Rake::Task
attr_accessor :delay
attr_reader :project
def initialize(*args)
super
@delay = 0.2
enhance do
monitor_and_compile
end
end
private
# run block on sub-projects depth-first, then on this project
def each_project(&block)
depth_first = lambda do |p|
p.projects.each { |c| depth_first.call(c, &block) }
block.call(p)
end
depth_first.call(@project)
end
def associate_with(project)
@project = project
end
def monitor_and_compile
# we don't want to actually fail if our dependencies don't succeed
begin
each_project { |p| p.test.compile.invoke }
build_completed(project)
rescue Exception => ex
$stderr.puts Buildr::Console.color(ex.message, :red)
$stderr.puts
build_failed(project, ex)
end
srcs = []
each_project do |p|
srcs += p.compile.sources.map(&:to_s)
srcs += p.test.compile.sources.map(&:to_s)
srcs += p.resources.sources.map(&:to_s)
end
if srcs.length == 1
info "Monitoring directory: #{srcs.first}"
else
info "Monitoring directories: [#{srcs.join ', '}]"
end
timestamps = lambda do
times = {}
srcs.each do |a|
if File.directory? a
Dir.glob("#{a}/**/*").map { |f| times[f] = File.mtime f }
elsif File.exist? a
times[a] = File.mtime a
end
end
times
end
old_times = timestamps.call()
while true
sleep delay
new_times = timestamps.call()
changed = changed(new_times, old_times)
old_times = new_times
unless changed.empty?
info '' # better spacing
changed.each do |file|
info "Detected changes in #{file}"
end
each_project do |p|
# transitively reenable prerequisites
reenable = lambda do |t|
t = task(t)
t.reenable
t.prerequisites.each { |c| reenable.call(c) }
end
reenable.call(p.test.compile)
end
successful = true
begin
each_project { |p| p.test.compile.invoke }
build_completed(project)
rescue Exception => ex
$stderr.puts Buildr::Console.color(ex.message, :red)
build_failed(project, ex)
successful = false
end
puts Buildr::Console.color("Build complete", :green) if successful
end
end
end
def build_completed(project)
Buildr.application.build_completed('Compilation successful', project.path_to)
end
def build_failed(project, ex = nil)
Buildr.application.build_failed('Compilation failed', project.path_to, ex)
end
def changed(new_times, old_times)
changed = []
new_times.each do |(fname,newtime)|
if old_times[fname].nil? || old_times[fname] < newtime
changed << fname
end
end
# detect deletion (slower than it could be)
old_times.each_key do |fname|
changed << fname unless new_times.has_key? fname
end
changed
end
end
module CC
include Extension
first_time do
desc 'Execute continuous compilation, listening to changes'
Project.local_task('cc') { |name| "Executing continuous compilation for #{name}" }
end
before_define do |project|
cc = CCTask.define_task :cc
cc.send :associate_with, project
end
def cc
task :cc
end
end
class Project
include CC
end
end