Skip to content

Instantly share code, notes, and snippets.

@rshipp
Last active August 29, 2015 14:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rshipp/52af4a688a5da2866085 to your computer and use it in GitHub Desktop.
Save rshipp/52af4a688a5da2866085 to your computer and use it in GitHub Desktop.
Get variables and functions from PKGBUILDs into Python variables.

pkgvars

With pkgvars.py in your PATH, and a PKGBUILD in your current directory, run bash pkgvars.sh. The output is formatted JSON.

A patch for Pacman (makepkg) and an updated Pacman PKGBUILD are included, along with an example working split PKGBUILD and an example PKGBUILD with a custom array, to show how custom arrays are not handled by this script.

Bugs?

  • This will not find custom arrays, like __svnmod=(). Bash (and other shells) do not export arrays, so there is no way to support them in all cases. Instead, all known and custom functions and variables are found, along with known arrays.
  • If the package the user is creating contains a .srcinfo.json file, this file will be overwritten without warning in the .src.tar.gz file.
#
# Chakra Packages for Chakra, part of chakra-project.org
#
# maintainer <manutortosa[at]chakra-project[dot]org>
pkgname=pacman
pkgver=4.1.2
pkgrel=4
pkgdesc="A library-based package manager with dependency support"
arch=('x86_64')
url="http://www.archlinux.org/pacman/"
license=('GPL')
groups=('base' 'base-devel')
depends=('bash>=4.2.042-1' 'glibc>=2.15-2' 'libarchive=3.1.2' 'curl>=7.28.1'
'gpgme' 'pacman-mirrorlist' )
checkdepends=('python2' 'fakechroot')
makedepends=('asciidoc' 'nettle')
optdepends=('fakeroot: for makepkg usage as normal user'
'python2: for srcinfo generator')
provides=('pacman-contrib')
conflicts=('pacman-contrib')
replaces=('pacman-contrib')
backup=(etc/pacman.conf etc/makepkg.conf)
install=pacman.install
options=(!libtool)
source=(ftp://ftp.archlinux.org/other/pacman/$pkgname-$pkgver.tar.gz{,.sig}
pacman.conf
makepkg.conf
srcinfo-$pkgver.patch
pkgvars.py)
sha1sums=('ed9a40a9b532bc43e48680826d57518134132538'
'SKIP'
'0390fd27a62aadf0f7b5933632e858c442f2e167'
'badd6ecea8dd3e690f4ed383120b6671576355da'
'a249a45449126099ba072a0af28c37f0dcf71467'
'886a1de1ad39a4444f7d0a61786363087dee0307')
build() {
cd $srcdir/$pkgname-$pkgver
patch -p1 -i $srcdir/srcinfo-$pkgver.patch
./configure --prefix=/usr --sysconfdir=/etc \
--localstatedir=/var --enable-doc \
--with-scriptlet-shell=/bin/bash \
--with-ldconfig=/usr/bin/ldconfig
make
make -C contrib
}
check() {
make -C "$pkgname-$pkgver" check
}
package() {
cd $srcdir/$pkgname-$pkgver
make DESTDIR=$pkgdir install
make DESTDIR=$pkgdir -C contrib install
# install Arch specific stuff
install -dm755 $pkgdir/etc
install -m644 $srcdir/pacman.conf $pkgdir/etc/pacman.conf
mycarch="x86_64"
mychost="x86_64-unknown-linux-gnu"
myflags="-march=x86-64"
install -m644 $srcdir/makepkg.conf $pkgdir/etc/
# set things correctly in the default conf file
sed -i $pkgdir/etc/makepkg.conf \
-e "s|@CARCH[@]|$mycarch|g" \
-e "s|@CHOST[@]|$mychost|g" \
-e "s|@CARCHFLAGS[@]|$myflags|g"
# put bash_completion in the right location
install -dm755 ${pkgdir}/usr/share/bash-completion/completions
mv ${pkgdir}/etc/bash_completion.d/pacman \
${pkgdir}/usr/share/bash-completion/completions
rmdir ${pkgdir}/etc/bash_completion.d
# install pkgvars script
install -Dm755 ${srcdir}/pkgvars.py \
${pkgdir}/usr/bin/pkgvars.py
for f in makepkg pacman-key; do
ln -s pacman "$pkgdir/usr/share/bash-completion/completions/$f"
done
}
# Contributor: AlmAck <almack@chakraos.org>
# Maintainer: Bruce Liu <brli@users.sourceforge.net>
pkgbase=octopi
pkgname=('octopi' 'octopi-notifier' 'octopi-qt5' 'octopi-notifier-qt5')
pkgver=0.4.2
pkgrel=2
url="https://octopiproject.wordpress.com/"
arch=('x86_64')
license=('GPL3')
depends=('pacman' 'pacmanlogviewer' 'mirror-check')
makedepends=('automoc4' 'qt' 'qt5-declarative')
conflicts=('oktopi')
replaces=('oktopi')
categories=('system')
screenshot='http://octopiproject.files.wordpress.com/2014/01/octopi_in_kaos.png'
gitsha=0cd9398
source=("$pkgname"::"git://github.com/aarnt/${pkgname}.git#commit=${gitsha}")
md5sums=('SKIP')
prepare(){
cd "${srcdir}/${pkgbase}"
# patch .desktop files
sed -i 's/Categories=GNOME;GTK;System;/Categories=System;Tools;/g' octopi.desktop octopi-notifier.desktop
sed -i 's/\/\/#define NO_GTK_STYLE/#define NO_GTK_STYLE/g' src/main.cpp notifier/octopi-notifier/main.cpp
sed -i 's/Icon=octopi/Icon=octopi-notifier/g' octopi-notifier.desktop
# prepare for package split
cp -r "${srcdir}/${pkgbase}" "${srcdir}/${pkgbase}-qt5"
}
build() {
# first we build Qt4 version
cd "${srcdir}/${pkgbase}"
qmake octopi.pro
make
pushd "notifier/pacmanhelper"
qmake pacmanhelper.pro
make
popd
pushd "notifier/octopi-notifier"
qmake octopi-notifier.pro
make
popd
pushd "repoeditor"
qmake repoeditor.pro
make
popd
# next, the qt5 flavor
cd "${srcdir}/${pkgbase}-qt5"
qmake-qt5 octopi.pro
make
pushd "notifier/pacmanhelper"
qmake-qt5 pacmanhelper.pro
make
popd
pushd "notifier/octopi-notifier"
qmake-qt5 octopi-notifier.pro
make
popd
pushd "repoeditor"
qmake-qt5 repoeditor.pro
make
popd
}
package_octopi() {
pkgdesc="Octopi, a powerful Pacman frontend using Qt libs"
depends+=('qt')
# start package
cd ${srcdir}/${pkgbase}
install -Dm 755 bin/octopi ${pkgdir}/usr/bin/octopi
install -Dm 755 repoeditor/bin/octopi-repoeditor ${pkgdir}/usr/bin/octopi-repoeditor
install -Dm 644 octopi.desktop ${pkgdir}/usr/share/applications/octopi.desktop
install -Dm 644 resources/images/octopi_green.png ${pkgdir}/usr/share/icons/octopi.png
}
package_octopi-notifier() {
pkgdesc="Octopi system tray notification"
depends+=('qt')
# main application
cd "${srcdir}/${pkgbase}"
install -Dm755 notifier/bin/octopi-notifier ${pkgdir}/usr/bin/${pkgname}
install -Dm644 octopi-notifier.desktop ${pkgdir}/usr/share/applications/octopi-notifier.desktop
install -Dm644 resources/images/octopi_red.png ${pkgdir}/usr/share/icons/${pkgname}.png
#Pacmanhelper service files
install -Dm755 notifier/bin/pacmanhelper ${pkgdir}/usr/lib/octopi/pacmanhelper
install -Dm644 notifier/pacmanhelper/polkit/org.octopi.pacman.policy ${pkgdir}/usr/share/polkit-1/actions/org.octopi.pacman.policy
install -Dm644 notifier/pacmanhelper/polkit/org.octopi.pacmanhelper.conf ${pkgdir}/etc/dbus-1/system.d/org.octopi.pacmanhelper.conf
install -Dm644 notifier/pacmanhelper/polkit/org.octopi.pacmanhelper.xml ${pkgdir}/usr/share/dbus-1/interfaces/org.octopi.pacmanhelper.xml
install -Dm644 notifier/pacmanhelper/polkit/org.octopi.pacmanhelper.service ${pkgdir}/usr/share/dbus-1/system-services/org.octopi.pacmanhelper.service
}
package_octopi-qt5() {
pkgdesc="Octopi, a powerful Pacman frontend using Qt libs - Qt5 version"
depends+=('qt5-declarative')
provides+=('octopi')
conflicts+=('octopi')
# start package
cd ${srcdir}/${pkgbase}-qt5
install -Dm 755 bin/octopi ${pkgdir}/usr/bin/octopi
install -Dm 755 repoeditor/bin/octopi-repoeditor ${pkgdir}/usr/bin/octopi-repoeditor
install -Dm 644 octopi.desktop ${pkgdir}/usr/share/applications/octopi.desktop
install -Dm 644 resources/images/octopi_green.png ${pkgdir}/usr/share/icons/octopi.png
}
package_octopi-notifier-qt5() {
pkgdesc="Octopi system tray notification - Qt5 version"
depends+=('qt5-declarative')
provides+=('octopi-notifier')
conflicts+=('octopi-notifier')
# main application
cd "${srcdir}/${pkgbase}-qt5"
install -Dm755 notifier/bin/octopi-notifier ${pkgdir}/usr/bin/octopi-notifier
install -Dm644 octopi-notifier.desktop ${pkgdir}/usr/share/applications/octopi-notifier.desktop
install -Dm644 resources/images/octopi_red.png ${pkgdir}/usr/share/icons/octopi-notifier.png
#Pacmanhelper service files
install -Dm755 notifier/bin/pacmanhelper ${pkgdir}/usr/lib/octopi/pacmanhelper
install -Dm644 notifier/pacmanhelper/polkit/org.octopi.pacman.policy ${pkgdir}/usr/share/polkit-1/actions/org.octopi.pacman.policy
install -Dm644 notifier/pacmanhelper/polkit/org.octopi.pacmanhelper.conf ${pkgdir}/etc/dbus-1/system.d/org.octopi.pacmanhelper.conf
install -Dm644 notifier/pacmanhelper/polkit/org.octopi.pacmanhelper.xml ${pkgdir}/usr/share/dbus-1/interfaces/org.octopi.pacmanhelper.xml
install -Dm644 notifier/pacmanhelper/polkit/org.octopi.pacmanhelper.service ${pkgdir}/usr/share/dbus-1/system-services/org.octopi.pacmanhelper.service
}
#!/bin/bash
# Maintainer: Kurt J. Bosch <kjb-temp-2009 at alpenjodel.de>
_lang='en-US'
_arch='x86-64'
# Source directories containing the RPMs to install
_source_dirs=( "${_lang}/RPMS" )
# Install path components as found in RPMs
_install_prefix='opt'
_install_name='openoffice4'
_install_path=${_install_prefix}/${_install_name}
pkgname=openoffice
pkgver=4.0.1
pkgrel=1
pkgdesc="OpenOffice - Repackaged from upstream"
arch=('x86_64')
url="http://www.openoffice.org/"
license=('Apache') # see below
# Some depends can be found in the README, some with namcap, some with _extract_depends() below
depends=('freetype2'
'glibc>=2.5'
'gtk2>=2.10.4'
'hicolor-icon-theme'
'desktop-file-utils' 'shared-mime-info' # install script
)
makedepends=('rpmextract')
optdepends=('apr-util: adds apr support'
'java-environment: adds java support'
'gconf: adds additional gnome support'
'gstreamer0.10-base: + some gstr-plugins to support multimedia content, e.g. in impress'
#'libgail-gnome: GNOME Assistive Technology'
'mesa: for the OGLTrans extension of impress'
'mime-types: provides /etc/mime.types'
'nss: adds support for signed files/macros'
'openoffice-de-bin: adds additional language pack (example)'
'python2: adds python support'
'raptor1: adds rdf support'
'sqlite: adds sqlite support')
backup=( extra/opt/openoffice4/program/sofficerc )
options=(!strip docs)
source=( "http://sourceforge.net/projects/openofficeorg.mirror/files/${pkgver}/binaries/${_lang}/Apache_OpenOffice_${pkgver}_Linux_${_arch}_install-rpm_${_lang}.tar.gz"
'openoffice4'
'openoffice4-printeradmin')
sha256sums=('c7abdb7e436e03c22a80e21df32a1964df5d9f8cc3d90f26801502506214ef83'
'bc39874911bb05dc011f13eb34fd1f678fa25cdf4441a1b7523b8d8e57ecc1ab'
'b3bc2b1d8605fef368b7eff56ddd3827e31f4903918f679e0e68873b7ff92f9d')
install=openoffice.install
_find_rpms() {
local dir file
for dir in "${_source_dirs[@]}"; do
dir=${srcdir:-src}/${dir}
( cd "${dir}" ) # check existing
for file in $( find "${dir}" -type f -name '*.rpm' ); do
if ! [[ $file == */desktop-integration/* && $file != *-freedesktop-menus-* ]] \
&& ! [[ $file == */jre-* ]] \
&& ! [[ $file == *-gnome-integration-* ]] ; then
echo "${file}"
elif type -p msg2 >/dev/null; then
msg2 "Skipping ${file##*/}" >&2
else
echo "Skipping ${file##*/}" >&2
fi
done
done
}
_ln_s_t() {
local dir=$1 prefix=$2
shift 2
mkdir -p "$dir"
local file
for file in "${@}"; do
readlink -v -e "${file}" >/dev/null # check existing
ln -s -T /"${file}" "${dir}/${prefix}${file##*/}"
done
}
package() {
cd "${pkgdir}"
# unpack RPMs
local file
for file in $( _find_rpms ); do
msg2 "Extracting ${file##*/}"
rpmextract.sh "${file}"
done
msg2 "Completing package"
# remove symlink to avoid conflict with libreoffice-common 3.5.2-1
# (not used in the desktop files)
[[ -h usr/bin/soffice ]] && rm -f usr/bin/soffice
# add licenses (found by find pkg -ipath '*license*')
_ln_s_t usr/share/licenses/${pkgname} '' \
${_install_path}/program/LICENSE
# Fix python shebang calls
sed -i -re "1s;^#! *(/usr(/local)?)?/bin/(env +)?python(2[^ ]*)?( |$);#!/usr/bin/env python2 ;" $(
find opt/${_install_name}/program/python-core-2.7.5/lib -type f -name '*.py'
)
# # link mozilla plugin
# _ln_s_t extra/usr/lib/mozilla/plugins ${_install_name}- ${_install_path}/program/libnpsoplugin.so
# # link desktop files
# _ln_s_t usr/share/applications ${_install_name}- ${_install_path}/share/xdg/*.desktop
# # get desktop files to do something
# mkdir -p usr/bin
# install -m 755 -T <( cat <<EOF
msg "Note: For checking the package, you may run: namcap -e elfpaths,emptydir ${pkgname}-${pkgver}-${pkgrel}-${CARCH}.pkg.tar.?z"
#[extra] complement - bad hack
mkdir ${pkgdir}/extra
cp -r ${pkgdir}/{opt,usr} ${pkgdir}/extra/
rm -rf ${pkgdir}/{opt,usr}
rm ${pkgdir}/extra/usr/bin/*
rm ${pkgdir}/extra/usr/share/applications/*
install -Dm 644 ${pkgdir}/extra/opt/openoffice4/share/xdg/* ${pkgdir}/extra/usr/share/applications/
rm -rf ${pkgdir}/extra/opt/openoffice4/share/xdg/
install -Dm 755 ${srcdir}/openoffice4* ${pkgdir}/extra/usr/bin/
}
## Functions for manual usage
# makepkg -o && source PKGBUILD && _list_rpm_depends
# Helper for finding external dependencies
_list_rpm_depends() {
local file
for file in $( _find_rpms ); do
r=$( rpmmeta -t requirename "${file}" | sed -re 's;(ooobasis|ooo-dev|ooodev|openoffice|rpmlib)[^ ]*;;g' )
[[ $r ]] || continue
echo ${file##*/} $r
done
}
# makepkg -o && source PKGBUILD && _find_license_files
# Helper for finding license files
_find_license_files() {
find pkg -ipath '*license*' -type f
}
# makepkg -o && source PKGBUILD && _make_install_script >${install}.new
# Helper for porting install scripts
_make_install_script() {
cat <<EOF
#!/bin/bash
# Inappropriate parts should be removed:
# - mime.type stuff is already provided by mime-types package
# - /etc/mailcap does not exist on ArchLinux normaly
# - Don't use 'which' because tools are already in depends
EOF
for args in 'prein pre_install' 'postin post_install' 'preun pre_remove' 'postun post_remove'; do
set -- $args
echo "$2() {"
echo " local RPM_INSTALL_PREFIX='${_install_prefix}'"
echo
local file code
for file in $( _find_rpms ); do
code=$( rpmmeta -t $1 "${file}" )
[[ $code ]] || continue
echo " ( ### ${file##*/} $1"
echo "$code"
echo " )"
echo
done
echo "}"
echo
done
cat <<EOF
## arg 1: the new package version
## arg 2: the old package version
pre_upgrade() {
pre_install "\$1"
}
## arg 1: the new package version
## arg 2: the old package version
post_upgrade() {
post_install "\$1"
}
# vim:set ts=2 sw=2 et:
EOF
}
#!/usr/bin/env python
import json
import fileinput
def main():
fileno = -1
files = ['', '', '']
for line in fileinput.input():
if fileinput.filelineno() == 1:
fileno += 1
files[fileno] += line
before = set(files[0].split('\x00'))
after = set(files[1].split('\x00'))
arrays = set(files[2].strip().split('\n'))
print(to_json(before, after, arrays))
def to_json(before, after, arrays):
"""Returns a valid JSON string containing functions and variables.
Parameters are three sets, in the format produced by ``pkgvars.sh`` and
this module's main() function.
"""
variables = {}
functions = {}
for line in after.difference(before):
split_at = line.find('=')
var = line[:split_at]
value = line[split_at+1:]
if value.startswith('() {'):
functions[var] = [line.strip('\n; ') for line in value.strip('() {}\n').split('\n')]
else:
variables[var] = value.rstrip()
for line in arrays:
split_at = line.find('=')
var = line[:split_at]
value = line[split_at+1:]
if value == '( )':
continue
value = [v.replace('\0', ' ').strip(' \'') for v in value.strip("'() \n").split(' ')]
variables[var] = value
return json.dumps({'variables': variables, 'functions': functions}, indent=4)
if __name__ == "__main__":
main()
#!/bin/bash
(arrays=(
pkgname
arch
license
groups
categories
depends
makedepends
optdepends
provides
conflicts
replaces
backup
options
hooks
source
noextract
md5sums
sha1sums
sha224sums
sha256sums
sha384sums
sha512sums
)
before=$(env -0|base64)
set -a
source PKGBUILD
set +a
IFS=$'\n'
pkgarrays="$(for array in ${arrays[@]}; do
echo -n "${array}=( "
for value in $(eval "for v in $(echo \${$array[@]}); do echo \$v; done;"); do
echo -ne "'${value// /\0}' "
done
echo ")"
done|base64)"
pkgvars.py <(base64 -d <<< "$before") <(env -0) <(base64 -d <<< "$pkgarrays"))
diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in
index 940e947..f937fa8 100644
--- a/scripts/makepkg.sh.in
+++ b/scripts/makepkg.sh.in
@@ -2044,6 +2044,49 @@ create_srcpackage() {
local fullver=$(get_full_version)
local pkg_file="$SRCPKGDEST/${pkgbase}-${fullver}${SRCEXT}"
+ # Create the info file in a subshell.
+ (arrays=(
+ pkgname
+ arch
+ license
+ groups
+ categories
+ depends
+ makedepends
+ optdepends
+ provides
+ conflicts
+ replaces
+ backup
+ options
+ hooks
+ source
+ noextract
+ md5sums
+ sha1sums
+ sha224sums
+ sha256sums
+ sha384sums
+ sha512sums
+ )
+
+ before=$(env -0|base64)
+ set -a
+ source PKGBUILD
+ set +a
+
+ IFS=$'\n'
+ pkgarrays="$(for array in ${arrays[@]}; do
+ echo -n "${array}=( "
+ for value in $(eval "for v in $(echo \${$array[@]}); do echo \$v; done;"); do
+ echo -ne "'${value// /\0}' "
+ done
+ echo ")"
+ done|base64)"
+
+ pkgvars.py <(base64 -d <<< "$before") <(env -0) <(base64 -d <<< "$pkgarrays")) \
+ > "${srclinks}/${pkgbase}/.srcinfo.json"
+
# tar it up
msg2 "$(gettext "Compressing source package...")"
cd_safe "${srclinks}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment