fpm-fry 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9d58721a3f79317f65181422ff3a7e5d28ef823e
4
- data.tar.gz: 85229c608182080d92b67b81c2e6d09f701d19ba
3
+ metadata.gz: 9052cdc66f349423b938cefae76a81ddf5504c65
4
+ data.tar.gz: 6084e244c0f01eb10f0c4ec2dbd6f18f1831ddd4
5
5
  SHA512:
6
- metadata.gz: 5fc67b6dcbe5d6d8944028721665cbee9ae9bdb4f615c68812e012063e66c22ab278b943dc155d1e2ecc58e23021af133e8c0f29185db0ba0b5faa4f2dba5e5e
7
- data.tar.gz: 03c12a7c8743715a8a33fff09c84e423ef67cbcd6a4a3a8659a6f7a1bd0b2e361797932117478950fb6ca6e5ac9af35049a4087c094a521b16a3e16a8d1fe22a
6
+ metadata.gz: 3667766c65cb233def8e06ae14029bea06ebae06f03a8f9b5a4c45ae9d851557dcef27a510c8a361d8099b8a50f1ebb632182598192c27ae5355f1c908611ec0
7
+ data.tar.gz: 81c95585118d529c4438b09aff3c96b3044b60a8b181d65bb6611635dc5fed9d672083796b13afb3fe6b4e38acdf81b1f9b54fbf3ade555b68237b12cc74d132
@@ -2,24 +2,31 @@ module FPM; module Fry
2
2
  class BlockEnumerator < Struct.new(:io, :blocksize)
3
3
  include Enumerable
4
4
 
5
+ # @param io [IO]
6
+ # @param blocksize [Numeric]
5
7
  def initialize(_, blocksize = 128)
6
8
  super
7
9
  end
8
10
 
11
+ # @return [Enumerator] unless called with a block
12
+ # @yield [chunk] One chunk from the io
13
+ # @yieldparam chunk [String]
9
14
  def each
10
15
  return to_enum unless block_given?
11
- # Reading bigger chunks is far more efficient that eaching over the
16
+ # Reading bigger chunks is far more efficient than invoking #each on an IO.
12
17
  while chunk = io.read(blocksize)
13
18
  yield chunk
14
19
  end
20
+ return nil
15
21
  end
16
22
 
23
+ # @return [String] chunk or empty string at EOF
17
24
  def call
18
25
  while x = io.read(blocksize)
19
26
  next if x == ""
20
27
  return x
21
28
  end
22
29
  return ""
23
- end
30
+ end
24
31
  end
25
32
  end ; end
@@ -19,5 +19,25 @@ module FPM; module Fry
19
19
 
20
20
  include Hint
21
21
 
22
+ # @private
23
+ def _log(message, data={})
24
+ case message
25
+ when Hash
26
+ data.merge!(message)
27
+ when Exception
28
+ # message is an exception
29
+ data[:message] = message.to_s
30
+ data[:exception] = message
31
+ data[:backtrace] = message.backtrace
32
+ if message.respond_to? :data
33
+ data = message.data.merge(data)
34
+ end
35
+ else
36
+ data = { :message => message }.merge(data)
37
+ end
38
+
39
+ publish(data)
40
+ end
41
+
22
42
  end
23
43
  end ; end
