autobuild 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
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
- <b>importer/source</b>::
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 = OpenStruct.new
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
- Config.load(conffile, options)
68
-
69
- $trace = $DEBUG = options.debug
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
+
@@ -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 Regexp
9
- def each_match(string)
10
- string = string.to_str
11
- while data = match(string)
12
- yield(data)
13
- string = data.post_match
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
- interpolated = Hash.new
44
- @node.each do |k, v|
45
- next if k == VarDefKey
46
- interpolated[k] = Interpolator.interpolate(v, self)
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
- interpolated
50
-
51
- when Array
52
- @node.collect { |v| Interpolator.interpolate(v, self) }
53
-
54
- else
55
- if @node.respond_to?(:to_str)
56
- do_string(@node.to_str) { |varname| value_of(varname) }
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 value_of(name)
64
- if @defines.has_key?(name)
65
- value = @defines.delete(name)
66
- @variables[name] = do_string(value) { |varname|
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
- raise UndefinedVariable.new(name), "Interpolated variable #{name} is not defined"
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
- interpolated = ''
90
- data = nil
91
- InterpolationMatch.each_match(value) do |data|
92
- varname = data[1] || data[2]
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
- module Config
100
- def self.load(conffile, user_options)
101
- data = YAML.load( File.open(conffile) )
102
- data = Interpolator.interpolate(data)
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
- get_autobuild_config(data, user_options)
105
- get_package_config(data)
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(data, options)
115
- $PROGRAMS = (data["programs"] or "make")
86
+ def self.get_autobuild_config(config)
87
+ $PROGRAMS = (config[:programs] or "make")
116
88
 
117
- setup = data["autobuild-config"]
118
- raise ConfigException, "no autobuild-config block" if !setup
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, "you must at least set srcdir and prefix in the config files"
93
+ raise ConfigException, 'you must at least set srcdir and prefix in the config files'
124
94
  end
125
95
 
126
- $LOGDIR = (options.logdir or setup["logdir"] or "#{$PREFIX}/autobuild")
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 setup["clean-log"]
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 = setup["mail"]
136
- $UPDATE = options.update
137
- $UPDATE = setup["update"] if $UPDATE.nil?
138
- $UPDATE = true if $UPDATE.nil?
105
+ $MAIL = autobuild[:mail]
106
+ $UPDATE = autobuild[:update]
107
+ $NICE = autobuild[:nice]
139
108
 
140
- envvars = setup["environment"]
141
- envvars.each { |k, v|
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
- # Get the package config
171
- def self.get_package_config(data)
172
- setup = data["packages"]
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
- common_config = Hash.new
176
- setup["common-config"].each { |k, v| common_config[k.to_sym] = v } if setup.has_key?("common-config")
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(common_config) { |k, v1, v2|
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 common_config
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)
@@ -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
- # def patch(package)
30
- # patch = $PROGRAMS['patch'] || 'patch'
31
- # # Apply patches, if any
32
- # @options[:patch].to_a.each do |path|
33
- # subcommand(package.target, 'patch', patch
34
- # end
35
- # end
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
 
@@ -75,9 +75,9 @@ module RMail
75
75
  end
76
76
 
77
77
  def send_mail(subject, body)
78
- from = ($MAIL['from'] || "autobuild@#{Socket.gethostname}")
79
- to = $MAIL['to']
80
- smtp = ($MAIL['smtp'] || "localhost" )
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['port'] || 25))
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 |in, out, err|
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|
@@ -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 = command.reject { |o| o.nil? || (o.respond_to?(:empty?) && o.empty?) }
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
- status = File.open(logname, "a") { |logfile|
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,6 @@
1
+ $LOAD_PATH << File.expand_path('../lib', File.dirname(__FILE__))
2
+ require 'rubygems'
3
+ require 'test/unit'
4
+ require 'test/tc_config_interpolation.rb'
5
+ require 'test/tc_config.rb'
6
+ require 'test/tc_subcommand.rb'
@@ -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.2"
7
- date: 2005-09-12 00:00:00 +02:00
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.0.0
79
+ version: 0.6.0
72
80
  version:
73
81
  - !ruby/object:Gem::Dependency
74
82
  name: rmail