rant 0.4.2 → 0.4.4

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.
Files changed (56) hide show
  1. data/NEWS +14 -0
  2. data/README +13 -7
  3. data/Rantfile +11 -0
  4. data/doc/md5.rdoc +49 -0
  5. data/doc/rantfile.rdoc +1 -1
  6. data/lib/rant/coregen.rb +193 -0
  7. data/lib/rant/import/archive/zip.rb +2 -0
  8. data/lib/rant/import/archive.rb +10 -2
  9. data/lib/rant/import/autoclean.rb +16 -7
  10. data/lib/rant/import/c/dependencies.rb +1 -1
  11. data/lib/rant/import/directedrule.rb +2 -2
  12. data/lib/rant/import/md5.rb +16 -0
  13. data/lib/rant/import/metadata.rb +162 -0
  14. data/lib/rant/import/nodes/default.rb +490 -0
  15. data/lib/rant/import/nodes/signed.rb +84 -0
  16. data/lib/rant/import/package/zip.rb +2 -0
  17. data/lib/rant/import/rubydoc.rb +5 -1
  18. data/lib/rant/import/rubypackage.rb +2 -1
  19. data/lib/rant/import/signature/md5.rb +38 -0
  20. data/lib/rant/import/signedfile.rb +235 -0
  21. data/lib/rant/import/subfile.rb +1 -1
  22. data/lib/rant/import.rb +5 -1
  23. data/lib/rant/node.rb +165 -0
  24. data/lib/rant/plugin/csharp.rb +2 -0
  25. data/lib/rant/rantlib.rb +64 -9
  26. data/lib/rant/rantsys.rb +39 -27
  27. data/lib/rant/rantvar.rb +32 -2
  28. data/misc/TODO +66 -0
  29. data/test/import/c/dependencies/test_on_the_fly.rb +52 -0
  30. data/test/import/metadata/Rantfile +16 -0
  31. data/test/import/metadata/sub/Rantfile +17 -0
  32. data/test/import/metadata/test_metadata.rb +126 -0
  33. data/test/import/nodes/signed/Rantfile +89 -0
  34. data/test/import/nodes/signed/sub1/Rantfile +6 -0
  35. data/test/import/nodes/signed/test_signed.rb +455 -0
  36. data/test/import/package/md5.rf +10 -0
  37. data/test/import/package/test_package.rb +127 -1
  38. data/test/import/signeddirectory/Rantfile +15 -0
  39. data/test/import/signeddirectory/test_signeddirectory.rb +84 -0
  40. data/test/import/signedfile/Rantfile +90 -0
  41. data/test/import/signedfile/sub1/Rantfile +4 -0
  42. data/test/import/signedfile/test_signedfile.rb +338 -0
  43. data/test/project1/Rantfile +0 -9
  44. data/test/project1/test_project.rb +2 -0
  45. data/test/project_rb1/test_project_rb1.rb +27 -10
  46. data/test/rant-import/test_rant-import.rb +46 -9
  47. data/test/subdirs/sub2/sub/rantfile +0 -5
  48. data/test/subdirs/test_subdirs.rb +0 -9
  49. data/test/test_examples.rb +131 -3
  50. data/test/test_filelist.rb +44 -0
  51. data/test/test_sys.rb +19 -1
  52. data/test/test_task.rb +2 -2
  53. data/test/tutil.rb +9 -3
  54. metadata +34 -4
  55. data/lib/rant/rantfile.rb +0 -897
  56. data/test/test_lighttask.rb +0 -68
data/lib/rant/rantsys.rb CHANGED
@@ -19,7 +19,8 @@ module Rant
19
19
  # Initialized to 0.
20
20
  attr_accessor :glob_flags
21
21
 
22
- attr_reader :ignore_rx
22
+ attr_accessor :ignore_rx
23
+ protected :ignore_rx=
23
24
 
24
25
  class << self
25
26
  def [](*patterns)
@@ -33,6 +34,7 @@ module Rant
33
34
  @actions = patterns.map { |pat| [:apply_include, pat] }
34
35
  @ignore_rx = nil
35
36
  @pending = true
37
+ @keep = {}
36
38
  yield self if block_given?
37
39
  end
38
40
 
@@ -41,6 +43,7 @@ module Rant
41
43
  c.files = @files.dup
42
44
  c.actions = @actions.dup
43
45
  c.ignore_rx = @ignore_rx.dup if @ignore_rx
46
+ c.instance_variable_set(:@keep, @keep.dup)
44
47
  c
45
48
  end
46
49
 
@@ -67,35 +70,32 @@ module Rant
67
70
  end
68
71
 
69
72
  def +(other)
70
- case other
71
- when Array
72
- c = dup
73
- c.files.concat(other)
74
- c
75
- when FileList
73
+ if FileList === other
76
74
  c = other.dup
77
75
  c.actions.concat(@actions)
78
76
  c.files.concat(@files)
79
77
  c.pending = !c.actions.empty?
80
78
  c
81
- else
79
+ elsif other.respond_to? :to_ary
80
+ c = dup
81
+ c.actions <<
82
+ [:apply_ary_method_1, :concat, other.to_ary.dup]
83
+ c.pending = true
84
+ c
85
+ else
82
86
  raise "argument has to be an Array or FileList"
83
- end
87
+ end
84
88
  end
85
89
 
86
- # Add file to filelist unless it matches an exclude pattern.
87
- # Take care: Don't rely on any order when inserting a file
88
- # with this method!
89
- def add(file)
90
- @files << file unless file =~ ignore_rx
91
- self
92
- end
93
-
94
- # Like #add but doesn't honor exclude patterns.
90
+ # Use this method to append +file+ to this list. +file+ will
91
+ # stay in this list even if it matches an exclude or ignore
92
+ # pattern.
93
+ #
95
94
  # Returns self.
96
95
  def <<(file)
97
- #STDERR.puts caller unless String === file
98
96
  @actions << [:apply_ary_method_1, :push, file]
97
+ @keep[file] = true
98
+ @pending = true
99
99
  self
100
100
  end
101
101
 
@@ -132,7 +132,7 @@ module Rant
132
132
  @actions.clear
133
133
  ix = ignore_rx
134
134
  if ix
135
- @files.reject! { |f| f =~ ix }
135
+ @files.reject! { |f| f =~ ix && !@keep[f] }
136
136
  end
137
137
  end
138
138
 
@@ -182,14 +182,14 @@ module Rant
182
182
 
183
183
  def apply_exclude(pattern)
184
184
  @files.reject! { |elem|
185
- File.fnmatch? pattern, elem, @glob_flags
185
+ File.fnmatch?(pattern, elem, @glob_flags) && !@keep[elem]
186
186
  }
187
187
  end
188
188
  private :apply_exclude
189
189
 
190
190
  def apply_exclude_rx(rx)
191
191
  @files.reject! { |elem|
192
- elem =~ rx
192
+ elem =~ rx && !@keep[elem]
193
193
  }
194
194
  end
195
195
  private :apply_exclude_rx
@@ -262,12 +262,13 @@ module Rant
262
262
  entry = nil
263
263
  unless name
264
264
  @files.reject! { |entry|
265
- test(?d, entry)
265
+ test(?d, entry) && !@keep[entry]
266
266
  }
267
267
  return
268
268
  end
269
269
  elems = nil
270
270
  @files.reject! { |entry|
271
+ next if @keep[entry]
271
272
  elems = Sys.split_path(entry)
272
273
  i = elems.index(name)
273
274
  if i
@@ -283,7 +284,9 @@ module Rant
283
284
  # Remove all files which have the given name.
284
285
  def no_file(name)
285
286
  @actions << [:apply_ary_method, :reject!,
286
- lambda { |entry| entry == name and test(?f, entry) }]
287
+ lambda { |entry|
288
+ entry == name && !@keep[entry] && test(?f, entry)
289
+ }]
287
290
  @pending = true
