fpm-fry 0.1.3 → 0.2.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: 6d10781e6b5740b80f68e6a7130acd844c2b1d5c
4
- data.tar.gz: 5dc23f36f547bd2359b433424ae8ef091dd2cf53
3
+ metadata.gz: 9d58721a3f79317f65181422ff3a7e5d28ef823e
4
+ data.tar.gz: 85229c608182080d92b67b81c2e6d09f701d19ba
5
5
  SHA512:
6
- metadata.gz: ba95b38a5652f87439105db3c7430505695e5429ef90fdfadcb1b6f517556259c8add886a2c0b0cca72e0d7c7683a4584883d3e1263266ad5f4e162fa911b9f0
7
- data.tar.gz: 9ded152eb45fbab21bdef04a651bee26689f0dd8a45a10d096ece7fe5cbc646f727fbc082e353f49bd62b6a303887d6ab86b6bb0e245625667d0529779f39f3e
6
+ metadata.gz: 5fc67b6dcbe5d6d8944028721665cbee9ae9bdb4f615c68812e012063e66c22ab278b943dc155d1e2ecc58e23021af133e8c0f29185db0ba0b5faa4f2dba5e5e
7
+ data.tar.gz: 03c12a7c8743715a8a33fff09c84e423ef67cbcd6a4a3a8659a6f7a1bd0b2e361797932117478950fb6ca6e5ac9af35049a4087c094a521b16a3e16a8d1fe22a
@@ -6,14 +6,16 @@ class Cabin::NiceOutput
6
6
  :red => "\e[1;31m",
7
7
  :green => "\e[1;32m",
8
8
  :yellow => "\e[0;33m",
9
- :white => "\e[0;37m"
9
+ :white => "\e[0;37m",
10
+ :blue => "\e[1;34m"
10
11
  }
11
12
 
12
13
  DIM_CODEMAP = {
13
14
  red: "\e[0;31m",
14
15
  green: "\e[0;32m",
15
16
  white: "\e[1;30m",
16
- yellow: "\e[33m"
17
+ yellow: "\e[33m",
18
+ blue: "\e[0;34m"
17
19
  }
18
20
 
19
21
  LEVELMAP = {
@@ -21,6 +23,7 @@ class Cabin::NiceOutput
21
23
  :error => :red,
22
24
  :warn => :yellow,
23
25
  :info => :green,
26
+ :hint => :blue,
24
27
  :debug => :white,
25
28
  }
26
29
 
@@ -43,6 +46,9 @@ class Cabin::NiceOutput
43
46
  bold = data.delete(:bold) ? :bold : nil
44
47
 
45
48
  backtrace = data.delete(:backtrace)
49
+ if !backtrace && data[:exception].respond_to?(:backtrace)
50
+ backtrace = data[:exception].backtrace
51
+ end
46
52
 
47
53
  # Make 'error' and other log levels have color
48
54
  if color.nil?
@@ -52,6 +58,9 @@ class Cabin::NiceOutput
52
58
  message = [event[:level] ? '====> ' : ' ',event[:message]]
53
59
  message.unshift(CODEMAP[color.to_sym]) if !color.nil?
54
60
  message << DIM_CODEMAP[color] if !color.nil?
61
+ if documentation = data.delete(:documentation)
62
+ message << "\n\tRead more on this topic here: #{documentation}"
63
+ end
55
64
  if data.any?
56
65
  message << "\n" << pp(data)
57
66
  end
@@ -0,0 +1,23 @@
1
+ require 'cabin/channel'
2
+ module FPM; module Fry
3
+ class Channel < Cabin::Channel
4
+
5
+ module Hint
6
+ def hint( message, data = {} )
7
+ return unless hint?
8
+ log(message, data.merge(level: :hint))
9
+ end
10
+
11
+ def hint?
12
+ !defined?(@hint) || @hint
13
+ end
14
+
15
+ def hint=( bool )
16
+ @hint = !!bool
17
+ end
18
+ end
19
+
20
+ include Hint
21
+
22
+ end
23
+ end ; end
@@ -9,30 +9,6 @@ module FPM; module Fry; end ; end
9
9
 
10
10
  class FPM::Fry::Client
11
11
 
