autobuild 0.2 → 0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +13 -1
- data/bin/autobuild +13 -14
- data/lib/autobuild/config-interpolator.rb +96 -0
- data/lib/autobuild/config.rb +79 -119
- data/lib/autobuild/importer.rb +48 -7
- data/lib/autobuild/logging.rb +4 -4
- data/lib/autobuild/options.rb +15 -0
- data/lib/autobuild/packages/genom.rb +2 -1
- data/lib/autobuild/subcommand.rb +29 -7
- data/test/base.rb +6 -0
- data/test/conffile-generator.rb +34 -0
- data/test/dummy.ryml +24 -0
- data/test/tc_config.rb +38 -0
- data/test/tc_config_interpolation.rb +50 -0
- data/test/tc_subcommand.rb +61 -0
- metadata +13 -5
data/README
CHANGED
@@ -120,6 +120,7 @@ Autobuild uses three sections:
|
|
120
120
|
<b>clean-log</b>:: if we must remove all logfiles before each autobuild run or if we should append to them. The
|
121
121
|
default is +true+, that is log files are removed. Note that if mailing is active, all log
|
122
122
|
files are attached to notification mail.
|
123
|
+
*nice*:: The priority at which autobuild should launch subprocesses
|
123
124
|
|
124
125
|
|
125
126
|
=== Environment (<tt>autobuild-config/environment</tt>)
|
@@ -193,7 +194,12 @@ source and the builder to build and install it.
|
|
193
194
|
the importer type. For now, only +cvs+ and +svn+ are available. See the <b>Available importers</b>
|
194
195
|
section.
|
195
196
|
|
196
|
-
|
197
|
+
*patch*:: the list of patch we should apply. Patches are applied in order, with -p0. Autobuild
|
198
|
+
remembers the list of already applied patches, and will handle the changes to this list gracefully.
|
199
|
+
Since relative paths for patch files are relative to the autobuild working directory, I recommend
|
200
|
+
you put absolute paths here.
|
201
|
+
|
202
|
+
*source*</b>::
|
197
203
|
where the importer should get the sources. The format of this options depends on
|
198
204
|
the importer used. See Available importers.
|
199
205
|
|
@@ -279,6 +285,12 @@ The only program used during the build phase is +make+. The make command can too
|
|
279
285
|
= Running autobuild in daemon mode
|
280
286
|
The <tt>--daemon</tt> command line options makes autobuild go into daemon mode.
|
281
287
|
|
288
|
+
= Changes
|
289
|
+
== 0.2 to 0.3
|
290
|
+
* added support for patching source code. Add patch: [ patches ] to the package configuration
|
291
|
+
* renamed autobuild-config, common-config and clean-log to autobuild, common and clean_log. Autobuild
|
292
|
+
warns if it finds one the previous spelling
|
293
|
+
|
282
294
|
= Copyright and license
|
283
295
|
Author:: Sylvain Joyeux <sylvain.joyeux@m4x.org>
|
284
296
|
Copyright:: Copyright (c) 2005 Sylvain Joyeux
|
data/bin/autobuild
CHANGED
@@ -6,6 +6,7 @@ require 'rake'
|
|
6
6
|
require 'ostruct'
|
7
7
|
require 'optparse'
|
8
8
|
|
9
|
+
require 'autobuild/options'
|
9
10
|
require 'autobuild/config'
|
10
11
|
require 'autobuild/logging'
|
11
12
|
require 'daemons'
|
@@ -13,15 +14,7 @@ require 'daemons'
|
|
13
14
|
DEFAULT_HTTP_PORT = 2000
|
14
15
|
|
15
16
|
def parse_options(args)
|
16
|
-
options =
|
17
|
-
options.update = false
|
18
|
-
options.srcdir = nil
|
19
|
-
options.prefix = nil
|
20
|
-
options.builddir = "build"
|
21
|
-
options.logdir = nil
|
22
|
-
options.daemonize = false
|
23
|
-
options.use_http = false
|
24
|
-
$VERBOSE = false
|
17
|
+
options = Options.default
|
25
18
|
|
26
19
|
parser = OptionParser.new do |opts|
|
27
20
|
opts.banner = "Usage: autobuild [options] config.yml"
|
@@ -31,17 +24,19 @@ def parse_options(args)
|
|
31
24
|
opts.on("--prefix PATH", "Packages are installed in PATH") do |options.prefix|
|
32
25
|
options.logdir = "#{options.prefix}/autobuild"
|
33
26
|
end
|
34
|
-
|
35
27
|
opts.on("--logdir", "Where logs are saved (default: <prefix>/autobuild)") do |options.logdir| end
|
28
|
+
|
36
29
|
opts.on("--[no-]update", "Update already checked-out sources") do |options.update| end
|
37
|
-
opts.on("--verbose", "Display output of commands on stdout") do |$VERBOSE| end
|
38
30
|
|
31
|
+
opts.on('--nice NICE', Integer, 'Nice the subprocesses to the given value') do |options.nice| end
|
39
32
|
opts.on("--[no-]daemon", "Go into daemon mode") do |options.daemonize| end
|
40
33
|
#opts.on("--http [PORT]", Integer,
|
41
34
|
# "Display a HTTP information page on PORT (PORT default: #{DEFAULT_HTTP_PORT})") do |port|
|
42
35
|
# options.http = (port || DEFAULT_HTTP_PORT)
|
43
36
|
#end
|
37
|
+
opts.on("--[no-]verbose", "Display output of commands on stdout") do |options.verbose| end
|
44
38
|
opts.on("--[no-]debug", "Verbose information (for debugging purposes)") do |options.debug| end
|
39
|
+
|
45
40
|
opts.on_tail("-h", "--help", "Show this message") do
|
46
41
|
puts opts
|
47
42
|
exit
|
@@ -59,14 +54,18 @@ end
|
|
59
54
|
|
60
55
|
# Load the command line options
|
61
56
|
options, conffile, targets = parse_options(ARGV)
|
57
|
+
|
58
|
+
# make conffile an absolute path since daemonize mode makes
|
59
|
+
# / the current directory
|
60
|
+
conffile = File.expand_path(conffile, Dir.pwd)
|
62
61
|
if options.daemonize
|
63
62
|
puts "Going into daemon mode ..."
|
64
63
|
Daemons.daemonize
|
65
64
|
end
|
66
65
|
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
File.open(conffile) do |f|
|
67
|
+
Config.load(f, options)
|
68
|
+
end
|
70
69
|
|
71
70
|
begin
|
72
71
|
if targets.empty?
|
@@ -0,0 +1,96 @@
|
|
1
|
+
class Regexp
|
2
|
+
def each_match(string)
|
3
|
+
string = string.to_str
|
4
|
+
while data = match(string)
|
5
|
+
yield(data)
|
6
|
+
string = data.post_match
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class UndefinedVariable < Exception
|
12
|
+
attr_reader :name
|
13
|
+
def initialize(name); @name = name end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Interpolator
|
17
|
+
VarDefKey = 'defines'
|
18
|
+
MatchExpr = '\$\{([^}]+)\}|\$(\w+)'
|
19
|
+
PartialMatch = Regexp.new(MatchExpr)
|
20
|
+
WholeMatch = Regexp.new("^(?:#{MatchExpr})$")
|
21
|
+
|
22
|
+
def self.interpolate(config, parent = nil)
|
23
|
+
Interpolator.new(config, parent).interpolate
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(node, parent = nil, variables = {})
|
27
|
+
@node = node
|
28
|
+
@variables = {}
|
29
|
+
@defines = {}
|
30
|
+
@parent = parent
|
31
|
+
end
|
32
|
+
|
33
|
+
def interpolate
|
34
|
+
case @node
|
35
|
+
when Hash
|
36
|
+
@defines = (@node[VarDefKey] || {})
|
37
|
+
|
38
|
+
interpolated = Hash.new
|
39
|
+
@node.each do |k, v|
|
40
|
+
next if k == VarDefKey
|
41
|
+
interpolated[k] = Interpolator.interpolate(v, self)
|
42
|
+
end
|
43
|
+
|
44
|
+
interpolated
|
45
|
+
|
46
|
+
when Array
|
47
|
+
@node.collect { |v| Interpolator.interpolate(v, self) }
|
48
|
+
|
49
|
+
else
|
50
|
+
each_interpolation(@node) { |varname| value_of(varname) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def value_of(name)
|
55
|
+
if @defines.has_key?(name)
|
56
|
+
value = @defines.delete(name)
|
57
|
+
@variables[name] = each_interpolation(value) { |varname|
|
58
|
+
begin
|
59
|
+
value_of(varname)
|
60
|
+
rescue UndefinedVariable => e
|
61
|
+
if e.varname == name
|
62
|
+
raise "Cyclic reference found in definition of #{name}"
|
63
|
+
else
|
64
|
+
raise
|
65
|
+
end
|
66
|
+
end
|
67
|
+
}
|
68
|
+
elsif @variables.has_key?(name)
|
69
|
+
@variables[name]
|
70
|
+
elsif @parent
|
71
|
+
@parent.value_of(name)
|
72
|
+
else
|
73
|
+
raise UndefinedVariable.new(name), "Interpolated variable #{name} is not defined"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def each_interpolation(value)
|
78
|
+
return value if (!value.respond_to?(:to_str) || value.empty?)
|
79
|
+
|
80
|
+
# Special case: if 'value' is *only* an interpolation, avoid
|
81
|
+
# conversion to string
|
82
|
+
WholeMatch.each_match(value) do |data|
|
83
|
+
return yield(data[1] || data[2])
|
84
|
+
end
|
85
|
+
|
86
|
+
interpolated = ''
|
87
|
+
data = nil
|
88
|
+
PartialMatch.each_match(value) do |data|
|
89
|
+
varname = data[1] || data[2]
|
90
|
+
interpolated << data.pre_match << yield(varname)
|
91
|
+
end
|
92
|
+
return data ? (interpolated << data.post_match) : value
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
|
data/lib/autobuild/config.rb
CHANGED
@@ -1,108 +1,80 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'pathname'
|
3
3
|
|
4
|
+
require 'autobuild/config-interpolator'
|
4
5
|
require 'autobuild/logging'
|
5
6
|
require 'autobuild/package'
|
6
7
|
require 'autobuild/importer'
|
7
8
|
|
8
|
-
class
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
class Hash
|
10
|
+
def keys_to_sym
|
11
|
+
inject(Hash.new) do |h, sample|
|
12
|
+
k, v = sample[0], sample[1]
|
13
|
+
if v.respond_to?(:keys_to_sym)
|
14
|
+
h[k.to_sym] = v.keys_to_sym
|
15
|
+
else
|
16
|
+
h[k.to_sym] = v
|
17
|
+
end
|
18
|
+
h
|
14
19
|
end
|
15
20
|
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class UndefinedVariable < Exception
|
19
|
-
attr_reader :name
|
20
|
-
def initialize(name); @name = name end
|
21
|
-
end
|
22
|
-
|
23
|
-
class Interpolator
|
24
|
-
VarDefKey = 'defines'
|
25
|
-
InterpolationMatch = Regexp.new('\$\{([^}]+)\}|\$(\w+)')
|
26
|
-
|
27
|
-
def self.interpolate(config, parent = nil)
|
28
|
-
Interpolator.new(config, parent).interpolate
|
29
|
-
end
|
30
|
-
|
31
|
-
def initialize(node, parent = nil, variables = {})
|
32
|
-
@node = node
|
33
|
-
@variables = {}
|
34
|
-
@defines = {}
|
35
|
-
@parent = parent
|
36
|
-
end
|
37
|
-
|
38
|
-
def interpolate
|
39
|
-
case @node
|
40
|
-
when Hash
|
41
|
-
@defines = (@node[VarDefKey] || {})
|
42
21
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
22
|
+
def each_recursive(&p)
|
23
|
+
each { |k, v|
|
24
|
+
yield(k, v)
|
25
|
+
if v.respond_to?(:each_recursive)
|
26
|
+
v.each_recursive(&p)
|
47
27
|
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
48
31
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
if
|
56
|
-
|
57
|
-
else
|
58
|
-
@node
|
32
|
+
module Config
|
33
|
+
def self.check_backward_compatibility(config)
|
34
|
+
if config.has_key?('autobuild-config')
|
35
|
+
puts 'WARNING: the \'autobuild-config\' block is now named \'autobuild\''
|
36
|
+
end
|
37
|
+
config.each_recursive { |k, v|
|
38
|
+
if k == 'common-config'
|
39
|
+
puts 'WARNING: the \'common-config\' blocks are now named \'common\''
|
59
40
|
end
|
41
|
+
}
|
42
|
+
if config["autobuild"] && config["autobuild"]["clean-log"]
|
43
|
+
puts 'WARNING: the \'clean-log\' option is now named \'clean_log\''
|
60
44
|
end
|
61
45
|
end
|
62
46
|
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
begin
|
68
|
-
value_of(varname)
|
69
|
-
rescue UndefinedVariable => e
|
70
|
-
if e.varname == name
|
71
|
-
raise "Cyclic reference found in definition of #{name}"
|
72
|
-
else
|
73
|
-
raise
|
74
|
-
end
|
75
|
-
end
|
76
|
-
}
|
77
|
-
elsif @variables.has_key?(name)
|
78
|
-
@variables[name]
|
79
|
-
elsif @parent
|
80
|
-
@parent.value_of(name)
|
47
|
+
def self.load(conffile, user_options = Options.nil)
|
48
|
+
case conffile
|
49
|
+
when Hash
|
50
|
+
config = conffile
|
81
51
|
else
|
82
|
-
|
52
|
+
data = YAML.load(conffile)
|
53
|
+
config = Interpolator.interpolate(data)
|
83
54
|
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def do_string(value)
|
87
|
-
return value if value.empty?
|
88
55
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
interpolated << data.pre_match << yield(varname)
|
56
|
+
check_backward_compatibility(config)
|
57
|
+
config = config.keys_to_sym
|
58
|
+
if !config[:autobuild]
|
59
|
+
raise ConfigException, "no autobuild block"
|
94
60
|
end
|
95
|
-
return data ? (interpolated << data.post_match) : value
|
96
|
-
end
|
97
|
-
end
|
98
61
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
62
|
+
# Merge user_options into the autobuild block
|
63
|
+
autobuild_config = config[:autobuild]
|
64
|
+
default_options = Options.default
|
65
|
+
user_options.each_pair { |sym, value|
|
66
|
+
if !value.nil?
|
67
|
+
autobuild_config[sym] = value
|
68
|
+
elsif !autobuild_config.has_key?(sym)
|
69
|
+
autobuild_config[sym] = default_options.send(sym)
|
70
|
+
end
|
71
|
+
}
|
103
72
|
|
104
|
-
|
105
|
-
|
73
|
+
$VERBOSE = config[:verbose]
|
74
|
+
$DEBUG = config[:debug]
|
75
|
+
|
76
|
+
get_autobuild_config(config)
|
77
|
+
get_package_config(config)
|
106
78
|
rescue ConfigException => error
|
107
79
|
error(error, "Error in config file '#{conffile}'")
|
108
80
|
exit(1)
|
@@ -111,35 +83,31 @@ module Config
|
|
111
83
|
exit(1)
|
112
84
|
end
|
113
85
|
|
114
|
-
def self.get_autobuild_config(
|
115
|
-
$PROGRAMS = (
|
86
|
+
def self.get_autobuild_config(config)
|
87
|
+
$PROGRAMS = (config[:programs] or "make")
|
116
88
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
$SRCDIR = (options.srcdir or setup["srcdir"])
|
121
|
-
$PREFIX = (options.prefix or setup["prefix"])
|
89
|
+
autobuild = config[:autobuild]
|
90
|
+
$SRCDIR = autobuild[:srcdir]
|
91
|
+
$PREFIX = autobuild[:prefix]
|
122
92
|
if !$SRCDIR || !$PREFIX
|
123
|
-
raise ConfigException,
|
93
|
+
raise ConfigException, 'you must at least set srcdir and prefix in the config files'
|
124
94
|
end
|
125
95
|
|
126
|
-
$LOGDIR = (
|
96
|
+
$LOGDIR = (autobuild[:logdir] || "#{$PREFIX}/autobuild")
|
127
97
|
|
128
98
|
FileUtils.mkdir_p $SRCDIR if !File.directory?($SRCDIR)
|
129
99
|
FileUtils.mkdir_p $LOGDIR if !File.directory?($LOGDIR)
|
130
|
-
if
|
100
|
+
if autobuild[:clean_log]
|
131
101
|
puts "Cleaning log dir #{$LOGDIR}"
|
132
102
|
FileUtils.rm_rf Dir.glob("#{$LOGDIR}/*.log")
|
133
103
|
end
|
134
104
|
|
135
|
-
$MAIL
|
136
|
-
$UPDATE =
|
137
|
-
$
|
138
|
-
$UPDATE = true if $UPDATE.nil?
|
105
|
+
$MAIL = autobuild[:mail]
|
106
|
+
$UPDATE = autobuild[:update]
|
107
|
+
$NICE = autobuild[:nice]
|
139
108
|
|
140
|
-
|
141
|
-
|
142
|
-
ENV[k] = v.to_a.join(":")
|
109
|
+
autobuild[:environment].to_a.each { |k, v|
|
110
|
+
ENV[k.to_s] = v.to_a.join(':')
|
143
111
|
}
|
144
112
|
end
|
145
113
|
|
@@ -160,41 +128,33 @@ module Config
|
|
160
128
|
end
|
161
129
|
|
162
130
|
# Set the default dir if needed
|
163
|
-
config[:srcdir] ||= name
|
164
|
-
config[:prefix] ||= name
|
131
|
+
config[:srcdir] ||= name.to_s
|
132
|
+
config[:prefix] ||= name.to_s
|
165
133
|
|
166
134
|
# Build the rake rules for this package
|
167
135
|
Package.build(package_type, name, config)
|
168
136
|
end
|
169
137
|
|
170
|
-
|
171
|
-
|
172
|
-
|
138
|
+
def self.get_package_config(config)
|
139
|
+
packages = config[:packages]
|
140
|
+
return if !packages
|
173
141
|
|
174
142
|
# Get the common config block
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
setup.each do |p, yml_config|
|
179
|
-
next if p == "common-config"
|
180
|
-
|
181
|
-
# Change keys into symbols
|
182
|
-
config = {}
|
183
|
-
yml_config.each do |k, v|
|
184
|
-
config[k.to_sym] = v
|
185
|
-
end
|
143
|
+
common = packages[:common]
|
144
|
+
packages.each do |p, config|
|
145
|
+
next if p == :common
|
186
146
|
|
187
147
|
# Merge the common config
|
188
|
-
config = config.merge(
|
148
|
+
config = config.merge(common) { |k, v1, v2|
|
189
149
|
if v2.respond_to?(:to_ary)
|
190
150
|
v1.to_a | v2.to_ary
|
191
151
|
elsif v2.respond_to?(:to_str)
|
192
152
|
v1.to_s + " " + v2.to_str
|
193
153
|
end
|
194
154
|
}
|
195
|
-
# Remove p -> p dependency which may come from
|
155
|
+
# Remove p -> p dependency which may come from common
|
196
156
|
if config.has_key?(:depends)
|
197
|
-
config[:depends] = config[:depends].to_a.reject { |el| el == p }
|
157
|
+
config[:depends] = config[:depends].to_a.reject { |el| el == p.to_s }
|
198
158
|
end
|
199
159
|
|
200
160
|
add_package(p, config)
|
data/lib/autobuild/importer.rb
CHANGED
@@ -8,6 +8,7 @@ class Importer
|
|
8
8
|
if File.directory?(srcdir)
|
9
9
|
if $UPDATE
|
10
10
|
update(package)
|
11
|
+
patch(package)
|
11
12
|
else
|
12
13
|
puts "Not updating #{package.target}"
|
13
14
|
return
|
@@ -26,12 +27,52 @@ class Importer
|
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
#
|
32
|
-
#
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
private
|
31
|
+
|
32
|
+
# We assume that package.srcdir already exists (checkout
|
33
|
+
# is supposed to have been called)
|
34
|
+
def patchlist(package)
|
35
|
+
"#{package.srcdir}/autobuild-patches"
|
36
|
+
end
|
37
|
+
|
38
|
+
def call_patch(package, reverse, file)
|
39
|
+
patch = ($PROGRAMS['patch'] || 'patch')
|
40
|
+
Dir.chdir(package.srcdir) {
|
41
|
+
subcommand(package.target, 'patch', patch, '-p0', (reverse ? '-R' : nil), "<#{file}")
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def apply(package, path); call_patch(package, false, path) end
|
46
|
+
def unapply(package, path); call_patch(package, true, path) end
|
47
|
+
|
48
|
+
def patch(package)
|
49
|
+
# Get the list of already applied patches
|
50
|
+
patches_file = patchlist(package)
|
51
|
+
cur_patches = if !File.exists?(patches_file) then []
|
52
|
+
else
|
53
|
+
File.open(patches_file) do |f|
|
54
|
+
f.readlines.collect { |path| path.rstrip }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Do not be smart, remove all already applied patches
|
59
|
+
# and then apply the new ones
|
60
|
+
begin
|
61
|
+
while p = cur_patches.pop
|
62
|
+
unapply(package, p)
|
63
|
+
end
|
64
|
+
|
65
|
+
@options[:patch].to_a.each { |p|
|
66
|
+
apply(package, p)
|
67
|
+
cur_patches << p
|
68
|
+
}
|
69
|
+
rescue SubcommandFailed => e
|
70
|
+
raise ImportException.new(e), "can't patch #{package.target} (#{e.message})"
|
71
|
+
ensure
|
72
|
+
File.open(patchlist(package), 'w+') do |f|
|
73
|
+
f.write(cur_patches.join("\n"))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
36
77
|
end
|
37
78
|
|
data/lib/autobuild/logging.rb
CHANGED
@@ -75,9 +75,9 @@ module RMail
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def send_mail(subject, body)
|
78
|
-
from = ($MAIL[
|
79
|
-
to = $MAIL[
|
80
|
-
smtp = ($MAIL[
|
78
|
+
from = ($MAIL[:from] || "autobuild@#{Socket.gethostname}")
|
79
|
+
to = $MAIL[:to]
|
80
|
+
smtp = ($MAIL[:smtp] || "localhost" )
|
81
81
|
|
82
82
|
mail = RMail::Message.new
|
83
83
|
mail.header.date = Time.now
|
@@ -96,7 +96,7 @@ def send_mail(subject, body)
|
|
96
96
|
end
|
97
97
|
|
98
98
|
# Send the mail
|
99
|
-
smtp = Net::SMTP.new(smtp, Integer($MAIL[
|
99
|
+
smtp = Net::SMTP.new(smtp, Integer($MAIL[:port] || 25))
|
100
100
|
smtp.start {
|
101
101
|
smtp.send_mail RMail::Serialize.write('', mail), from, to
|
102
102
|
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Options = Struct.new( :update, :nice,
|
2
|
+
:srcdir, :prefix, :builddir, :logdir,
|
3
|
+
:verbose, :debug,
|
4
|
+
:daemonize, :use_http )
|
5
|
+
|
6
|
+
class Options
|
7
|
+
def self.default
|
8
|
+
default_values = { :update => true, :nice => 0,
|
9
|
+
:srcdir => nil, :prefix => nil, :builddir => nil, :logdir => nil,
|
10
|
+
:verbose => false, :debug => false,
|
11
|
+
:daemonize => false, :use_http => false }
|
12
|
+
Options.new default_values
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'autobuild/packages/autotools'
|
2
|
+
require 'open3'
|
2
3
|
|
3
4
|
class GenomModule < Autotools
|
4
5
|
def initialize(target, options)
|
@@ -15,7 +16,7 @@ class GenomModule < Autotools
|
|
15
16
|
|
16
17
|
def get_requires
|
17
18
|
cpp = ($PROGRAMS['cpp'] || 'cpp')
|
18
|
-
Open3.popen3("#{cpp} #{cpp_options.join(" ")} #{srcdir}/#{target}.gen") do |
|
19
|
+
Open3.popen3("#{cpp} #{cpp_options.join(" ")} #{srcdir}/#{target}.gen") do |cin, out, err|
|
19
20
|
out.each_line { |line|
|
20
21
|
if line =~ /^\s*requires\s*:\s*([\w\-]+(?:\s*,\s*[\w\-]+)*);/
|
21
22
|
$1.split(/, /).each { |name|
|
data/lib/autobuild/subcommand.rb
CHANGED
@@ -2,14 +2,19 @@ require 'autobuild/logging'
|
|
2
2
|
|
3
3
|
def subcommand(target, type, *command)
|
4
4
|
# Filter nil and empty? in command
|
5
|
-
command
|
5
|
+
command.reject! { |o| o.nil? || (o.respond_to?(:empty?) && o.empty?) }
|
6
6
|
command.collect! { |o| o.to_s }
|
7
|
-
|
8
7
|
logname = "#{$LOGDIR}/#{target}-#{type}.log"
|
9
8
|
puts "#{target}: running #{command.join(" ")}\n (output goes to #{logname})"
|
10
9
|
|
11
|
-
|
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
|
+
|
12
16
|
pid = fork {
|
17
|
+
Process.setpriority(Process::PRIO_PROCESS, 0, $NICE) if $NICE
|
13
18
|
if $VERBOSE
|
14
19
|
$stderr.dup.reopen(logfile.dup)
|
15
20
|
$stdout.dup.reopen(logfile.dup)
|
@@ -17,20 +22,37 @@ def subcommand(target, type, *command)
|
|
17
22
|
$stderr.reopen(logfile.dup)
|
18
23
|
$stdout.reopen(logfile.dup)
|
19
24
|
end
|
25
|
+
|
26
|
+
if !input_streams.empty?
|
27
|
+
pwrite.close
|
28
|
+
$stdin.reopen(pread)
|
29
|
+
end
|
20
30
|
|
21
31
|
if !exec(*command)
|
22
32
|
raise "Error running command"
|
23
33
|
end
|
24
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) }
|
42
|
+
end
|
43
|
+
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
|
47
|
+
end
|
48
|
+
pwrite.close
|
49
|
+
|
25
50
|
childpid, childstatus = Process.wait2(pid)
|
26
51
|
childstatus
|
27
|
-
|
52
|
+
end
|
28
53
|
|
29
54
|
if status.exitstatus > 0
|
30
55
|
raise SubcommandFailed.new(target, command.join(" "), logname, status.exitstatus)
|
31
|
-
return false
|
32
|
-
else
|
33
|
-
return true
|
34
56
|
end
|
35
57
|
end
|
36
58
|
|
data/test/base.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
DATADIR = File.dirname(__FILE__)
|
5
|
+
|
6
|
+
class ConffileGenerator
|
7
|
+
class << self
|
8
|
+
def tempdir
|
9
|
+
@tmpdir = Dir::tmpdir + "/autobuild-#{Process.uid}"
|
10
|
+
FileUtils.mkdir_p(@tmpdir, :mode => 0700)
|
11
|
+
end
|
12
|
+
|
13
|
+
def dummy(basedir = tempdir)
|
14
|
+
apply(binding, basedir, 'dummy')
|
15
|
+
end
|
16
|
+
|
17
|
+
def clean
|
18
|
+
FileUtils.rm_rf tempdir
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def apply(binding, basedir, basename)
|
24
|
+
template = File.open(File.join(DATADIR, "#{basename}.ryml")) { |f| f.readlines }.join('')
|
25
|
+
result = ERB.new(template).result(binding)
|
26
|
+
|
27
|
+
yml = File.join(basedir, "#{basename}.yml")
|
28
|
+
File.open(yml, 'w+') { |f| f.write(result) }
|
29
|
+
|
30
|
+
return yml
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
data/test/dummy.ryml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
defines:
|
2
|
+
global_prefix: <%= "#{basedir}/prefix" %>
|
3
|
+
platform: B21R
|
4
|
+
buildname: i386-linux
|
5
|
+
mail: doudou@melix.net
|
6
|
+
nice: 0
|
7
|
+
|
8
|
+
autobuild:
|
9
|
+
prefix: ${global_prefix}/build
|
10
|
+
srcdir: ${global_prefix}/src
|
11
|
+
clean_log: true
|
12
|
+
nice: $nice
|
13
|
+
|
14
|
+
mail:
|
15
|
+
to: $mail
|
16
|
+
|
17
|
+
environment:
|
18
|
+
PATH: [ /bin, /usr/bin, $global_prefix/$buildname/tools/bin ]
|
19
|
+
PKG_CONFIG_PATH: $global_prefix/$buildname/tools/lib/pkgconfig
|
20
|
+
LD_LIBRARY_PATH:
|
21
|
+
|
22
|
+
programs:
|
23
|
+
aclocal: aclocal-1.9
|
24
|
+
|
data/test/tc_config.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/conffile-generator'
|
3
|
+
require 'autobuild/options'
|
4
|
+
require 'autobuild/config'
|
5
|
+
|
6
|
+
class TC_Config < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@conffile = ConffileGenerator.dummy
|
9
|
+
@options_hash = File.open(@conffile) { |f| YAML.load(f) }
|
10
|
+
@options = File.open(@conffile) { |f| Config.load(f, Options.default) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
ConffileGenerator.clean
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_keys_to_sym
|
18
|
+
symed = @options_hash.keys_to_sym
|
19
|
+
|
20
|
+
pass_through = {}
|
21
|
+
symed.each_recursive { |k, v|
|
22
|
+
assert_kind_of(Symbol, k)
|
23
|
+
pass_through[k] = true
|
24
|
+
}
|
25
|
+
|
26
|
+
assert(pass_through[:PATH])
|
27
|
+
assert(pass_through[:prefix])
|
28
|
+
assert(pass_through[:autobuild])
|
29
|
+
assert_kind_of(String, symed[:autobuild][:srcdir])
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_value_type
|
33
|
+
assert_kind_of(String, $SRCDIR)
|
34
|
+
assert_kind_of(Fixnum, $NICE)
|
35
|
+
assert_equal(0, $NICE)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'yaml'
|
3
|
+
require 'autobuild/config-interpolator'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
class TC_ConfigInterpolation < Test::Unit::TestCase
|
7
|
+
WELL_FORMED = <<EOF
|
8
|
+
defines:
|
9
|
+
global_prefix: /home/doudou
|
10
|
+
srcdir: ${global_prefix}/src
|
11
|
+
prefix: ${global_prefix}/build
|
12
|
+
nice: 10
|
13
|
+
|
14
|
+
autobuild:
|
15
|
+
srcdir: $srcdir
|
16
|
+
prefix: $prefix
|
17
|
+
nice: $nice
|
18
|
+
|
19
|
+
EOF
|
20
|
+
|
21
|
+
def setup
|
22
|
+
@wellformed = StringIO.open(WELL_FORMED, 'r') { |d| YAML.load(d) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def teardown
|
26
|
+
@wellformed = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
# Check that interpolation matches both forms ${var} and $var
|
30
|
+
def test_match
|
31
|
+
data = @wellformed['defines']['srcdir']
|
32
|
+
all_matches = []
|
33
|
+
Interpolator::PartialMatch.each_match(data) { |m| all_matches << m[1] }
|
34
|
+
assert_equal( ['global_prefix'], all_matches )
|
35
|
+
|
36
|
+
data = @wellformed['autobuild']['srcdir']
|
37
|
+
all_matches = []
|
38
|
+
Interpolator::PartialMatch.each_match(data) { |m| all_matches << m[2] }
|
39
|
+
assert_equal( ['srcdir'], all_matches )
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_interpolation
|
43
|
+
data = Interpolator.interpolate(@wellformed)
|
44
|
+
assert_equal('/home/doudou/src', data["autobuild"]["srcdir"])
|
45
|
+
assert_equal('/home/doudou/build', data["autobuild"]["prefix"])
|
46
|
+
assert_equal(10, data["autobuild"]["nice"])
|
47
|
+
assert_kind_of(Fixnum, data["autobuild"]["nice"])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'autobuild/options'
|
4
|
+
require 'autobuild/config'
|
5
|
+
require 'tmpdir'
|
6
|
+
|
7
|
+
require 'test/conffile-generator'
|
8
|
+
|
9
|
+
TESTDIR = File.join(File.dirname(__FILE__), 'dummy.yml')
|
10
|
+
|
11
|
+
class TC_Subcommand < Test::Unit::TestCase
|
12
|
+
EXAMPLE_1 = <<EOF
|
13
|
+
This is a file
|
14
|
+
It will be the first part of the two-part cat
|
15
|
+
EOF
|
16
|
+
|
17
|
+
EXAMPLE_2 = <<EOF
|
18
|
+
This is another file
|
19
|
+
It will be the second part of the two-part cat
|
20
|
+
EOF
|
21
|
+
|
22
|
+
attr_reader :tmpdir
|
23
|
+
attr_reader :source1, :source2
|
24
|
+
def setup
|
25
|
+
conffile = ConffileGenerator.dummy
|
26
|
+
@tmpdir = File.dirname(conffile)
|
27
|
+
|
28
|
+
options = Options.default
|
29
|
+
options.logdir = tmpdir
|
30
|
+
File.open(conffile) do |confstream|
|
31
|
+
Config.load confstream, options
|
32
|
+
end
|
33
|
+
|
34
|
+
# Write example files
|
35
|
+
@source1 = File.join(tmpdir, 'source1')
|
36
|
+
@source2 = File.join(tmpdir, 'source2')
|
37
|
+
File.open(source1, 'w+') { |f| f.write(EXAMPLE_1) }
|
38
|
+
File.open(source2, 'w+') { |f| f.write(EXAMPLE_2) }
|
39
|
+
end
|
40
|
+
|
41
|
+
def teardown
|
42
|
+
ConffileGenerator.clean
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_subcommand
|
46
|
+
assert_raise(SubcommandFailed) { || subcommand('test', 'copy', 'cat', 'bla') }
|
47
|
+
|
48
|
+
subcommand('test', 'simple', 'cat', nil, '', source1)
|
49
|
+
assert( FileUtils.identical?(source1, File.join(tmpdir, 'test-simple.log')) )
|
50
|
+
|
51
|
+
subcommand('test', 'use-lt', 'cat', "<#{source1}")
|
52
|
+
assert( FileUtils.identical?(source1, File.join(tmpdir, 'test-use-lt.log')) )
|
53
|
+
|
54
|
+
subcommand('test', 'use-both', 'cat', source1, '-', "<#{source2}")
|
55
|
+
result = File.open( File.join(tmpdir, 'test-use-both.log') ) do |f|
|
56
|
+
f.readlines
|
57
|
+
end
|
58
|
+
assert_equal(EXAMPLE_1 + EXAMPLE_2, result.join(""))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: autobuild
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: "0.
|
7
|
-
date: 2005-09-
|
6
|
+
version: "0.3"
|
7
|
+
date: 2005-09-13 00:00:00 +02:00
|
8
8
|
summary: Rake-based utility to build and install multiple packages with dependencies
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -40,6 +40,8 @@ files:
|
|
40
40
|
- lib/autobuild/package.rb
|
41
41
|
- lib/autobuild/subcommand.rb
|
42
42
|
- lib/autobuild/timestamps.rb
|
43
|
+
- lib/autobuild/options.rb
|
44
|
+
- lib/autobuild/config-interpolator.rb
|
43
45
|
- lib/autobuild/import/cvs.rb
|
44
46
|
- lib/autobuild/import/svn.rb
|
45
47
|
- lib/autobuild/packages/autotools.rb
|
@@ -47,7 +49,13 @@ files:
|
|
47
49
|
- lib/autobuild/packages/import.rb
|
48
50
|
- bin/autobuild
|
49
51
|
- README
|
50
|
-
test_files:
|
52
|
+
test_files:
|
53
|
+
- test/tc_subcommand.rb
|
54
|
+
- test/tc_config_interpolation.rb
|
55
|
+
- test/tc_config.rb
|
56
|
+
- test/dummy.ryml
|
57
|
+
- test/base.rb
|
58
|
+
- test/conffile-generator.rb
|
51
59
|
rdoc_options:
|
52
60
|
- "--title"
|
53
61
|
- Autobuild
|
@@ -66,9 +74,9 @@ dependencies:
|
|
66
74
|
version_requirements: !ruby/object:Gem::Version::Requirement
|
67
75
|
requirements:
|
68
76
|
-
|
69
|
-
- "
|
77
|
+
- ">="
|
70
78
|
- !ruby/object:Gem::Version
|
71
|
-
version: 0.
|
79
|
+
version: 0.6.0
|
72
80
|
version:
|
73
81
|
- !ruby/object:Gem::Dependency
|
74
82
|
name: rmail
|