epm-repack 13.9 KB
Newer Older
1 2
#!/bin/sh
#
3 4
# Copyright (C) 2017-2018, 2020  Etersoft
# Copyright (C) 2017-2018, 2020  Vitaly Lipatov <lav@etersoft.ru>
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

load_helper epm-sh-altlinux
load_helper epm-assure

23 24
[ -n "$EPM_REPACK_SCRIPTS_DIR" ] || EPM_REPACK_SCRIPTS_DIR="$CONFIGDIR/repack.d"

25 26 27 28 29 30

__epm_check_if_needed_repack()
{
    # FIXME: use real way (for any archive)
    # FIXME: from вроде не существует и не работает
    local pkgname="$(epm print name from "$1")"
31
    local repackcode="$EPM_REPACK_SCRIPTS_DIR/$pkgname.sh"
32
    [ -s "$repackcode" ] || return
33 34 35
    warning "There is repack rule for $pkgname package. It is better install this package via 'epm --repack install' or 'epm play'."
}

36 37 38
# arg: rpm or deb
# fills split_replaced_pkgs with packages of that type
__epm_split_by_pkg_type()
39
{
40 41 42 43 44 45 46
	local type="$1"
	shift

	split_replaced_pkgs=''

	for pkg in "$@" ; do
		[ "$(get_package_type "$pkg")" = "$type" ] || return 1
47
		[ -e "$pkg" ] || fatal "Can't read $pkg"
48
		split_replaced_pkgs="$split_replaced_pkgs $pkg"
49
	done
50 51 52 53

	[ -n "$split_replaced_pkgs" ]
}

54 55
# fills repacked_pkgs
__epm_repack_to_deb()
56 57
{
	local pkg
58
	local pkgs="$*"
59 60 61 62 63

	assure_exists alien
	assure_exists fakeroot
	assure_exists rpm

64
	repacked_pkgs=''
65

66
	local TDIR=$(mktemp -d --tmpdir=$BIGTMPDIR)
67 68
	to_clean_tmp_dirs="$to_clean_tmp_dirs $TDIR"
	trap "__epm_remove_tmp_files" EXIT
69

70
	for pkg in $pkgs ; do
71
		abspkg="$(realpath "$pkg")"
72
		info "Repacking $abspkg to local deb format (inside $TDIR) ..."
73 74 75 76 77

		alpkg=$(basename $pkg)
		# don't use abs package path: copy package to temp dir and use there
		cp $verbose $pkg $TDIR/$alpkg

78
		cd $TDIR || fatal
79 80 81
		__prepare_source_package "$pkg"

		showcmd_store_output fakeroot alien -d -k $scripts "$alpkg"
82
		local DEBCONVERTED=$(grep "deb generated" $RC_STDOUT | sed -e "s| generated||g")
83 84 85 86
		if [ -n "$DEBCONVERTED" ] ; then
			repacked_pkgs="$repacked_pkgs $(realpath $DEBCONVERTED)"
			to_remove_pkg_files="$to_remove_pkg_files $(realpath $DEBCONVERTED)"
		fi
87
		clean_store_output
88
		cd - >/dev/null
89
	done
90 91 92 93 94

	return 0
}


95 96 97 98 99 100 101 102 103
# $spec $PKGNAME $VERSION
__set_name_version()
{
    SPEC="$1"
    PKGNAME="$2"
    VERSION="$3"
    [ -n "$PKGNAME" ] && subst "s|^Name:.*|Name: $PKGNAME|" $SPEC
    [ -n "$VERSION" ] && subst "s|^Version:.*|Version: $VERSION|" $SPEC
}
104