288
291
  self
289
292
  end
@@ -302,7 +305,7 @@ module Rant
302
305
  @files.reject! { |entry|
303
306
  elems = Sys.split_path(entry)
304
307
  elems.any? { |elem|
305
- elem =~ /#{suffix}$/
308
+ elem =~ /#{suffix}$/ && !@keep[entry]
306
309
  }
307
310
  }
308
311
  end
@@ -321,7 +324,7 @@ module Rant
321
324
  @files.reject! { |entry|
322
325
  elems = Sys.split_path(entry)
323
326
  elems.any? { |elem|
324
- elem =~ /^#{prefix}/
327
+ elem =~ /^#{prefix}/ && !@keep[entry]
325
328
  }
326
329
  }
327
330
  end
@@ -356,6 +359,8 @@ module Rant
356
359
  self
357
360
  end
358
361
 
362
+ # Same as #map! but evaluation is delayed until the next read
363
+ # access (e.g. by calling #each). Always returns self.
359
364
  def lazy_map!(&block)
360
365
  @actions << [:apply_ary_method, :map!, block]
361
366
  @pending = true
@@ -510,6 +515,13 @@ module Rant
510
515
  def fu_output_message(msg) #:nodoc:
511
516
  ::Rant.rac.cmd_msg msg if ::Rant.rac
512
517
  end
518
+ private :fu_output_message
519
+
520
+ def fu_each_src_dest(src, *rest)
521
+ src = src.to_ary if src.respond_to? :to_ary
522
+ super(src, *rest)
523
+ end
524
+ private :fu_each_src_dest
513
525
 
514
526
  # Run an external command. When given one argument, this is
515
527
  # subject to shell interpretation. Otherwise the first
@@ -553,7 +565,7 @@ module Rant
553
565
  else
554
566
  begin
555
567
  ln(*args)
556
- rescue Errno::EOPNOTSUPP
568
+ rescue Exception #Errno::EOPNOTSUPP
557
569
  Sys.symlink_supported = false
558
570
  cp(*args)
559
571
  end
data/lib/rant/rantvar.rb CHANGED
@@ -16,7 +16,7 @@
16
16
  # If you're looking for general info about Rant, read the
17
17
  # README[link:files/README.html].
18
18
  module Rant
19
- VERSION = '0.4.2'
19
+ VERSION = '0.4.4'
20
20
 
21
21
  # Those are the filenames for rantfiles.
22
22
  # Case matters!
@@ -52,7 +52,7 @@ module Rant
52
52
  end
53
53
 
54
54
  module MetaUtils
55
- # Creates two accessor methods:
55
+ # Creates three accessor methods:
56
56
  # obj.attr_name:: Return value of instance variable
57
57
  # @attr_name
58
58
  # obj.attr_name = val:: Set value instance variable
@@ -72,6 +72,24 @@ module Rant
72
72
  EOD
73
73
  nil
74
74
  end
75
+ # Creates three accessor methods:
76
+ # obj.attr_name?:: Return value, true or false
77
+ # obj.attr_name:: Set attribute to true
78
+ # obj.no_attr_name:: Set attribute to false
79
+ def rant_flag attr_name
80
+ attr_name = valid_attr_name attr_name
81
+ module_eval <<-EOD
82
+ def #{attr_name}?
83
+ @#{attr_name}
84
+ end
85
+ def #{attr_name}
86
+ @#{attr_name} = true
87
+ end
88
+ def no_#{attr_name}
89
+ @#{attr_name} = false
90
+ end
91
+ EOD
92
+ end
75
93
  # Creates accessor methods like #rant_attr for the attribute
76
94
  # attr_name. Additionally, values are converted with to_str
77
95
  # before assignment to instance variables happens.
