autobuild 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,20 +1,22 @@
1
1
  require 'autobuild/timestamps'
2
2
  require 'autobuild/package'
3
3
 
4
- class ImporterPackage < Package
5
- def installstamp
6
- "#{srcdir}/#{STAMPFILE}"
7
- end
8
- def initialize(target, options)
9
- super(target, options)
10
- source_tree srcdir, installstamp
11
- file installstamp => srcdir do
12
- touch_stamp installstamp
4
+ module Autobuild
5
+ class ImporterPackage < Package
6
+ def installstamp
7
+ "#{srcdir}/#{STAMPFILE}"
13
8
  end
14
- end
15
- def prepare; end
9
+ def initialize(target, options)
10
+ super(target, options)
11
+ source_tree srcdir, installstamp
12
+ file installstamp => srcdir do
13
+ touch_stamp installstamp
14
+ end
15
+ end
16
+ def prepare; end
16
17
 
17
- factory :import, ImporterPackage
18
+ factory :import, ImporterPackage
19
+ end
18
20
  end
19
21
 
20
22
 
@@ -2,77 +2,113 @@ require 'rmail'
2
2
  require 'rmail/serialize'
3
3
  require 'net/smtp'
4
4
  require 'socket'
5
+ require 'etc'
5
6
 
6
- module Reporting
7
- def self.report
8
- begin
9
- yield
10
- rescue Exception => e
11
- raise unless e.respond_to?(:target)
12
- error(e)
13
- exit(1) if e.fatal?
7
+ require 'autobuild/exceptions'
8
+
9
+ module Autobuild
10
+ class Reporting
11
+ @@reporters = Array.new
12
+
13
+ def self.report
14
+ begin
15
+ yield
16
+ rescue Autobuild::Exception => e
17
+ raise unless e.kind_of?(Autobuild::Exception)
18
+ error(e)
19
+ exit(1) if e.fatal?
20
+ end
21
+ end
22
+
23
+ def self.success
24
+ @@reporters.each do |rep| rep.success end
25
+ end
26
+
27
+ def self.error(error)
28
+ @@reporters.each do |rep| rep.error(error) end
14
29
  end
15
- end
16
-
17
- def self.success
18
- message = "Build finished successfully at #{Time.now}"
19
- puts message
20
- send_mail("Build success", message) if $MAIL
21
- end
22
30
 
23
- def self.error(object)
24
- if object.kind_of?(SubcommandFailed)
25
- body = <<EOF
26
- #{object.target}: #{object.message}
27
- command '#{object.command}' failed with status #{object.status}
28
- see #{File.basename(object.logfile)} for details
29
- EOF
30
-
31
- message = <<EOF
32
- #{object.target}: #{object.message}
33
- command '#{object.command}' failed with status #{object.status}
34
- see #{object.logfile} for details
35
- EOF
36
- else
37
- body = message = "#{object.target}: #{object.message}"
31
+ def self.<<(reporter)
32
+ @@reporters << reporter
38
33
  end
39
34
 
40
- puts message
41
- send_mail("Build failed", body) if $MAIL && object.mail?
35
+ def self.each_log(&iter)
36
+ Dir.glob("#{$LOGDIR}/*.log", &iter)
37
+ end
42
38
  end
43
39
 
44
- private
40
+ class Reporter
41
+ def error(error); end
42
+ def success; end
43
+ end
45
44
 
46
- def self.send_mail(subject, body)
47
- from = ($MAIL[:from] || "autobuild@#{Socket.gethostname}")
48
- to = $MAIL[:to]
49
- smtp = ($MAIL[:smtp] || "localhost" )
45
+ class StdoutReporter < Reporter
46
+ def error(error)
47
+ puts "Build failed: #{error}"
48
+ end
49
+ def success
50
+ puts "Build finished successfully at #{Time.now}"
51
+ end
52
+ end
50
53
 
51
- mail = RMail::Message.new
52
- mail.header.date = Time.now
53
- mail.header.from = from
54
- mail.header.to = to
55
- mail.header.subject = subject
54
+ class MailReporter < Reporter
55
+ def default_mail
56
+ Etc::endpwent
57
+ uname = while (pwent = Etc::getpwent)
58
+ break (pwent.name) if pwent.uid == Process.uid
59
+ end
56
60
 