@@ -0,0 +1,119 @@
1
+ require 'fpm/fry/with_data'
2
+ module FPM ; module Fry
3
+ # Helper class for filesystem operations inside staging directory.
4
+ # Resolves all symlinks relativ to a given base directory.
5
+ class Chroot
6
+
7
+ attr :base
8
+
9
+ # @param [String] base filesystem base
10
+ def initialize(base)
11
+ raise ArgumentError, "Base #{base.inspect} is not a directory" unless File.directory? base
12
+ @base = base
13
+ end
14
+
15
+ # Returns all directory entries like Dir.entries.
16
+ # @param [String] path
17
+ # @result [Array<String>] entries
18
+ def entries(path)
19
+ dir = rebase(path)
20
+ return Dir.entries(dir)
21
+ rescue => ex
22
+ raise Fry::WithData(ex, path: path)
23
+ end
24
+
25
+ # Opens a file like File.open.
26
+ # @param [String] path
27
+ # @see (File.open)
28
+ def open(path,*args,&block)
29
+ file = rebase(path)
30
+ return File.open(file,*args,&block)
31
+ rescue => ex
32
+ raise Fry::WithData(ex, path: path)
33
+ end
34
+
35
+ # Yields all entries recursively like Find.find.
36
+ # @param [String] path
37
+ # @yields entry
38
+ # @yieldparam [String] entry
39
+ def find(path, &block)
40
+ if stat(path).directory?
41
+ catch(:prune) do
42
+ block.call(path)
43
+ entries(path).each do | e |
44
+ next if e == "."
45
+ next if e == ".."
46
+ ep = File.join(path,e)
47
+ find(ep, &block)
48
+ end
49
+ end
50
+ else
51
+ block.call(path)
52
+ end
53
+ return nil
54
+ end
55
+
56
+ # Stats a file without following the last symlink like File.lstat.
57
+ # @param [String] file
58
+ # @return [File::Stat] stat
59
+ # @see (File.lstat)
60
+ def lstat(file)
61
+ File.lstat(rebase(file, FOLLOW_ALL_BUT_LAST))
62
+ end
63
+
64
+ # Stats a file like File.stat.
65
+ # @param [String] file
66
+ # @return [File::Stat] stat
67
+ # @see (File.stat)
68
+ def stat(file)
69
+ File.stat(rebase(file))
70
+ end
71
+
72
+ private
73
+
74
+ FOLLOW = lambda do |base, current, rest|
75
+ path = [base, *current].join('/')
76
+ if File.symlink?(path)
77
+ File.readlink(path)
78
+ else
79
+ nil
80
+ end
81
+ end
82
+
83
+ FOLLOW_ALL_BUT_LAST = lambda do |base, current, rest|
84
+ if rest.any?
85
+ FOLLOW.call(base, current, rest)
86
+ else
87
+ nil
88
+ end
89
+ end
90
+
91
+ def rebase(path, symlink_strategy = FOLLOW)
92
+ segs = path.split('/')
93
+ current = []
94
+ while segs.any?
95
+ seg = segs.shift
96
+ case seg
97
+ when '', '.' then next
98
+ when '..' then
99
+ # We don't check if anything was actually removed.
100
+ # This is consistent with File/Dir behavior.
101
+ current.pop
102
+ else
103
+ current << seg
104
+ rl = symlink_strategy.call(base, current, segs)
105
+ if rl
106
+ if rl.start_with? '/'
107
+ current = []
108
+ else
109
+ current.pop
110
+ end
111
+ segs.unshift *rl.split('/')
112
+ end
113
+ end
114
+ end
115
+ return [base,*current].join('/')
116
+ end
117
+
118
+ end
119
+ end ; end
@@ -90,31 +90,25 @@ module FPM; module Fry
90
90
  df << "FROM #{base}"
91
91
  df << "WORKDIR /tmp/build"
92
92
 
93
- deps = (recipe.build_depends.merge recipe.depends)\
94
- .select{|_,v| v.fetch(:install,true) }\
95
- .map do |k,v|
96
- i = v.fetch(:install,true)
97
- if i == true then
98
- k
99
- else
100
- i
101
- end
102
- end.sort
103
- if deps.any?
93
+ if build_dependencies.any?
104
94
  case(variables[:flavour])
105
95
  when 'debian'
106
96
  update = ''
107
97
  if options[:update]
108
98
  update = 'apt-get update && '
109
99
  end
110
- df << "RUN #{update}apt-get install --yes #{Shellwords.join(deps)}"
100
+ df << "RUN #{update}apt-get install --yes #{Shellwords.join(build_dependencies)}"
111
101
  when 'redhat'
112
- df << "RUN yum -y install #{Shellwords.join(deps)}"
102
+ df << "RUN yum -y install #{Shellwords.join(build_dependencies)}"
113
103
  else
114
104
  raise "Unknown flavour: #{variables[:flavour]}"
115
105
  end
116
106
  end
117
107
 
108
+ recipe.before_build_steps.each do |step|
109
+ df << "RUN #{step.to_s}"
110
+ end
111
+
118
112
  df << "ADD .build.sh /tmp/build/"
119
113
  df << "ENTRYPOINT /tmp/build/.build.sh"
120
114
  df << ''
@@ -147,6 +141,27 @@ module FPM; module Fry
147
141
  sio.rewind
148
142
  return sio
149
143
  end
144
+
145
+ private
146
+ def build_dependencies
147
+ return @build_dependencies if @build_dependencies
148
+ deps = []
149
+ (recipe.build_depends.merge recipe.depends).each do |k,v|
150
+ install = v.fetch(:install,true)
151
+ next unless install
152
+ case( install )
153
+ when true
154
+ deps << simplify_build_dependency(k)
155
+ when String
156
+ deps << simplify_build_dependency(install)
157
+ end
158
+ end
159
+ @build_dependencies = deps.sort
160
+ end
161
+
162
+ def simplify_build_dependency( dep )
163
+ dep.split('|').first.strip
164
+ end
150
165
  end
151
166
 
152
167
  end
@@ -1,13 +1,18 @@
1
1
  module FPM; module Fry
2
+ # Joins together multiple IOs
2
3
  class JoinedIO
3
4
  include Enumerable
4
5
 
6
+ # @param [IO] ios
5
7
  def initialize(*ios)
6
8
  @ios = ios
7
9
  @pos = 0
8
10
  @readbytes = 0
9
11
  end
10
12
 
13
+ # Reads length bytes or all if length is nil.
14
+ # @param [Numeric, nil] length
15
+ # @return [String] resulting bytes
11
16
  def read( len = nil )
12
17
  buf = []
13
18
  if len.nil?
@@ -35,27 +40,37 @@ module FPM; module Fry
35
40
  end
36
41
  end
37
42
 
38
- def readpartial( len )
43
+ # Reads up to length bytes.
44
+ # @param [Numeric] length
45
+ # @return [String] chunk
46
+ # @return [nil] at eof
47
+ def readpartial( length )
39
48
  while (io = @ios[@pos])
40
- r = io.read( len )
49
+ r = io.read( length )
41
50
  if r.nil?
42
51
  @pos = @pos + 1
43
52
  next
44
53
  else
54
+ if io.eof?
55
+ @pos = @pos + 1
56
+ end
45
57
  return r
46
58
  end
47
59
  end
48
60
  return nil
49
61
  end
50
62
 
63
+ # @return [Numeric] number bytes read
51
64
  def pos
52
65
  @readbytes
53
66
  end
54
67
 
68
+ # @return [true,false]
55
69
  def eof?
56
70
  @pos == @ios.size
57
71
  end
58
72
 
73
+ # Closes all IOs.
59
74
  def close
60
75
  @ios.each(&:close)
61
76
  end
@@ -1,4 +1,5 @@
1
1
  require 'fpm/fry/plugin'
2
+ require 'fpm/fry/chroot'
2
3
  module FPM::Fry::Plugin::Config
3
4
 
4
5
  # @api private
@@ -15,6 +16,7 @@ module FPM::Fry::Plugin::Config
15
16
  class Callback < Struct.new(:files)
16
17
 
17
18
  def call(_, package)
19
+ chroot = FPM::Fry::Chroot.new(package.staging_path)
18
20
  prefix_length = package.staging_path.size + 1
19
21
  candidates = []
20
22
  # Sorting is important so that more specific rules override more generic
@@ -23,10 +25,31 @@ module FPM::Fry::Plugin::Config
23
25
  keys.each do | key |
24
26
  if files[key]
25
27
  # Inclusion rule. Crawl file system for candidates
26
- Find.find( File.expand_path(key, package.staging_path) ) do | path |
27
- next unless File.file? path
28
- name = path[prefix_length..-1]
29
- candidates << name
28
+ begin
29
+ lstat = chroot.lstat( key )
30
+ if lstat.symlink?
31
+ package.logger.warn("Config file is a symlink",
32
+ path: key,
33
+ plugin: 'config',
34
+ documentation: 'https://github.com/xing/fpm-fry/wiki/Plugin-config#config-path-not-foun://github.com/xing/fpm-fry/wiki/Plugin-config#config-file-is-a-symlink')
35
+ next
36
+ end
37
+ chroot.find( key ) do | path |
38
+ lstat = chroot.lstat(path)
39
+ if lstat.symlink?
40
+ package.logger.debug("Ignoring symlink",
41
+ path: path,
42
+ plugin: 'config')
43
+ throw :prune
44
+ elsif lstat.file?
45
+ candidates << path
46
+ end
47
+ end
48
+ rescue Errno::ENOENT
49
+ package.logger.warn("Config path not found",
50
+ path: key,
51
+ plugin: 'config',
52
+ documentation: 'https://github.com/xing/fpm-fry/wiki/Plugin-config#config-path-not-found')
30
53
  end