@@ -314,6 +332,18 @@ module Rant
314
332
  !self[vid].nil?
315
333
  end
316
334
 
335
+ def _set(vid, val) #:nodoc:
336
+ @store[vid] = val
337
+ end
338
+
339
+ def _get(vid) #:nodoc:
340
+ @store[vid]
341
+ end
342
+
343
+ def _init(vid, val) #:nodoc:
344
+ @store[vid] ||= val
345
+ end
346
+
317
347
  end # class Space
318
348
 
319
349
  module Constraint
data/misc/TODO CHANGED
@@ -1,6 +1,72 @@
1
1
 
2
2
  = TODO
3
3
 
4
+ == Improve SourceNode types
5
+
6
+ Currently a SourceNode can only have other SourceNodes or files as
7
+ prerequisites. But if e.g., a header file should be autogenerated,
8
+ this isn't sufficient anymore.
9
+
10
+ ---
11
+ Update
12
+
13
+ Done (0.4.3) for SignedSourceNodes.
14
+
15
+ == Deprecate plugin API
16
+
17
+ ... and provide alternatives for the Configure and CSharp plugins.
18
+
19
+ == FileList
20
+
21
+ FileList objects need a method which adds a file which won't be
22
+ removed by any pattern (also not affected by var[:ignore]).
23
+
24
+ ---
25
+ Done (0.4.3).
26
+
27
+ Use FileList#<< to append a single entry which won't be removed by
28
+ exclude/ignore patterns.
29
+
30
+ == Semantics of directories as prerequisites of file creating nodes.
31
+
32
+ Currently there are two so called "file creating" nodes: FileTask and
33
+ SignedFile. The following treatments of a directory as prerequisite
34
+ are possible:
35
+
36
+ 1. Current behaviour:
37
+ FileTask:: If a directory node exists, invoke it and compare if
38
+ the modification time of the directory is newer than
39
+ the target file.
40
+ SignedFile:: If a directory node exists, invoke it. If the
41
+ invocation return true, rebuild target file. If no
42
+ directory node exists, create a signature of the
43
+ directory by reading its entries and check this
44
+ signature against the signature of the last time the
45
+ target file was built.
46
+
47
+ 2. Just check if a directory node exists and invoke it. Trigger target
48
+ rebuild if +invoke+ returns true. If no node exists do nothing
49
+ special, the directory doesn't trigger a target file rebuild.
50
+
51
+ I'm currently in favour of #2.
52
+
53
+ ---
54
+ *Update*
55
+
56
+ Current behaviour:
57
+ FileTask:: If a directory node exists, invoke it and compare if
58
+ the modification time of the directory is newer than
59
+ the target file. If no node exists, just compare the
60
+ modification time.
61
+ SignedFile:: If a directory node exists, invoke it and trigger a
62
+ rebuild if +invoke+ returns true. Anyway create a
63
+ signature of the path, which results in a rebuild if
64
+ the directory path changes once. This could be
65
+ considered an inconsistency since path/name changes of
66
+ other prerequisites don't trigger a rebuild.
67
+
68
+ == Don't use testrb as testrunner for RubyTest.
69
+
4
70
  == Solve archiving dependency problem
5
71
  Because of timed depdencies, the archiving tasks don't recognize if
6
72
  the only change is that a file was removed. The only exception is a
@@ -41,4 +41,56 @@ class TestImportCDependenciesOnTheFly < Test::Unit::TestCase
41
41
  assert_rant("-frf.t")
42
42
  assert(File.mtime("bar.t") > old_mtime)
43
43
  end