105
# args: pkgname buildroot spec
106 107
__fix_spec()
{
108 109 110
    local pkgname="$1"
    local buildroot="$2"
    local spec="$3"
111
    local i
112 113 114

    # drop forbidded paths
    # https://bugzilla.altlinux.org/show_bug.cgi?id=38842
115
    for i in / /etc /etc/init.d /etc/systemd /bin /opt /usr /usr/bin /usr/share /usr/share/doc /var /var/log /var/run \
116
            /etc/cron.daily /usr/share/icons /usr/share/pixmaps /usr/share/man /usr/share/man/man1 /usr/share/appdata /usr/share/applications /usr/share/menu ; do
117
        sed -i \
118
            -e "s|/\./|/|" \
119 120
            -e "s|^%dir[[:space:]]\"$i/*\"$||" \
            -e "s|^%dir[[:space:]]$i/*$||" \
121 122 123 124 125
            -e "s|^\"$i/*\"$||" \
            -e "s|^$i/*$||" \
            $spec
    done

126
    # commented out: conflicts with already installed package
127
    # drop %dir for existed system dirs
128 129 130 131
    #for i in $(grep '^%dir "' $spec | sed -e 's|^%dir  *"\(.*\)".*|\1|' ) ; do #"
    #    echo "$i" | grep -q '^/opt/' && continue
    #    [ -d "$i" ] && [ -n "$verbose" ] && echo "drop dir $i from packing, it exists in the system"
    #done
132

133
    # replace dir "/path/dir" -> %dir /path/dir
134
    grep '^"/' $spec | sed -e 's|^"\(/.*\)"$|\1|' | while read i ; do
135
        # add dir as %dir in the filelist
136
        if [ -d "$buildroot$i" ] ; then
137
            subst "s|^\(\"$i\"\)$|%dir \1|" $spec
138 139
        #else
        #    subst 's|^\("'$i'"\)$|\1|' $spec
140 141
        fi
    done
142 143 144

    # FIXME: where is a source of the bug with empty Summary?
    subst "s|Summary: *$|Summary: $pkgname (was empty Summary after alien)|" $spec
145
    subst "s|^\(Version: .*\)~.*|\1|" $spec
146
    subst "s|^Release: |Release: alt1.repacked.with.epm.|" $spec
Vitaly Lipatov's avatar
Vitaly Lipatov committed
147
    subst "s|^Distribution:.*||" $spec
148
    subst "s|^\((Converted from a\) \(.*\) \(package.*\)|(Repacked from binary \2 package with epm $EPMVERSION)\n\1 \2 \3|" $spec
149 150 151
    #" hack for highlight
}

152 153 154 155 156 157 158 159 160 161 162 163 164
# TODO: move this list from external file
__check_stoplist()
{
    cat <<EOF | grep -q "^$1$"
kesl
kesl-astra
klnagent
klnagent64
klnagent64-astra
EOF
}


165
# args: pkgname buildroot spec
166 167
__apply_fix_code()
{
168
    local repackcode="$EPM_REPACK_SCRIPTS_DIR/$1.sh"
169
    [ -s "$repackcode" ] || return
170
    shift
171
    export PATH=$PROGDIR:$PATH
172 173
    local bashopt=''
    [ -n "$verbose" ] && bashopt='-x'
174
    ( unset EPMCURDIR ; docmd $CMDSHELL $bashopt $repackcode "$1" "$2" "$3" ) || fatal "There is an error from $repackcode script"
175 176
}

177 178
__create_rpmmacros()
{
179 180 181
# FIXME:
[ -n "$TMPDIR" ] || TMPDIR=/tmp

182 183 184 185 186
    cat <<EOF >$HOME/.rpmmacros
%_topdir	$HOME/RPM
%_tmppath	$TMPDIR

%packager	EPM <support@etersoft.ru>
187
%_vendor	EEPM
188
%_gpg_name	support@etersoft.ru
189 190

%_allow_root_build	1
191
EOF
192
    to_remove_pkg_files="$to_remove_pkg_files $HOME/.rpmmacros"
193 194
}

195

