fpm-fry 0.2.2 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/cabin/nice_output.rb +16 -1
- data/lib/fpm/fry/block_enumerator.rb +6 -3
- data/lib/fpm/fry/build_output_parser.rb +10 -5
- data/lib/fpm/fry/channel.rb +13 -0
- data/lib/fpm/fry/chroot.rb +2 -2
- data/lib/fpm/fry/client.rb +96 -12
- data/lib/fpm/fry/command.rb +15 -32
- data/lib/fpm/fry/command/cook.rb +38 -56
- data/lib/fpm/fry/detector.rb +43 -98
- data/lib/fpm/fry/docker_file.rb +60 -26
- data/lib/fpm/fry/exec.rb +76 -0
- data/lib/fpm/fry/inspector.rb +70 -0
- data/lib/fpm/fry/joined_io.rb +1 -1
- data/lib/fpm/fry/plugin/apt.rb +52 -0
- data/lib/fpm/fry/plugin/edit_staging.rb +1 -1
- data/lib/fpm/fry/plugin/env.rb +45 -0
- data/lib/fpm/fry/plugin/init.rb +71 -42
- data/lib/fpm/fry/plugin/service.rb +108 -49
- data/lib/fpm/fry/plugin/systemd.rb +75 -0
- data/lib/fpm/fry/recipe.rb +64 -23
- data/lib/fpm/fry/recipe/builder.rb +53 -20
- data/lib/fpm/fry/source.rb +41 -12
- data/lib/fpm/fry/source/{package.rb → archive.rb} +115 -35
- data/lib/fpm/fry/source/dir.rb +13 -8
- data/lib/fpm/fry/source/git.rb +81 -45
- data/lib/fpm/fry/source/patched.rb +61 -32
- data/lib/fpm/fry/tar.rb +63 -0
- data/lib/fpm/fry/templates/debian/after_remove.erb +1 -1
- data/lib/fpm/fry/templates/debian/before_remove.erb +1 -1
- data/lib/fpm/fry/ui.rb +1 -1
- data/lib/fpm/fry/with_data.rb +34 -0
- data/lib/fpm/package/docker.rb +16 -0
- metadata +82 -13
- data/lib/fpm/fry/os_db.rb +0 -36
@@ -4,32 +4,67 @@ require 'net/http'
|
|
4
4
|
require 'forwardable'
|
5
5
|
require 'zlib'
|
6
6
|
require 'fpm/fry/source'
|
7
|
+
require 'fpm/fry/exec'
|
7
8
|
require 'cabin'
|
9
|
+
require 'cabin/channel'
|
10
|
+
|
8
11
|
module FPM; module Fry ; module Source
|
9
|
-
|
12
|
+
# Used to build from an archive.
|
13
|
+
#
|
14
|
+
# @example in a recipe
|
15
|
+
# source 'http://curl.haxx.se/download/curl-7.36.0.tar.gz',
|
16
|
+
# checksum: '33015795d5650a2bfdd9a4a28ce4317cef944722a5cfca0d1563db8479840e90'
|
17
|
+
#
|
18
|
+
# It is highly advised to supply a checksum ( althought it's not mandatory ).
|
19
|
+
# This checksum will be used to test for cache validity and data integrity. The
|
20
|
+
# checksum algorithm is automatically guessed based on the length of the checksum.
|
21
|
+
#
|
22
|
+
# - 40 characters = sha1
|
23
|
+
# - 64 characters = sha256
|
24
|
+
#
|
25
|
+
# Let's be honest: all other checksum algorithms aren't or shouldn't be in use anyway.
|
26
|
+
class Archive
|
10
27
|
|
11
28
|
REGEX = %r!\Ahttps?:!
|
12
29
|
|
30
|
+
# @return [:archive]
|
13
31
|
def self.name
|
14
32
|
:package
|
15
33
|
end
|
16
34
|
|
17
35
|
def self.aliases
|
18
|
-
[:http]
|
36
|
+
[:package,:http]
|
19
37
|
end
|
20
38
|
|
39
|
+
# Guesses if the given url is an archive.
|
40
|
+
#
|
41
|
+
# @example not an archive
|
42
|
+
# FPM::Fry::Source::Archive.guess("bzr://something") # => nil
|
43
|
+
#
|
44
|
+
# @example an archive
|
45
|
+
# FPM::Fry::Source::Archive.guess("https://some/thing.tar.gz") #=> 6
|
46
|
+
#
|
47
|
+
# @return [nil] when it's not an archive
|
48
|
+
# @return [Numeric] number of characters used
|
21
49
|
def self.guess( url )
|
22
50
|
Source::guess_regex(REGEX, url)
|
23
51
|
end
|
24
52
|
|
53
|
+
# Raised when too many redirects happened.
|
25
54
|
class RedirectError < CacheFailed
|
26
55
|
end
|
27
56
|
|
57
|
+
# Raised when the archive type is not known.
|
58
|
+
class UnknownArchiveType < StandardError
|
59
|
+
include WithData
|
60
|
+
end
|
61
|
+
|
28
62
|
class Cache < Struct.new(:package,:tempdir)
|
29
63
|
extend Forwardable
|
30
64
|
|
31
|
-
def_delegators :package, :url, :checksum, :checksum_algorithm, :
|
65
|
+
def_delegators :package, :url, :checksum, :checksum_algorithm, :logger, :file_map, :to
|
32
66
|
|
67
|
+
# @return [String] cachekey which is equal to the checksum
|
33
68
|
def cachekey
|
34
69
|
@observed_checksum || checksum
|
35
70
|
end
|
@@ -92,7 +127,7 @@ module FPM; module Fry ; module Source
|
|
92
127
|
case(resp)
|
93
128
|
when Net::HTTPRedirection
|
94
129
|
if redirs == 0
|
95
|
-
raise RedirectError
|
130
|
+
raise RedirectError.new("Too many redirects", url: url.to_s, location: resp['location'])
|
96
131
|
end
|
97
132
|
logger.debug("Following redirect", url: url.to_s , location: resp['location'])
|
98
133
|
return fetch_url( resp['location'], redirs - 1, &block)
|
@@ -119,9 +154,33 @@ module FPM; module Fry ; module Source
|
|
119
154
|
|
120
155
|
def copy_to(dst)
|
121
156
|
update!
|
122
|
-
|
123
|
-
|
124
|
-
|
157
|
+
Exec['tar','-xf',tempfile,'-C',dst, logger: logger]
|
158
|
+
end
|
159
|
+
|
160
|
+
def prefix
|
161
|
+
update!
|
162
|
+
@prefix ||= prefix!
|
163
|
+
end
|
164
|
+
|
165
|
+
def prefix!
|
166
|
+
longest = nil
|
167
|
+
Exec.popen('tar','-tf',tempfile, logger: logger).each_line.map do |line|
|
168
|
+
line = line.chomp
|
169
|
+
parts = line.split('/')
|
170
|
+
parts.pop unless line[-1] == '/'
|
171
|
+
if longest.nil?
|
172
|
+
longest = parts
|
173
|
+
else
|
174
|
+
longest.each_with_index do | e, i |
|
175
|
+
if parts[i] != e
|
176
|
+
longest = longest[0...i]
|
177
|
+
break
|
178
|
+
end
|
179
|
+
end
|
180
|
+
break if longest.none?
|
181
|
+
end
|
182
|
+
end
|
183
|
+
return Array(longest).join('/')
|
125
184
|
end
|
126
185
|
|
127
186
|
protected
|
@@ -142,9 +201,7 @@ module FPM; module Fry ; module Source
|
|
142
201
|
|
143
202
|
def tar_io
|
144
203
|
update!
|
145
|
-
|
146
|
-
logger.debug("Running bzcat",cmd: cmd)
|
147
|
-
return IO.popen(cmd)
|
204
|
+
return Exec::popen('bzcat', tempfile, logger: logger)
|
148
205
|
end
|
149
206
|
|
150
207
|
end
|
@@ -152,6 +209,22 @@ module FPM; module Fry ; module Source
|
|
152
209
|
class ZipCache < Cache
|
153
210
|
|
154
211
|
def tar_io
|
212
|
+
unpack!
|
213
|
+
return Exec::popen('tar','-c','.', chdir: unpacked_tmpdir)
|
214
|
+
end
|
215
|
+
|
216
|
+
def copy_to(dst)
|
217
|
+
update!
|
218
|
+
Exec['unzip', tempfile, '-d', dst ]
|
219
|
+
end
|
220
|
+
|
221
|
+
def prefix
|
222
|
+
unpack!
|
223
|
+
Source::prefix(unpacked_tmpdir)
|
224
|
+
end
|
225
|
+
private
|
226
|
+
|
227
|
+
def unpack!
|
155
228
|
if !::File.directory?( unpacked_tmpdir )
|
156
229
|
workdir = unpacked_tmpdir + '.tmp'
|
157
230
|
begin
|
@@ -163,18 +236,6 @@ module FPM; module Fry ; module Source
|
|
163
236
|
copy_to( workdir )
|
164
237
|
File.rename(workdir, unpacked_tmpdir)
|
165
238
|
end
|
166
|
-
cmd = ['tar','-c','.']
|
167
|
-
logger.debug("Running tar",cmd: cmd, dir: unpacked_tmpdir)
|
168
|
-
::Dir.chdir(unpacked_tmpdir) do
|
169
|
-
return IO.popen(cmd)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
def copy_to(dst)
|
174
|
-
update!
|
175
|
-
cmd = ['unzip', tempfile, '-d', dst ]
|
176
|
-
logger.debug("Running unzip",cmd: cmd)
|
177
|
-
system(*cmd, out: '/dev/null')
|
178
239
|
end
|
179
240
|
|
180
241
|
def unpacked_tmpdir
|
@@ -186,12 +247,8 @@ module FPM; module Fry ; module Source
|
|
186
247
|
|
187
248
|
def tar_io
|
188
249
|
update!
|
189
|
-
cmd = ['tar','-c',::File.basename(tempfile)]
|
190
250
|
dir = File.dirname(tempfile)
|
191
|
-
|
192
|
-
::Dir.chdir(dir) do
|
193
|
-
return IO.popen(cmd)
|
194
|
-
end
|
251
|
+
Exec::popen('tar','-c',::File.basename(tempfile), logger: logger, chdir: dir)
|
195
252
|
end
|
196
253
|
|
197
254
|
def copy_to(dst)
|
@@ -199,6 +256,10 @@ module FPM; module Fry ; module Source
|
|
199
256
|
FileUtils.cp( tempfile, dst )
|
200
257
|
end
|
201
258
|
|
259
|
+
def prefix
|
260
|
+
""
|
261
|
+
end
|
262
|
+
|
202
263
|
end
|
203
264
|
|
204
265
|
CACHE_CLASSES = {
|
@@ -211,26 +272,45 @@ module FPM; module Fry ; module Source
|
|
211
272
|
'.bundle' => PlainCache
|
212
273
|
}
|
213
274
|
|
214
|
-
attr :file_map, :data, :url, :
|
275
|
+
attr :file_map, :data, :url, :checksum, :checksum_algorithm, :logger, :to
|
215
276
|
|
277
|
+
# @param [URI] url
|
278
|
+
# @param [Hash] options
|
279
|
+
# @option options [Cabin::Channel] :logger (default cabin channel)
|
280
|
+
# @option options [String] :checksum a checksum of the archive
|
281
|
+
# @raise [UnknownArchiveType] when the archive type is unknown
|
216
282
|
def initialize( url, options = {} )
|
217
283
|
@url = URI(url)
|
218
|
-
@
|
219
|
-
CACHE_CLASSES.keys.find{|ext|
|
220
|
-
@url.path.end_with?(ext)
|
221
|
-
}
|
222
|
-
}
|
284
|
+
@cache_class = guess_cache_class(@url)
|
223
285
|
@logger = options.fetch(:logger){ Cabin::Channel.get }
|
224
286
|
@checksum = options[:checksum]
|
225
287
|
@checksum_algorithm = guess_checksum_algorithm(options[:checksum])
|
226
|
-
@file_map = options
|
288
|
+
@file_map = options[:file_map]
|
289
|
+
@to = options[:to]
|
227
290
|
end
|
228
291
|
|
292
|
+
# Creates a cache.
|
293
|
+
#
|
294
|
+
# @param [String] tempdir
|
295
|
+
# @return [TarCache] for plain .tar files
|
296
|
+
# @return [TarGzCache] for .tar.gz files
|
297
|
+
# @return [TarBz2Cache] for .tar.bz2 files
|
298
|
+
# @return [ZipCache] for .zip files
|
299
|
+
# @return [PlainCache] for .bin files
|
229
300
|
def build_cache(tempdir)
|
230
|
-
|
301
|
+
@cache_class.new(self, tempdir)
|
231
302
|
end
|
232
303
|
private
|
233
304
|
|
305
|
+
def guess_cache_class( url )
|
306
|
+
CACHE_CLASSES.each do |ext,klass|
|
307
|
+
if url.path.end_with?(ext)
|
308
|
+
return klass
|
309
|
+
end
|
310
|
+
end
|
311
|
+
raise UnknownArchiveType.new("Unknown archive type", url: url.to_s, known_extensions: CACHE_CLASSES.keys)
|
312
|
+
end
|
313
|
+
|
234
314
|
def guess_checksum_algorithm( checksum )
|
235
315
|
case(checksum)
|
236
316
|
when nil
|
data/lib/fpm/fry/source/dir.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require 'fpm/fry/source'
|
2
|
+
require 'fpm/fry/exec'
|
2
3
|
require 'fileutils'
|
3
4
|
require 'digest'
|
5
|
+
require 'cabin/channel'
|
6
|
+
require 'fpm/fry/tar'
|
7
|
+
|
4
8
|
module FPM; module Fry ; module Source
|
5
9
|
class Dir
|
6
10
|
|
@@ -17,14 +21,10 @@ module FPM; module Fry ; module Source
|
|
17
21
|
class Cache < Struct.new(:package, :dir)
|
18
22
|
extend Forwardable
|
19
23
|
|
20
|
-
def_delegators :package, :url, :logger, :file_map
|
24
|
+
def_delegators :package, :url, :logger, :file_map, :to
|
21
25
|
|
22
26
|
def tar_io
|
23
|
-
|
24
|
-
logger.debug("Running tar",cmd: cmd, dir: dir)
|
25
|
-
::Dir.chdir(dir) do
|
26
|
-
return IO.popen(cmd)
|
27
|
-
end
|
27
|
+
Exec::popen('tar','-c','.', chdir: dir, logger: logger)
|
28
28
|
end
|
29
29
|
|
30
30
|
def copy_to(dst)
|
@@ -39,9 +39,13 @@ module FPM; module Fry ; module Source
|
|
39
39
|
end
|
40
40
|
return dig.hexdigest
|
41
41
|
end
|
42
|
+
|
43
|
+
def prefix
|
44
|
+
Source::prefix(dir)
|
45
|
+
end
|
42
46
|
end
|
43
47
|
|
44
|
-
attr :url, :logger, :file_map
|
48
|
+
attr :url, :logger, :file_map, :to
|
45
49
|
|
46
50
|
def initialize( url, options = {} )
|
47
51
|
@url = URI(url)
|
@@ -49,7 +53,8 @@ module FPM; module Fry ; module Source
|
|
49
53
|
@url.path = File.expand_path(@url.path)
|
50
54
|
end
|
51
55
|
@logger = options.fetch(:logger){ Cabin::Channel.get }
|
52
|
-
@file_map = options
|
56
|
+
@file_map = options[:file_map]
|
57
|
+
@to = options[:to]
|
53
58
|
end
|
54
59
|
|
55
60
|
def build_cache(_)
|
data/lib/fpm/fry/source/git.rb
CHANGED
@@ -1,16 +1,41 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'forwardable'
|
3
|
-
require '
|
3
|
+
require 'fpm/fry/exec'
|
4
4
|
require 'fpm/fry/source'
|
5
5
|
module FPM; module Fry ; module Source
|
6
|
+
# Used to build directly from git.
|
7
|
+
#
|
8
|
+
# @example in a recipe
|
9
|
+
# source 'https://github.com/ggreer/the_silver_searcher.git'
|
10
|
+
#
|
11
|
+
# It automatically recognizes the following url patterns:
|
12
|
+
#
|
13
|
+
# - git://…
|
14
|
+
# - git+…://…
|
15
|
+
# - user@host:….git
|
16
|
+
# - https://….git
|
17
|
+
# - https://git.…
|
18
|
+
#
|
6
19
|
class Git
|
7
20
|
|
8
|
-
REGEX = %r!\A(?:git:|\S+@\S+:\S+\.git\z|https
|
21
|
+
REGEX = %r!\A(?:git:|\S+@\S+:\S+\.git\z|https?:(?://git\.|.*\.git\z)|ssh:.*\.git\z|git\+[a-z0-9]+:)!
|
9
22
|
|
23
|
+
# @return [:git]
|
10
24
|
def self.name
|
11
25
|
:git
|
12
26
|
end
|
13
27
|
|
28
|
+
# Guesses if this url is a git url.
|
29
|
+
#
|
30
|
+
# @example not a git url
|
31
|
+
# FPM::Fry::Source::Git.guess( "bzr://something" ) #=> nil
|
32
|
+
#
|
33
|
+
# @example a git url
|
34
|
+
# FPM::Fry::Source::Git.guess( "git://something" ) #=> 4
|
35
|
+
#
|
36
|
+
# @param [URI,String] url
|
37
|
+
# @return [nil] when this uri doesn't match
|
38
|
+
# @return [Numeric] number of characters that were used
|
14
39
|
def self.guess( url )
|
15
40
|
Source::guess_regex(REGEX, url)
|
16
41
|
end
|
@@ -18,76 +43,87 @@ module FPM; module Fry ; module Source
|
|
18
43
|
class Cache < Struct.new(:package, :tempdir)
|
19
44
|
extend Forwardable
|
20
45
|
|
21
|
-
def_delegators :package, :url, :rev, :logger, :file_map
|
22
|
-
|
23
|
-
def update
|
24
|
-
begin
|
25
|
-
if !File.exists? repodir
|
26
|
-
if (ecode = git('init', '--bare')) != 0
|
27
|
-
raise CacheFailed.new("Initializing git repository failed", exit_code: ecode)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
if (ecode = git('fetch','--depth=1', url.to_s, rev)) != 0
|
31
|
-
raise CacheFailed.new("Failed to fetch from remote", exit_code: ecode, url: url.to_s, rev: rev)
|
32
|
-
end
|
33
|
-
return self
|
34
|
-
rescue Errno::ENOENT
|
35
|
-
raise "Cannot find git binary. Is it installed?"
|
36
|
-
end
|
37
|
-
end
|
46
|
+
def_delegators :package, :url, :rev, :logger, :file_map, :to
|
38
47
|
|
39
48
|
def tar_io
|
40
|
-
|
41
|
-
logger.debug("Running git",cmd: cmd)
|
42
|
-
IO.popen(cmd)
|
49
|
+
Exec::popen(package.git, "--git-dir=#{repodir}",'archive','--format=tar','FETCH_HEAD', logger: logger)
|
43
50
|
end
|
44
51
|
|
45
52
|
def copy_to(dst)
|
46
|
-
|
47
|
-
|
48
|
-
|
53
|
+
Exec[
|
54
|
+
package.git, "--git-dir=#{repodir}", "--work-tree=#{dst}",'checkout','FETCH_HEAD','--','*',
|
55
|
+
chdir: dst, logger: logger
|
56
|
+
]
|
49
57
|
end
|
50
58
|
|
51
59
|
def cachekey
|
52
|
-
|
53
|
-
|
54
|
-
|
60
|
+
Exec::exec(package.git, "--git-dir=#{repodir}",'rev-parse','FETCH_HEAD^{tree}', logger: logger).chomp
|
61
|
+
end
|
62
|
+
|
63
|
+
def prefix
|
64
|
+
""
|
55
65
|
end
|
66
|
+
|
56
67
|
private
|
57
|
-
def
|
58
|
-
|
68
|
+
def initialize(*_)
|
69
|
+
super
|
70
|
+
update
|
59
71
|
end
|
60
72
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
sin.close
|
66
|
-
out.each_line do |line|
|
67
|
-
logger.debug(line.chomp)
|
68
|
-
end
|
69
|
-
err.each_line do |line|
|
70
|
-
logger.debug(line.chomp)
|
73
|
+
def update
|
74
|
+
begin
|
75
|
+
if !File.exists? repodir
|
76
|
+
Exec::exec(package.git, "--git-dir=#{repodir}",'init', '--bare', description: "initializing git repository", logger: logger)
|
71
77
|
end
|
72
|
-
|
78
|
+
Exec::exec(package.git, "--git-dir=#{repodir}",'fetch','--depth=1', url.to_s, rev, description: 'fetching from remote', logger: logger)
|
79
|
+
return self
|
80
|
+
rescue => e
|
81
|
+
raise CacheFailed.new(e, url: url.to_s, rev: rev)
|
73
82
|
end
|
74
83
|
end
|
75
|
-
|
84
|
+
def repodir
|
85
|
+
File.join(tempdir,File.basename(url.path))
|
86
|
+
end
|
76
87
|
end
|
77
88
|
|
78
|
-
|
89
|
+
# @return [Cabin::Channel] logger
|
90
|
+
attr :logger
|
91
|
+
|
92
|
+
# @return [String] the git binary (default: "git")
|
93
|
+
attr :git
|
94
|
+
|
95
|
+
# @return [String] the git rev to pull (default "HEAD")
|
96
|
+
attr :rev
|
97
|
+
|
98
|
+
# @return [Hash<String,String>,nil] the file map for generating a docker file
|
99
|
+
attr :file_map
|
100
|
+
|
101
|
+
# @return [URI] the uri to pull from
|
102
|
+
attr :url
|
103
|
+
|
104
|
+
# @return [String,nil]
|
105
|
+
attr :to
|
79
106
|
|
107
|
+
# @param [URI] url the url to pull from
|
108
|
+
# @param [Hash] options
|
109
|
+
# @option options [Cabin::Channel] :logger (cabin default channel)
|
110
|
+
# @option options [String] :branch git branch to pull
|
111
|
+
# @option options [String] :tag git tag to pull
|
112
|
+
# @option options [Hash<String,String>] :file_map ({""=>""}) the file map to create the docker file from
|
80
113
|
def initialize( url, options = {} )
|
81
114
|
url = url.sub(/\A(\S+@\S+):(\S+\.git)\z/,'ssh://\1/\2')
|
82
115
|
@url = URI(url)
|
83
116
|
@logger = options.fetch(:logger){ Cabin::Channel.get }
|
84
117
|
@rev = options[:branch] || options[:tag] || options[:rev] || 'HEAD'
|
85
|
-
@file_map = options
|
118
|
+
@file_map = options[:file_map]
|
86
119
|
@git = options[:git] || 'git'
|
120
|
+
@to = options[:to]
|
87
121
|
end
|
88
122
|
|
123
|
+
# @param [String] tempdir
|
124
|
+
# @return [Cache]
|
89
125
|
def build_cache(tempdir)
|
90
|
-
Cache.new(self, tempdir)
|
126
|
+
Cache.new(self, tempdir)
|
91
127
|
end
|
92
128
|
|
93
129
|
end
|