31
54
  else
32
55
  # Exclusion rule. Remove matching candidates
@@ -1,10 +1,18 @@
1
+ require 'stringio'
1
2
  require 'fpm/fry/plugin'
2
3
  require 'fileutils'
4
+ # A plugin to edit the final build results.
5
+ # @example Add a file
6
+ # plugin 'edit_staging' do
7
+ # add_file '/a_file'
8
+ # end
3
9
  module FPM::Fry::Plugin::EditStaging
4
10
 
11
+ # @api private
5
12
  class AddFile < Struct.new(:path, :io, :options)
6
13
  def call(_ , package)
7
14
  file = package.staging_path(path)
15
+ package.logger.debug("Writing file directly to staging", target: file, content: io.inspect)
8
16
  FileUtils.mkdir_p(File.dirname(file))
9
17
  File.open(file,'w') do | f |
10
18
  IO.copy_stream(io, f)
@@ -16,16 +24,28 @@ module FPM::Fry::Plugin::EditStaging
16
24
  end
17
25
  end
18
26
 
27
+ # @api private
19
28
  class LnS < Struct.new(:src, :dest)
20
29
  def call(_ , package)
21
30
  file = package.staging_path(dest)
31
+ package.logger.debug("Linking file directly in staging", target: file, to: src)
22
32
  FileUtils.mkdir_p(File.dirname(file))
23
33
  File.symlink(src, file)
24
34
  end
25
35
  end
26
36
 
27
37
  class DSL < Struct.new(:builder)
28
- def add_file(path, io, options = {})
38
+
39
+ # @param [String] path
40
+ # @param [IO, String] content
41
+ def add_file(path, content, options = {})
42
+ if content.kind_of?(IO) || content.kind_of?(StringIO)
43
+ io = content
44
+ elsif content.kind_of? String
45
+ io = StringIO.new(content)
46
+ else
47
+ raise ArgumentError.new("File content must be a String or IO, got #{content.inspect}")
48
+ end
29
49
  options = options.dup
30
50
  options[:chmod] = convert_chmod(options[:chmod]) if options[:chmod]
31
51
  options.freeze
@@ -51,6 +71,9 @@ module FPM::Fry::Plugin::EditStaging
51
71
 
52
72
  end
53
73
 
74
+ # @yield [dsl]
75
+ # @yieldparam [DSL] dsl
76
+ # @return [DSL]
54
77
  def self.apply(builder, &block)
55
78
  d = DSL.new(builder)
56
79
  if !block
@@ -92,9 +92,17 @@ module FPM::Fry::Plugin ; module Service
92
92
  sh.after_install_or_upgrade(<<BASH)
93
93
  if status #{Shellwords.shellescape name} 2>/dev/null | grep -q ' start/'; then
94
94
  # It has to be stop+start because upstart doesn't pickup changes with restart.
95
- stop #{Shellwords.shellescape name}
95
+ if which invoke-rc.d >/dev/null 2>&1; then
96
+ invoke-rc.d #{Shellwords.shellescape name} stop
97
+ else
98
+ stop #{Shellwords.shellescape name}
99
+ fi
100
+ fi
101
+ if which invoke-rc.d >/dev/null 2>&1; then
102
+ invoke-rc.d #{Shellwords.shellescape name} start
103
+ else
104
+ start #{Shellwords.shellescape name}
96
105
  fi
97
- start #{Shellwords.shellescape name}
98
106
  BASH
99
107
  sh.before_remove_entirely(<<BASH)
100
108
  if status #{Shellwords.shellescape name} 2>/dev/null | grep -q ' start/'; then
@@ -104,7 +112,6 @@ BASH
104
112
  end
105
113
  builder.plugin('config', FPM::Fry::Plugin::Config::IMPLICIT => true) do |co|
106
114
  co.include "etc/init/#{name}.conf"
107
- co.include "etc/init.d/#{name}"
108
115
  end
109
116
  when 'sysv' then