12
- class LogInstrumentor < Struct.new(:logger)
13
-
14
- def instrument(event, data = {})
15
- if block_given?
16
- logger.debug('Requesting HTTP', filtered(data))
17
- r = yield
18
- return r
19
- else
20
- logger.debug('Getting HTTP response', filtered(data))
21
- end
22
- end
23
-
24
- def filtered(data)
25
- filtered = {}
26
- filtered[:path] = data[:path] if data[:path]
27
- filtered[:verb] = data[:method] if data[:method]
28
- filtered[:status] = data[:status] if data[:status]
29
- filtered[:body] = data[:body][0..500] if data[:body]
30
- filtered[:headers] = data[:headers]
31
- return filtered
32
- end
33
-
34
- end
35
-
36
12
  class FileNotFound < StandardError
37
13
  end
38
14
 
@@ -141,7 +117,6 @@ class FPM::Fry::Client
141
117
  def agent_for( uri, tls )
142
118
  proto, address = uri.split('://',2)
143
119
  options = {
144
- instrumentor: LogInstrumentor.new(logger),
145
120
  read_timeout: 10000
146
121
  }.merge( tls )
147
122
  case(proto)
@@ -18,10 +18,6 @@ module FPM; module Fry
18
18
  parameter 'image', 'Docker image to build from'
19
19
  parameter '[recipe]', 'Recipe file to cook', default: 'recipe.rb'
20
20
 
21
- attr :ui
22
- extend Forwardable
23
- def_delegators :ui, :out, :err, :logger, :tmpdir
24
-
25
21
  def initialize(invocation_path, ctx = {}, parent_attribute_values = {})
26
22
  @tls = nil
27
23
  require 'digest'
@@ -35,10 +31,6 @@ module FPM; module Fry
35
31
  require 'fpm/fry/block_enumerator'
36
32
  require 'fpm/fry/build_output_parser'
37
33
  super
38
- @ui = ctx.fetch(:ui){ UI.new }
39
- if debug?
40
- ui.logger.level = :debug
41
- end
42
34
  end
43
35
 
44
36
  def detector
@@ -53,12 +45,8 @@ module FPM; module Fry
53
45
  end
54
46
 
55
47
  def detector=(d)
56
- begin
57
- unless d.detect!
58
- raise "Unable to detect distribution from given image"
59
- end
60
- rescue Excon::Errors::NotFound
61
- raise "Image not found"
48
+ unless d.detect!
49
+ raise "Unable to detect distribution from given image"
62
50
  end
63
51
  @detector = d
64
52
  end
@@ -70,7 +58,7 @@ module FPM; module Fry
70
58
 
71
59
  def output_class
72
60
  @output_class ||= begin
73
- logger.info("Autodetecting package type",flavour: flavour)
61
+ logger.debug("Autodetecting package type",flavour: flavour)
74
62
  case(flavour)
75
63
  when 'debian'
76
64
  require 'fpm/package/deb'
@@ -92,7 +80,7 @@ module FPM; module Fry
92
80
  distribution_version: detector.version,
93
81
  flavour: flavour
94
82
  }
95
- logger.info("Loading recipe",variables: vars, recipe: recipe)
83
+ logger.debug("Loading recipe",variables: vars, recipe: recipe)
96
84
  b = Recipe::Builder.new(vars, Recipe.new, logger: ui.logger)
97
85
  b.load_file( recipe )
98
86
  b
@@ -150,7 +138,7 @@ module FPM; module Fry
150
138
  'Content-Type'=>'application/tar'
151
139
  },
152
140
  expects: [200],
153
- path: client.url("build?rm=1&t=#{cachetag}"),
141
+ path: client.url("build?rm=1&dockerfile=#{DockerFile::NAME}&t=#{cachetag}"),
154
142
  request_block: BlockEnumerator.new(df.tar_io)
155
143
  )
156
144
  end
@@ -162,12 +150,12 @@ module FPM; module Fry
162
150
  'Content-Type'=>'application/tar'
163
151
  },
164
152
  expects: [200],
165
- path: client.url('build?rm=1'),
153
+ path: client.url("build?rm=1&dockerfile=#{DockerFile::NAME}"),
166
154
  request_block: BlockEnumerator.new(df.tar_io),
167
155
  response_block: parser
168
156
  )