44
+ def write(fn, content)
45
+ open fn, "w" do |f|
46
+ f.write content
47
+ end
48
+ end
49
+ def test_md5
50
+ write "include/a.tt", <<-EOF
51
+ void abc(void);
52
+ EOF
53
+ write "a.tt", <<-EOF
54
+ #include "a.tt"
55
+ EOF
56
+ write "rf.t", <<-EOF
57
+ import "md5", "c/dependencies", "autoclean"
58
+ gen C::Dependencies,
59
+ :search => ["include"],
60
+ :sources => ["a.tt", "include/a.tt"]
61
+ gen Action do source "c_dependencies" end
62
+ gen AutoClean
63
+ file "a.out" => "a.tt" do |t|
64
+ sys.cp t.source, t.name
65
+ end
66
+ EOF
67
+ out, err = assert_rant("-frf.t", "a.out")
68
+ assert(err.empty?)
69
+ assert(!out.empty?)
70
+ assert(test(?f, "c_dependencies"))
71
+ assert(test(?f, "a.out"))
72
+ assert_equal(File.read("a.tt"), File.read("a.out"))
73
+ out, err = assert_rant("-frf.t", "a.out")
74
+ assert(err.empty?)
75
+ assert(out.empty?)
76
+ write "include/a.tt", <<-EOF
77
+ int abc(void);
78
+ EOF
79
+ out, err = assert_rant("-frf.t", "a.out")
80
+ assert(err.empty?)
81
+ assert(!out.empty?)
82
+ assert(test(?f, "c_dependencies"))
83
+ assert(test(?f, "a.out"))
84
+ assert_equal(File.read("a.tt"), File.read("a.out"))
85
+ out, err = assert_rant("-frf.t", "a.out")
86
+ assert(err.empty?)
87
+ assert(out.empty?)
88
+ assert_rant("-frf.t", "autoclean")
89
+ assert(!test(?e, ".rant.meta"))
90
+ assert(!test(?e, "a.out"))
91
+ assert(test(?f, "include/a.tt"))
92
+ assert(test(?f, "a.tt"))
93
+ ensure
94
+ FileUtils.rm_f %w(include/a.tt a.tt rf.t a.out .rant.meta)
95
+ end
44
96
  end
