
commit
0bb0b0294e
3 changed files with 346 additions and 0 deletions
@ -0,0 +1,132 @@
@@ -0,0 +1,132 @@
|
||||
arch-ppa |
||||
======== |
||||
|
||||
arch-ppa is a tool that easily creates and maintains your own Arch |
||||
package repositories. Kind of like the Personal Package Archives (PPA) |
||||
that Ubuntu has, but way easier. |
||||
|
||||
The Arch User Repository (AUR) is convenient, has tons of software, is |
||||
generally awesome, but is inherently insecure. Anyone can upload |
||||
anything they want to the AUR. This is why I don't like to use AUR |
||||
helpers like `yaourt` or `pacaur`. Using the AUR with a helper |
||||
requires you to be diligent in reviewing the PKGBUILDs it downloads, |
||||
in order to make sure it doesn't include things like viruses or |
||||
trojans, or downloading from a weird URL. |
||||
|
||||
I wanted a way to maintain my own repository of PKGBUILDs, downloaded |
||||
from the AUR, that I have manually verified. Building and installing |
||||
packages built from those pre-verified PKGBUILDs resolves the |
||||
insecurity of the AUR in my mind. This gives me the full power of the |
||||
AUR, but allows me to automate my package installs in a way that I |
||||
never felt comfortable with before. Seriously, why does pacaur have a |
||||
`--noconfirm` option? That's scary. |
||||
|
||||
The packages this tool builds can be hosted as a regular arch |
||||
repository, which you put into your `/etc/pacman.conf`. The added |
||||
convenience here is that although the packages came from the AUR, your |
||||
clients install it through regular-old pacman. |
||||
|
||||
|
||||
Usage |
||||
----- |
||||
|
||||
Clone this repo somewhere. Everything will be self contained in this |
||||
directory wherever you put it. |
||||
|
||||
arch-ppa should not be run as root, but the user that does run it does |
||||
need sudo privileges as the underlying devtools need it. |
||||
|
||||
Run setup: |
||||
|
||||
./arch-ppa setup |
||||
|
||||
The setup installs a few dependencies like `devtools` and `git`. It |
||||
also creates a chroot directory which is a container that will be used |
||||
to build packages in a completely clean environment using |
||||
`systemd-nspawn`. |
||||
|
||||
Add packages from the AUR: |
||||
|
||||
./arch-ppa add cower curlbomb pasystray |
||||
|
||||
This downloads PKGBUILDs from the AUR for the listed packages: cower, |
||||
curlbomb, pasystray, as well as all of their AUR dependencies, and |
||||
placed into the `src` directory. You can put PKGBUILDs from other |
||||
sources in the src directory too; they don't have to be from the |
||||
AUR. Note that any PKGBUILD that lists a dependency of another |
||||
package, that is not found in one of the arch repositories, needs to |
||||
have it's own PKGBUILD in the `src` directory too. (The `add` command |
||||
does this for you automatically, thanks to `cower -d -d`) |
||||
|
||||
Build everything: |
||||
|
||||
./arch-ppa clean ryan |
||||
./arch-ppa build ryan |
||||
|
||||
The build process operates on a single repository, in this example |
||||
called `ryan`. You can maintain several repositories, each containing |
||||
different sets of packages. Just make sure to give each repository a |
||||
unique name. |
||||
|
||||
The clean process removes the repository directory containing all the |
||||
built packages. It also deletes the chroot for the repository from the |
||||
`chroot` directory. |
||||
|
||||
The build process creates a new package repository called `ryan` (or |
||||
whatever you called yours.) It finds PKGBUILD files in the `src` |
||||
directory and figures out the dependency chain and builds all the |
||||
packages in the correct order. Additionally, you can specify |
||||
individual package names after the repository name if you only wish to |
||||
build certain packages. If you do specify package names, make sure to |
||||
include all dependencies, as they will not be included otherwise. |
||||
|
||||
The repository directory can be listed in your /etc/pacman.conf like this: |
||||
|
||||
[ryan] |
||||
Server = file:///home/ryan/git/arch-ppa/ryan |
||||
SigLevel = Required TrustedOnly |
||||
|
||||
This is the full path to the ryan repository just created. Run `pacman |
||||
-Sy` and you should see pacman synchronize with the new repository |
||||
name. Alternatively, upload the directory to a webserver and share it |
||||
with all your friends. |
||||
|
||||
The SigLevel option specifies how pacman should trust our |
||||
repository. `Required TruestedOnly` is a strict rule that the key must |
||||
be in the local pacman keyring and be assigned a trust level. Pacman |
||||
will usually download the key without a problem, but you will still |
||||
need to locally sign the key to trust it. |
||||
|
||||
Mini gpg tutorial |
||||
----------------- |
||||
View your key information: |
||||
|
||||
gpg -K |
||||
|
||||
This should output something like this: |
||||
|
||||
/home/ryan/.gnupg/pubring.kbx |
||||
----------------------------- |
||||
sec rsa2048/4BAACCF8 2016-04-15 [SC] |
||||
uid [ultimate] test guy <ryantest@enigmacurry.com> |
||||
ssb rsa2048/C22BDAA5 2016-04-15 [E] |
||||
|
||||
My public key ID is 4BAACCF8. Always omit the part before the |
||||
slash. If it didn't output any key information at all, this means you |
||||
don't have a key yet. Create one and follow the prompts: |
||||
|
||||
gpg --gen-key |
||||
|
||||
Send your public key to the keyserver (replace with your ID): |
||||
|
||||
gpg --send-keys 4BAACCF8 |
||||
|
||||
On each machine you will use your package repository, run the |
||||
following to import the key and to locally sign (assign trust) the |
||||
key (again, replace with your key ID): |
||||
|
||||
sudo pacman-key -r 4BAACCF8 |
||||
sudo pacman-key --lsign-key 4BAACCF8 |
||||
|
||||
If you don't sign the key, pacman will complain that your packages are |
||||
not trusted. |
@ -0,0 +1,211 @@
@@ -0,0 +1,211 @@
|
||||
BASEDIR=$(cd $(dirname $0); pwd) |
||||
CHROOT=$BASEDIR/chroot |
||||
|
||||
if [ `whoami` == 'root' ]; then |
||||
echo "Must not be run as root." |
||||
exit 1; |
||||
fi |
||||
|
||||
exe() { echo "\$ $@" ; "$@" ; } |
||||
|
||||
create_chroot() { |
||||
( |
||||
set -e |
||||
if [ ! -d $CHROOT ]; then |
||||
echo "## Creating arch chroot ..." |
||||
exe mkdir $CHROOT |
||||
exe mkarchroot $CHROOT/root base-devel |
||||
# install cower: |
||||
TMP_BUILD=`mktemp -d` |
||||
exe cd $TMP_BUILD |
||||
curl https://aur.archlinux.org/cgit/aur.git/snapshot/cower.tar.gz | tar xz |
||||
exe cd cower |
||||
exe makechrootpkg -r $CHROOT -l root -- -i |
||||
exe rm -rf $TMP_BUILD |
||||
echo "## Root chroot build complete." |
||||
fi |
||||
) |
||||
} |
||||
|
||||
install_system_deps() { |
||||
( |
||||
set -e |
||||
pkg_dep() { |
||||
if !(pacman -Q $1 > /dev/null 2>&1); then |
||||
echo "Installing $1..." |
||||
exe sudo pacman -S --noconfirm $1 |
||||
fi |
||||
} |
||||
pkg_dep devtools |
||||
pkg_dep git |
||||
) |
||||
} |
||||
|
||||
package_build() { |
||||
# Build a package in a container. $1=container $2=package |
||||
# PKGBUILD must already exist in src/ |
||||
# If package has dependencies we also maintain in src/, recursively build those first. |
||||
( |
||||
set -e |
||||
if [ "$#" -ne 2 ]; then |
||||
echo "package_build takes two args: repo_name and package_name" |
||||
return 1 |
||||
fi |
||||
repo_name=$1 |
||||
package_name=$2 |
||||
setup |
||||
pkgdir=$BASEDIR/src/$package_name |
||||
if [ ! -d $pkgdir ]; then |
||||
echo "Package $package_name not found in $pkgdir" |
||||
echo "Try running: package_add $package_name" |
||||
return 1 |
||||
fi |
||||
if [ ! -f $pkgdir/PKGBUILD ]; then |
||||
echo "Cannot find PKGBUILD in $pkgdir" |
||||
return 1 |
||||
fi |
||||
if (arch-nspawn $CHROOT/$repo_name pacman -Q $package_name > /dev/null 2>&1); then |
||||
echo "Package $package_name already built" |
||||
return |
||||
fi |
||||
# Find and build dependencies: |
||||
find_deps $package_name | while read dep; do |
||||
# Build the dep if we haven't already yet: |
||||
if !(arch-nspawn $CHROOT/$repo_name pacman -Q $dep > /dev/null 2>&1); then |
||||
package_build $repo_name $dep |
||||
fi |
||||
done |
||||
# Build package: |
||||
cd $pkgdir |
||||
rm -f *.pkg.tar.xz |
||||
mkdir -p $BASEDIR/$repo_name |
||||
exe makechrootpkg -r $CHROOT -l $repo_name -- -i |
||||
exe mv *.pkg.tar.xz $BASEDIR/$repo_name |
||||
) |
||||
} |
||||
|
||||
sign_packages() { |
||||
if [ "$#" -lt 1 ]; then |
||||
echo "sign_packages requires specifying the list of packages to sign" |
||||
return 1 |
||||
fi |
||||
( |
||||
set -e |
||||
cd $(dirname $1) |
||||
for pkg in "$@"; do |
||||
gpg --detach-sign --use-agent $pkg |
||||
done |
||||
) |
||||
} |
||||
|
||||
find_deps() { |
||||
# Inspect package srcinfo and pull out the dependencies that we maintain in src |
||||
( |
||||
set -e |
||||
setup |
||||
cat $BASEDIR/src/$1/.SRCINFO | sed -nr 's/^\W*depends = ([-a-zA-Z0-9]+).*$/\1/p' | while read dep; do |
||||
if [ -d $BASEDIR/src/$dep ]; then |
||||
echo $dep |
||||
fi |
||||
done |
||||
) |
||||
} |
||||
|
||||
add() { |
||||
# Add packages and their AUR dependencies to src |
||||
( |
||||
set -e |
||||
if [ "$#" -lt 1 ]; then |
||||
echo "Must specify package(s) to add" |
||||
return 1 |
||||
fi |
||||
setup |
||||
if [ ! -d $BASEDIR/src ]; then |
||||
mkdir $BASEDIR/src |
||||
fi |
||||
for pkg in "$@"; do |
||||
arch-nspawn $CHROOT/root --bind=$BASEDIR/src:/src cower -q -t /src -d -d $pkg |
||||
done |
||||
sudo chown $USER -R $BASEDIR/src |
||||
echo "## All requested packages added" |
||||
) |
||||
} |
||||
|
||||
list() { |
||||
if [ "$#" -ne 1 ]; then |
||||
echo "Must specify repository name to list" |
||||
return 1 |
||||
fi |
||||
setup |
||||
arch-nspawn $CHROOT/$1 pacman -Qm |
||||
} |
||||
|
||||
setup() { |
||||
mkdir -p $BASEDIR/src |
||||
install_system_deps |
||||
create_chroot |
||||
} |
||||
|
||||
clean() { |
||||
( |
||||
set -e |
||||
if [ "$#" -lt 1 ]; then |
||||
echo "Must specify repository names to clean" |
||||
return 1 |
||||
fi |
||||
for repo in "$@"; do |
||||
# Clean repository and chroot |
||||
if [ -d $BASEDIR/chroot/$repo ]; then |
||||
exe sudo rm -rf $BASEDIR/chroot/$repo $BASEDIR/chroot/$repo.lock |
||||
fi |
||||
if [ -d $BASEDIR/$repo ]; then |
||||
exe rm -rf $BASEDIR/$repo |
||||
fi |
||||
done |
||||
) |
||||
} |
||||
|
||||
build() { |
||||
( |
||||
set -e |
||||
if [ "$#" -lt 1 ]; then |
||||
echo "Must specify repository name to build (and optional package list to include)" |
||||
return 1 |
||||
fi |
||||
setup |
||||
repo_name=$1 |
||||
mkdir -p $BASEDIR/$repo_name |
||||
shift |
||||
if [ "$#" -gt 0 ]; then |
||||
# Build only requested packages |
||||
for pkg in "$@"; do |
||||
package_build $repo_name $pkg |
||||
done |
||||
echo "## All requested packages built" |
||||
else |
||||
# Build all packages: |
||||
cd $BASEDIR/src |
||||
find -type d | sed 's/\.\///' | tail -n +2 | while read pkg; do |
||||
package_build $repo_name $pkg |
||||
done |
||||
echo "## All packages built" |
||||
fi |
||||
echo "## Updating repository database" |
||||
cd $BASEDIR/$repo_name |
||||
if [ `ls *.pkg.tar.xz 2> /dev/null | wc -l` -lt 1 ]; then |
||||
echo "No packages found in $BASEDIR/$repo_name" |
||||
return 1; |
||||
fi |
||||
sign_packages *.pkg.tar.xz |
||||
repo-add $repo_name.db.tar.gz *.pkg.tar.xz |
||||
sign_packages $repo_name.db |
||||
) |
||||
} |
||||
|
||||
|
||||
if [ "$#" -gt 0 ]; then |
||||
$* |
||||
else |
||||
echo "Must specify a command, eg: add, build, list, clean" |
||||
exit 1 |
||||
fi |
Loading…
Reference in new issue