vanagon 0.9.3 → 0.10.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 79f3affb2f2797cad077ac7341d99cc2f613dd96
4
- data.tar.gz: 4a90613f59d7e96c9015e61ff0200404f063fb3d
3
+ metadata.gz: f50d333d7dc08205687fc7058b19a3580a0b5028
4
+ data.tar.gz: c345a2510f5d6fb4d522a680da59f2aebaa274f3
5
5
  SHA512:
6
- metadata.gz: 0f6b28cd90a8917063035914d5a094ce123aad6991aa721df89bab0c8bd9251e9aafbe924c5253b9c1ea8a6d046fa20149870b448496d126a0d354dd7ebee925
7
- data.tar.gz: 6bc644ee0a223cebe705c0c43d7e69cc4de66b099dc05cfb436967298d21b194b320cb9d385e7beafb9132737eedd945268a93b7b8a75b45540940fdeae3a3c2
6
+ metadata.gz: 259aac01aa4832879c74a99e3578bc9d59d76e07e283729f78ebd71e4807650c508b306f7a1da13c2d7738b989cb0b40f9583ad629e0fe68ad828a35d74f421e
7
+ data.tar.gz: 7b72a6e2947e07cc178fd373cfc381e28f84259715bfa260362334dedda3a6e99a4fe56f1f228ead0f7bbc74d8cdcc41b25e2be9086b55e530bc3a6b30e1d5c4
data/lib/makefile.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'vanagon/environment'
2
+
1
3
  class Makefile
2
4
  # The Rule class defines a single Makefile rule.
3
5
  #
@@ -11,6 +13,11 @@ class Makefile
11
13
  # @return [Array<String>] A list of dependencies that this rule depends on.
12
14
  attr_accessor :dependencies
13
15
 
16
+ # @!attribute [rw] environment
17
+ # @return [Array<String>] A list of environment variables that this rule
18
+ # will export
19
+ attr_accessor :environment
20
+
14
21
  # @!attribute [rw] recipe
15
22
  # @return [Array<String>] A list of commands to execute upon invocation of this rule.
16
23
  attr_accessor :recipe
@@ -36,28 +43,84 @@ class Makefile
36
43
  # "make cpplint",
37
44
  # ]
38
45
  # end
39
- def initialize(target, dependencies: [], recipe: [], &block)
46
+ def initialize(target, dependencies: [], environment: Vanagon::Environment.new, recipe: [], &block)
40
47
  @target = target
41
48
  @dependencies = dependencies
49
+ @environment = environment
42
50
  @recipe = recipe
43
51
 
44
52
  yield(self) if block
45
53
  end
46
54
 
55
+ # @return [String, Nil] the name of all dependencies for a given rule,
56
+ # flattened and joined for a Makefule target
57
+ def flatten_dependencies
58
+ return nil if dependencies.empty?
59
+ dependencies.flatten.join("\s")
60
+ end
61
+
62
+ # @return [String] the base Rule for a Makefile target, including
63
+ # all dependencies.
64
+ def base_target
65
+ ["#{target}:", dependencies].flatten.compact.join("\s")
66
+ end
67
+
68
+ # @return [String] the Makefile target's name, rendered in a format
69
+ # suitable for using as a Graphite group -- any periods in the name of
70
+ # the component being built will be removed.
71
+ # e.g. "ruby-2.1.9-unpack" will become "ruby-219.unpack"
72
+ def tokenize_target_name
73
+ target_name, _, rule = target.rpartition('-')
74
+ [target_name.tr('.', ''), rule]
75
+ .select { |s| !(s.nil? || s.empty?) }
76
+ .join('.')
77
+ end
78
+
79
+ def tokenized_environment_variable
80
+ "#{target}: export VANAGON_TARGET := #{tokenize_target_name}"
81
+ end
82
+
83
+ def environment_variables
84
+ environment.map { |k, v| "#{k} := #{v}" }.map do |env|
85
+ "#{target}: export #{env}"
86
+ end
87
+ end
88
+
47
89
  # Format this rule as a Makefile rule.
48
90
  #
49
91
  # Recipes that have multiline statements will have tabs inserted after each
50
92
  # newline to ensure that the recipe is parsed as part of a single makefile rule.
51
93
  #
52
94
  # @return [String]
