fpm-fry 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/fpm-fry +10 -0
- data/lib/cabin/nice_output.rb +70 -0
- data/lib/fpm/fry/block_enumerator.rb +25 -0
- data/lib/fpm/fry/build_output_parser.rb +22 -0
- data/lib/fpm/fry/client.rb +162 -0
- data/lib/fpm/fry/command/cook.rb +370 -0
- data/lib/fpm/fry/command.rb +90 -0
- data/lib/fpm/fry/detector.rb +109 -0
- data/lib/fpm/fry/docker_file.rb +149 -0
- data/lib/fpm/fry/joined_io.rb +63 -0
- data/lib/fpm/fry/os_db.rb +35 -0
- data/lib/fpm/fry/plugin/alternatives.rb +90 -0
- data/lib/fpm/fry/plugin/edit_staging.rb +66 -0
- data/lib/fpm/fry/plugin/exclude.rb +18 -0
- data/lib/fpm/fry/plugin/init.rb +53 -0
- data/lib/fpm/fry/plugin/platforms.rb +10 -0
- data/lib/fpm/fry/plugin/script_helper.rb +176 -0
- data/lib/fpm/fry/plugin/service.rb +100 -0
- data/lib/fpm/fry/plugin.rb +3 -0
- data/lib/fpm/fry/recipe/builder.rb +267 -0
- data/lib/fpm/fry/recipe.rb +141 -0
- data/lib/fpm/fry/source/dir.rb +56 -0
- data/lib/fpm/fry/source/git.rb +90 -0
- data/lib/fpm/fry/source/package.rb +202 -0
- data/lib/fpm/fry/source/patched.rb +118 -0
- data/lib/fpm/fry/source.rb +47 -0
- data/lib/fpm/fry/stream_parser.rb +98 -0
- data/lib/fpm/fry/tar.rb +71 -0
- data/lib/fpm/fry/templates/debian/after_install.erb +9 -0
- data/lib/fpm/fry/templates/debian/before_install.erb +13 -0
- data/lib/fpm/fry/templates/debian/before_remove.erb +13 -0
- data/lib/fpm/fry/templates/redhat/after_install.erb +2 -0
- data/lib/fpm/fry/templates/redhat/before_install.erb +6 -0
- data/lib/fpm/fry/templates/redhat/before_remove.erb +6 -0
- data/lib/fpm/fry/templates/sysv.erb +125 -0
- data/lib/fpm/fry/templates/upstart.erb +15 -0
- data/lib/fpm/fry/ui.rb +12 -0
- data/lib/fpm/package/docker.rb +186 -0
- metadata +111 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'clamp'
|
4
|
+
require 'json'
|
5
|
+
require 'forwardable'
|
6
|
+
require 'fpm/fry/ui'
|
7
|
+
require 'fpm/command'
|
8
|
+
|
9
|
+
module FPM; module Fry
|
10
|
+
|
11
|
+
class Command < Clamp::Command
|
12
|
+
|
13
|
+
option '--debug', :flag, 'Turns on debugging'
|
14
|
+
option '--[no-]tls', :flag, 'Turns on tls ( default is false for schema unix, tcp and http and true for https )'
|
15
|
+
option '--[no-]tlsverify', :flag, 'Turns off tls peer verification', default:true, environment_variable: 'DOCKER_TLS_VERIFY'
|
16
|
+
|
17
|
+
subcommand 'fpm', 'Works like fpm but with docker support', FPM::Command
|
18
|
+
|
19
|
+
def client
|
20
|
+
@client ||= begin
|
21
|
+
client = FPM::Fry::Client.new(
|
22
|
+
logger: logger,
|
23
|
+
tls: tls?, tlsverify: tlsverify?
|
24
|
+
)
|
25
|
+
logger.info("Docker connected",client.server_version)
|
26
|
+
client
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_writer :client
|
31
|
+
|
32
|
+
subcommand 'detect', 'Detects distribution from an image, a container or a given name' do
|
33
|
+
|
34
|
+
option '--image', 'image', 'Docker image to detect'
|
35
|
+
option '--container', 'container', 'Docker container to detect'
|
36
|
+
option '--distribution', 'distribution', 'Distribution name to detect'
|
37
|
+
|
38
|
+
attr :ui
|
39
|
+
extend Forwardable
|
40
|
+
def_delegators :ui, :logger
|
41
|
+
|
42
|
+
def initialize(*_)
|
43
|
+
super
|
44
|
+
@ui = UI.new()
|
45
|
+
if debug?
|
46
|
+
ui.logger.level = :debug
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def execute
|
51
|
+
require 'fpm/fry/os_db'
|
52
|
+
require 'fpm/fry/detector'
|
53
|
+
|
54
|
+
if image
|
55
|
+
d = Detector::Image.new(client, image)
|
56
|
+
elsif distribution
|
57
|
+
d = Detector::String.new(distribution)
|
58
|
+
elsif container
|
59
|
+
d = Detector::Container.new(client, container)
|
60
|
+
else
|
61
|
+
logger.error("Please supply either --image, --distribution or --container")
|
62
|
+
return 1
|
63
|
+
end
|
64
|
+
|
65
|
+
begin
|
66
|
+
if d.detect!
|
67
|
+
data = {distribution: d.distribution, version: d.version}
|
68
|
+
if i = OsDb[d.distribution]
|
69
|
+
data[:flavour] = i[:flavour]
|
70
|
+
else
|
71
|
+
data[:flavour] = "unknown"
|
72
|
+
end
|
73
|
+
logger.info("Detected distribution",data)
|
74
|
+
return 0
|
75
|
+
else
|
76
|
+
logger.error("Detection failed")
|
77
|
+
return 2
|
78
|
+
end
|
79
|
+
rescue => e
|
80
|
+
logger.error(e)
|
81
|
+
return 3
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end ; end
|
89
|
+
|
90
|
+
require 'fpm/fry/command/cook'
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'fpm/fry/client'
|
2
|
+
module FPM; module Fry
|
3
|
+
|
4
|
+
module Detector
|
5
|
+
|
6
|
+
class String < Struct.new(:value)
|
7
|
+
attr :distribution
|
8
|
+
attr :version
|
9
|
+
|
10
|
+
def detect!
|
11
|
+
@distribution, @version = value.split('-',2)
|
12
|
+
return true
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class Container < Struct.new(:client,:container)
|
18
|
+
attr :distribution
|
19
|
+
attr :version
|
20
|
+
|
21
|
+
def detect!
|
22
|
+
begin
|
23
|
+
client.read(container,'/etc/lsb-release') do |file|
|
24
|
+
file.read.each_line do |line|
|
25
|
+
case(line)
|
26
|
+
when /\ADISTRIB_ID=/ then
|
27
|
+
@distribution = $'.strip.downcase
|
28
|
+
when /\ADISTRIB_RELEASE=/ then
|
29
|
+
@version = $'.strip
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
return !!(@distribution and @version)
|
34
|
+
rescue Client::FileNotFound
|
35
|
+
end
|
36
|
+
begin
|
37
|
+
client.read(container,'/etc/debian_version') do |file|
|
38
|
+
content = file.read
|
39
|
+
if /\A\d+(?:\.\d+)+\Z/ =~ content
|
40
|
+
@distribution = 'debian'
|
41
|
+
@version = content.strip
|
42
|
+
end
|
43
|
+
end
|
44
|
+
return !!(@distribution and @version)
|
45
|
+
rescue Client::FileNotFound
|
46
|
+
end
|
47
|
+
begin
|
48
|
+
client.read(container,'/etc/redhat-release') do |file|
|
49
|
+
if file.header.typeflag == "2" # centos links this file
|
50
|
+
client.read(container,File.absolute_path(file.header.linkname,'/etc')) do |file|
|
51
|
+
detect_redhat_release(file)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
detect_redhat_release(file)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
return !!(@distribution and @version)
|
58
|
+
rescue Client::FileNotFound
|
59
|
+
end
|
60
|
+
return false
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def detect_redhat_release(file)
|
65
|
+
file.read.each_line do |line|
|
66
|
+
case(line)
|
67
|
+
when /\A(\w+) release ([\d\.]+)/ then
|
68
|
+
@distribution = $1.strip.downcase
|
69
|
+
@version = $2.strip
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class Image < Struct.new(:client,:image,:factory)
|
76
|
+
attr :distribution
|
77
|
+
attr :version
|
78
|
+
|
79
|
+
def initialize(client, image, factory = Container)
|
80
|
+
super
|
81
|
+
end
|
82
|
+
|
83
|
+
def detect!
|
84
|
+
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
|
+
)
|
90
|
+
body = JSON.parse(res.body)
|
91
|
+
container = body.fetch('Id')
|
92
|
+
begin
|
93
|
+
d = factory.new(client,container)
|
94
|
+
if d.detect!
|
95
|
+
@distribution = d.distribution
|
96
|
+
@version = d.version
|
97
|
+
return true
|
98
|
+
else
|
99
|
+
return false
|
100
|
+
end
|
101
|
+
ensure
|
102
|
+
client.delete(path: client.url('containers',container))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
end
|
109
|
+
end ; end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'fiber'
|
2
|
+
require 'shellwords'
|
3
|
+
require 'rubygems/package'
|
4
|
+
require 'fpm/fry/os_db'
|
5
|
+
require 'fpm/fry/source'
|
6
|
+
require 'fpm/fry/joined_io'
|
7
|
+
module FPM; module Fry
|
8
|
+
class DockerFile < Struct.new(:variables,:cache,:recipe)
|
9
|
+
|
10
|
+
class Source < Struct.new(:variables, :cache)
|
11
|
+
|
12
|
+
def initialize(variables, cache = Source::Null::Cache)
|
13
|
+
variables = variables.dup
|
14
|
+
if variables[:distribution] && !variables[:flavour] && OsDb[variables[:distribution]]
|
15
|
+
variables[:flavour] = OsDb[variables[:distribution]][:flavour]
|
16
|
+
end
|
17
|
+
variables.freeze
|
18
|
+
super(variables, cache)
|
19
|
+
end
|
20
|
+
|
21
|
+
def dockerfile
|
22
|
+
df = []
|
23
|
+
df << "FROM #{variables[:image]}"
|
24
|
+
|
25
|
+
df << "RUN mkdir /tmp/build"
|
26
|
+
|
27
|
+
cache.file_map.each do |from, to|
|
28
|
+
df << "ADD #{map_from(from)} #{map_to(to)}"
|
29
|
+
end
|
30
|
+
|
31
|
+
df << ""
|
32
|
+
return df.join("\n")
|
33
|
+
end
|
34
|
+
|
35
|
+
def tar_io
|
36
|
+
JoinedIO.new(
|
37
|
+
self_tar_io,
|
38
|
+
cache.tar_io
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self_tar_io
|
43
|
+
sio = StringIO.new
|
44
|
+
tar = Gem::Package::TarWriter.new(sio)
|
45
|
+
tar.add_file('Dockerfile','0777') do |io|
|
46
|
+
io.write(dockerfile)
|
47
|
+
end
|
48
|
+
#tar.close
|
49
|
+
sio.rewind
|
50
|
+
return sio
|
51
|
+
end
|
52
|
+
|
53
|
+
def map_to(dir)
|
54
|
+
if ['','.'].include? dir
|
55
|
+
return '/tmp/build'
|
56
|
+
else
|
57
|
+
return File.join('/tmp/build',dir)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def map_from(dir)
|
62
|
+
if dir == ''
|
63
|
+
return '.'
|
64
|
+
else
|
65
|
+
return dir
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
class Build < Struct.new(:base, :variables, :recipe)
|
72
|
+
|
73
|
+
attr :options
|
74
|
+
private :options
|
75
|
+
|
76
|
+
def initialize(base, variables, recipe, options = {})
|
77
|
+
variables = variables.dup
|
78
|
+
if variables[:distribution] && !variables[:flavour] && OsDb[variables[:distribution]]
|
79
|
+
variables[:flavour] = OsDb[variables[:distribution]][:flavour]
|
80
|
+
end
|
81
|
+
variables.freeze
|
82
|
+
@options = options.dup.freeze
|
83
|
+
super(base, variables, recipe)
|
84
|
+
end
|
85
|
+
|
86
|
+
def dockerfile
|
87
|
+
df = []
|
88
|
+
df << "FROM #{base}"
|
89
|
+
df << "WORKDIR /tmp/build"
|
90
|
+
|
91
|
+
deps = (recipe.build_depends.merge recipe.depends)\
|
92
|
+
.select{|_,v| v.fetch(:install,true) }\
|
93
|
+
.map do |k,v|
|
94
|
+
i = v.fetch(:install,true)
|
95
|
+
if i == true then
|
96
|
+
k
|
97
|
+
else
|
98
|
+
i
|
99
|
+
end
|
100
|
+
end.sort
|
101
|
+
if deps.any?
|
102
|
+
case(variables[:flavour])
|
103
|
+
when 'debian'
|
104
|
+
update = ''
|
105
|
+
if options[:update]
|
106
|
+
update = 'apt-get update && '
|
107
|
+
end
|
108
|
+
df << "RUN #{update}apt-get install --yes #{Shellwords.join(deps)}"
|
109
|
+
when 'redhat'
|
110
|
+
df << "RUN yum -y install #{Shellwords.join(deps)}"
|
111
|
+
else
|
112
|
+
raise "Unknown flavour: #{variables[:flavour]}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
df << "ADD .build.sh /tmp/build/"
|
117
|
+
df << "ENTRYPOINT /tmp/build/.build.sh"
|
118
|
+
df << ''
|
119
|
+
return df.join("\n")
|
120
|
+
end
|
121
|
+
|
122
|
+
def build_sh
|
123
|
+
df = ['#!/bin/bash']
|
124
|
+
df << 'set -e'
|
125
|
+
recipe.steps.each do |k,v|
|
126
|
+
df << "echo -e '\\e[1;32m====> #{Shellwords.escape k}\\e[0m'"
|
127
|
+
df << v.to_s
|
128
|
+
end
|
129
|
+
df << ''
|
130
|
+
return df.join("\n")
|
131
|
+
end
|
132
|
+
|
133
|
+
def tar_io
|
134
|
+
sio = StringIO.new
|
135
|
+
tar = Gem::Package::TarWriter.new(sio)
|
136
|
+
tar.add_file('.build.sh','0777') do |io|
|
137
|
+
io.write(build_sh)
|
138
|
+
end
|
139
|
+
tar.add_file('Dockerfile','0777') do |io|
|
140
|
+
io.write(dockerfile)
|
141
|
+
end
|
142
|
+
#tar.close
|
143
|
+
sio.rewind
|
144
|
+
return sio
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end ; end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module FPM; module Fry
|
2
|
+
class JoinedIO
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def initialize(*ios)
|
6
|
+
@ios = ios
|
7
|
+
@pos = 0
|
8
|
+
@readbytes = 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def read( len = nil )
|
12
|
+
buf = []
|
13
|
+
if len.nil?
|
14
|
+
while chunk = readpartial(512)
|
15
|
+
buf << chunk
|
16
|
+
@readbytes += chunk.bytesize
|
17
|
+
end
|
18
|
+
return buf.join
|
19
|
+
else
|
20
|
+
con = 0
|
21
|
+
while con < len
|
22
|
+
chunk = readpartial(len - con)
|
23
|
+
if chunk.nil?
|
24
|
+
if con == 0
|
25
|
+
return nil
|
26
|
+
else
|
27
|
+
return buf.join
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@readbytes += chunk.bytesize
|
31
|
+
con += chunk.bytesize
|
32
|
+
buf << chunk
|
33
|
+
end
|
34
|
+
return buf.join
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def readpartial( len )
|
39
|
+
while (io = @ios[@pos])
|
40
|
+
r = io.read( len )
|
41
|
+
if r.nil?
|
42
|
+
@pos = @pos + 1
|
43
|
+
next
|
44
|
+
else
|
45
|
+
return r
|
46
|
+
end
|
47
|
+
end
|
48
|
+
return nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def pos
|
52
|
+
@readbytes
|
53
|
+
end
|
54
|
+
|
55
|
+
def eof?
|
56
|
+
@pos == @ios.size
|
57
|
+
end
|
58
|
+
|
59
|
+
def close
|
60
|
+
@ios.each(&:close)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end ; end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module FPM; module Fry
|
2
|
+
|
3
|
+
# Structure is
|
4
|
+
#
|
5
|
+
# <distribution> => {
|
6
|
+
# codenames: {
|
7
|
+
# <codename> => <version>
|
8
|
+
# },
|
9
|
+
# flavour: <flavour>
|
10
|
+
# }
|
11
|
+
OsDb = {
|
12
|
+
'centos' => {
|
13
|
+
codenames: {},
|
14
|
+
flavour: 'redhat'
|
15
|
+
},
|
16
|
+
|
17
|
+
'debian' => {
|
18
|
+
codenames: {
|
19
|
+
'lenny' => '5',
|
20
|
+
'squeeze' => '6',
|
21
|
+
'wheezy' => '7'
|
22
|
+
},
|
23
|
+
flavour: 'debian'
|
24
|
+
},
|
25
|
+
|
26
|
+
'ubuntu' => {
|
27
|
+
codenames: {
|
28
|
+
'precise' => '12.04',
|
29
|
+
'trusty' => '14.04'
|
30
|
+
},
|
31
|
+
flavour: 'debian'
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
end ; end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'fpm/fry/plugin'
|
2
|
+
module FPM::Fry::Plugin::Alternatives
|
3
|
+
|
4
|
+
BASH_HEADER = ['#!/bin/bash']
|
5
|
+
DEFAULT_PRIORITY = 10000
|
6
|
+
EXPECTED_KEYS = [:path, :link, :priority]
|
7
|
+
|
8
|
+
class DSL < Struct.new(:builder, :alternatives)
|
9
|
+
|
10
|
+
def initialize( b, a = {})
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def []=(name, options={}, value)
|
15
|
+
name = name.to_s
|
16
|
+
if value.kind_of? String
|
17
|
+
options = normalize(name, options.merge(path: value) )
|
18
|
+
else
|
19
|
+
options = normalize(name, options.merge(value) )
|
20
|
+
end
|
21
|
+
alternatives[name] = options
|
22
|
+
end
|
23
|
+
|
24
|
+
def add(name, value, options={})
|
25
|
+
self[name, options] = value
|
26
|
+
end
|
27
|
+
|
28
|
+
def finish!
|
29
|
+
install = alternatives.map{|_,v| install_command(v) }
|
30
|
+
uninstall = alternatives.map{|_,v| uninstall_command(v) }
|
31
|
+
builder.plugin('script_helper') do
|
32
|
+
after_install_or_upgrade(*install)
|
33
|
+
before_remove_entirely(*uninstall)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def normalize_without_slaves(name, options)
|
39
|
+
if options.kind_of? String
|
40
|
+
options = {path: options}
|
41
|
+
elsif options.kind_of? Hash
|
42
|
+
additional_keys = options.keys - EXPECTED_KEYS
|
43
|
+
raise ArgumentError, "Unexpected options: #{additional_keys.inspect}" if additional_keys.any?
|
44
|
+
options = options.dup
|
45
|
+
else
|
46
|
+
raise ArgumentError, "Options must be either a Hash or a String, got #{options.inspect}"
|
47
|
+
end
|
48
|
+
options[:name] = name
|
49
|
+
options[:link] ||= File.join('/usr/bin',name)
|
50
|
+
return options
|
51
|
+
end
|
52
|
+
|
53
|
+
def normalize( name, options )
|
54
|
+
slaves = {}
|
55
|
+
if options.kind_of?(Hash) && options.key?(:slaves)
|
56
|
+
options = options.dup
|
57
|
+
slaves = options.delete(:slaves)
|
58
|
+
end
|
59
|
+
options = normalize_without_slaves(name, options)
|
60
|
+
options[:slaves] = slaves.map{|k,v| normalize_without_slaves(k, v) }
|
61
|
+
options[:priority] ||= DEFAULT_PRIORITY
|
62
|
+
return options
|
63
|
+
end
|
64
|
+
|
65
|
+
def install_command(options)
|
66
|
+
slaves = options.fetch(:slaves,[]).flat_map{|options| ['--slave', options[:link],options[:name],options[:path]] }
|
67
|
+
Shellwords.join(['update-alternatives','--install',options[:link],options[:name],options[:path],options[:priority].to_s, *slaves])
|
68
|
+
end
|
69
|
+
|
70
|
+
def uninstall_command(options)
|
71
|
+
Shellwords.join(['update-alternatives','--remove',options[:name],options[:path]])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.apply(builder, options = {}, &block)
|
76
|
+
dsl = DSL.new(builder)
|
77
|
+
options.each do |k,v|
|
78
|
+
dsl.add(k,v)
|
79
|
+
end
|
80
|
+
if block
|
81
|
+
if block.arity == 1
|
82
|
+
yield dsl
|
83
|
+
else
|
84
|
+
dsl.instance_eval(&block)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
dsl.finish!
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'fpm/fry/plugin'
|
2
|
+
require 'fileutils'
|
3
|
+
module FPM::Fry::Plugin::EditStaging
|
4
|
+
|
5
|
+
class AddFile < Struct.new(:path, :io, :options)
|
6
|
+
def call(_ , package)
|
7
|
+
file = package.staging_path(path)
|
8
|
+
FileUtils.mkdir_p(File.dirname(file))
|
9
|
+
File.open(file,'w') do | f |
|
10
|
+
IO.copy_stream(io, f)
|
11
|
+
if options[:chmod]
|
12
|
+
f.chmod(options[:chmod])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
io.close if io.respond_to? :close
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class LnS < Struct.new(:src, :dest)
|
20
|
+
def call(_ , package)
|
21
|
+
file = package.staging_path(dest)
|
22
|
+
FileUtils.mkdir_p(File.dirname(file))
|
23
|
+
File.symlink(src, file)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class DSL < Struct.new(:builder)
|
28
|
+
def add_file(path, io, options = {})
|
29
|
+
options = options.dup
|
30
|
+
options[:chmod] = convert_chmod(options[:chmod]) if options[:chmod]
|
31
|
+
options.freeze
|
32
|
+
io.rewind if io.respond_to? :rewind
|
33
|
+
builder.output_hooks << AddFile.new(path, io, options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def ln_s(src, dest)
|
37
|
+
builder.output_hooks << LnS.new(src,dest)
|
38
|
+
end
|
39
|
+
private
|
40
|
+
|
41
|
+
def convert_chmod(chmod)
|
42
|
+
if chmod.kind_of? Numeric
|
43
|
+
num = chmod
|
44
|
+
elsif chmod.kind_of? String
|
45
|
+
num = chmod.to_i(8)
|
46
|
+
else
|
47
|
+
raise ArgumentError, "Invalid chmod format: #{chmod}"
|
48
|
+
end
|
49
|
+
return num
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.apply(builder, &block)
|
55
|
+
d = DSL.new(builder)
|
56
|
+
if !block
|
57
|
+
return d
|
58
|
+
elsif block.arity == 1
|
59
|
+
block.call(d)
|
60
|
+
else
|
61
|
+
d.instance_eval(&block)
|
62
|
+
end
|
63
|
+
return d
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'fpm/fry/plugin'
|
2
|
+
module FPM::Fry::Plugin::Exclude
|
3
|
+
|
4
|
+
class Exclude < Struct.new(:matches)
|
5
|
+
|
6
|
+
def call(_, package)
|
7
|
+
(package.attributes[:excludes] ||= []).push(*matches)
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
def exclude(*matches)
|
13
|
+
return if matches.none?
|
14
|
+
input_hooks << Exclude.new(matches)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'fpm/fry/plugin'
|
2
|
+
module FPM::Fry::Plugin::Init
|
3
|
+
|
4
|
+
def self.detect_init(variables)
|
5
|
+
if variables[:init]
|
6
|
+
return variables[:init]
|
7
|
+
end
|
8
|
+
d = variables[:distribution]
|
9
|
+
v = variables[:distribution_version].split('.').map(&:to_i)
|
10
|
+
case(d)
|
11
|
+
when 'debian'
|
12
|
+
if v[0] < 8
|
13
|
+
return 'sysv'
|
14
|
+
else
|
15
|
+
return 'systemd'
|
16
|
+
end
|
17
|
+
when 'ubuntu'
|
18
|
+
if v[0] <= 14 && v[1] < 10
|
19
|
+
return 'upstart'
|
20
|
+
else
|
21
|
+
return 'systemd'
|
22
|
+
end
|
23
|
+
when 'centos','redhat'
|
24
|
+
if v[0] <= 5
|
25
|
+
return 'sysv'
|
26
|
+
elsif v[0] == 6
|
27
|
+
return 'upstart'
|
28
|
+
else
|
29
|
+
return 'systemd'
|
30
|
+
end
|
31
|
+
else
|
32
|
+
raise "Unknown init system for #{d} #{v.join '.'}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def init(*inits)
|
37
|
+
inits = inits.flatten.map(&:to_s)
|
38
|
+
actual = FPM::Fry::Plugin::Init.detect_init(variables)
|
39
|
+
if inits.none?
|
40
|
+
return actual
|
41
|
+
elsif inits.include? actual
|
42
|
+
if block_given?
|
43
|
+
yield
|
44
|
+
else
|
45
|
+
return true
|
46
|
+
end
|
47
|
+
else
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
end
|