196 197 198
__set_version_pkgname()
{
    local alpkg="$1"
199
    VERSION="$(echo "$alpkg" | grep -o -P '[-_.][0-9][0-9]*([.]*[0-9])*' | head -n1 | sed -e 's|^[-_.]||')" #"
200
    [ -n "$VERSION" ] && PKGNAME="$(echo "$alpkg" | sed -e "s|[-_.]$VERSION.*||")"
201 202 203 204 205
    # set version as all between name and extension
    #local woext="$(echo "alpkg" | sed -e 's|\.tar.*||')"
    #if [ "$woext" != "$alpkg" ] ; then
    #    VERSION="$(echo "$woext" " | sed -e "s|^$PKGNAME[-_.]||")"
    #fi
206 207
}

208 209 210 211 212 213

# AppImage version
# hack for ktalk2.4.2 -> ktalk 2.4.2
__set_version_apppkgname()
{
    local alpkg="$1"
214 215
    VERSION="$(echo "$alpkg" | grep -o -P "[-_.a-zA-Z]([0-9])([0-9])*([.]*[0-9])*" | head -n1 | sed -e 's|^[-_.a-zA-Z]||' -e 's|--|-|g' )"  #"
    [ -n "$VERSION" ] && PKGNAME="$(echo "$alpkg" | sed -e "s|[-_.]$VERSION.*||")"
216 217 218
}


219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
# arg: <package file>
# sets:
#   alpkg      - package file name without path
#   PKGNAME    - package name
#   VERSION    - version of the package
#   SUBGENERIC - name of generic file's extension
__prepare_source_package()
{
    local pkg="$1"

    alpkg=$(basename $pkg)

    # TODO: use func for get name from deb pkg
    # TODO: epm print name from deb package
    # TODO: use stoplist only for deb?
    [ -z "$force" ] && __check_stoplist $(echo $alpkg | sed -e "s|_.*||") && fatal "Please use official package instead of $alpkg repacking (It is not recommended to use --force to skip this checking."

    PKGNAME=''
    VERSION=''
    SUBGENERIC=''

    # convert tarballs to tar (for alien)
    if rhas "$alpkg" "\.(rpm|deb)$" ; then
        return
    fi

    if rhas "$alpkg" "\.AppImage$" ; then
246
        __set_version_apppkgname $alpkg
247 248 249
        [ -n "$VERSION" ] || fatal "Can't get version from $alpkg."
        SUBGENERIC='appimage'
        # TODO: move repack archive to erc?
250
        [ -x "$alpkg" ] || docmd chmod u+x $verbose "$alpkg"
251 252 253
        ./$alpkg --appimage-extract || fatal
        alpkg=$PKGNAME-$VERSION.tar
        # make a tar for alien
254
        erc a $alpkg squashfs-root
255 256 257 258 259
        return
    fi

    __set_version_pkgname $alpkg
    if [ -n "$VERSION" ] ; then
260
        # TODO: don't use erc for detect type? then we potentially can skip install it
261
        pkgtype="$(erc type $alpkg)"
262 263 264
        local newalpkg
        newalpkg=$PKGNAME-$VERSION.$pkgtype
        #[ -n "$PKGNAME" ] || PKGNAME=$(basename $alpkg .$pkgtype)
265
        if [ "$pkgtype" = "tar" ] || [ "$pkgtype" = "tar.gz" ] || [ "$pkgtype" = "tgz" ] ; then
266 267 268 269
            # just rename supported formats
            if [ "$alpkg" != "$newalpkg" ] ; then
                mv $alpkg $newalpkg
            fi
270
        else
271
            # converts directly unsupported formats
272 273
            newalpkg=$PKGNAME-$VERSION.tar
            #newalpkg=$(basename $alpkg .$pkgtype).tar
274
            erc repack $alpkg $newalpkg || fatal
275 276
        fi
        if [ "$alpkg" != "$newalpkg" ] ; then
277 278 279
            rm -f $verbose $alpkg
            alpkg=$newalpkg
        fi
280 281
    else
        warning "Can't detect version in $alpkg. We have almost no chance it will supported in alien."
282 283 284 285 286
    fi
}