57
- part = RMail::Message.new
58
- part.header.set('Content-Type', 'text/plain')
59
- part.body = body
60
- mail.add_part(part)
61
+ raise "FATAL: cannot find a user with uid=#{Process.uid}" unless uname
62
+ "#{pwent.name}@#{Socket.gethostname}"
63
+ end
64
+
65
+ def initialize(config)
66
+ @from = (config[:from] || default_mail)
67
+ @to = (config[:to] || default_mail)
68
+ @smtp = (config[:smtp] || "localhost" )
69
+ @port = Integer(config[:port] || Socket.getservbyname('smtp'))
70
+ end
71
+
72
+ def error(error)
73
+ if error.mail?
74
+ send_mail("Build failed", error.to_s)
75
+ end
76
+ end
61
77
 
62
- # Attach log files
63
- Dir.glob("#{$LOGDIR}/*.log") do |file|
64
- mail.add_file(file)
78
+ def success
79
+ send_mail("Build success", "finished successfully at #{Time.now}")
65
80
  end
66
81
 
67
- # Send the mail
68
- smtp = Net::SMTP.new(smtp, Integer($MAIL[:port] || 25))
69
- smtp.start {
70
- smtp.send_mail RMail::Serialize.write('', mail), from, to
71
- }
82
+ def send_mail(subject, body)
83
+ mail = RMail::Message.new
84
+ mail.header.date = Time.now
85
+ mail.header.from = @from
86
+ mail.header.to = @to
87
+ mail.header.subject = subject
88
+
89
+ part = RMail::Message.new
90
+ part.header.set('Content-Type', 'text/plain')
91
+ part.body = body
92
+ mail.add_part(part)
93
+
94
+ # Attach log files
95
+ Reporting.each_log do |file|
96
+ mail.add_file(file)
97
+ end
98
+
99
+ # Send the mail
100
+ smtp = Net::SMTP.new(@smtp, @port)
101
+ smtp.start {
102
+ smtp.send_mail RMail::Serialize.write('', mail), @from, @to
103
+ }
104
+
105
+ # Notify the sending
106
+ puts "Sent notification mail to #{@to} with source #{@from}"
107
+
108
+ end
72
109
  end
73
110
  end
74
111
 
75
-
76
112
  module RMail
77
113
  class Message
78
114
  def add_file(path, content_type='text/plain')
@@ -1,58 +1,101 @@
1
1
  require 'autobuild/reporting'
2
2
 
