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 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