@@ -0,0 +1,16 @@
1
+
2
+ import "metadata"
3
+
4
+ task :dummy
5
+
6
+ p var[:__metadata__].fetch("cmd", "a")
7
+ var[:__metadata__].set("cmd", "touch a", "a")
8
+
9
+ if var[:subdir]
10
+ subdirs "sub"
11
+ rac.goto "sub"
12
+ p var[:__metadata__].fetch("cmd", "b", "sub")
13
+ rac.goto "#"
14
+ else
15
+ p var[:__metadata__].fetch("cmd", "a")
16
+ end
@@ -0,0 +1,17 @@
1
+
2
+ gen Task, "b" do |t|
3
+ t.needed {
4
+ #puts Dir.pwd
5
+ #puts rac.current_subdir
6
+ rv = var[:__metadata__].fetch("cmd", "b") != "create b"
7
+ #p var[:__metadata__].fetch("cmd", "b")
8
+ #p var[:__metadata__].instance_variable_get(:@read_dirs)
9
+ #p var[:__metadata__].instance_variable_get(:@store)
10
+ rv
11
+ }
12
+ t.act {
13
+ sys.touch t.name
14
+ var[:__metadata__].set("cmd", "create b", "b")
15
+ #p var[:__metadata__].instance_variable_get(:@store)
16
+ }
17
+ end
@@ -0,0 +1,126 @@
1
+
2
+ require 'test/unit'
3
+ require 'tutil'
4
+
5
+ $testImportMetaDataDir ||= File.expand_path(File.dirname(__FILE__))
6
+
7
+ class TestMetaData < Test::Unit::TestCase
8
+ def setup
9
+ # Ensure we run in test directory.
10
+ Dir.chdir($testImportMetaDataDir)
11
+ end
12
+ def teardown
13
+ Dir.chdir($testImportMetaDataDir)
14
+ FileUtils.rm_rf(Dir["*.t"] + %w(.rant.meta sub/.rant.meta sub/b))
15
+ end
16
+ def test_fetch_set_fetch
17
+ out, err = assert_rant
18
+ assert(err.empty?)
19
+ assert_equal("nil\n\"touch a\"\n", out)
20
+ out, err = assert_rant
21
+ assert(err.empty?)
22
+ assert_equal("\"touch a\"\n\"touch a\"\n", out)
23
+ end
24
+ def test_subdir
25
+ out, err = assert_rant("subdir=true", "sub/b")
26
+ assert(err.empty?)
27
+ assert_equal("nil\nnil\ntouch b\n", out)
28
+ assert(test(?f, ".rant.meta"))
29
+ assert(test(?f, "sub/.rant.meta"))
30
+ out, err = assert_rant("subdir=true", "sub/b")
31
+ assert(err.empty?)
32
+ assert_equal("\"touch a\"\n\"create b\"\n", out)
33
+ end
34
+ def test_rant_import
35
+ run_import("-q", "--auto", "make.t")
36
+ assert_exit
37
+ FileUtils.rm ".rant.meta"
38
+ out = run_ruby("make.t", "subdir=true", "sub/b")
39
+ assert_exit
40
+ assert_equal("nil\nnil\ntouch b\n", out)
41
+ assert(test(?f, ".rant.meta"))
42
+ assert(test(?f, "sub/.rant.meta"))
43
+ out = run_ruby("make.t", "subdir=true", "sub/b")
44
+ assert_exit
45
+ assert_equal("\"touch a\"\n\"create b\"\n", out)
46
+ end
47
+ def test_more_commands_and_lines
48
+ FileUtils.mkdir "more.t"
49
+ Dir.chdir "more.t"
50
+ open "Rantfile", "w" do |f|
51
+ f << <<-EOF
52
+ import "metadata"
53
+ task :dummy
54
+ puts var[:__metadata__].fetch("x", "a")
55
+ puts var[:__metadata__].fetch("y", "a")
56
+ puts var[:__metadata__].fetch("x", "b")
57
+ #STDERR.puts(var[:__metadata__].instance_variable_get(:@store).inspect)
58
+ var[:__metadata__].set("x", "1\n2\n\n", "a")
59
+ var[:__metadata__].set("y", "3\n4", "a")
60
+ var[:__metadata__].set("x", "5", "b")
61
+ #STDERR.puts(var[:__metadata__].instance_variable_get(:@store).inspect)
62
+ EOF
63
+ end
64
+ out, err = assert_rant
65
+ assert(err.empty?)
66
+ assert_equal("nil\nnil\nnil\n", out)
67
+ assert(test(?f, ".rant.meta"))
68
+ out, err = assert_rant
69
+ assert(err.empty?)
70
+ assert_equal("1\n2\n3\n4\n5\n", out)
71
+ out, err = assert_rant
72
+ assert(err.empty?)
73
+ assert_equal("1\n2\n3\n4\n5\n", out)
74
+ end
75
+ def test_write_current_version
76
+ top_data = <<EOF
77
+ Rant
78
+ a
79
+ 1
80
+ cmd
81
+ 1
82
+ touch a
83
+ EOF
84
+ sub_data = <<EOF
85
+ Rant
86
+ b
87
+ 1
88
+ cmd
89
+ 1
90
+ create b
91
+ EOF
92
+ assert_rant("subdir=true", "sub/b")
93
+ assert_equal(top_data, File.read(".rant.meta"))
94
+ assert_equal(sub_data, File.read("sub/.rant.meta"))
95
+ end
96
+ def test_read_meta_data_format_version_0_4_4
97
+ assert(!test(?e, ".rant.meta"))
98
+ assert(!test(?e, "sub/.rant.meta"))
99
+ open ".rant.meta", "w" do |f|
100
+ f << <<EOF
101
+ Rant
102
+ a
103
+ 1
104
+ cmd
105
+ 1
106
+ touch a
107
+ EOF
108
+ end
109
+ open "sub/.rant.meta", "w" do |f|
110
+ f << <<EOF
111
+ Rant
112
+ b
113
+ 1
114
+ cmd
115
+ 1
116
+ create b
117
+ EOF
118
+ end
119
+ out, err = assert_rant
120
+ assert(err.empty?)
121
+ assert_equal("\"touch a\"\n\"touch a\"\n", out)
122
+ out, err = assert_rant("subdir=true", "sub/b")
123
+ assert(err.empty?)
124
+ assert_equal("\"touch a\"\n\"create b\"\n", out)
125
+ end
126
+ end
@@ -0,0 +1,89 @@
1
+
2
+ import "md5", "autoclean"
3
+
4
+ var :content => "1\n"
5
+
6
+ task :a => "f1.t"
7
+
8
+ file "f1.t" do |t|
9
+ write_content(t.name)
10
+ end
11
+
12
+ gen Directory, "d1.t"
13
+
14
+ gen Directory, "base.t", "s/s" => ["a.t", "f1.t"] do |t|
15
+ fn = t.name + "/t"
16
+ puts "copying to #{fn}"
17
+ open fn, "w" do |f|
18
+ f.write(File.read(t.source))
19
+ f.write(File.read("f1.t"))
20
+ end; sys.cd "sub1"
21
+ end
22
+
23
+ if var["subfile"]
24
+ import "subfile"
25
+ gen SubFile, "d2.t/f" => "f1.t" do |t|
26
+ sys.cp t.source, t.name
27
+ end
28
+ end
29
+
30
+ file "f2.t" => ["base.t/s/s"] do |t|
31
+ sys.cp "#{t.source}/t", t.name
32
+ end
33
+
34
+ gen SourceNode, "c1.t"
35
+
36
+ gen SourceNode, "c2.t" => ["c1.t", "c3.t"]
37
+
38
+ file "f3.t" => "c1.t" do |t|
39
+ var[:content] = File.read(t.source)
40
+ write_content(t.name)
41
+ end
42
+
43
+ file "f4.t" => ["f3.t", "c2.t"] do |t|
44
+ var[:content] = t.deps.inject("") { |c, fn| c + File.read(fn) }
45
+ write_content(t.name)
46
+ end
47
+
48
+ gen SourceNode, "c4.t" => "c2.t"
49
+
50
+ file "f5.t" => "c2.t" do |t|
51
+ sys.cp t.source, t.name
52
+ end
53
+
54
+ gen SourceNode, "c5.t" => ["sub1/c1.t", "c6.t"]
55
+
56
+ file "f6.t" => "c5.t" do |t|
57
+ write_content(t.name)
58
+ end
59
+
60
+ gen Rule, ".r.t" => ".t" do |t|
61
+ sys.cp t.source, t.name
62
+ end
63
+
64
+ gen Rule, ".r.t" => ".tt" do |t|
65
+ sys.cp t.source, t.name
66
+ end
67
+
68
+ gen SourceNode, "c7.t" => ["f1.t", "c8.t"]
69
+
70
+ file "f7.t" => "c7.t" do |t|
71
+ sys.cp t.source, t.name
72
+ sys.cd "sub1"
73
+ end
74
+
75
+ desc "copy f1.t from sub1 to f8.t"
76
+ file "f8.t" => "sub1/f1.t" do |t|
77
+ sys.cp t.source, t.name
78
+ end
79
+
80
+ subdirs "sub1"
81
+
82
+ def write_content(fn)
83
+ puts "writing #{fn}"
84
+ open fn, "w" do |f|
85
+ f.write var[:content]
86
+ end
87
+ end
88
+
89
+ gen AutoClean
@@ -0,0 +1,6 @@
1
+
2
+ gen SourceNode, "c1.t" => "c2.t"
3
+
4
+ file "f1.t" do |t|
5
+ write_content(t.name)
6
+ end