3
- def subcommand(target, type, *command)
4
- # Filter nil and empty? in command
5
- command.reject! { |o| o.nil? || (o.respond_to?(:empty?) && o.empty?) }
6
- command.collect! { |o| o.to_s }
7
- logname = "#{$LOGDIR}/#{target}-#{type}.log"
8
- puts "#{target}: running #{command.join(" ")}\n (output goes to #{logname})"
9
-
10
- input_streams = command.collect { |o| $1 if o =~ /^\<(.+)/ }.compact
11
- command.reject! { |o| o =~ /^\<(.+)/ }
12
-
13
- status = File.open(logname, "a") do |logfile|
14
- pread, pwrite = IO.pipe
15
-
16
- pid = fork {
17
- Process.setpriority(Process::PRIO_PROCESS, 0, $NICE) if $NICE
18
- if $VERBOSE
19
- $stderr.dup.reopen(logfile.dup)
20
- $stdout.dup.reopen(logfile.dup)
21
- else
22
- $stderr.reopen(logfile.dup)
23
- $stdout.reopen(logfile.dup)
24
- end
3
+ module Autobuild::Subprocess
4
+ @@nice = 0
5
+ def self.nice=(value)
6
+ @@nice = value
7
+ end
25
8
 
26
- if !input_streams.empty?
27
- pwrite.close
28
- $stdin.reopen(pread)
29
- end
30
-
31
- if !exec(*command)
32
- raise SubcommandFailed.new(target, command.join(" "), logname, 0), "error running command"
9
+ class Failed < Exception
10
+ attr_reader :status
11
+ def initialize(status = 0)
12
+ @status = status
13
+ end
14
+ end
15
+
16
+ CONTROL_COMMAND_NOT_FOUND = 1
17
+ CONTROL_UNEXPECTED = 2
18
+ def self.run(target, phase, *command)
19
+ # Filter nil and empty? in command
20
+ command.reject! { |o| o.nil? || (o.respond_to?(:empty?) && o.empty?) }
21
+ command.collect! { |o| o.to_s }
22
+ logname = "#{$LOGDIR}/#{target}-#{phase}.log"
23
+
24
+ puts "#{target}: running #{command.join(" ")}\n (output goes to #{logname})"
25
+
26
+ input_streams = command.collect { |o| $1 if o =~ /^\<(.+)/ }.compact
27
+ command.reject! { |o| o =~ /^\<(.+)/ }
28
+
29
+ status = File.open(logname, "a") do |logfile|
30
+ pread, pwrite = IO.pipe # to feed subprocess stdin
31
+ cread, cwrite = IO.pipe # to control that exec goes well
32
+
33
+ pid = fork {
34
+ cwrite.sync = true
35
+ begin
36
+ Process.setpriority(Process::PRIO_PROCESS, 0, @@nice)
37
+ if $VERBOSE
38
+ $stderr.dup.reopen(logfile.dup)
39
+ $stdout.dup.reopen(logfile.dup)
40
+ else
41
+ $stderr.reopen(logfile.dup)
42
+ $stdout.reopen(logfile.dup)
43
+ end
44
+
45
+ if !input_streams.empty?
46
+ pwrite.close
47
+ $stdin.reopen(pread)
48
+ end
49
+
50
+ exec(*command)
51
+ rescue Errno::ENOENT
52
+ cwrite.write([CONTROL_COMMAND_NOT_FOUND].pack('I'))
53
+ raise
54
+ rescue Exception
55
+ cwrite.write([CONTROL_UNEXPECTED].pack('I'))
56
+ raise
57
+ end
58
+ }
59
+
60
+ # Feed the input
61
+ pread.close
62
+ begin
63
+ input_streams.each do |infile|
64
+ File.open(infile) do |instream|
65
+ instream.each_line { |line| pwrite.write(line) }
66
+ end
67
+ end
68
+ rescue Errno::ENOENT => e
69
+ raise Failed.new, "cannot open input files: #{e.message}"
33
70
  end
34
- }
35
-
36
- # Feed the input
37
- pread.close
38
- begin
39
- input_streams.each do |infile|
40
- File.open(infile) do |instream|
41
- instream.each_line { |line| pwrite.write(line) }
71
+ pwrite.close
72
+
73
+ # Get control status
74
+ cwrite.close
75
+ value = cread.read(4)
76
+ if value
77
+ # An error occured
78
+ value = value.unpack('I').first
79
+ if value == CONTROL_COMMAND_NOT_FOUND
80
+ raise Failed.new, "file not found"
81
+ else
82
+ raise Failed.new, "something unexpected happened"
42
83
  end
43
84
  end
44
- rescue Errno::ENOENT => e
45
- logfile.puts "Cannot open input files: #{e.message}"
46
- raise SubcommandFailed.new(target, command.join(" "), logname, 0), e.message
85
+
86
+ childpid, childstatus = Process.wait2(pid)
87
+ childstatus
47
88
  end
48
- pwrite.close
49
89
 
50
- childpid, childstatus = Process.wait2(pid)
51
- childstatus
52
- end
90
+ if status.exitstatus > 0
91
+ raise Failed.new(status.exitstatus), "command returned with status #{status.exitstatus}"
92
+ end
53
93
 
54
- if status.exitstatus > 0
55
- raise SubcommandFailed.new(target, command.join(" "), logname, status.exitstatus)
94
+ rescue Failed => e
95
+ error = SubcommandFailed.new(target, command.join(" "), logname, e.status)
96
+ error.phase = phase
97
+ raise error, e.message
56
98
  end
99
+
57
100
  end
58
101
 
@@ -4,47 +4,57 @@ require 'fileutils'
4
4
 