169
157
  if parser.images.none?
170
- raise "Unable to detect build image"
158
+ raise "Didn't find a build image in the stream. This usually means that the build script failed."
171
159
  end
172
160
  image = parser.images.last
173
161
  logger.debug("Detected build image", image: image)
@@ -191,13 +179,12 @@ module FPM; module Fry
191
179
  begin
192
180
  client.read( container, '/var/lib/apt/lists') do |file|
193
181
  next if file.header.name == 'lists/'
194
- logger.info("/var/lib/apt/lists is not empty, no update is required ( force update with --apt-update=always )")
195
- return false
182
+ logger.hint("/var/lib/apt/lists is not empty, you could try to speed up builds with --update=never", documentation: 'https://github.com/xing/fpm-fry/wiki/The-update-parameter')
183
+ return true
196
184
  end
197
185
  ensure
198
186
  client.delete(path: client.url('containers',container))
199
187
  end
200
- logger.info("/var/lib/apt/lists is empty, update is required ( disable update with --apt-update=never )")
201
188
  return true
202
189
  when 'always'
203
190
  return true
@@ -250,7 +237,7 @@ module FPM; module Fry
250
237
  )
251
238
  json = JSON.parse(res.body)
252
239
  if json["StatusCode"] != 0
253
- raise "Build failed"
240
+ raise "Build failed with exit code #{json["StatusCode"]}"
254
241
  end
255
242
  return yield container
256
243
  ensure
@@ -283,6 +270,12 @@ module FPM; module Fry
283
270
 
284
271
  output.output(tmp_package_file)
285
272
 
273
+ if output.config_files.any?
274
+ logger.debug("Found config files for #{output.name}", files: output.config_files)
275
+ else
276
+ logger.debug("No config files for #{output.name}")
277
+ end
278
+
286
279
  begin
287
280
  FileUtils.rm_rf package_file
288
281
  rescue Errno::ENOENT
@@ -311,6 +304,7 @@ module FPM; module Fry
311
304
 
312
305
  out_map.each do |output, package|
313
306
  package.apply_output(output)
307
+ adjust_config_files(output)
314
308
  end
315
309
 
316
310
  out_map.each do |output, _|
@@ -327,6 +321,39 @@ module FPM; module Fry
327
321
  end
328
322
 
329
323
 
324
+ def adjust_config_files( output )
325
+ # FPM flags all files in /etc as config files but only for debian :/.
326
+ # Actually this behavior makes sense to me for all packages because it's
327
+ # the thing I usually want. By setting this attribute at least the
328
+ # misleading warning goes away.
329
+ output.attributes[:deb_no_default_config_files?] = true
330
+ output.attributes[:deb_auto_config_files?] = false
331
+
332
+ return if output.attributes[:fry_config_explicitly_used]
333
+
334
+ # Now that we have disabled this for debian we have to reenable if it for
335
+ # all.
336
+ etc = File.expand_path('etc', output.staging_path)
337
+ if File.exists?( etc )
338
+ # Config plugin wasn't used. Add everything under /etc
339
+ prefix_length = output.staging_path.size + 1
340
+ added = []
341
+ Find.find(etc) do | path |
342
+ next unless File.file? path
343
+ name = path[prefix_length..-1]
344
+ if !output.config_files.include? name
345
+ added << name
346
+ output.config_files << name
347
+ end
348
+ end
349
+ if added.any?
350
+ logger.hint( "#{output.name} contains some config files in /etc. They were automatically added. You can customize this using the \"config\" plugin.",
351
+ documentation: "https://github.com/xing/fpm-fry/wiki/Plugin-config",
352
+ files: added)
353
+ end
354
+ end
355
+ end
356
+
330
357
  public
331
358
 
332
359
  def execute
@@ -355,7 +382,7 @@ module FPM; module Fry
355
382
 
356
383
  return 0
357
384
  rescue Recipe::NotFound => e
358
- logger.error("Recipe not found", recipe: recipe, exeception: e)
385
+ logger.error("Recipe not found", recipe: recipe, exception: e)
359
386
  return 1
360
387
  rescue => e
361
388
  logger.error(e)
@@ -16,13 +16,29 @@ module FPM; module Fry
16
16
 
17
17
  subcommand 'fpm', 'Works like fpm but with docker support', FPM::Command
18
18
 
19
+ attr :ui
20
+ extend Forwardable
21
+ def_delegators :ui, :out, :err, :logger, :tmpdir
22
+
23
+ def initialize(invocation_path, ctx = {}, parent_attribute_values = {})
24
+ super
25
+ @ui = ctx.fetch(:ui){ UI.new }
26
+ end
27
+
28
+ def parse(attrs)
29
+ super
30
+ if debug?
31
+ ui.logger.level = :debug
32
+ end
33
+ end
34
+
19
35
  def client
20
36
  @client ||= begin
21
37
  client = FPM::Fry::Client.new(
22
38
  logger: logger,
23
39
  tls: tls?, tlsverify: tlsverify?
24
40
  )
25
- logger.info("Docker connected",client.server_version)
41
+ logger.debug("Docker connected",client.server_version)
26
42
  client
27
43
  end
28
44
  end
@@ -39,14 +55,6 @@ module FPM; module Fry
39
55
  extend Forwardable
40
56
  def_delegators :ui, :logger
41
57
 
42
- def initialize(*_)
43
- super
44
- @ui = UI.new()
45
- if debug?
46
- ui.logger.level = :debug
47
- end
48
- end
49
-
50
58
  def execute
51
59
  require 'fpm/fry/os_db'
52
60
  require 'fpm/fry/detector'
@@ -73,6 +73,10 @@ module FPM; module Fry
73
73
  end
74
74
 
75
75
  class Image < Struct.new(:client,:image,:factory)
76
+
77
+ class ImageNotFound < StandardError
78
+ end
79
+
76
80
  attr :distribution
77
81
  attr :version
78
82
 
@@ -82,11 +86,15 @@ module FPM; module Fry
82
86
 
83
87
  def detect!
84
88
  body = JSON.generate({"Image" => image, "Cmd" => "exit 0"})
85
- res = client.post( path: client.url('containers','create'),
86
- headers: {'Content-Type' => 'application/json'},
87
- body: body,
88
- expects: [201]
89
- )
89
+ begin
90
+ res = client.post( path: client.url('containers','create'),
91
+ headers: {'Content-Type' => 'application/json'},
92
+ body: body,
93
+ expects: [201]
94
+ )
95
+ rescue Excon::Errors::NotFound
96
+ raise ImageNotFound, "Image #{image.inspect} not found. Did you do a `docker pull #{image}` before?"
97
+ end
90
98
  body = JSON.parse(res.body)
91
99
  container = body.fetch('Id')
92
100
  begin
@@ -7,6 +7,8 @@ require 'fpm/fry/joined_io'
7
7
  module FPM; module Fry
8
8
  class DockerFile < Struct.new(:variables,:cache,:recipe)
9
9
 
10
+ NAME = 'Dockerfile.fpm-fry'
11
+
10
12
  class Source < Struct.new(:variables, :cache)
11
13
 
12
14
  def initialize(variables, cache = Source::Null::Cache)
@@ -42,7 +44,7 @@ module FPM; module Fry
42
44
  def self_tar_io
43
45
  sio = StringIO.new
44
46
  tar = Gem::Package::TarWriter.new(sio)
45
- tar.add_file('Dockerfile','0777') do |io|
47
+ tar.add_file(NAME,'0777') do |io|
46
48
  io.write(dockerfile)
47
49
  end
48
50
  #tar.close
@@ -122,8 +124,10 @@ module FPM; module Fry
122
124
  def build_sh
123
125
  df = ['#!/bin/bash']
124
126
  df << 'set -e'
125
- recipe.steps.each do |k,v|
126
- df << "echo -e '\\e[1;32m====> #{Shellwords.escape k}\\e[0m'"
127
+ recipe.steps.each do |v|
128
+ if v.respond_to? :name
129
+ df << "echo -e '\\e[1;32m====> #{Shellwords.escape v.name}\\e[0m'"
130
+ end
127
131
  df << v.to_s
128
132
  end
129
133
  df << ''
@@ -136,7 +140,7 @@ module FPM; module Fry
136
140
  tar.add_file('.build.sh','0777') do |io|
137
141
  io.write(build_sh)
138
142
  end
