fpm 1.5.0 → 1.6.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 +4 -4
- data/CHANGELIST +10 -0
- data/LICENSE +1 -1
- data/lib/fpm/command.rb +14 -8
- data/lib/fpm/package.rb +25 -11
- data/lib/fpm/package/apk.rb +510 -0
- data/lib/fpm/package/cpan.rb +1 -1
- data/lib/fpm/package/deb.rb +3 -3
- data/lib/fpm/package/dir.rb +14 -0
- data/lib/fpm/package/freebsd.rb +15 -36
- data/lib/fpm/package/gem.rb +1 -1
- data/lib/fpm/package/osxpkg.rb +3 -2
- data/lib/fpm/package/pacman.rb +4 -3
- data/lib/fpm/package/pleaserun.rb +63 -0
- data/lib/fpm/package/python.rb +2 -1
- data/lib/fpm/package/rpm.rb +10 -3
- data/lib/fpm/package/tar.rb +12 -0
- data/lib/fpm/package/virtualenv.rb +1 -1
- data/lib/fpm/rake_task.rb +2 -1
- data/lib/fpm/util.rb +143 -38
- data/lib/fpm/util/tar_writer.rb +80 -0
- data/lib/fpm/version.rb +1 -1
- data/templates/pleaserun/generate-cleanup.sh +17 -0
- data/templates/pleaserun/install-path.sh +17 -0
- data/templates/pleaserun/install.sh +117 -0
- data/templates/pleaserun/scripts/after-install.sh +4 -0
- data/templates/pleaserun/scripts/before-remove.sh +12 -0
- metadata +15 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 173d3185b39df15876683e91714e7a93970490cc
|
4
|
+
data.tar.gz: 15ffd8f3ff5b2658cd35aeb8b6188d90a00d3f7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d25c03ef3397d2731d75d97c976a69174caa7b8eed89d8318d561e4516ecf5b4fb47d1f0fe5e96edb26094870b9c27e30d9366e89c3384bc527dea6cfd85c7f6
|
7
|
+
data.tar.gz: e6ee35e8c70e12f88d8350bfb7d5f4e06939d33257fcea64e3f16918f60acb84865c66bd7ac2ee6e6c0dea0ade119e7982256f0e9644ad860c6a8b40936427ca
|
data/CHANGELIST
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
1.6.0 (May 25, 2016)
|
2
|
+
- New source: pleaserun. This lets you create packages that will install a
|
3
|
+
system service. An after-install script is used in the package to determine
|
4
|
+
which service platform to target (systemd, upstart, etc). (#1119, #1112)
|
5
|
+
- New target: Alpine Linux "apk" packages. (#1054, George Lester)
|
6
|
+
- deb: don't append `.conf` to an upstart file if the file name already ends
|
7
|
+
in `.conf`. (#1115, josegonzalez)
|
8
|
+
- freebsd: fix bug where --package flag was ignored. (#1093, Paweł Tomulik)
|
9
|
+
- Improvements to the fpm rake tasks (#1101, Evan Gilman)
|
10
|
+
|
1
11
|
1.5.0 (April 12, 2016)
|
2
12
|
- Arch package support is now available via -s pacman and -t pacman.
|
3
13
|
(#916; wonderful community effort making this happen!)
|
data/LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
(This is an MIT-style license)
|
2
2
|
|
3
|
-
Copyright (c) 2011
|
3
|
+
Copyright (c) 2011-2016 Jordan Sissel and contributors.
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/lib/fpm/command.rb
CHANGED
@@ -111,8 +111,8 @@ class FPM::Command < Clamp::Command
|
|
111
111
|
"specified multiple times.", :multivalued => true,
|
112
112
|
:attribute_name => :conflicts
|
113
113
|
option "--replaces", "REPLACES",
|
114
|
-
"Other packages/versions this package replaces.
|
115
|
-
"specified multiple times.", :multivalued => true,
|
114
|
+
"Other packages/versions this package replaces. Equivalent of rpm's 'Obsoletes'. " \
|
115
|
+
"This flag can be specified multiple times.", :multivalued => true,
|
116
116
|
:attribute_name => :replaces
|
117
117
|
|
118
118
|
option "--config-files", "CONFIG_FILES",
|
@@ -332,12 +332,18 @@ class FPM::Command < Clamp::Command
|
|
332
332
|
end
|
333
333
|
end
|
334
334
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
input.
|
335
|
+
if input_type == "pleaserun"
|
336
|
+
# Special case for pleaserun that all parameters are considered the 'command'
|
337
|
+
# to run through pleaserun.
|
338
|
+
input.input(args)
|
339
|
+
else
|
340
|
+
# Each remaining command line parameter is used as an 'input' argument.
|
341
|
+
# For directories, this means paths. For things like gem and python, this
|
342
|
+
# means package name or paths to the packages (rails, foo-1.0.gem, django,
|
343
|
+
# bar/setup.py, etc)
|
344
|
+
args.each do |arg|
|
345
|
+
input.input(arg)
|
346
|
+
end
|
341
347
|
end
|
342
348
|
|
343
349
|
# If --inputs was specified, read it as a file.
|
data/lib/fpm/package.rb
CHANGED
@@ -331,17 +331,31 @@ class FPM::Package
|
|
331
331
|
return erb
|
332
332
|
end # def template
|
333
333
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
334
|
+
#######################################
|
335
|
+
# The following methods are provided to
|
336
|
+
# easily override particular substitut-
|
337
|
+
# ions performed by to_s for subclasses
|
338
|
+
#######################################
|
339
|
+
def to_s_arch; architecture.to_s; end
|
340
|
+
def to_s_name; name.to_s; end
|
341
|
+
def to_s_fullversion; iteration ? "#{version}-#{iteration}" : "#{version}"; end
|
342
|
+
def to_s_version; version.to_s; end
|
343
|
+
def to_s_iteration; iteration.to_s; end
|
344
|
+
def to_s_epoch; epoch.to_s; end
|
345
|
+
def to_s_type; type.to_s; end
|
346
|
+
def to_s_extension; type.to_s; end
|
347
|
+
#######################################
|
348
|
+
|
349
|
+
def to_s(fmt=nil)
|
350
|
+
fmt = "NAME.EXTENSION" if fmt.nil?
|
351
|
+
return fmt.gsub("ARCH", to_s_arch) \
|
352
|
+
.gsub("NAME", to_s_name) \
|
353
|
+
.gsub("FULLVERSION", to_s_fullversion) \
|
354
|
+
.gsub("VERSION", to_s_version) \
|
355
|
+
.gsub("ITERATION", to_s_iteration) \
|
356
|
+
.gsub("EPOCH", to_s_epoch) \
|
357
|
+
.gsub("TYPE", to_s_type) \
|
358
|
+
.gsub("EXTENSION", to_s_extension)
|
345
359
|
end # def to_s
|
346
360
|
|
347
361
|
def edit_file(path)
|
@@ -0,0 +1,510 @@
|
|
1
|
+
require "erb"
|
2
|
+
require "fpm/namespace"
|
3
|
+
require "fpm/package"
|
4
|
+
require "fpm/errors"
|
5
|
+
require "fpm/util"
|
6
|
+
require "backports"
|
7
|
+
require "fileutils"
|
8
|
+
require "digest"
|
9
|
+
require 'digest/sha1'
|
10
|
+
|
11
|
+
# Support for debian packages (.deb files)
|
12
|
+
#
|
13
|
+
# This class supports both input and output of packages.
|
14
|
+
class FPM::Package::APK< FPM::Package
|
15
|
+
|
16
|
+
TAR_CHUNK_SIZE = 512
|
17
|
+
TAR_TYPEFLAG_OFFSET = 156
|
18
|
+
TAR_NAME_OFFSET_START = 0
|
19
|
+
TAR_NAME_OFFSET_END = 99
|
20
|
+
TAR_LENGTH_OFFSET_START = 124
|
21
|
+
TAR_LENGTH_OFFSET_END = 135
|
22
|
+
TAR_CHECKSUM_OFFSET_START = 148
|
23
|
+
TAR_CHECKSUM_OFFSET_END = 155
|
24
|
+
TAR_MAGIC_START = 257
|
25
|
+
TAR_MAGIC_END = 264
|
26
|
+
TAR_UID_START = 108
|
27
|
+
TAR_UID_END = 115
|
28
|
+
TAR_GID_START = 116
|
29
|
+
TAR_GID_END = 123
|
30
|
+
TAR_UNAME_START = 265
|
31
|
+
TAR_UNAME_END = 296
|
32
|
+
TAR_GNAME_START = 297
|
33
|
+
TAR_GNAME_END = 328
|
34
|
+
TAR_MAJOR_START = 329
|
35
|
+
TAR_MAJOR_END = 336
|
36
|
+
TAR_MINOR_START = 337
|
37
|
+
TAR_MINOR_END = 344
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Get the name of this package. See also FPM::Package#name
|
42
|
+
#
|
43
|
+
# This accessor actually modifies the name if it has some invalid or unwise
|
44
|
+
# characters.
|
45
|
+
def name
|
46
|
+
if @name =~ /[A-Z]/
|
47
|
+
logger.warn("apk packages should not have uppercase characters in their names")
|
48
|
+
@name = @name.downcase
|
49
|
+
end
|
50
|
+
|
51
|
+
if @name.include?("_")
|
52
|
+
logger.warn("apk packages should not include underscores")
|
53
|
+
@name = @name.gsub(/[_]/, "-")
|
54
|
+
end
|
55
|
+
|
56
|
+
if @name.include?(" ")
|
57
|
+
logger.warn("apk packages should not contain spaces")
|
58
|
+
@name = @name.gsub(/[ ]/, "-")
|
59
|
+
end
|
60
|
+
|
61
|
+
return @name
|
62
|
+
end
|
63
|
+
|
64
|
+
def prefix
|
65
|
+
return (attributes[:prefix] or "/")
|
66
|
+
end
|
67
|
+
|
68
|
+
def architecture
|
69
|
+
|
70
|
+
# "native" in apk should be "noarch"
|
71
|
+
if @architecture.nil? or @architecture == "native"
|
72
|
+
@architecture = "noarch"
|
73
|
+
end
|
74
|
+
return @architecture
|
75
|
+
end
|
76
|
+
|
77
|
+
def input(input_path)
|
78
|
+
logger.error("apk extraction is not yet implemented")
|
79
|
+
end
|
80
|
+
|
81
|
+
def output(output_path)
|
82
|
+
|
83
|
+
output_check(output_path)
|
84
|
+
|
85
|
+
control_path = build_path("control")
|
86
|
+
controltar_path = build_path("control.tar")
|
87
|
+
datatar_path = build_path("data.tar")
|
88
|
+
|
89
|
+
FileUtils.mkdir(control_path)
|
90
|
+
|
91
|
+
# data tar.
|
92
|
+
tar_path(staging_path(""), datatar_path)
|
93
|
+
|
94
|
+
# control tar.
|
95
|
+
begin
|
96
|
+
write_pkginfo(control_path)
|
97
|
+
write_control_scripts(control_path)
|
98
|
+
tar_path(control_path, controltar_path)
|
99
|
+
ensure
|
100
|
+
FileUtils.rm_r(control_path)
|
101
|
+
end
|
102
|
+
|
103
|
+
# concatenate the two into a real apk.
|
104
|
+
begin
|
105
|
+
|
106
|
+
# cut end-of-tar record from control tar
|
107
|
+
cut_tar_record(controltar_path)
|
108
|
+
|
109
|
+
# calculate/rewrite sha1 hashes for data tar
|
110
|
+
hash_datatar(datatar_path)
|
111
|
+
|
112
|
+
# concatenate the two into the final apk
|
113
|
+
concat_zip_tars(controltar_path, datatar_path, output_path)
|
114
|
+
end
|
115
|
+
|
116
|
+
logger.warn("apk output does not currently sign packages.")
|
117
|
+
logger.warn("It's recommended that your package be installed with '--allow-untrusted'")
|
118
|
+
end
|
119
|
+
|
120
|
+
def write_pkginfo(base_path)
|
121
|
+
|
122
|
+
pkginfo = ""
|
123
|
+
|
124
|
+
pkginfo << "# Generated by fpm\n"
|
125
|
+
pkginfo << "pkgname = #{@name}\n"
|
126
|
+
pkginfo << "pkgver = #{to_s("FULLVERSION")}\n"
|
127
|
+
pkginfo << "arch = #{architecture()}\n"
|
128
|
+
pkginfo << "pkgdesc = #{description()}\n"
|
129
|
+
pkginfo << "url = #{url()}\n"
|
130
|
+
pkginfo << "size = 102400\n" # totally magic, not sure what it's used for.
|
131
|
+
|
132
|
+
# write depends lines
|
133
|
+
for dependency in dependencies()
|
134
|
+
pkginfo << "depend = #{dependency}\n"
|
135
|
+
end
|
136
|
+
|
137
|
+
File.write("#{base_path}/.PKGINFO", pkginfo)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Writes each control script from template into the build path,
|
141
|
+
# in the folder given by [base_path]
|
142
|
+
def write_control_scripts(base_path)
|
143
|
+
|
144
|
+
scripts = {}
|
145
|
+
|
146
|
+
scripts = register_script('post-install', :after_install, scripts)
|
147
|
+
scripts = register_script('post-install', :before_install, scripts)
|
148
|
+
scripts = register_script('post-install', :before_upgrade, scripts)
|
149
|
+
scripts = register_script('post-install', :after_upgrade, scripts)
|
150
|
+
scripts = register_script('pre-deinstall', :before_remove, scripts)
|
151
|
+
scripts = register_script('post-deinstall', :after_remove, scripts)
|
152
|
+
|
153
|
+
scripts.each do |key, content|
|
154
|
+
|
155
|
+
File.write("#{base_path}/.#{key}", content)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Convenience method for 'write_control_scripts' to register control scripts
|
160
|
+
# if they exist.
|
161
|
+
def register_script(key, value, hash)
|
162
|
+
|
163
|
+
if(script?(value))
|
164
|
+
hash[key] = scripts[value]
|
165
|
+
end
|
166
|
+
return hash
|
167
|
+
end
|
168
|
+
|
169
|
+
# Removes the end-of-tar records from the given [target_path].
|
170
|
+
# End of tar records are two contiguous empty tar records at the end of the file
|
171
|
+
# Taken together, they comprise 1k of null data.
|
172
|
+
def cut_tar_record(target_path)
|
173
|
+
|
174
|
+
temporary_target_path = target_path + "~"
|
175
|
+
|
176
|
+
record_length = 0
|
177
|
+
empty_records = 0
|
178
|
+
|
179
|
+
open(temporary_target_path, "wb") do |target_file|
|
180
|
+
|
181
|
+
# Scan to find the location of the two contiguous null records
|
182
|
+
open(target_path, "rb") do |file|
|
183
|
+
|
184
|
+
until(empty_records == 2)
|
185
|
+
|
186
|
+
header = file.read(TAR_CHUNK_SIZE)
|
187
|
+
|
188
|
+
# clear off ownership info
|
189
|
+
header = replace_ownership_headers(header, true)
|
190
|
+
|
191
|
+
typeflag = header[TAR_TYPEFLAG_OFFSET]
|
192
|
+
ascii_length = header[TAR_LENGTH_OFFSET_START..TAR_LENGTH_OFFSET_END]
|
193
|
+
|
194
|
+
if(file.eof?())
|
195
|
+
raise StandardError.new("Invalid tar stream, eof before end-of-tar record")
|
196
|
+
end
|
197
|
+
|
198
|
+
if(typeflag == "\0")
|
199
|
+
empty_records += 1
|
200
|
+
next
|
201
|
+
end
|
202
|
+
|
203
|
+
record_length = ascii_length.to_i(8)
|
204
|
+
record_length = determine_record_length(record_length)
|
205
|
+
|
206
|
+
target_file.write(header)
|
207
|
+
target_file.write(file.read(record_length))
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
FileUtils::mv(temporary_target_path, target_path)
|
213
|
+
end
|
214
|
+
|
215
|
+
# Rewrites the tar file located at the given [target_tar_path]
|
216
|
+
# to have its record headers use a simple checksum,
|
217
|
+
# and the apk sha1 hash extension.
|
218
|
+
def hash_datatar(target_path)
|
219
|
+
|
220
|
+
header = extension_header = ""
|
221
|
+
data = extension_data = ""
|
222
|
+
record_length = extension_length = 0
|
223
|
+
empty_records = 0
|
224
|
+
|
225
|
+
temporary_file_name = target_path + "~"
|
226
|
+
|
227
|
+
target_file = open(temporary_file_name, "wb")
|
228
|
+
file = open(target_path, "rb")
|
229
|
+
begin
|
230
|
+
|
231
|
+
until(file.eof?() || empty_records == 2)
|
232
|
+
|
233
|
+
header = file.read(TAR_CHUNK_SIZE)
|
234
|
+
typeflag = header[TAR_TYPEFLAG_OFFSET]
|
235
|
+
record_length = header[TAR_LENGTH_OFFSET_START..TAR_LENGTH_OFFSET_END].to_i(8)
|
236
|
+
|
237
|
+
data = ""
|
238
|
+
record_length = determine_record_length(record_length)
|
239
|
+
|
240
|
+
until(data.length == record_length)
|
241
|
+
data += file.read(TAR_CHUNK_SIZE)
|
242
|
+
end
|
243
|
+
|
244
|
+
# Clear ownership fields
|
245
|
+
header = replace_ownership_headers(header, false)
|
246
|
+
|
247
|
+
# If it's not a null record, do extension hash.
|
248
|
+
if(typeflag != "\0")
|
249
|
+
extension_header = header.dup()
|
250
|
+
|
251
|
+
extension_header = replace_ownership_headers(extension_header, true)
|
252
|
+
|
253
|
+
# directories have a magic string inserted into their name
|
254
|
+
full_record_path = extension_header[TAR_NAME_OFFSET_START..TAR_NAME_OFFSET_END].delete("\0")
|
255
|
+
full_record_path = add_paxstring(full_record_path)
|
256
|
+
|
257
|
+
# hash data contents with sha1, if there is any content.
|
258
|
+
if(typeflag == '5')
|
259
|
+
|
260
|
+
extension_data = ""
|
261
|
+
|
262
|
+
# ensure it doesn't end with a slash
|
263
|
+
if(full_record_path[full_record_path.length-1] == '/')
|
264
|
+
full_record_path = full_record_path.chop()
|
265
|
+
end
|
266
|
+
else
|
267
|
+
extension_data = hash_record(data)
|
268
|
+
end
|
269
|
+
|
270
|
+
full_record_path = pad_string_to(full_record_path, 100)
|
271
|
+
extension_header[TAR_NAME_OFFSET_START..TAR_NAME_OFFSET_END] = full_record_path
|
272
|
+
|
273
|
+
extension_header[TAR_TYPEFLAG_OFFSET] = 'x'
|
274
|
+
extension_header[TAR_LENGTH_OFFSET_START..TAR_LENGTH_OFFSET_END] = extension_data.length.to_s(8).rjust(12, '0')
|
275
|
+
extension_header = checksum_header(extension_header)
|
276
|
+
|
277
|
+
# write extension record
|
278
|
+
target_file.write(extension_header)
|
279
|
+
target_file.write(extension_data)
|
280
|
+
else
|
281
|
+
empty_records += 1
|
282
|
+
end
|
283
|
+
|
284
|
+
# write header and data to target file.
|
285
|
+
target_file.write(header)
|
286
|
+
target_file.write(data)
|
287
|
+
end
|
288
|
+
FileUtils.mv(temporary_file_name, target_path)
|
289
|
+
ensure
|
290
|
+
file.close()
|
291
|
+
target_file.close()
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
# Concatenates each of the given [apath] and [bpath] into the given [target_path]
|
296
|
+
def concat_zip_tars(apath, bpath, target_path)
|
297
|
+
|
298
|
+
temp_apath = apath + "~"
|
299
|
+
temp_bpath = bpath + "~"
|
300
|
+
|
301
|
+
# zip each path separately
|
302
|
+
Zlib::GzipWriter.open(temp_apath) do |target_writer|
|
303
|
+
open(apath, "rb") do |file|
|
304
|
+
until(file.eof?())
|
305
|
+
target_writer.write(file.read(4096))
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
Zlib::GzipWriter.open(temp_bpath) do |target_writer|
|
311
|
+
open(bpath, "rb") do |file|
|
312
|
+
until(file.eof?())
|
313
|
+
target_writer.write(file.read(4096))
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
# concat both into one.
|
319
|
+
File.open(target_path, "wb") do |target_writer|
|
320
|
+
open(temp_apath, "rb") do |file|
|
321
|
+
until(file.eof?())
|
322
|
+
target_writer.write(file.read(4096))
|
323
|
+
end
|
324
|
+
end
|
325
|
+
open(temp_bpath, "rb") do |file|
|
326
|
+
until(file.eof?())
|
327
|
+
target_writer.write(file.read(4096))
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
# Rounds the given [record_length] to the nearest highest evenly-divisble number of 512.
|
334
|
+
def determine_record_length(record_length)
|
335
|
+
|
336
|
+
sans_size = TAR_CHUNK_SIZE-1
|
337
|
+
|
338
|
+
if(record_length % TAR_CHUNK_SIZE != 0)
|
339
|
+
record_length = (record_length + sans_size) & ~sans_size;
|
340
|
+
end
|
341
|
+
return record_length
|
342
|
+
end
|
343
|
+
|
344
|
+
# Checksums the entire contents of the given [header]
|
345
|
+
# Writes the resultant checksum into indices 148-155 of the same [header],
|
346
|
+
# and returns the modified header.
|
347
|
+
# 148-155 is the "size" range in a tar/ustar header.
|
348
|
+
def checksum_header(header)
|
349
|
+
|
350
|
+
# blank out header checksum
|
351
|
+
replace_string_range(header, TAR_CHECKSUM_OFFSET_START, TAR_CHECKSUM_OFFSET_END, ' ')
|
352
|
+
|
353
|
+
# calculate new checksum
|
354
|
+
checksum = 0
|
355
|
+
|
356
|
+
for i in 0..(TAR_CHUNK_SIZE-1)
|
357
|
+
checksum += header.getbyte(i)
|
358
|
+
end
|
359
|
+
|
360
|
+
checksum = checksum.to_s(8).rjust(6, '0')
|
361
|
+
header[TAR_CHECKSUM_OFFSET_START..TAR_CHECKSUM_OFFSET_END-2] = checksum
|
362
|
+
header[TAR_CHECKSUM_OFFSET_END-1] = "\0"
|
363
|
+
return header
|
364
|
+
end
|
365
|
+
|
366
|
+
# SHA-1 hashes the given data, then places it in the APK hash string format
|
367
|
+
# then returns.
|
368
|
+
def hash_record(data)
|
369
|
+
|
370
|
+
# %u %s=%s\n
|
371
|
+
# len name=hash
|
372
|
+
|
373
|
+
hash = Digest::SHA1.hexdigest(data)
|
374
|
+
name = "APK-TOOLS.checksum.SHA1"
|
375
|
+
|
376
|
+
ret = "#{name}=#{hash}\n"
|
377
|
+
|
378
|
+
# the length requirement needs to know its own length too, because the length
|
379
|
+
# is the entire length of the line, not just the contents.
|
380
|
+
length = ret.length
|
381
|
+
line_length = length.to_s
|
382
|
+
length += line_length.length
|
383
|
+
candidate_ret = "#{line_length} #{ret}"
|
384
|
+
|
385
|
+
if(candidate_ret.length != length)
|
386
|
+
length += 1
|
387
|
+
candidate_ret = "#{length.to_s} #{ret}"
|
388
|
+
end
|
389
|
+
|
390
|
+
ret = candidate_ret
|
391
|
+
|
392
|
+
# pad out the result
|
393
|
+
ret = pad_string_to(ret, TAR_CHUNK_SIZE)
|
394
|
+
return ret
|
395
|
+
end
|
396
|
+
|
397
|
+
# Tars the current contents of the given [path] to the given [target_path].
|
398
|
+
def tar_path(path, target_path)
|
399
|
+
|
400
|
+
# Change directory to the source path, and glob files
|
401
|
+
# This is done so that we end up with a "flat" archive, that doesn't
|
402
|
+
# have any path artifacts from the packager's absolute path.
|
403
|
+
::Dir::chdir(path) do
|
404
|
+
entries = ::Dir::glob("**", File::FNM_DOTMATCH)
|
405
|
+
|
406
|
+
args =
|
407
|
+
[
|
408
|
+
tar_cmd,
|
409
|
+
"-f",
|
410
|
+
target_path,
|
411
|
+
"-c"
|
412
|
+
]
|
413
|
+
|
414
|
+
# Move pkginfo to the front, if it exists.
|
415
|
+
for i in (0..entries.length)
|
416
|
+
if(entries[i] == ".PKGINFO")
|
417
|
+
entries[i] = entries[0]
|
418
|
+
entries[0] = ".PKGINFO"
|
419
|
+
break
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
# add entries to arguments.
|
424
|
+
entries.each do |entry|
|
425
|
+
unless(entry == '..' || entry == '.')
|
426
|
+
args = args << entry
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
safesystem(*args)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
# APK adds a "PAX" magic string into most directory names.
|
435
|
+
# This takes an unchanged directory name and "paxifies" it.
|
436
|
+
def add_paxstring(ret)
|
437
|
+
|
438
|
+
pax_slash = ret.rindex('/')
|
439
|
+
if(pax_slash == nil)
|
440
|
+
pax_slash = 0
|
441
|
+
else
|
442
|
+
pax_slash = ret.rindex('/', pax_slash-1)
|
443
|
+
if(pax_slash == nil || pax_slash < 0)
|
444
|
+
pax_slash = 0
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
ret = ret.insert(pax_slash, "/PaxHeaders.14670/")
|
449
|
+
ret = ret.sub("//", "/")
|
450
|
+
return ret
|
451
|
+
end
|
452
|
+
|
453
|
+
# Appends null zeroes to the end of [ret] until it is divisible by [length].
|
454
|
+
# Returns the padded result.
|
455
|
+
def pad_string_to(ret, length)
|
456
|
+
|
457
|
+
until(ret.length % length == 0)
|
458
|
+
ret << "\0"
|
459
|
+
end
|
460
|
+
return ret
|
461
|
+
end
|
462
|
+
|
463
|
+
# Replaces every character between [start] and [finish] in the given [str]
|
464
|
+
# with [character].
|
465
|
+
def replace_string_range(str, start, finish, character)
|
466
|
+
|
467
|
+
for i in (start..finish)
|
468
|
+
str[i] = character
|
469
|
+
end
|
470
|
+
|
471
|
+
return str
|
472
|
+
end
|
473
|
+
|
474
|
+
# Nulls out the ownership bits of the given tar [header].
|
475
|
+
def replace_ownership_headers(header, nullify_names)
|
476
|
+
|
477
|
+
# magic
|
478
|
+
header[TAR_MAGIC_START..TAR_MAGIC_END] = "ustar\0" + "00"
|
479
|
+
|
480
|
+
# ids
|
481
|
+
header = replace_string_range(header, TAR_UID_START, TAR_UID_END, "0")
|
482
|
+
header = replace_string_range(header, TAR_GID_START, TAR_GID_END, "0")
|
483
|
+
header[TAR_GID_END] = "\0"
|
484
|
+
header[TAR_UID_END] = "\0"
|
485
|
+
|
486
|
+
# names
|
487
|
+
if(nullify_names)
|
488
|
+
header = replace_string_range(header, TAR_UNAME_START, TAR_UNAME_END, "\0")
|
489
|
+
header = replace_string_range(header, TAR_GNAME_START, TAR_GNAME_END, "\0")
|
490
|
+
|
491
|
+
# major/minor
|
492
|
+
header[TAR_MAJOR_START..TAR_MAJOR_END] = "0".rjust(8, '0')
|
493
|
+
header[TAR_MINOR_START..TAR_MINOR_END] = "0".rjust(8, '0')
|
494
|
+
header[TAR_MAJOR_END] = "\0"
|
495
|
+
header[TAR_MINOR_END] = "\0"
|
496
|
+
else
|
497
|
+
header[TAR_UNAME_START..TAR_UNAME_END] = pad_string_to("root", 32)
|
498
|
+
header[TAR_GNAME_START..TAR_GNAME_END] = pad_string_to("root", 32)
|
499
|
+
end
|
500
|
+
|
501
|
+
return header
|
502
|
+
end
|
503
|
+
|
504
|
+
def to_s(format=nil)
|
505
|
+
return super("NAME_FULLVERSION_ARCH.TYPE") if format.nil?
|
506
|
+
return super(format)
|
507
|
+
end
|
508
|
+
|
509
|
+
public(:input, :output, :architecture, :name, :prefix, :converted_from, :to_s)
|
510
|
+
end
|