autobuild 0.2 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|