53
- def format
54
- s = @target + ":"
55
- unless @dependencies.empty?
56
- s << " " << @dependencies.join(" ")
95
+ def format # rubocop:disable Metrics/AbcSize
96
+ # create a base target inside an Array, and construct the rest of
97
+ # the rule around that.
98
+ t = [base_target]
99
+
100
+ # prepend an environment variable that can be used inside a
101
+ # given Make rule/target. We have to do it this way instead of
102
+ # appending it to #environment because for reasons that I cannot
103
+ # work out, the "sane" way results in previous/incorrect names
104
+ # being used and objects being recycled. My working theory is
105
+ # a corner case between metaprogrammed methods in Component::Rules,
106
+ # and Ruby's preference for pass-by-reference.
107
+ # Ryan McKern 2017-02-02
108
+ t.unshift tokenized_environment_variable
109
+
110
+ # prepend any environment variables to the existing target,
111
+ # using the target prefix to identify them as such. they should
112
+ # end up ahead of the dependencies and the build recipe.
113
+ environment_variables.each do |env|
114
+ t.unshift env
57
115
  end
58
- s << "\n"
59
- s << @recipe.map { |line| "\t" + line.gsub("\n", "\n\t") + "\n" }.join
60
- s
116
+
117
+ # finally, append the build recipe after the base target condition.
118
+ # also, here's a fun edge case: if one were to call #squeeze on
119
+ # the iterator 'line', basically all of the phony make tasks that
120
+ # `touch` a file just disapear. Fragility ++.
121
+ # - Ryan McKern 2017-02-02
122
+ t.push recipe.compact.map { |line| "\t" + line.gsub("\n", "\n\t") + "\n" }.join
123
+ t.join("\n")
61
124
  end
62
125
 
63
126
  alias to_s format
@@ -7,12 +7,101 @@ class Vanagon
7
7
  # @!attribute [r] files
8
8
  # @return [Set] the list of files marked for installation
9
9
 