# will fill repacked_pkgs var
Vitaly Lipatov's avatar
Vitaly Lipatov committed
287
__epm_repack_to_rpm()
288
{
Vitaly Lipatov's avatar
Vitaly Lipatov committed
289
    local pkgs="$*"
290 291 292 293 294 295 296 297 298
    #case $DISTRNAME in
    #    ALTLinux|ALTServer)
    #        ;;
    #    *)
    #        assure_distr ALTLinux "install --repack for rpm target"
    #        ;;
    #esac

    # Note: install epm-repack for static (package based) dependencies
299
    assure_exists alien || fatal
300 301 302 303 304 305 306 307 308 309

    # TODO: check for all systems
	case $PKGFORMAT in
		rpm)
			assure_exists /usr/bin/rpmbuild rpm-build || fatal
			;;
		deb)
			assure_exists /usr/bin/rpmbuild rpm || fatal
			;;
	esac
310

311
    # TODO: improve
312
    if echo "$pkgs" | grep -q "\.deb" ; then
313 314 315 316 317
        assure_exists dpkg || fatal
        # TODO: Для установки требует: /usr/share/debconf/confmodule но пакет не может быть установлен
        # assure_exists debconf
    fi

318
    local pkg
319
    export HOME=$(mktemp -d --tmpdir=$BIGTMPDIR)
320 321
    to_clean_tmp_dirs="$to_clean_tmp_dirs $HOME"
    trap "__epm_remove_tmp_files" EXIT
322
    __create_rpmmacros
323

324
    local alpkg
325
    local abspkg
Vitaly Lipatov's avatar
Vitaly Lipatov committed
326
    local tmpbuilddir
327
    repacked_pkgs=''
Vitaly Lipatov's avatar
Vitaly Lipatov committed
328 329
    for pkg in $pkgs ; do
        tmpbuilddir=$HOME/$(basename $pkg).tmpdir
330
        mkdir $tmpbuilddir
331
        abspkg="$(realpath $pkg)"
332
        info ""
333
        info "Repacking $abspkg to local rpm format (inside $tmpbuilddir) ..."
334

335
        alpkg=$(basename $pkg)
336
        # don't use abs package path: copy package to temp dir and use there
337
        cp $verbose $pkg $tmpbuilddir/../$alpkg
338 339

        cd $tmpbuilddir/../ || fatal
340
        __prepare_source_package "$pkg"
341 342
        cd $tmpbuilddir/ || fatal

343
        if [ -n "$verbose" ] ; then
344
            docmd alien --generate --to-rpm $verbose $scripts "../$alpkg" || fatal
345
        else
346 347
            showcmd alien --generate --to-rpm $scripts "../$alpkg"
            a='' alien --generate --to-rpm $scripts "../$alpkg" >/dev/null || fatal
348
        fi
349 350

        local subdir="$(echo *)"
351
        [ -d "$subdir" ] || fatal "can't find subdir in $(pwd)"
352 353 354

        # detect spec and move to prev dir
        local spec="$(echo $tmpbuilddir/$subdir/*.spec)"
355
        [ -s "$spec" ] || fatal "Can't find spec $spec"
356 357
        mv $spec $tmpbuilddir || fatal
        spec="$tmpbuilddir/$(basename "$spec")"
358
        #__set_name_version $spec $PKGNAME $VERSION
359
        local pkgname="$(grep "^Name: " $spec | sed -e "s|Name: ||g" | head -n1)"
360 361

        # for tarballs fix permissions