110
117
  edit.add_file "/etc/init.d/#{name}",StringIO.new( env.render('sysv.erb') ), chmod: '750'
@@ -1,4 +1,5 @@
1
1
  require 'fpm/fry/recipe'
2
+ require 'fpm/fry/recipe/error'
2
3
  require 'forwardable'
3
4
  module FPM::Fry
4
5
  class Recipe
@@ -52,11 +53,21 @@ module FPM::Fry
52
53
 
53
54
  def depends( name , options = {} )
54
55
  name, options = parse_package(name, options)
56
+ if package_recipe.depends.key? name
57
+ raise Error.new("duplicate dependency",package: name)
58
+ elsif package_recipe.conflicts.key? name
59
+ raise Error.new("depending package is already a conflicting package",package: name)
60
+ end
55
61
  package_recipe.depends[name] = options
56
62
  end
57
63
 
58
64
  def conflicts( name , options = {} )
59
65
  name, options = parse_package(name, options)
66
+ if package_recipe.conflicts.key? name
67
+ raise Error.new("duplicate conflict",package: name)
68
+ elsif package_recipe.depends.key? name
69
+ raise Error.new("conflicting package is already a dependency",package: name)
70
+ end
60
71
  package_recipe.conflicts[name] = options
61
72
  end
62
73
 
@@ -176,7 +187,9 @@ module FPM::Fry
176
187
  end
177
188
  variables.freeze
178
189
  @recipe = recipe
179
- super(variables, recipe.packages[0], options = {})
190
+ @before_build = false
191
+ register_default_source_types!
192
+ super(variables, recipe.packages[0], options)
180
193
  end
181
194
 
182
195
  def load_file( file )
@@ -213,12 +226,23 @@ module FPM::Fry
213
226
 
214
227
  def bash( name = nil, code )
215
228
  if name
216
- recipe.steps << Recipe::Step.new(name, code)
229
+ code = Recipe::Step.new(name, code)
230
+ end
231
+ # Don't do this at home
232
+ if @before_build
233
+ recipe.before_build_steps << code
217
234
  else
218
- recipe.steps << code.to_s
235
+ recipe.steps << code
219
236
  end
220
237
  end
221
238
 
239
+ def before_build
240
+ @before_build = true
241
+ yield
242
+ ensure
243
+ @before_build = false
244
+ end
245
+
222
246
  def build_depends( name , options = {} )
223
247
  name, options = parse_package(name, options)
224
248
  recipe.build_depends[name] = options
@@ -240,19 +264,25 @@ module FPM::Fry
240
264
  protected
241
265
 
242
266
  def source_types
243
- @source_types ||= {
244
- git: Source::Git,
245
- http: Source::Package,
246
- tar: Source::Package,
247
- dir: Source::Dir
248
- }
267
+ @source_types ||= {}
249
268
  end
250
269
 
251
- def register_source_type( name, klass )
270
+ def register_source_type( klass )
252
271
  if !klass.respond_to? :new
253
272
  raise ArgumentError.new("Expected something that responds to :new, got #{klass.inspect}")
254
273
  end
255
- source_types[name] = klass
274
+ source_types[klass.name] = klass
275
+ if klass.respond_to? :aliases
276
+ klass.aliases.each do |al|
277
+ source_types[al] = klass
278
+ end
279
+ end
280
+ end
281
+
282
+ def register_default_source_types!
283
+ register_source_type Source::Git
284
+ register_source_type Source::Package
285
+ register_source_type Source::Dir
256
286
  end
257
287
 
258
288
  NEG_INF = (-1.0/0.0)
@@ -267,10 +297,10 @@ module FPM::Fry
267
297
  .sort_by{|score,_| score.nil? ? NEG_INF : score }
268
298
  score, klasses = scores.last
269
299
  if score == nil
270
- raise ArgumentError.new("No source provide found for #{url}.\nMaybe try explicitly setting the type using :with parameter. Valid options are: #{source_types.keys.join(', ')}")
300
+ raise Error.new("No source provider found for #{url}.\nMaybe try explicitly setting the type using :with parameter. Valid options are: #{source_types.keys.join(', ')}")
271
301
  end
272
302
  if klasses.size != 1