5
5
  STAMPFILE = "autobuild-stamp"
6
6
 
7
- def tree_timestamp(path, *exclude)
8
- latest = Time.at(0)
9
- latest_file = ""
10
- dot = "."[0]
11
-
12
- exclude.collect! { |e| File.expand_path(e, path) }
13
- Find.find(path) { |p|
14
- Find.prune if File.basename(p)[0] == dot
15
- exclude.each { |pattern|
16
- Find.prune if File.fnmatch?(pattern, p)
7
+ module Autobuild
8
+ def tree_timestamp(path, *exclude)
9
+ # Exclude autobuild timestamps
10
+ exclude << "*-#{STAMPFILE}"
11
+
12
+ puts "getting tree timestamp for #{path}" if $DEBUG
13
+ latest = Time.at(0)
14
+ latest_file = ""
15
+
16
+ exclude.collect! { |e| File.expand_path(e, path) }
17
+ Find.find(path) { |p|
18
+ Find.prune if File.basename(p) =~ /^\./
19
+ exclude.each { |pattern|
20
+ if File.fnmatch?(pattern, p)
21
+ puts " excluding #{p}" if $DEBUG
22
+ Find.prune
23
+ end
24
+ }
25
+ next if File.directory?(p)
26
+
27
+ p_time = File.mtime(p)
28
+ if latest < p_time
29
+ latest = p_time
30
+ latest_file = p
31
+ end
17
32
  }
18
- next if File.directory?(p)
19
33
 
20
- p_time = File.mtime(p)
21
- if latest < p_time
22
- latest = p_time
23
- latest_file = p
24
- end
25
- }
26
-
27
- return latest
28
- end
34
+ puts " #{latest}" if $DEBUG
35
+ return latest
36
+ end
29
37
 
30
- class SourceTreeTask < Rake::Task
31
- attr_accessor :exclude
32
- def timestamp
33
- tree_timestamp(name, "*CVS", *@exclude)
38
+ class SourceTreeTask < Rake::Task
39
+ attr_accessor :exclude
40
+ def timestamp
41
+ tree_timestamp(name, "*CVS", *@exclude)
42
+ end
43
+ end
44
+ def source_tree(path, exclude, &block)
45
+ task = SourceTreeTask.define_task(path, &block)
46
+ task.exclude = exclude
47
+ end
48
+
49
+ def get_stamp(stampfile)
50
+ return Time.at(0) if !File.exists?(stampfile)
51
+ return File.mtime(stampfile)
34
52
  end
35
- end
36
- def source_tree(path, exclude, &block)
37
- task = SourceTreeTask.define_task(path, &block)
38
- task.exclude = exclude
39
- end
40
-
41
- def get_stamp(stampfile)
42
- return Time.at(0) if !File.exists?(stampfile)
43
- return File.mtime(stampfile)
44
- end
45
53
 
46
- def touch_stamp(stampfile)
47
- puts "Touching #{stampfile}" if $trace
48
- FileUtils.touch(stampfile)
54
+ def touch_stamp(stampfile)
55
+ puts "Touching #{stampfile}" if $DEBUG
56
+ FileUtils.touch(stampfile)
57
+ sleep(1)
58
+ end
49
59
  end
50
60
 
metadata CHANGED
@@ -3,100 +3,65 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: autobuild
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.4"
7
- date: 2005-09-27 00:00:00 +02:00
6
+ version: "0.5"
7
+ date: 2005-12-09 00:00:00 +01:00
8
8
  summary: Rake-based utility to build and install multiple packages with dependencies
9
9
  require_paths:
10
- - lib
11
- - lib
10
+ - lib
12
11
  email: sylvain.joyeux@m4x.org
13
- homepage:
14
- rubyforge_project:
15
- description: "autobuild imports, configures, builds and installs software packages (mainly
16
- C/C++ autotools packages for now) with dependencies. It can be used in
17
- community-based software development to make sure that nothing is broken in the
18
- build process of a set of packages."
12
+ homepage: http://autobuild.rubyforge.org
13
+ rubyforge_project: autobuild
14
+ description: Autobuild imports, configures, builds and installs various kinds of software packages. It can be used in software development to make sure that nothing is broken in the build process of a set of packages, or can be used as an automated installation tool.
19
15
  autorequire:
20
16
  default_executable:
21
17
  bindir: bin
22
18
  has_rdoc: true
23
19
  required_ruby_version: !ruby/object:Gem::Version::Requirement
24
20
  requirements:
25
- -
26
- - ">"
27
- - !ruby/object:Gem::Version
28
- version: 0.0.0
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
29
24
  version:
30
25
  platform: ruby
31
26
  signing_key:
32
27
  cert_chain:
33
28
  authors:
34
- - Sylvain Joyeux
29
+ - Sylvain Joyeux
35
30
  files:
36
- - lib/autobuild/config.rb
37
- - lib/autobuild/environment.rb
38
- - lib/autobuild/importer.rb
39
- - lib/autobuild/reporting.rb
40
- - lib/autobuild/package.rb
41
- - lib/autobuild/subcommand.rb
42
- - lib/autobuild/timestamps.rb
43
- - lib/autobuild/exceptions.rb
44
- - lib/autobuild/options.rb
45
- - lib/autobuild/config-interpolator.rb
46
- - lib/autobuild/import/cvs.rb
47
- - lib/autobuild/import/svn.rb
48
- - lib/autobuild/packages/autotools.rb
49
- - lib/autobuild/packages/genom.rb
50
- - lib/autobuild/packages/import.rb
51
- - bin/autobuild
52
- - README
53
- test_files:
54
- - test/tc_subcommand.rb
55
- - test/tc_config_interpolation.rb
56
- - test/tc_config.rb
57
- - test/tc_import.rb
58
- - test/base.rb
59
- - test/data
60
- - test/tools.rb
31
+ - README
32
+ - Rakefile
33
+ - CHANGES
34
+ - lib/autobuild/importer.rb
35
+ - lib/autobuild/config-interpolator.rb
36
+ - lib/autobuild/subcommand.rb
37
+ - lib/autobuild/options.rb
38
+ - lib/autobuild/environment.rb
39
+ - lib/autobuild/package.rb
40
+ - lib/autobuild/reporting.rb
41
+ - lib/autobuild/timestamps.rb
42
+ - lib/autobuild/exceptions.rb
43
+ - lib/autobuild/config.rb
44
+ - lib/autobuild/import/svn.rb
45
+ - lib/autobuild/import/cvs.rb
46
+ - lib/autobuild/import/tar.rb
47
+ - lib/autobuild/packages/import.rb
48
+ - lib/autobuild/packages/autotools.rb
49
+ - lib/autobuild/packages/genom.rb
50
+ test_files: []
51
+
61
52
  rdoc_options:
62
- - "--title"
63
- - Autobuild
64
- - "--main"
65
- - README
53
+ - --title
54
+ - Autobuild
55
+ - --main
56
+ - README
66
57
  extra_rdoc_files:
67
- - README
68
- executables:
69
- - autobuild
58
+ - README
59
+ - CHANGES
60
+ executables: []
61
+
70
62
  extensions: []
63
+
71
64
  requirements: []
72
- dependencies:
73
- - !ruby/object:Gem::Dependency
74
- name: rake
75
- version_requirement:
76
- version_requirements: !ruby/object:Gem::Version::Requirement
77
- requirements:
78
- -
79
- - ">="
80
- - !ruby/object:Gem::Version
81
- version: 0.6.0
82
- version:
83
- - !ruby/object:Gem::Dependency
84
- name: rmail
85
- version_requirement:
86
- version_requirements: !ruby/object:Gem::Version::Requirement
87
- requirements:
88
- -
89
- - ">"
90
- - !ruby/object:Gem::Version
91
- version: 0.0.0
92
- version:
93
- - !ruby/object:Gem::Dependency
94
- name: daemons
95
- version_requirement:
96
- version_requirements: !ruby/object:Gem::Version::Requirement
97
- requirements:
98
- -
99
- - ">"
100
- - !ruby/object:Gem::Version
101
- version: 0.0.0
102
- version:
65
+
66
+ dependencies: []
67
+