10
- attr_accessor :name, :version, :source, :url, :configure, :build, :check, :install
11
- attr_accessor :environment, :extract_with, :dirname, :build_requires, :build_dir
12
- attr_accessor :settings, :platform, :patches, :requires, :service, :options
13
- attr_accessor :directories, :replaces, :provides, :conflicts, :cleanup_source
14
- attr_accessor :sources, :preinstall_actions, :postinstall_actions
15
- attr_accessor :preremove_actions, :postremove_actions, :license
10
+ # 30 accessors is too many. These have got to be refactored.
11
+ # - Ryan McKern, 2017-01-27
12
+
13
+ # The name, version, primary source, supplementary sources,
14
+ # associated patches, upstream URL, and license of a given component
15
+ attr_accessor :name
16
+ attr_accessor :version
17
+ attr_accessor :source
18
+ attr_accessor :sources
19
+ attr_accessor :patches
20
+ attr_accessor :url
21
+ attr_accessor :license
22
+
23
+ # holds an OpenStruct describing all of the particular details about
24
+ # how any services associated with a given component should be defined.
25
+ attr_accessor :service
26
+
27
+ # holds the expected directory name of a given component, once it's
28
+ # been unpacked/decompressed. For git repos, it's usually the directory
29
+ # that they were cloned to. For the outlying flat files, it'll
30
+ # end up being defined explicitly as the string './'
31
+ attr_accessor :dirname
32
+ # what special tool should be used to extract the primary source
33
+ attr_accessor :extract_with
34
+ # how should this component be configured?
35
+ attr_accessor :configure
36
+ # the optional name of a directory to build a component in; most
37
+ # likely to be used for cmake projects, which do not like to be
38
+ # configured or compiled in their own top-level directories.
39
+ attr_accessor :build_dir
40
+ # build will hold an Array of the commands required to build
41
+ # a given component
42
+ attr_accessor :build
43
+ # check will hold an Array of the commands required to validate/test
44
+ # a given component
45
+ attr_accessor :check
46
+ # install will hold an Array of the commands required to install
47
+ # a given component
48
+ attr_accessor :install
49
+
50
+ # holds a Vanagon::Environment object, to map out any desired
51
+ # environment variables that should be rendered into the Makefile
52
+ attr_accessor :environment
53
+ # holds a OpenStruct, or an Array, or maybe it's a Hash? It's often
54
+ # overloaded as a freeform key-value lookup for platforms that require
55
+ # additional configuration beyond the "basic" component attributes.
56
+ # it's pretty heavily overloaded and should maybe be refactored before
57
+ # Vanagon 1.0.0 is tagged.
58
+ attr_accessor :settings
59
+ # used to hold the checksum settings or other weirdo metadata related
60
+ # to building a given component (git ref, sha, etc.). Probably conflicts
61
+ # or collides with #settings to some degree.
62
+ attr_accessor :options
63
+ # the platform that a given component will be built for -- due to the
64
+ # fact that Ruby is pass-by-reference, it's usually just a reference
65
+ # to the same Platform object that the overall Project object also
66
+ # contains. This is a definite code smell, and should be slated
67
+ # for refactoring ASAP because it's going to have weird side-effects
68
+ # if the underlying pass-by-reference assumptions change.
69
+ attr_accessor :platform
70
+
71
+ # directories holds an Array with a list of expected directories that will
72
+ # be packed into the resulting artifact's bill of materials.
73
+ attr_accessor :directories
74
+ # build_requires holds an Array with a list of the dependencies that a given
75
+ # component needs satisfied before it can be built.
76
+ attr_accessor :build_requires
77
+ # requires holds an Array with a list of all dependencies that a given
78
+ # component needs satisfied before it can be installed.
79
+ attr_accessor :requires
80
+ # replaces holds an Array of OpenStructs that describe a package that a given
81
+ # component will replace on installation.
82
+ attr_accessor :replaces
83
+ # provides holds an Array of OpenStructs that describe any capabilities that
84
+ # a given component will provide beyond the its filesystem payload.
85
+ attr_accessor :provides
86
+ # conflicts holds an Array of OpenStructs that describe a package that a
87
+ # given component will replace on installation.
88
+ attr_accessor :conflicts
89
+ # preinstall_actions is a two-dimensional Array, describing scripts that
90
+ # should be executed before a given component is installed.
91
+ attr_accessor :preinstall_actions
92
+ # postinstall_actions is a two-dimensional Array, describing scripts that
93
+ # should be executed after a given component is installed.
94
+ attr_accessor :postinstall_actions
95
+ # preremove_actions is a two-dimensional Array, describing scripts that
96
+ # should be executed before a given component is uninstalled.
97
+ attr_accessor :preremove_actions
98
+ # preinstall_actions is a two-dimensional Array, describing scripts that
99
+ # should be executed after a given component is uninstalled.
100
+ attr_accessor :postremove_actions
101
+ # cleanup_source contains whatever value a given component's Source has
102
+ # specified as instructions for cleaning up after a build is completed.
103
+ # usually a String, but not required to be.
104
+ attr_accessor :cleanup_source
16
105
 
17
106
  # Loads a given component from the configdir
18
107
  #
@@ -58,7 +147,7 @@ class Vanagon
58
147
  @replaces = []
59
148
  @provides = []
60
149
  @conflicts = []
61
- @environment = {}
150
+ @environment = Vanagon::Environment.new
62
151
  @sources = []
63
152
  @preinstall_actions = []
64
153
  @postinstall_actions = []
@@ -111,7 +200,7 @@ class Vanagon
111
200
  @source = Vanagon::Component::Source.source(url, opts)
112
201
  source.fetch
113
202
  source.verify
114
- @extract_with = source.respond_to?(:extract) ? source.extract(platform.tar) : ':'
203
+ @extract_with = source.respond_to?(:extract) ? source.extract(platform.tar) : nil
115
204
  @cleanup_source = source.cleanup if source.respond_to?(:cleanup)
116
205
  @dirname = source.dirname
117
206
 
@@ -126,7 +215,7 @@ class Vanagon
126
215
  @dirname = './'
127
216
 
128
217
  # If there is no source, there is nothing to do to extract
129
- @extract_with = ':'
218
+ @extract_with = ': no source, so nothing to extract'
130
219
  end
131
220
  end
132
221
 
@@ -144,10 +233,9 @@ class Vanagon
144
233
  # @param workdir [String] working directory to put the source into
145
234
  def get_sources(workdir)
146
235
  sources.each do |source|
147
- src = Vanagon::Component::Source.source source.url,
148
- workdir: workdir,
149
- ref: source.ref,
150
- sum: source.sum
236
+ src = Vanagon::Component::Source.source(
237
+ source.url, workdir: workdir, ref: source.ref, sum: source.sum
238
+ )
151
239
  src.fetch
152
240
  src.verify
153
241
  end
@@ -165,12 +253,20 @@ class Vanagon
165
253
  end
166
254
 
167
255
  # Prints the environment in a way suitable for use in a Makefile
168
- # or shell script.
256
+ # or shell script. This is deprecated, because all Env. Vars. are
257
+ # moving directly into the Makefile (and out of recipe subshells).
169
258
  #
170
259
  # @return [String] environment suitable for inclusion in a Makefile
260
+ # @deprecated
171
261
  def get_environment
262
+ warn <<-eos.undent
263
+ #get_environment is deprecated; environment variables have been moved
264
+ into the Makefile, and should not be used within a Makefile's recipe.
265
+ The #get_environment method will be removed by Vanagon 1.0.0.
266
+ eos
267
+
172
268
  if @environment.empty?
173
- ":"
269
+ ": no environment variables defined"
174
270
  else
175
271
  env = @environment.map { |key, value| %(#{key}="#{value}") }
176
272
  "export #{env.join(' ')}"
@@ -230,14 +230,14 @@ class Vanagon
230
230
  # upgrade if it has been modified
231
231
  #
232
232
  # @param file [String] name of the configfile
233
- def configfile(file, mode: nil, owner: nil, group: nil)
233
+ def configfile(file)
234
234
  # I AM SO SORRY
235
235
  @component.delete_file file
236
236
  if @component.platform.name =~ /solaris-10|osx/
237
237
  @component.install << "mv '#{file}' '#{file}.pristine'"
238
- @component.add_file Vanagon::Common::Pathname.configfile("#{file}.pristine", mode: mode, owner: owner, group: group)
238
+ @component.add_file Vanagon::Common::Pathname.configfile("#{file}.pristine")
239
239
  else
240
- @component.add_file Vanagon::Common::Pathname.configfile(file, mode: mode, owner: owner, group: group)
240
+ @component.add_file Vanagon::Common::Pathname.configfile(file)
241
241
  end
242
242
  end
243
243
 
@@ -245,9 +245,9 @@ class Vanagon
245
245
  #
246
246
  # @param source [String] path to the configfile to copy
247
247
  # @param target [String] path to the desired target of the configfile
248
- def install_configfile(source, target, mode: '0644', owner: nil, group: nil)
249
- install_file(source, target, mode: mode, owner: owner, group: group)
250
- configfile(target, mode: mode, owner: owner, group: group)
248
+ def install_configfile(source, target)
249
+ install_file(source, target)
250
+ configfile(target)
251
251
  end
252
252
 
253
253
  # link will add a command to the install to create a symlink from source to target
@@ -339,8 +339,25 @@ class Vanagon
339
339
  # This environment is included in the configure, build and install steps.
340
340
  #
341
341
  # @param env [Hash] mapping of keys to values to add to the environment for the component
342
- def environment(env)
343
- @component.environment.merge!(env)
342
+ def environment(*env) # rubocop:disable Metrics/AbcSize
343
+ if env.size == 1 && env.first.is_a?(Hash)
344
+ warn <<-eos.undent
345
+ the component DSL method signature #environment({Key => Value}) is deprecated
346
+ and will be removed by Vanagon 1.0.0.
347
+
348
+ Please update your project configurations to use the form:
349
+ #environment(key, value)
350
+ eos
351
+ return @component.environment.merge!(env.first)
352
+ elsif env.size == 2
353
+ return @component.environment[env.key] = env.value
354
+ end
355
+ raise ArgumentError, <<-eos.undent
356
+ component DSL method #environment only accepts a single Hash (deprecated)
357
+ or a key-value pair (preferred):
358
+ environment({"KEY" => "value"})
359
+ environment("KEY", "value")
360
+ eos
344
361
  end
345
362
 
346
363
  # Adds action to run during the preinstall phase of packaging
@@ -20,14 +20,18 @@ class Vanagon
20
20
  #
21
21
  # @!macro [attach] rule
22
22
  # @return [Makefile::Rule] The $1 rule
23
- def self.rule(target, dependencies: [], &block)
23
+ def self.rule(target, &block)
24
24
  define_method("#{target}_rule") do
25
- Makefile::Rule.new("#{@component.name}-#{target}", dependencies: dependencies) do |rule|
25
+ Makefile::Rule.new("#{component.name}-#{target}", environment: component.environment) do |rule|
26
26
  instance_exec(rule, &block)
27
27
  end
28
28
  end
29
29
  end
30
30
 
31
+ attr_accessor :component
32
+ attr_accessor :project
33
+ attr_accessor :platform
34
+
31
35
  # @param component [Vanagon::Component] The component to create rules for.
32
36
  # @param project [Vanagon::Project] The project associated with the component.
33
37
  # @param platform [Vanagon::Platform] The platform where this component will be built.
@@ -55,7 +59,7 @@ class Vanagon
55
59
  clean_rule,
56
60
  clobber_rule,
57
61
  ]
58
- if @project.cleanup
62
+ if project.cleanup
59
63
  list << cleanup_rule
60
64
  end
61
65
 
@@ -66,27 +70,29 @@ class Vanagon
66
70
  #
67
71
  # @return [Makefile::Rule]
68
72
  def component_rule
69
- Makefile::Rule.new(@component.name, dependencies: ["#{@component.name}-install"])
73
+ Makefile::Rule.new(component.name, environment: component.environment) do |rule|
74
+ rule.dependencies = ["#{component.name}-install"]
75
+ end
70
76
  end
71
77
 
72
78
  # Unpack the source for this component. The unpacking behavior depends on
73
79
  # the source type of the component.
74
80
  #
75
81
  # @see [Vanagon::Component::Source]
76
- rule("unpack", dependencies: ['file-list-before-build']) do |r|
77
- r.recipe << andand(@component.get_environment, @component.extract_with)
82
+ rule("unpack") do |r|
83
+ r.dependencies = ['file-list-before-build']
84
+ r.recipe << component.extract_with
78
85
  r.recipe << "touch #{r.target}"
79
86
  end
80
87
 
81
88
  # Apply any patches for this component.
82
89
  rule("patch") do |r|
83
- r.dependencies = ["#{@component.name}-unpack"]
84
-
85
- after_unpack_patches = @component.patches.select { |patch| patch.after == "unpack" }
90
+ r.dependencies = ["#{component.name}-unpack"]
91
+ after_unpack_patches = component.patches.select { |patch| patch.after == "unpack" }
86
92
  unless after_unpack_patches.empty?
87
93
  r.recipe << andand_multiline(
88
- "cd #{@component.dirname}",
89
- after_unpack_patches.map { |patch| patch.cmd(@platform) }
94
+ "cd #{component.dirname}",
95
+ after_unpack_patches.map { |patch| patch.cmd(platform) }
90
96
  )
91
97
  end
92
98
 
@@ -96,17 +102,15 @@ class Vanagon
96
102
  # Create a build directory for this component if an out of source tree build is specified,
97
103
  # and any configure steps, if any.
98
104
  rule("configure") do |r|
99
- r.dependencies = ["#{@component.name}-patch"].concat(@project.list_component_dependencies(@component))
100
-
101
- if @component.get_build_dir
102
- r.recipe << "[ -d #{@component.get_build_dir} ] || mkdir -p #{@component.get_build_dir}"
105
+ r.dependencies = ["#{component.name}-patch"].concat(project.list_component_dependencies(component))
106
+ if component.get_build_dir
107
+ r.recipe << "[ -d #{component.get_build_dir} ] || mkdir -p #{component.get_build_dir}"
103
108
  end
104
109
 
105
- unless @component.configure.empty?
110
+ unless component.configure.empty?
106
111
  r.recipe << andand_multiline(
107
- "cd #{@component.get_build_dir}",
108
- @component.get_environment,
109
- @component.configure
112
+ "cd #{component.get_build_dir}",
113
+ component.configure
110
114
  )
111
115
  end
112
116
 
@@ -115,13 +119,11 @@ class Vanagon
115
119
 
116
120
  # Build this component.
117
121
  rule("build") do |r|
118
- r.dependencies = ["#{@component.name}-configure"]
119
-
120
- unless @component.build.empty?
122
+ r.dependencies = ["#{component.name}-configure"]
123
+ unless component.build.empty?
121
124
  r.recipe << andand_multiline(
122
- "cd #{@component.get_build_dir}",
123
- @component.get_environment,
124
- @component.build
125
+ "cd #{component.get_build_dir}",
126
+ component.build
125
127
  )
126
128
  end
127
129
 
@@ -130,13 +132,11 @@ class Vanagon
130
132
 
131
133
  # Run tests for this component.
132
134
  rule("check") do |r|
133
- r.dependencies = ["#{@component.name}-build"]
134
-
135
- unless @component.check.empty? || @project.settings[:skipcheck]
135
+ r.dependencies = ["#{component.name}-build"]
136
+ unless component.check.empty? || project.settings[:skipcheck]
136
137
  r.recipe << andand_multiline(
137
- "cd #{@component.get_build_dir}",
138
- @component.get_environment,
139
- @component.check
138
+ "cd #{component.get_build_dir}",
139
+ component.check
140
140
  )
141
141
  end
142
142
 
@@ -145,21 +145,19 @@ class Vanagon
145
145
 
146
146
  # Install this component.
147
147
  rule("install") do |r|
148
- r.dependencies = ["#{@component.name}-check"]
149
-
150
- unless @component.install.empty?
148
+ r.dependencies = ["#{component.name}-check"]
149
+ unless component.install.empty?
151
150
  r.recipe << andand_multiline(
152
- "cd #{@component.get_build_dir}",
153
- @component.get_environment,
154
- @component.install
151
+ "cd #{component.get_build_dir}",
152
+ component.install
155
153
  )
156
154
  end
157
155
 
158
- after_install_patches = @component.patches.select { |patch| patch.after == "install" }
156
+ after_install_patches = component.patches.select { |patch| patch.after == "install" }
159
157
  after_install_patches.each do |patch|
160
158
  r.recipe << andand(
161
159
  "cd #{patch.destination}",
162
- patch.cmd(@platform),
160
+ patch.cmd(platform),
163
161
  )
164
162
  end
165
163
 
@@ -171,8 +169,8 @@ class Vanagon
171
169
  # This component is only included by {#rules} if the associated project has
172
170
  # the `cleanup` attribute set.
173
171
  rule("cleanup") do |r|
174
- r.dependencies = ["#{@component.name}-install"]
175
- r.recipe = [@component.cleanup_source, "touch #{r.target}"]
172
+ r.dependencies = ["#{component.name}-install"]
173
+ r.recipe = [component.cleanup_source, "touch #{r.target}"]
176
174
  end
177
175
 
178
176
  # Clean up any files generated while building this project.
@@ -181,13 +179,13 @@ class Vanagon
181
179
  # for the configure/build/install steps.
182
180
  rule("clean") do |r|
183
181
  r.recipe << andand(
184
- "[ -d #{@component.get_build_dir} ]",
185
- "cd #{@component.get_build_dir}",
186
- "#{@platform[:make]} clean"
182
+ "[ -d #{component.get_build_dir} ]",
183
+ "cd #{component.get_build_dir}",
184
+ "#{platform[:make]} clean"
187
185
  )
188
186
 
189
187
  %w(configure build install).each do |type|
190
- touchfile = "#{@component.name}-#{type}"
188
+ touchfile = "#{component.name}-#{type}"
191
189
  r.recipe << andand(
192
190
  "[ -e #{touchfile} ]",
193
191
  "rm #{touchfile}"
@@ -197,10 +195,10 @@ class Vanagon
197
195
 
198
196
  # Remove all files associated with this component.
199
197
  rule("clobber") do |r|
200
- r.dependencies = ["#{@component.name}-clean"]
198
+ r.dependencies = ["#{component.name}-clean"]
201
199
  r.recipe = [
202
- andand("[ -d #{@component.dirname} ]", "rm -r #{@component.dirname}"),
203
- andand("[ -e #{@component.name}-unpack ]", "rm #{@component.name}-unpack")
200
+ andand("[ -d #{component.dirname} ]", "rm -r #{component.dirname}"),
201
+ andand("[ -e #{component.name}-unpack ]", "rm #{component.name}-unpack")
204
202
  ]
205
203
  end
206
204