273
- raise ArgumentError.new("Multiple possible source providers found for #{url}: #{klasses.join(', ')}.\nMaybe try explicitly setting the type using :with parameter. Valid options are: #{source_types.keys.join(', ')}")
303
+ raise Error.new("Multiple possible source providers found for #{url}: #{klasses.join(', ')}.\nMaybe try explicitly setting the type using :with parameter. Valid options are: #{source_types.keys.join(', ')}")
274
304
  end
275
305
  return klasses.first
276
306
  end
@@ -0,0 +1,15 @@
1
+ require 'fpm/fry/recipe'
2
+ module FPM::Fry
3
+ class Recipe
4
+ class Error < StandardError
5
+
6
+ attr :data
7
+
8
+ def initialize(msg=nil, data={})
9
+ super(msg)
10
+ @data = data
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -18,6 +18,9 @@ module FPM; module Fry
18
18
  end
19
19
  end
20
20
 
21
+ class DuplicateDependency < ArgumentError
22
+ end
23
+
21
24
  class PackageRecipe
22
25
  attr_accessor :name,
23
26
  :iteration,
@@ -121,10 +124,16 @@ module FPM; module Fry
121
124
  end
122
125
  end
123
126
 
124
- attr_accessor :source, :steps, :packages, :build_depends, :input_hooks
127
+ attr_accessor :source,
128
+ :before_build_steps,
129
+ :steps,
130
+ :packages,
131
+ :build_depends,
132
+ :input_hooks
125
133
 
126
134
  def initialize
127
135
  @source = Source::Null
136
+ @before_build_steps = []
128
137
  @steps = []
129
138
  @packages = [PackageRecipe.new]
130
139
  @packages[0].files << '**'
@@ -6,6 +6,10 @@ module FPM; module Fry ; module Source
6
6
 
7
7
  REGEX = %r!\A(?:file:|/|\.)!
8
8
 
9
+ def self.name
10
+ :dir
11
+ end
12
+
9
13
  def self.guess( url )
10
14
  Source::guess_regex(REGEX, url)
11
15
  end
@@ -7,6 +7,10 @@ module FPM; module Fry ; module Source
7
7
 
8
8
  REGEX = %r!\A(?:git:|\S+@\S+:\S+\.git\z|https?:.*\.git\z|ssh:.*\.git\z)!
9
9
 
10
+ def self.name
11
+ :git
12
+ end
13
+
10
14
  def self.guess( url )
11
15
  Source::guess_regex(REGEX, url)
12
16
  end
@@ -9,6 +9,14 @@ module FPM; module Fry ; module Source
9
9
 
10
10
  REGEX = %r!\Ahttps?:!
11
11
 
12
+ def self.name
13
+ :package
14
+ end
15
+
16
+ def self.aliases
17
+ [:http]
18
+ end
19
+
12
20
  def self.guess( url )
13
21
  Source::guess_regex(REGEX, url)
14
22
  end
@@ -158,11 +166,32 @@ module FPM; module Fry ; module Source
158
166
  end
159
167
  end
160
168
 
169
+ class PlainCache < Cache
170
+
171
+ def tar_io
172
+ update!
173
+ cmd = ['tar','-c',::File.basename(tempfile)]
174
+ dir = File.dirname(tempfile)
175
+ logger.debug("Running tar",cmd: cmd, dir: dir)
176
+ ::Dir.chdir(dir) do
177
+ return IO.popen(cmd)
178
+ end
179
+ end
180
+
181
+ def copy_to(dst)
182
+ update!
183
+ FileUtils.cp( tempfile, dst )
184
+ end
185
+
186
+ end
187
+
161
188
  CACHE_CLASSES = {
162
189
  '.tar' => TarCache,
163
190
  '.tar.gz' => TarGzCache,
164
191
  '.tgz' => TarGzCache,
165
- '.zip' => ZipCache
192
+ '.zip' => ZipCache,
193
+ '.bin' => PlainCache,
194
+ '.bundle' => PlainCache
166
195
  }
167
196
 
168
197
  attr :file_map, :data, :url, :extension, :checksum, :checksum_algorithm, :agent, :logger
@@ -0,0 +1,8 @@
1
+ module FPM ; module Fry
2
+
3
+ def self.WithData(ex, data)
4
+ ex.define_singleton_method(:data){ data }
5
+ return ex
6
+ end
7
+
8
+ end ; end
@@ -24,8 +24,12 @@ class FPM::Package::Docker < FPM::Package
24
24
 