362
        [ -n "$VERSION" ] && chmod $verbose -R a+rX $tmpbuilddir/$subdir/*
363

364
        __fix_spec $pkgname $tmpbuilddir/$subdir $spec
365
        __apply_fix_code "generic" $tmpbuilddir/$subdir $spec $pkgname
366
        [ -n "$SUBGENERIC" ] && __apply_fix_code "generic-$SUBGENERIC" $tmpbuilddir/$subdir $spec
367
        __apply_fix_code $pkgname $tmpbuilddir/$subdir $spec $pkgname
368 369
        # TODO: we need these dirs to be created
        to_remove_pkg_dirs="$to_remove_pkg_dirs $HOME/RPM/BUILD $HOME/RPM"
370 371 372 373

        TARGETARCH=$(epm print info -a | sed -e 's|^x86$|i586|')

        showcmd rpmbuild --buildroot $tmpbuilddir/$subdir --target $TARGETARCH -bb $spec
374
        if [ -n "$verbose" ] ; then
375
            a='' rpmbuild --buildroot $tmpbuilddir/$subdir --target $TARGETARCH -bb $spec || fatal
376
        else
377
            a='' rpmbuild --buildroot $tmpbuilddir/$subdir --target $TARGETARCH -bb $spec >/dev/null || fatal
378
        fi
379 380 381
        # remove copy of source binary package (don't mix with generated)
        rm -f $tmpbuilddir/../$alpkg
        local repacked_rpm="$(realpath $tmpbuilddir/../*.rpm)"
382
        if [ -s "$repacked_rpm" ] ; then
383
            repacked_pkgs="$repacked_pkgs $repacked_rpm"
384 385
            to_remove_pkg_files="$to_remove_pkg_files $repacked_rpm"
        else
386
            warning "Can't find converted rpm for source binary package '$pkg'"
387 388 389 390 391
        fi
        cd - >/dev/null
        rm -rf $tmpbuilddir/$subdir/
        rm -rf $spec
    done
392

393 394 395 396 397
    rmdir $tmpbuilddir
    #rmdir $tmpbuilddir/..
    true
}

398 399 400 401 402 403 404 405 406 407 408 409

# FIXME: Нужно как-то обеспечить непродолжение выполнения.
# used in epm install
# fill repacked_pkgs
__epm_repack()
{
	repacked_pkgs=''
	case $PKGFORMAT in
		rpm)
			__epm_repack_to_rpm "$@" || return
			;;
		deb)
410 411 412
			# FIXME: only one package in $@ is supported
			#local pkgname="$(epm print name from "$@")"
			__set_version_pkgname "$1"
413
			local repackcode="$EPM_REPACK_SCRIPTS_DIR/$PKGNAME.sh"
414 415 416 417 418 419 420
			if [ -x "$repackcode" ] ; then
				__epm_repack_to_rpm "$@" || return
				[ -n "$repacked_pkgs" ] || return
				__epm_repack_to_deb $repacked_pkgs
			else
				__epm_repack_to_deb "$@" || return
			fi
421 422 423 424 425
			;;
		*)
			fatal "$PKGFORMAT is not supported for repack yet"
			;;
	esac
426

427
	return 0
428 429
}

430 431 432 433 434 435 436 437
__epm_repack_if_needed()
{
	# return 1 if there is a package in host package format
	__epm_split_by_pkg_type $PKGFORMAT "$@" && return 1

	__epm_repack "$@"
	return 0
}
438

439 440 441 442 443 444 445 446
epm_repack()
{
    # if possible, it will put pkg_urls into pkg_files and reconstruct pkg_filenames
    if [ -n "$pkg_urls" ] ; then
        load_helper epm-download
        __handle_pkg_urls_to_install
    fi

447
    [ -n "$pkg_names" ] && warning "Can't find $pkg_names files"
448 449
    [ -z "$pkg_files" ] && info "Skip empty repack list" && return 22

450
    if __epm_repack $pkg_files && [ -n "$repacked_pkgs" ] ; then
451
        cp $repacked_pkgs "$EPMCURDIR"
452
        if [ -z "$quiet" ] ; then
453 454
            echo
            echo "Adapted packages:"
455
            for i in $repacked_pkgs ; do
456
                echo "	$EPMCURDIR/$(basename "$i")"
457
            done
458
        fi
459 460
    fi

461
    __epm_remove_tmp_files
462
}