139
- tar.add_file('Dockerfile','0777') do |io|
143
+ tar.add_file(NAME,'0777') do |io|
140
144
  io.write(dockerfile)
141
145
  end
142
146
  #tar.close
@@ -0,0 +1,90 @@
1
+ require 'fpm/fry/plugin'
2
+ module FPM::Fry::Plugin::Config
3
+
4
+ # @api private
5
+ IMPLICIT = Module.new
6
+
7
+ # @api private
8
+ MARK_EXPLICIT = Module.new do
9
+ def self.call(_, package)
10
+ package.attributes[:fry_config_explicitly_used] = true
11
+ end
12
+ end
13
+
14
+ # @api private
15
+ class Callback < Struct.new(:files)
16
+
17
+ def call(_, package)
18
+ prefix_length = package.staging_path.size + 1
19
+ candidates = []
20
+ # Sorting is important so that more specific rules override more generic
21
+ # rules.
22
+ keys = files.keys.sort_by(&:size)
23
+ keys.each do | key |
24
+ if files[key]
25
+ # 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
30
+ end
31
+ else
32
+ # Exclusion rule. Remove matching candidates
33
+ keydir = key + "/"
34
+ candidates.reject!{ |can|
35
+ can.start_with?(keydir) || can == key
36
+ }
37
+ end
38
+ end
39
+ package.config_files |= candidates
40
+ end
41
+
42
+ end
43
+
44
+ class DSL < Struct.new(:builder, :options, :callback)
45
+
46
+ def initialize( builder, options )
47
+ callback = builder.output_hooks.find{|h| h.kind_of? Callback }
48
+ if !callback
49
+ callback = Callback.new({'etc' => true})
50
+ builder.output_hooks << callback
51
+ end
52
+ # This looks kind of dirty. The callback tells the cook comamnd that the
53
+ # user has explictly used the config plugin. This way the cook command
54
+ # can hint the user to use this plugin if config files were automatically
55
+ # added.
56
+ if !options[IMPLICIT]
57
+ builder.output_hooks << MARK_EXPLICIT
58
+ end
59
+ super( builder, options, callback )
60
+ end
61
+
62
+ def include( path )
63
+ if path[0] == "/"
64
+ path = path[1..-1]
65
+ end
66
+ callback.files[path] = true
67
+ end
68
+
69
+ def exclude( path )
70
+ if path[0] == "/"
71
+ path = path[1..-1]
72
+ end
73
+ callback.files[path] = false
74
+ end
75
+
76
+ end
77
+
78
+ def self.apply( builder, options = {}, &block )
79
+ dsl = DSL.new(builder, options)
80
+ if block
81
+ if block.arity == 1
82
+ yield dsl
83
+ else
84
+ dsl.instance_eval(&block)
85
+ end
86
+ end
87
+ dsl
88
+ end
89
+
90
+ end
@@ -0,0 +1,19 @@
1
+ module FPM::Fry::Plugin::SameVersion
2
+
3
+ # Generates a special constraint that ignores iterations.
4
+ # This is especially pointful in multi-package recipes.
5
+ # @example
6
+ # name 'mainpackage'
7
+ # version '0.2.3'
8
+ # package 'subpackage'
9
+ # plugin 'same_version'
10
+ # depends 'mainpackage', same_version
11
+ # end
12
+ #
13
+ def same_version
14
+ *head, last = version.split('.')
15
+ last = last.to_i + 1
16
+ return ">= #{version}, << #{head.join '.'}.#{last}"
17
+ end
18
+
19
+ end
@@ -1,29 +1,39 @@
1
1
  require 'fpm/fry/plugin'
2
2
  require 'fpm/fry/plugin/init'
3
3
  require 'fpm/fry/plugin/edit_staging'
4
+ require 'fpm/fry/plugin/config'
4
5
  require 'erb'
5
6
  require 'shellwords'
6
7
  module FPM::Fry::Plugin ; module Service
7
8
 
8
- class Environment < Struct.new(:name,:command, :description)
9
+ class Environment < Struct.new(:name,:command, :description, :limits, :user, :group, :chdir)
9
10
 
10
11
  def render(file)
11
12
  _erbout = ""
12
13
  erb = ERB.new(
13
- IO.read(File.join(File.dirname(__FILE__),'..','templates',file))
14
+ IO.read(File.join(File.dirname(__FILE__),'..','templates',file)),
15
+ 0, "-"
14
16
  )
15
- eval(erb.src)
17
+ eval(erb.src,nil,File.join(File.dirname(__FILE__),'..','templates',file))
16
18
  return _erbout
17
19
  end
18
20
 
19
21
  end
20
22
 
23
+ LIMITS = %w(core cpu data fsize memlock msgqueue nice nofile nproc rss rtprio sigpending stack)
24
+
21
25
  class DSL
22
26
 
27
+ attr :limits
28
+
23
29
  def initialize(*_)
24
30
  super
25
31
  @name = nil
26
32
  @command = []
33
+ @limits = {}
34
+ @user = nil
35
+ @group = nil
36
+ @chdir = nil
27
37
  end
28
38
 
29
39
  def name( n = nil )
@@ -33,6 +43,34 @@ module FPM::Fry::Plugin ; module Service
33
43
  return @name
34
44
  end
35
45
 
46
+ def group( n = nil )
47
+ if n
48
+ @group = n
49
+ end
50
+ return @group
51
+ end
52
+
53
+ def user( n = nil )
54
+ if n
55
+ @user = n
56
+ end
57
+ return @user
58
+ end
59
+
60
+ def limit( name, soft, hard = soft )
61
+ unless LIMITS.include? name
62
+ raise ArgumentError, "Unknown limit #{name.inspect}. Known limits are: #{LIMITS.inspect}"
63
+ end
64
+ @limits[name] = [soft,hard]
65
+ end
66
+
67
+ def chdir( dir = nil )
68
+ if dir
69
+ @chdir = dir
70
+ end
71
+ @chdir
72
+ end
73
+
36
74
  def command( *args )
37
75
  if args.any?
38
76
  @command = args
@@ -45,7 +83,7 @@ module FPM::Fry::Plugin ; module Service
45
83
  name = self.name || builder.name || raise
46
84
  init = Init.detect_init(builder.variables)
47
85
  edit = builder.plugin('edit_staging')
48
- env = Environment.new(name, command, "")
86
+ env = Environment.new(name, command, "", @limits, @user, @group, @chdir)
49
87
  case(init)
50
88
  when 'upstart' then
51
89
  edit.add_file "/etc/init/#{name}.conf",StringIO.new( env.render('upstart.erb') )
@@ -64,6 +102,10 @@ if status #{Shellwords.shellescape name} 2>/dev/null | grep -q ' start/'; then
64
102
  fi
65
103
  BASH
66
104
  end
105
+ builder.plugin('config', FPM::Fry::Plugin::Config::IMPLICIT => true) do |co|
106
+ co.include "etc/init/#{name}.conf"
107
+ co.include "etc/init.d/#{name}"
108
+ end
67
109
  when 'sysv' then
68
110
  edit.add_file "/etc/init.d/#{name}",StringIO.new( env.render('sysv.erb') ), chmod: '750'
69
111
  builder.plugin('script_helper') do |sh|
@@ -76,6 +118,9 @@ BASH
76
118
  update-rc.d -f #{Shellwords.shellescape name} remove
77
119
  BASH
78
120
  end
121
+ builder.plugin('config', FPM::Fry::Plugin::Config::IMPLICIT => true) do |co|
122
+ co.include "etc/init.d/#{name}"
123
+ end
79
124
  when 'systemd' then
80
125
 
81
126
  end
@@ -0,0 +1,21 @@
1
+ require 'fpm/fry/plugin'
2
+ module FPM::Fry::Plugin ; module User
3
+
4
+ def self.apply(builder, name, options = {}, &block)
5
+ cmd = ["adduser", "--system"]
6
+ case options[:group]
7
+ when String
8
+ cmd << '--ingroup' << options[:group]
9
+ when true
10
+ cmd << '--group'
11
+ when nil
12
+ else
13
+ raise ArgumentError, ":group must be a String or true, got #{options[:group].inspect}"
14
+ end
15
+ cmd << name
16
+ builder.plugin('script_helper') do |sh|
17
+ sh.after_install_or_upgrade(Shellwords.shelljoin(cmd))
18
+ end
19
+ end
20
+
21
+ end ; end
@@ -86,6 +86,9 @@ module FPM::Fry
86
86
  if mod.respond_to? :apply
87
87
  mod.apply(self, *args, &block)
88
88
  else
89
+ if args.any? or block_given?
90
+ raise ArgumentError, "Simple plugins can't accept additional arguments and blocks."
91
+ end
89
92
  extend(mod)
90
93
  end
91
94
  end
@@ -131,14 +134,16 @@ module FPM::Fry
131
134
 
132
135
  def parse_package( name, options = {} )
133
136
  if options.kind_of? String
134
- options = {version: options}
137
+ options = {constraints: options}
135
138
  end
136
- case(v = options[:version])
139
+ case(v = options[:constraints])
137
140
  when String
138
- if v =~ /\A(<=|<<|>=|>>|<>|=|>|<)(\s*)/
139
- options[:version] = ' ' + $1 + ' ' + $'
140
- else
141
- options[:version] = ' = ' + v
141
+ options[:constraints] = v.split(',').map do |c|
142
+ if c =~ /\A\s*(<=|<<|>=|>>|<>|=|>|<)(\s*)/
143
+ $1 + ' ' + $'
144
+ else
145
+ '= ' + c
146
+ end
142
147
  end
143
148
  end
144
149
  return name, options
@@ -202,8 +207,16 @@ module FPM::Fry
202
207
  options = {}
203
208
  end
204
209
  command = args.shift
205
- name = options.fetch(:name){ [command,*args].select{|c| c[0] != '-' }.join('-') }
206
- recipe.steps[name] = Shellwords.join([command, *args])
210
+ name = options.fetch(:name){ [command,*args].select{|c| c[0] != '-' }.join(' ') }
211
+ bash( name, Shellwords.join([command, *args]) )
212
+ end
213
+
214
+ def bash( name = nil, code )
215
+ if name
216
+ recipe.steps << Recipe::Step.new(name, code)
217
+ else
218
+ recipe.steps << code.to_s
219
+ end
207
220
  end
208
221
 
209
222
  def build_depends( name , options = {} )
@@ -12,6 +12,12 @@ module FPM; module Fry
12
12
 
13
13
  class Recipe
14
14
 
15
+ class Step < Struct.new(:name, :value)
16
+ def to_s
17
+ value.to_s
18
+ end
19
+ end
20
+
15
21
  class PackageRecipe
16
22
  attr_accessor :name,
17
23
  :iteration,
@@ -62,7 +68,14 @@ module FPM; module Fry
62
68
  end
63
69
  [:dependencies, :conflicts, :replaces, :provides].each do |sym|
64
70
  send(sym).each do |name, options|
65
- package.send(sym) << "#{name}#{options[:version]}"
71
+ constr = Array(options[:constraints])
72
+ if constr.any?
73
+ constr.each do | c |
74
+ package.send(sym) << "#{name} #{c}"
75
+ end
76
+ else
77
+ package.send(sym) << name
78
+ end
66
79
  end
67
80
  end
68
81
  output_hooks.each{|h| h.call(self, package) }
@@ -112,7 +125,7 @@ module FPM; module Fry
112
125
 
113
126
  def initialize
114
127
  @source = Source::Null
115
- @steps = {}
128
+ @steps = []
116
129
  @packages = [PackageRecipe.new]
117
130
  @packages[0].files << '**'
118
131
  @build_depends = {}
@@ -1,4 +1,21 @@
1
1
  #!/bin/sh
2
+ <%
3
+ startopts = ['']
4
+ if user
5
+ if group
6
+ startopts << '-c' << Shellwords.escape(user + ':' + group)
7
+ else
8
+ startopts << '-c' << Shellwords.escape(user)
9
+ end
10
+ else
11
+ if group
12
+ startopts << '-g' << Shellwords.escape(group)
13
+ end
14
+ end
15
+ if chdir
16
+ startopts << '-d' << Shellwords.escape(chdir)
17
+ end
18
+ -%>
2
19
  ### BEGIN INIT INFO
3
20
  # Provides: <%= name %>
4
21
  # Required-Start: $remote_fs $syslog
@@ -42,7 +59,7 @@ do_start()
42
59
  # 2 if daemon could not be started
43
60
  start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
44
61
  || return 1
45
- start-stop-daemon --start --quiet --pidfile $PIDFILE --background --exec $DAEMON -- \
62
+ start-stop-daemon --start --quiet --pidfile $PIDFILE --background<%= startopts.join(" ") %> --exec $DAEMON -- \
46
63
  $DAEMON_ARGS \
47
64
  || return 2
48
65
  # Add code here, if necessary, that waits for the process to be ready
@@ -7,6 +7,15 @@ env NAME=<%= name.inspect %>
7
7
  env DAEMON=<%= command[0].inspect %>
8
8
  env DAEMON_ARGS=<%= Shellwords.shelljoin(command[1..-1]).inspect %>
9
9
 
10
+ <% if user %>setuid <%= user.inspect %>
11
+ <% end -%>
12
+ <% if group %>setgid <%= group.inspect %>
13
+ <% end -%>
14
+ <% if chdir %>chdir <%= chdir.inspect %>
15
+ <% end -%>
16
+ <% limits.each do | name, (soft, hard) | -%>
17
+ limit <%= name %> <%= soft %> <%= hard %>
18
+ <% end -%>
10
19
  respawn
11
20
 
12
21
  script
data/lib/fpm/fry/ui.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  require 'cabin/nice_output'
2
+ require 'fpm/fry/channel'
2
3
  module FPM; module Fry
3
4
  class UI < Struct.new(:out, :err, :logger, :tmpdir)
4
5
 
5
6
  def initialize( out = STDOUT, err = STDERR, logger = nil , tmpdir = '/tmp/fpm-fry' )
6
- logger ||= Cabin::Channel.new.tap{|chan| chan.subscribe(Cabin::NiceOutput.new(out)) }
7
+ logger ||= Channel.new.tap{|chan| chan.subscribe(Cabin::NiceOutput.new(out)) }
7
8
  FileUtils.mkdir_p( tmpdir )
8
9
  super( out, err, logger, tmpdir )
9
10
  end
@@ -25,7 +25,7 @@ class FPM::Package::Docker < FPM::Package
25
25
  def split( name, map )
26
26
  changes = changes(name)
27
27
  changes.remove_modified_leaves! do | ml |
28
- @logger.warn("Found a modified file. You can only create new files in a package",file: ml)
28
+ @logger.warn("Found a modified file. You can only create new files in a package",name: ml)
29
29
  end
30
30
  fmap = {}
31
31
  changes.leaves.each do | change |
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.1.3
4
+ version: 0.2.0
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-10-13 00:00:00.000000000 Z
11
+ date: 2015-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: excon
@@ -49,6 +49,7 @@ files:
49
49
  - lib/cabin/nice_output.rb
50
50
  - lib/fpm/fry/block_enumerator.rb
51
51
  - lib/fpm/fry/build_output_parser.rb
52
+ - lib/fpm/fry/channel.rb
52
53
  - lib/fpm/fry/client.rb
53
54
  - lib/fpm/fry/command.rb
54
55
  - lib/fpm/fry/command/cook.rb
@@ -58,12 +59,15 @@ files:
58
59
  - lib/fpm/fry/os_db.rb
59
60
  - lib/fpm/fry/plugin.rb
60
61
  - lib/fpm/fry/plugin/alternatives.rb
62
+ - lib/fpm/fry/plugin/config.rb
61
63
  - lib/fpm/fry/plugin/edit_staging.rb
62
64
  - lib/fpm/fry/plugin/exclude.rb
63
65
  - lib/fpm/fry/plugin/init.rb
64
66
  - lib/fpm/fry/plugin/platforms.rb
67
+ - lib/fpm/fry/plugin/same_version.rb
65
68
  - lib/fpm/fry/plugin/script_helper.rb
66
69
  - lib/fpm/fry/plugin/service.rb
70
+ - lib/fpm/fry/plugin/user.rb
67
71
  - lib/fpm/fry/recipe.rb
68
72
  - lib/fpm/fry/recipe/builder.rb
69
73
  - lib/fpm/fry/source.rb
@@ -103,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
107
  version: '0'
104
108
  requirements: []
105
109
  rubyforge_project:
106
- rubygems_version: 2.2.1
110
+ rubygems_version: 2.4.8
107
111
  signing_key:
108
112
  specification_version: 4
109
113
  summary: FPM Fry