25
25
  def split( name, map )
26
26
  changes = changes(name)
27
- changes.remove_modified_leaves! do | ml |
28
- @logger.warn("Found a modified file. You can only create new files in a package",name: ml)
27
+ changes.remove_modified_leaves! do | kind, ml |
28
+ if kind == DELETED
29
+ @logger.warn("Found a deleted file. You can only create new files in a package",name: ml)
30
+ else
31
+ @logger.warn("Found a modified file. You can only create new files in a package",name: ml)
32
+ end
29
33
  end
30
34
  fmap = {}
31
35
  changes.leaves.each do | change |
@@ -72,6 +76,10 @@ private
72
76
  return false
73
77
  end
74
78
 
79
+ MODIFIED = 0
80
+ CREATED = 1
81
+ DELETED = 2
82
+
75
83
  class Node < Struct.new(:children, :kind)
76
84
 
77
85
  def initialize
@@ -105,8 +113,8 @@ private
105
113
  def modified_leaves( prefix = '/', &block )
106
114
  return to_enum(:modified_leaves, prefix) unless block
107
115
  if leaf?
108
- if kind != 1
109
- yield prefix
116
+ if kind != CREATED
117
+ yield kind, prefix
110
118
  end
111
119
  else
112
120
  children.each do |name, cld|
@@ -119,15 +127,15 @@ private
119
127
  to_remove = {}
120
128
  children.each do |name, cld|
121
129
  removed_children = cld.remove_modified_leaves!(File.join(prefix,name), &block)
122
- if cld.leaf? and cld.kind != 1
123
- to_remove[name] = removed_children
130
+ if cld.leaf? and cld.kind != CREATED
131
+ to_remove[name] = [cld.kind, removed_children]
124
132
  end
125
133
  end
126
134
  if to_remove.any?
127
- to_remove.each do |name, removed_children|
135
+ to_remove.each do |name, (kind, removed_children)|
128
136
  children.delete(name)
129
137
  if !removed_children
130
- yield File.join(prefix,name)
138
+ yield kind, File.join(prefix,name)
131
139
  end
132
140
  end
133
141
  return true
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fpm-fry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hannes Georg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-29 00:00:00.000000000 Z
11
+ date: 2016-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: excon
@@ -38,7 +38,7 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.0'
41
- description: packages docker changes with fpm
41
+ description: deep-fried package builder
42
42
  email: hannes.georg@xing.com
43
43
  executables:
44
44
  - fpm-fry
@@ -50,6 +50,7 @@ files:
50
50
  - lib/fpm/fry/block_enumerator.rb
51
51
  - lib/fpm/fry/build_output_parser.rb
52
52
  - lib/fpm/fry/channel.rb
53
+ - lib/fpm/fry/chroot.rb
53
54
  - lib/fpm/fry/client.rb
54
55
  - lib/fpm/fry/command.rb
55
56
  - lib/fpm/fry/command/cook.rb
@@ -70,6 +71,7 @@ files:
70
71
  - lib/fpm/fry/plugin/user.rb
71
72
  - lib/fpm/fry/recipe.rb
72
73
  - lib/fpm/fry/recipe/builder.rb
74
+ - lib/fpm/fry/recipe/error.rb
73
75
  - lib/fpm/fry/source.rb
74
76
  - lib/fpm/fry/source/dir.rb
75
77
  - lib/fpm/fry/source/git.rb
@@ -86,6 +88,7 @@ files:
86
88
  - lib/fpm/fry/templates/sysv.erb
87
89
  - lib/fpm/fry/templates/upstart.erb
88
90
  - lib/fpm/fry/ui.rb
91
+ - lib/fpm/fry/with_data.rb
89
92
  - lib/fpm/package/docker.rb
90
93
  homepage: https://github.com/xing/fpm-fry
91
94
  licenses:
@@ -107,9 +110,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
110
  version: '0'
108
111
  requirements: []
109
112
  rubyforge_project:
110
- rubygems_version: 2.4.8
113
+ rubygems_version: 2.5.1
111
114
  signing_key:
112
115
  specification_version: 4
113
116
  summary: FPM Fry
114
117
  test_files: []
115
- has_rdoc: