1 |
any feedback before merging this initial version ? |
2 |
https://bugs.gentoo.org/399019 |
3 |
-mike |
4 |
|
5 |
# Copyright 1999-2012 Gentoo Foundation |
6 |
# Distributed under the terms of the GNU General Public License v2 |
7 |
# $Header: /var/cvsroot/gentoo-x86/eclass/eutils.eclass,v 1.377 2012/01/03 08:45:36 jlec Exp $ |
8 |
|
9 |
# @ECLASS: unpacker.eclass |
10 |
# @MAINTAINER: |
11 |
# base-system@g.o |
12 |
# @BLURB: helpers for extraneous file formats and consistent behavior across EAPI's |
13 |
# @DESCRIPTION: |
14 |
# Some extraneous file formats are not part of PMS, or are only in certain |
15 |
# EAPI's. Rather than worrying about that, support the crazy cruft here |
16 |
# and for all EAPI versions. |
17 |
|
18 |
# Possible todos: |
19 |
# - merge rpm unpacking |
20 |
# - support partial unpacks? |
21 |
|
22 |
if [[ ${___ECLASS_ONCE_UNPACKER} != "recur -_+^+_- spank" ]] ; then |
23 |
___ECLASS_ONCE_UNPACKER="recur -_+^+_- spank" |
24 |
|
25 |
# @ECLASS-VARIABLE: UNPACKER_BZ2 |
26 |
# @DEFAULT_UNSET |
27 |
# @DESCRIPTION: |
28 |
# Utility to use to decompress bzip2 files. Will dynamically pick between |
29 |
# `pbzip2` and `bzip2`. Make sure your choice accepts the "-c" option. |
30 |
# Note: this is meant for users to set, not ebuilds. |
31 |
|
32 |
# for internal use only (unpack_pdv and unpack_makeself) |
33 |
find_unpackable_file() { |
34 |
local src=$1 |
35 |
if [[ -z ${src} ]] ; then |
36 |
src=${DISTDIR}/${A} |
37 |
else |
38 |
if [[ ${src} == ./* ]] ; then |
39 |
: # already what we want |
40 |
elif [[ -e ${DISTDIR}/${src} ]] ; then |
41 |
src=${DISTDIR}/${src} |
42 |
elif [[ -e ${PWD}/${src} ]] ; then |
43 |
src=${PWD}/${src} |
44 |
elif [[ -e ${src} ]] ; then |
45 |
src=${src} |
46 |
fi |
47 |
fi |
48 |
[[ ! -e ${src} ]] && return 1 |
49 |
echo "${src}" |
50 |
} |
51 |
|
52 |
unpack_banner() { |
53 |
echo ">>> Unpacking ${1##*/} to ${PWD}" |
54 |
} |
55 |
|
56 |
# @FUNCTION: unpack_pdv |
57 |
# @USAGE: <file to unpack> <size of off_t> |
58 |
# @DESCRIPTION: |
59 |
# Unpack those pesky pdv generated files ... |
60 |
# They're self-unpacking programs with the binary package stuffed in |
61 |
# the middle of the archive. Valve seems to use it a lot ... too bad |
62 |
# it seems to like to segfault a lot :(. So lets take it apart ourselves. |
63 |
# |
64 |
# You have to specify the off_t size ... I have no idea how to extract that |
65 |
# information out of the binary executable myself. Basically you pass in |
66 |
# the size of the off_t type (in bytes) on the machine that built the pdv |
67 |
# archive. |
68 |
# |
69 |
# One way to determine this is by running the following commands: |
70 |
# |
71 |
# @CODE |
72 |
# strings <pdv archive> | grep lseek |
73 |
# strace -elseek <pdv archive> |
74 |
# @CODE |
75 |
# |
76 |
# Basically look for the first lseek command (we do the strings/grep because |
77 |
# sometimes the function call is _llseek or something) and steal the 2nd |
78 |
# parameter. Here is an example: |
79 |
# |
80 |
# @CODE |
81 |
# vapier@vapier 0 pdv_unpack # strings hldsupdatetool.bin | grep lseek |
82 |
# lseek |
83 |
# vapier@vapier 0 pdv_unpack # strace -elseek ./hldsupdatetool.bin |
84 |
# lseek(3, -4, SEEK_END) = 2981250 |
85 |
# @CODE |
86 |
# |
87 |
# Thus we would pass in the value of '4' as the second parameter. |
88 |
unpack_pdv() { |
89 |
local src=$(find_unpackable_file "$1") |
90 |
local sizeoff_t=$2 |
91 |
|
92 |
[[ -z ${src} ]] && die "Could not locate source for '$1'" |
93 |
[[ -z ${sizeoff_t} ]] && die "No idea what off_t size was used for this pdv :(" |
94 |
|
95 |
unpack_banner "${src}" |
96 |
|
97 |
local metaskip=$(tail -c ${sizeoff_t} "${src}" | hexdump -e \"%i\") |
98 |
local tailskip=$(tail -c $((${sizeoff_t}*2)) "${src}" | head -c ${sizeoff_t} | hexdump -e \"%i\") |
99 |
|
100 |
# grab metadata for debug reasons |
101 |
local metafile=$(emktemp) |
102 |
tail -c +$((${metaskip}+1)) "${src}" > "${metafile}" |
103 |
|
104 |
# rip out the final file name from the metadata |
105 |
local datafile=$(tail -c +$((${metaskip}+1)) "${src}" | strings | head -n 1) |
106 |
datafile=$(basename "${datafile}") |
107 |
|
108 |
# now lets uncompress/untar the file if need be |
109 |
local tmpfile=$(emktemp) |
110 |
tail -c +$((${tailskip}+1)) ${src} 2>/dev/null | head -c 512 > ${tmpfile} |
111 |
|
112 |
local iscompressed=$(file -b "${tmpfile}") |
113 |
if [[ ${iscompressed:0:8} == "compress" ]] ; then |
114 |
iscompressed=1 |
115 |
mv ${tmpfile}{,.Z} |
116 |
gunzip ${tmpfile} |
117 |
else |
118 |
iscompressed=0 |
119 |
fi |
120 |
local istar=$(file -b "${tmpfile}") |
121 |
if [[ ${istar:0:9} == "POSIX tar" ]] ; then |
122 |
istar=1 |
123 |
else |
124 |
istar=0 |
125 |
fi |
126 |
|
127 |
#for some reason gzip dies with this ... dd cant provide buffer fast enough ? |
128 |
#dd if=${src} ibs=${metaskip} count=1 \ |
129 |
# | dd ibs=${tailskip} skip=1 \ |
130 |
# | gzip -dc \ |
131 |
# > ${datafile} |
132 |
if [ ${iscompressed} -eq 1 ] ; then |
133 |
if [ ${istar} -eq 1 ] ; then |
134 |
tail -c +$((${tailskip}+1)) ${src} 2>/dev/null \ |
135 |
| head -c $((${metaskip}-${tailskip})) \ |
136 |
| tar -xzf - |
137 |
else |
138 |
tail -c +$((${tailskip}+1)) ${src} 2>/dev/null \ |
139 |
| head -c $((${metaskip}-${tailskip})) \ |
140 |
| gzip -dc \ |
141 |
> ${datafile} |
142 |
fi |
143 |
else |
144 |
if [ ${istar} -eq 1 ] ; then |
145 |
tail -c +$((${tailskip}+1)) ${src} 2>/dev/null \ |
146 |
| head -c $((${metaskip}-${tailskip})) \ |
147 |
| tar --no-same-owner -xf - |
148 |
else |
149 |
tail -c +$((${tailskip}+1)) ${src} 2>/dev/null \ |
150 |
| head -c $((${metaskip}-${tailskip})) \ |
151 |
> ${datafile} |
152 |
fi |
153 |
fi |
154 |
true |
155 |
#[ -s "${datafile}" ] || die "failure unpacking pdv ('${metaskip}' '${tailskip}' '${datafile}')" |
156 |
#assert "failure unpacking pdv ('${metaskip}' '${tailskip}' '${datafile}')" |
157 |
} |
158 |
|
159 |
# @FUNCTION: unpack_makeself |
160 |
# @USAGE: [file to unpack] [offset] [tail|dd] |
161 |
# @DESCRIPTION: |
162 |
# Unpack those pesky makeself generated files ... |
163 |
# They're shell scripts with the binary package tagged onto |
164 |
# the end of the archive. Loki utilized the format as does |
165 |
# many other game companies. |
166 |
# |
167 |
# If the file is not specified, then ${A} is used. If the |
168 |
# offset is not specified then we will attempt to extract |
169 |
# the proper offset from the script itself. |
170 |
unpack_makeself() { |
171 |
local src_input=${1:-${A}} |
172 |
local src=$(find_unpackable_file "${src_input}") |
173 |
local skip=$2 |
174 |
local exe=$3 |
175 |
|
176 |
[[ -z ${src} ]] && die "Could not locate source for '${src_input}'" |
177 |
|
178 |
unpack_banner "${src}" |
179 |
|
180 |
if [[ -z ${skip} ]] ; then |
181 |
local ver=$(grep -m1 -a '#.*Makeself' "${src}" | awk '{print $NF}') |
182 |
local skip=0 |
183 |
exe=tail |
184 |
case ${ver} in |
185 |
1.5.*|1.6.0-nv) # tested 1.5.{3,4,5} ... guessing 1.5.x series is same |
186 |
skip=$(grep -a ^skip= "${src}" | cut -d= -f2) |
187 |
;; |
188 |
2.0|2.0.1) |
189 |
skip=$(grep -a ^$'\t'tail "${src}" | awk '{print $2}' | cut -b2-) |
190 |
;; |
191 |
2.1.1) |
192 |
skip=$(grep -a ^offset= "${src}" | awk '{print $2}' | cut -b2-) |
193 |
(( skip++ )) |
194 |
;; |
195 |
2.1.2) |
196 |
skip=$(grep -a ^offset= "${src}" | awk '{print $3}' | head -n 1) |
197 |
(( skip++ )) |
198 |
;; |
199 |
2.1.3) |
200 |
skip=`grep -a ^offset= "${src}" | awk '{print $3}'` |
201 |
(( skip++ )) |
202 |
;; |
203 |
2.1.4|2.1.5) |
204 |
skip=$(grep -a offset=.*head.*wc "${src}" | awk '{print $3}' | head -n 1) |
205 |
skip=$(head -n ${skip} "${src}" | wc -c) |
206 |
exe="dd" |
207 |
;; |
208 |
*) |
209 |
eerror "I'm sorry, but I was unable to support the Makeself file." |
210 |
eerror "The version I detected was '${ver}'." |
211 |
eerror "Please file a bug about the file ${src##*/} at" |
212 |
eerror "http://bugs.gentoo.org/ so that support can be added." |
213 |
die "makeself version '${ver}' not supported" |
214 |
;; |
215 |
esac |
216 |
debug-print "Detected Makeself version ${ver} ... using ${skip} as offset" |
217 |
fi |
218 |
case ${exe} in |
219 |
tail) exe="tail -n +${skip} '${src}'";; |
220 |
dd) exe="dd ibs=${skip} skip=1 if='${src}'";; |
221 |
*) die "makeself cant handle exe '${exe}'" |
222 |
esac |
223 |
|
224 |
# lets grab the first few bytes of the file to figure out what kind of archive it is |
225 |
local filetype tmpfile=$(emktemp) |
226 |
eval ${exe} 2>/dev/null | head -c 512 > "${tmpfile}" |
227 |
filetype=$(file -b "${tmpfile}") || die |
228 |
case ${filetype} in |
229 |
*tar\ archive*) |
230 |
eval ${exe} | tar --no-same-owner -xf - |
231 |
;; |
232 |
bzip2*) |
233 |
eval ${exe} | bzip2 -dc | tar --no-same-owner -xf - |
234 |
;; |
235 |
gzip*) |
236 |
eval ${exe} | tar --no-same-owner -xzf - |
237 |
;; |
238 |
compress*) |
239 |
eval ${exe} | gunzip | tar --no-same-owner -xf - |
240 |
;; |
241 |
*) |
242 |
eerror "Unknown filetype \"${filetype}\" ?" |
243 |
false |
244 |
;; |
245 |
esac |
246 |
assert "failure unpacking (${filetype}) makeself ${src##*/} ('${ver}' +${skip})" |
247 |
} |
248 |
|
249 |
# @FUNCTION: unpack_deb |
250 |
# @USAGE: <one deb to unpack> |
251 |
# @DESCRIPTION: |
252 |
# Unpack a Debian .deb archive in style. |
253 |
unpack_deb() { |
254 |
[[ $# -eq 1 ]] || die "Usage: ${FUNCNAME} <file>" |
255 |
|
256 |
local deb=$(find_unpackable_file "$1") |
257 |
|
258 |
unpack_banner "${deb}" |
259 |
|
260 |
ar x "${deb}" |
261 |
unpack ./data.tar* |
262 |
} |
263 |
|
264 |
# @FUNCTION: _unpacker |
265 |
# @USAGE: <one archive to unpack> |
266 |
# @INTERNAL |
267 |
# @DESCRIPTION: |
268 |
# Unpack the specified archive. We only operate on one archive here |
269 |
# to keep down on the looping logic (that is handled by `unpacker`). |
270 |
_unpacker() { |
271 |
[[ $# -eq 1 ]] || die "Usage: ${FUNCNAME} <file>" |
272 |
|
273 |
local a=$1 |
274 |
local m=$(echo "${a}" | tr '[:upper:]' '[:lower:]') |
275 |
a=$(find_unpackable_file "${a}") |
276 |
|
277 |
# first figure out the decompression method |
278 |
case ${m} in |
279 |
*.bz2|*.tbz|*.tbz2) |
280 |
: ${PORTAGE_BZIP2_COMMAND:=$(type -P pbzip2 || bzip2)} |
281 |
: ${PORTAGE_BUNZIP2_COMMAND:=${PORTAGE_BZIP2_COMMAND} -d} |
282 |
: ${UNPACKER_BZ2:=${PORTAGE_BUNZIP2_COMMAND}} |
283 |
comp="${PORTAGE_BUNZIP2_COMMAND} -c" |
284 |
;; |
285 |
*.z|*.gz|*.tgz) |
286 |
comp="gzip -dc" ;; |
287 |
*.lzma|*.xz|*.txz) |
288 |
comp="xz -dc" ;; |
289 |
*) comp="" ;; |
290 |
esac |
291 |
|
292 |
# then figure out if there are any archiving aspects |
293 |
case ${m} in |
294 |
*.tgz|*.tbz|*.tbz2|*.txz|*.tar.*|*.tar) |
295 |
arch="tar --no-same-owner -xof" ;; |
296 |
*.deb) |
297 |
arch="unpack_deb" ;; |
298 |
*.run) |
299 |
arch="unpack_makeself" ;; |
300 |
*) arch="" ;; |
301 |
esac |
302 |
|
303 |
# finally do the unpack |
304 |
[[ -z ${arch}${comp} ]] && return 1 |
305 |
|
306 |
[[ ${arch} != unpack_* ]] && unpack_banner "${a}" |
307 |
|
308 |
if [[ -z ${arch} ]] ; then |
309 |
${comp} "${a}" > "${a%.*}" |
310 |
elif [[ -z ${comp} ]] ; then |
311 |
${arch} "${a}" |
312 |
else |
313 |
${comp} "${a}" | ${arch} - |
314 |
fi |
315 |
|
316 |
assert "unpacking ${a} failed (comp=${comp} arch=${arch})" |
317 |
} |
318 |
|
319 |
# @FUNCTION: unpacker |
320 |
# @USAGE: [archives to unpack] |
321 |
# @DESCRIPTION: |
322 |
# This works in the same way that `unpack` does. If you don't specify |
323 |
# any files, it will default to ${A}. |
324 |
unpacker() { |
325 |
local a |
326 |
[[ $# -eq 0 ]] && set -- ${A} |
327 |
for a ; do _unpacker "${a}" ; done |
328 |
} |
329 |
|
330 |
# @FUNCTION: unpacker_src_unpack |
331 |
# @DESCRIPTION: |
332 |
# Run `unpacker` to unpack all our stuff. |
333 |
unpacker_src_unpack() { |
334 |
unpacker |
335 |
} |
336 |
|
337 |
# @FUNCTION: unpacker |
338 |
# @USAGE: [archives that we will unpack] |
339 |
# @RETURN: Dependencies needed to unpack all the archives |
340 |
# @DESCRIPTION: |
341 |
# Walk all the specified files (defaults to $SRC_URI) and figure out the |
342 |
# dependencies that are needed to unpack things. |
343 |
# |
344 |
# Note: USE flags are not yet handled. |
345 |
unpacker_src_uri_depends() { |
346 |
local uri deps d |
347 |
|
348 |
[[ $# -eq 0 ]] && set -- ${SRC_URI} |
349 |
|
350 |
for uri in "$@" ; do |
351 |
case ${uri} in |
352 |
*.rar|*.RAR) |
353 |
d="app-arch/unrar" ;; |
354 |
*.7z) |
355 |
d="app-arch/p7zip" ;; |
356 |
*.xz) |
357 |
d="app-arch/xz-utils" ;; |
358 |
esac |
359 |
deps+=" ${d}" |
360 |
done |
361 |
|
362 |
echo "${deps}" |
363 |
} |
364 |
|
365 |
EXPORT_FUNCTIONS src_unpack |
366 |
|
367 |
fi |