#!/bin/bash #This is a script for automatic create addons for openSUSE # # Copyright (c) 2010-2011 Alex Savin # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 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 General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, see . # # Authors: Alex Savin # # Version Date Changes # 0.1.1 2010-06-01 Initial release # 0.2.0 2011-09-02 Major rewrite and change script name #Require: zypper sudo fuseiso yast2 yast2-add-on-creator gpg2 #Require_bin: sha1sum md5sum SUSE_ADDON_CREATOR_VERSION="0.2.0" #====================================== # Init options #-------------------------------------- init_options(){ # /.../ # this function should always enable, # it don't change anything - just init empty and constant variables # ---- #====================================== # Init empty variables #-------------------------------------- : ${ARCH:=`arch`} [[ -n `echo $ARCH | egrep "i[3456]86"` ]] && ARCH=i586 : ${SUSEVERSION:="11.4"} : ${ADDON_VERSION:="1.1"} : ${ADDON_NAME:="codecs-set-$ADDON_VERSION-$SUSEVERSION-$ARCH"} : ${ADDON_DESCRIPTION:="Proprietary codecs set for openSUSE $SUSEVERSION $ARCH"} : ${BUILDDIR:=$(mktemp -d --dry-run "/tmp/$ADDON_NAME-XXXXXXXXX")} : ${VENDOR:=$USER} [[ -z "$PKG_LIST" ]] && PKG_LIST=" ffmpeg gstreamer gstreamer-0_10 gstreamer-0_10-ffmpeg gstreamer-0_10-plugins-good gstreamer-0_10-plugins-good-extra gstreamer-0_10-utils gstreamer-0_10-plugins-gl gstreamer-0_10-plugins-bad gstreamer-0_10-plugin-gnomevfs gstreamer-0_10-fluendo-mp3 gstreamer-0_10-fluendo-mpegdemux gstreamer-0_10-fluendo-mpegmux gstreamer-0_10-lang gstreamer-0_10-libnice libQtGStreamer-0_10-0 k3b-codecs lame libdivx6 libdvdcss libopenjpeg2 libvpx0 libxine1-codecs libxine1-pulse mac mplayer2 MPlayer smplayer umplayer phonon-backend-mplayer phonon-backend-vlc phonon-backend-xine phonon-backend-gstreamer-0_10 vlc vlc-aout-pulse vlc-gnome vlc-qt w32codec-all wine-mp3 xvid4conf xvidcore h264enc avidemux-qt avidemux-gtk mediainfo-gui libdv libdv4 amrwb amrnb libbluray0 " # umplayer-themes # smplayer-themes [[ -z "$PKG_BLACK_LIST" ]] && PKG_BLACK_LIST=" rubygem webyast apache2 nginx syslog-ng bundle-lang-common " [[ -z "$REPO_LIST" ]] && REPO_LIST=" http://ftp.gwdg.de/pub/linux/misc/packman/suse/ http://www.opensuse-guide.org/repo/ " PKG_LIST="$(echo $PKG_LIST)" # remove unneeded space REPO_LIST="$(echo $REPO_LIST)" PKG_BLACK_LIST="$(echo $PKG_BLACK_LIST)" if [[ -z "$FACTORYVERSION" ]] ; then FACTORYVERSION=$(curl --silent http://download.opensuse.org/factory/repo/oss/content | \ grep VERSION --max-count=1 | cut -f2- -d' ' | tr -d [:space:] ) echo "FACTORYVERSION is autodetect as $FACTORYVERSION" fi if [[ "$SUSEVERSION" == "factory" || "$SUSEVERSION" == "$FACTORYVERSION" ]] ; then SUSE_REPO="http://download.opensuse.org/factory/repo/oss/" SUSEVERSION="factory" else SUSE_REPO="http://download.opensuse.org/distribution/$SUSEVERSION/repo/oss/" fi #====================================== # Init constant variables #-------------------------------------- # ZYPPLOG="`mktemp /tmp/zypper-XXXXXXX.log`" ZYPPLOG="$BUILDDIR/zypper.log" zypper="eval zypper 2> >( tee -a $ZYPPLOG | sed 's/^/Zypper: '\$@'/' 1>&2 ) 1> >( cat >> $ZYPPLOG ) " zypper="$zypper --root $BUILDDIR/root/ --no-gpg-checks " zypperaddrepo="$zypper addrepo --keep-packages --check --refresh " zypperin="$zypper --non-interactive install --auto-agree-with-licenses --download-only -f " } #====================================== # Print configs (and exit if var USAGE set) #-------------------------------------- print_conf() { # /.../ # just print configs, # if used "--help" option, it also show help and quit # ---- CONF=`mktemp /tmp/addon.conf-XXXXXXXXX` echo "=======================Start addon creation============================" cat < $CONF # suse-addon-creator build settings: ADDON_NAME="$ADDON_NAME" # name of your addon ADDON_DESCRIPTION="$ADDON_DESCRIPTION" # description of your addon VENDOR="$VENDOR" # your name SUSEVERSION=$SUSEVERSION ARCH=$ARCH GPG_KEY="$GPG_KEY" # gpg key uid, if empty - will be created unsigned addon, # run: gpg --list-secret-keys # to see list of avialable keys DVD_ISO="$DVD_ISO" # path to openSUSE install dvd PKG_LIST="$PKG_LIST" # rpms for install REPO_LIST="$REPO_LIST" # list of additional repositories (except main and dvd) PKG_BLACK_LIST="$PKG_BLACK_LIST" # list of rpms which shouldn't be added into addon RPMDIR_FOR_ADDON="$RPMDIR_FOR_ADDON" # directory with/for rpm files (empty by default) BUILDDIR="$BUILDDIR" # dir for build (should be autocreated) EOF cat $CONF cat </dev/null local chroot="$BUILDDIR/root" #====================================== # check RPMDIR_FOR_ADDON variable #-------------------------------------- if [[ -n "$RPMDIR_FOR_ADDON" && $RUNPARAM == "download" ]] ; then if [[ -d "$RPMDIR_FOR_ADDON" || ! -e "$RPMDIR_FOR_ADDON" ]] ; then mkdir -p "$RPMDIR_FOR_ADDON" 2>/dev/null echo "Rpms will be downloaded into $RPMDIR_FOR_ADDON dir" else echo "Error: wrong value of RPMDIR_FOR_ADDON=\"$RPMDIR_FOR_ADDON\" - Exiting!" exit 1 fi elif [[ -d "$RPMDIR_FOR_ADDON" ]] ; then echo "You manually setup directory with rpms: RPMDIR_FOR_ADDON=\"$RPMDIR_FOR_ADDON\"," echo "skipping rpms download!" return 0 fi : ${RPMDIR_FOR_ADDON:="$BUILDDIR/rpm"} #====================================== # check required variables #-------------------------------------- if [[ -z "$DVD_ISO" ]] ; then echo "Error: You should setup DVD_ISO variable!" echo "You can download openSUSE DVD from here: " if [[ $SUSEVERSION == factory ]] ; then echo "http://download.opensuse.org/distribution/ (directory $FACTORYVERSION)" else echo "http://download.opensuse.org/distribution/$SUSEVERSION/iso/openSUSE-$SUSEVERSION-DVD-$ARCH.iso" fi exit 1 fi #====================================== # Setup zypper config #-------------------------------------- local zypp_exit=0 mkdir -p $chroot/etc/zypp/ export ZYPP_CONF="$chroot/etc/zypp/zypp.conf" # this required cat <$chroot/etc/zypp/zypp.conf [main] arch = $ARCH commit.downloadMode = DownloadOnly EOF #====================================== # Setup main repo #-------------------------------------- $zypperaddrepo $SUSE_REPO oss #====================================== # Setup additional repos #-------------------------------------- local j=0 for repo in $REPO_LIST do # use repo alias if repo is not path to *.repo files local reponame= [[ -z `echo $repo | egrep "*.repo$"` ]] && \ reponame="add$((j++))" # try add repo echo "Try add $repo repository" $zypperaddrepo $repo $reponame zypp_exit=$? # try add repo/$SUSEVERSION if [[ $zypp_exit != 0 && -n $reponame && -z `echo $repo | grep $SUSEVERSION` ]] ; then echo "Try add $repo/$SUSEVERSION repository" $zypperaddrepo "$repo/$SUSEVERSION" $reponame zypp_exit=$? fi echo "" # exit if failed add repo [[ $zypp_exit != 0 ]] && echo "Error: can't add $repo repository - exiting!" && exit 1 done #====================================== # Add DVD_ISO repo #-------------------------------------- if [[ -f $DVD_ISO ]] ; then if [[ -n `type -p fuseiso` ]] ; then mkdir $BUILDDIR/dvd_iso fuseiso $DVD_ISO $BUILDDIR/dvd_iso -o allow_other [[ $? != 0 ]] && \ sudo fuseiso $DVD_ISO $BUILDDIR/dvd_iso -o allow_other $zypperaddrepo --check --refresh $BUILDDIR/dvd_iso dvd zypp_exit=$? else if [[ `whoami` == "root" ]] ; then local iso_path="iso:/?iso=$(basename $DVD_ISO)&url=file:$(dirname $DVD_ISO)" $zypper addrepo --no-keep-packages --check --refresh $iso_path dvd zypp_exit=$? else echo "Error: fuseiso - not found" echo "install fuseiso using:" echo "sudo zypper in fuseiso" fi fi elif [[ -d $DVD_ISO ]] ; then $zypperaddrepo --check --refresh $DVD_ISO dvd zypp_exit=$? else echo "iso image of openSUSE dvd: $DVD_ISO - not found" exit 1 fi if [[ $zypp_exit != 0 ]] ; then echo "Error: can't add $DVD_ISO - check it, exiting!" exit 1 fi #====================================== # Lower priority for main repos - will be used rpms for additional repos #-------------------------------------- $zypper mr --priority 150 oss dvd echo "Refreshing repositories, please wait..." if [[ -z $DEBUG ]] ; then $zypper refresh fi #====================================== # Show which package download - it run in background #-------------------------------------- CUR_LN=1 while true do sleep 5 local LAST_LN=`sed -n "$ = " $BUILDDIR/zypper.log` [[ $((--LAST_LN>=1)) == 1 ]] || continue # if log not exist local downloads="`sed -n "$CUR_LN,$LAST_LN s/\(\[.*]\)\$//p" $BUILDDIR/zypper.log`" [[ -n "$downloads" ]] && \ echo "$downloads" && \ CUR_LN=$LAST_LN done 2>/dev/null & local download_progress_pid=$! #====================================== # Download rpms (Use separate commands to avoid stop install if package not found) #-------------------------------------- echo "See $BUILDDIR/zypper.log for details" echo "Downloading packages, please wait..." if [[ -z $DEBUG ]] ; then # $zypperin -t pattern codecs for i in $PKG_LIST do $zypperin $i >> $BUILDDIR/zypper.log done else echo "Used --debug option - rpms will not be downloaded!" fi kill $download_progress_pid 2>/dev/null umount $BUILDDIR/dvd_iso 2>/dev/null #====================================== # If package exist on dvd, we shouldn't put it into addon #-------------------------------------- rm -rf $chroot/var/cache/zypp/packages/dvd #====================================== # Put rpms into $RPMDIR_FOR_ADDON dir #-------------------------------------- mkdir -p $RPMDIR_FOR_ADDON \ $RPMDIR_FOR_ADDON-blacklist # $RPMDIR_FOR_ADDON/$ARCH \ # $RPMDIR_FOR_ADDON/noarch \ # $RPMDIR_FOR_ADDON/i686 \ # $RPMDIR_FOR_ADDON/x86_64 # find $chroot/var/cache/zypp/packages/ -name "*$ARCH.rpm" -exec cp -p {} $RPMDIR_FOR_ADDON/$ARCH \; # find $chroot/var/cache/zypp/packages/ -name "*noarch.rpm" -exec cp -p {} $RPMDIR_FOR_ADDON/noarch \; # find $chroot/var/cache/zypp/packages/ -name "*i686.rpm" -exec cp -p {} $RPMDIR_FOR_ADDON/i686 \; # find $chroot/var/cache/zypp/packages/ -name "*x86_64.rpm" -exec cp -p {} $RPMDIR_FOR_ADDON/x86_64 \; # find $RPMDIR_FOR_ADDON -type d -empty -exec rmdir {} \; if [[ -n $PKG_BLACK_LIST ]] ; then echo "You use variable PKG_BLACK_LIST=\"$PKG_BLACK_LIST\" ," echo "due this your should manually check that all requirements are provided!" fi local rpmlist=`find $chroot/var/cache/zypp/packages/ -name "*.rpm" -printf "%P "` for i in $rpmlist do local iname=`basename $i` local addrpm=1 for b in $PKG_BLACK_LIST do if [[ -n `echo $iname | grep $b` ]] ; then echo "$iname will not be put into addon" addrpm=0 fi done if [[ $addrpm == 1 ]] ; then cp -p "$chroot/var/cache/zypp/packages/$i" "$RPMDIR_FOR_ADDON/" else cp -p "$chroot/var/cache/zypp/packages/$i" "$RPMDIR_FOR_ADDON-blacklist/" fi done echo "Rpm files copied to $RPMDIR_FOR_ADDON directory" } #====================================== # Create tar archive with rpms #-------------------------------------- create_tar_with_rpms() { echo "Creating simple tar archive with rpms:" echo "$ADDON_DESCRIPTION" > $RPMDIR_FOR_ADDON/$ADDON_NAME.readme local name=$BUILDDIR/$ADDON_NAME-$SUSEVERSION-$ARCH.tar tar -cf $name $RPMDIR_FOR_ADDON $BUILDDIR/addon/ echo "Archive with rpms: $name" } #====================================== # Test script parameters (is it in list?) #-------------------------------------- test_Runparam (){ for i in $RUNPARAM do if [[ ` echo " $1 " | grep " $i " ` ]] ; then return 0 fi done return 1 } #====================================== # Setup addon files #-------------------------------------- set_addon_files() { #====================================== # Check: is dir with rpms exist? #-------------------------------------- if [[ ! -d "$RPMDIR_FOR_ADDON" ]] ; then echo "Directory $RPMDIR_FOR_ADDON with rpms - not exist, can't create addon!" echo "Change variable RPMDIR_FOR_ADDON=$RPMDIR_FOR_ADDON and try again." exit 0 fi #====================================== # Setup addon template #-------------------------------------- if [[ -d $BUILDDIR/addon ]] ; then echo "Removing old: $BUILDDIR/addon " rm -rf $BUILDDIR/addon fi mkdir -p $BUILDDIR/addon/suse/setup/descr/ cat < $BUILDDIR/addon/content CONTENTSTYLE 11 BASEARCHS $ARCH DATADIR suse DESCRDIR suse/setup/descr DISTRIBUTION $ADDON_DESCRIPTION 1.0 LABEL $ADDON_DESCRIPTION LINGUAS en NAME $ADDON_DESCRIPTION PATTERNS codecs-set RELEASE 0 VENDOR $VENDOR VERSION 1.0 EOF #====================================== # Generate pattern file #-------------------------------------- pattern="$BUILDDIR/addon/suse/setup/descr/codecs-set-1.0-1.noarch.pat" cat < $pattern =Ver: 5.0 =Pat: codecs-set 1.0 1 noarch +Prq: EOF # add list of rpm to require section find $RPMDIR_FOR_ADDON -name *".rpm" -printf "%f\n" | sed 's/\(-[^-]*\)\{2\}rpm//' >> $pattern # end of pattern file cat <> $pattern -Prq: =Vis: true EOF #====================================== # Generate info.txt file #-------------------------------------- local bdate="`date "+%Y.%m.%d %R"`" cat < "$BUILDDIR/addon/info.txt" Addon generated with suse-addon-creator $SUSE_ADDON_CREATOR_VERSION Build date: $bdate Used repositories: $REPO_LIST EOF } #====================================== # Create yast addon if possible otherwise tar archive #-------------------------------------- create_addon() { echo ======================================================= echo "Start addon creation" #====================================== # Check: can we create addon? #-------------------------------------- if [[ ! -f /sbin/yast ]] ; then echo "Yast not found, can't create addon!" create_tar_with_rpms exit 0 fi local yast2="`echo sudo GNUPGHOME=\"$HOME/.gnupg/\" LC_ALL=C /sbin/yast2 `" # GPG_AGENT_INFO=\"$GPG_AGENT_INFO\" #====================================== # Remove previous build #-------------------------------------- if [[ -d $BUILDDIR/$ADDON_NAME || -f $BUILDDIR/$ADDON_NAME.iso ]] ; then echo "Removing old: $BUILDDIR/$ADDON_NAME $BUILDDIR/$ADDON_NAME.iso" sudo rm -rf $BUILDDIR/$ADDON_NAME $BUILDDIR/$ADDON_NAME.iso* fi mkdir $BUILDDIR/$ADDON_NAME #====================================== # Check: is addon already exist? (and remove if exist) #-------------------------------------- local list_conflict_addon="`$yast2 add-on-creator list 2>&1`" list_conflict_addon=`echo $list_conflict_addon | \ tr '\n' ' ' | tr '(' '\n' | sed 's/^/(/' | \ egrep "^\([0-9]+\) Product Name: $ADDON_DESCRIPTION"` if [[ -n $list_conflict_addon ]] ; then echo "Follow addons will be removed:" echo "$list_conflict_addon" local addonnum=$( echo "$list_conflict_addon" | egrep "^\([0-9]+\) Product Name: $ADDON_DESCRIPTION$" | cut -f1 -d')' | cut -f2 -d'(' ) for i in $addonnum do $yast2 add-on-creator delete number=$i done fi #====================================== # Hack: obs-productconverter is required but not exist in default repos #-------------------------------------- if [[ -z `rpm -q obs-productconverter` ]] ; then echo "Try install obs-productconverter package" sudo zypper in obs-productconverter if [[ $? != 0 ]] ; then local tools_repo="obs://openSUSE:Tools/openSUSE_`lsb_release --short --release`" echo "obs-productconverter - not found, try install obs-productconverter from $tools_repo" sudo zypper addrepo $tools_repo suse-tools sudo zypper --non-interactive install obs-productconverter fi fi #====================================== # Should we sign addon? #-------------------------------------- local gpg_key= if [[ -n $GPG_KEY ]] ; then gpg_key="gpg_key=\"$GPG_KEY\"" else echo "Warning: Will be created unsigned iso image, strongly recommended sign it, run:" echo "suse-addon-creator --create BUILDDIR=\"$BUILDDIR\" GPG_KEY=\"uid of your key\"" echo "or use yast2 -> Add-On Creator to sign it manually." echo "List of available gpg keys:" gpg --list-secret-keys gpg_key="do_not_sign" fi #====================================== # Create addon #-------------------------------------- $yast2 add-on-creator create "$gpg_key" \ content="$BUILDDIR/addon/content" \ rpm_dir="$RPMDIR_FOR_ADDON" \ output_dir="$BUILDDIR/$ADDON_NAME" \ create_iso \ iso_name="$ADDON_NAME" \ iso_output_dir="$BUILDDIR" \ changelog \ verbose \ patterns_dir="`dirname $pattern`" \ info="$BUILDDIR/addon/info.txt" if [[ $? == 0 ]] ; then echo "New profile in yast add-on-creator created successfull!" echo ".iso file was writen in $BUILDDIR/$ADDON_NAME.iso" fi } #====================================== # Sign created iso file #-------------------------------------- sign_iso() { sha1sum $BUILDDIR/$ADDON_NAME.iso > $BUILDDIR/$ADDON_NAME.iso.sha1 md5sum $BUILDDIR/$ADDON_NAME.iso > $BUILDDIR/$ADDON_NAME.iso.md5 if [[ -n $GPG_KEY ]] ; then gpg --local-user "$GPG_KEY" --detach-sign $BUILDDIR/$ADDON_NAME.iso fi } #====================================== # Read variables from file (option --conf-file="file") #-------------------------------------- read_conf_file "$@" #====================================== # Parse command line (and fill/overwrite variables) #-------------------------------------- DEBUG= RUNPARAM= while [[ -n "$1" ]] do case "$1" in --debug) DEBUG=1 ;; -h|--help|--usage|usage|help) RUNPARAM="help" shift $# ;; --*) RUNPARAM="$RUNPARAM ${1#--}" ;; -*) echo "Wrong option $1" exit 1 ;; *=*) eval ${1%%=*}=\"${1#*=}\" ;; *) echo "Wrong option $1" exit 1 ;; esac shift done : ${RUNPARAM:="default"} #====================================== # Init options - this function should always enable, # it don't change anything - just init empty and constant variables #-------------------------------------- init_options #====================================== # Print configs (and exit if USAGE==1) #-------------------------------------- test_Runparam "default download create tar help" && \ print_conf #====================================== # Download rpms from repos #-------------------------------------- test_Runparam "default download tar" && \ get_rpms #====================================== # Setup addon files #-------------------------------------- test_Runparam "default create tar" && \ set_addon_files #====================================== # Create yast addon if possible otherwise tar archive #-------------------------------------- test_Runparam "default create" && \ create_addon #====================================== # Create tar archive with rpms #-------------------------------------- test_Runparam "tar" && \ create_tar_with_rpms #====================================== # Write variables to config file #-------------------------------------- test_Runparam "default download create tar" && \ write_conf_file #====================================== # Sign created iso file #-------------------------------------- test_Runparam "default create" && \ sign_iso echo "ALL DONE" exit 0