You are not logged in.
edit: the script will be available in pacman 3.2 when it's released (HOORAY!)
Meanwhile you can grab the most recent version of the script here:
http://projects.archlinux.org/?p=pacman … an;hb=HEAD
Hi,
I'm one of those guys who is always low on space:
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda3              44G   43G  335M 100% /I actually recovered those 300 mB by running pacman -Scc, but I forgot to safekeep some packages (especially truecrypt and the 2.6.24 kernel), so if this kernel upgrade goes wrong I can't downgrade.
Well, I couldn't downgrade because lately I've been trying to learn a little bit of bash scripting, so today I came up with this script which rebuilds an installed package using the metadata in the pacman db.
#!/bin/bash
#
# repacman 0.1
# Recreate a package from a running system
#
pac_db='/var/lib/pacman/local'
work_dir=$PWD
IFS=$'\n'
mkdir $work_dir/pkg
cd $work_dir/pkg || exit 1
echo 
echo Processing desc and generating .PKGINFO metadata
echo "# Generated by repacman 0.1"    >> .PKGINFO
echo "# $(date)"            >> .PKGINFO
for i in $(cat $pac_db/$1/desc) ; do
    if [[ "$i" =~ %*[A-Z]% ]] ; then
        current=$i
        continue
    fi
        case "$current" in
        %NAME%)
           echo "pkgname = $i"    >> .PKGINFO
           pkgname=$i
        ;;
        %VERSION%)
           echo "pkgver = $i"    >> .PKGINFO
           pkgver=$i
           ;;
        %DESC%)
           echo "pkgdesc = $i"    >> .PKGINFO
        ;;
        %URL%)
           echo "url = $i"    >> .PKGINFO
        ;;
        %LICENSE%)
           echo "license = $i"    >> .PKGINFO
        ;;
        %ARCH%)
           echo "arch = $i"    >> .PKGINFO
           pkgarch=$i
        ;;
        %BUILDDATE%)
           echo "builddate = $i" >> .PKGINFO
        ;;
        %PACKAGER%)
           echo "packager = $i"    >> .PKGINFO
        ;;
        %SIZE%)
           echo "size = $i"    >> .PKGINFO
        ;;
        %GROUPS%)
           echo "group = $i"    >> .PKGINFO
        ;;
    esac
done
echo Processing files and copying package files
for i in $(cat $pac_db/$1/files) ; do
    if [[ "$i" =~ %*[A-Z]% ]] ; then
        current=$i
        continue
    fi
    case $current in
        %FILES%)
           if [ -d /$i ]; then
            mkdir $i
           fi
           if [ -f /$i ]; then
            install -D /$i $i
           fi
        ;;
        %BACKUP%)
           echo "backup = $i"    >> .PKGINFO
        ;;
    esac
done
echo Adding install commands and changelogs, if any
if [ -f $pac_db/$1/install ] ; then
    cp $pac_db/$1/install $work_dir/pkg/.install
fi
if [ -f $pac_db/$1/changelog ] ; then
    cp $pac_db/$1/changelog $work_dir/pkg/.changelog
fi
echo Processing depends and adding the dependancies to the .PKGINFO
for i in $(cat $pac_db/$1/depends) ; do
    if [[ "$i" =~ %*[A-Z]% ]] ; then
        current=$i
        continue
    fi
    case "$current" in
        %DEPENDS%)
           echo "depend = $i"    >> .PKGINFO
        ;;
        %OPTDEPENDS%)
           echo "optdepend = $i" >> .PKGINFO
        ;;
        %CONFLICTS%)
           echo "conflict = $i"    >> .PKGINFO
        ;;
        %PROVIDES%)
           echo "provide = $i"    >> .PKGINFO
        ;;
    esac
done
echo 
echo Generating the package...
bsdtar -czf ../"$pkgname-$pkgver-$pkgarch.tar.gz" $(ls -A)
echo Removing temporary files...
cd $work_dir || exit 1
rm -r pkg/This is one of my first scripts I write from scratch, so suggestions to improve my scripting style are very welcome.
I couldn't find %REPLACES% for the replace = in any of the package I have installed, but I think %CONFLICTS% is enough?
I think I will clear my cache everytime, and then, when I need to backup some pkgs before an upgrade, I will use the script (at least I won't have to keep the same files twice on my hard drive).
edit: understood what %REASON% meant
Last edited by carlocci (2008-06-23 15:16:55)
Offline

Ohh... nice.
Just so you know, there is an outdated version of this script (also called repacman) in the contrib directory of the pacman source. Also, another version (possibly updated) here: http://foulmetal.free.fr/archlinux/repacman-0.98.tar.gz
My intention is to include this in the pacman-contrib package when it was updated/tested but I haven't had time to do this...  Now, I will probably borrow heavily from this script (unless you want to combine them and submit it to the pacman-dev mailing list) 
Offline
Ohh... nice.
Just so you know, there is an outdated version of this script (also called repacman) in the contrib directory of the pacman source.
Great minds think alike! 
Also, another version (possibly updated) here: http://foulmetal.free.fr/archlinux/repacman-0.98.tar.gz
Thank you, that looks so much more complete and structured. I think I will fiddle with bash functions next: for once I think I could unify desc, files and depends under one function.
My intention is to include this in the pacman-contrib package when it was updated/tested but I haven't had time to do this... Now, I will probably borrow heavily from this script (unless you want to combine them and submit it to the pacman-dev mailing list)
Well, it would be nice if pacman could autobackup packages: pacman -U installs, pacman -Rp removes and recreates the package
Last edited by carlocci (2008-05-26 14:57:54)
Offline
Here we are, new version:
this one figures out takes the db path and pkg cache dir from pacman.conf, or default them
performs some checks, like asking to use the package you already have in the cache if any
I unified the part which generates .PKGINFO and used better variable names
Changed the name
#!/bin/bash
#
#   bacman: recreate a package from a running system
#   This script rebuilds an already installed package using metadata
#   stored into the pacman database and system files
#
#   (c) 2008 - locci <carlocci_at_gmail_dot_com>
#   
#   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 <http://www.gnu.org/licenses/>.
#
_bacman_ver="0.1.½"
#
# Setting env variables
#
IFS=$'\n'
eval $(awk '/DBPath|CacheDir/ {print $1$2$3}' /etc/pacman.conf)
pac_db=${DBPath:-'/var/lib/pacman/'}/local/
pac_cache=${CacheDir:-'/var/cache/pacman/pkg/'}
work_dir=$PWD
pkg_name="$1"
pkg_dir=$(echo $pac_db/$pkg_name-[0-9]*)
#
# Checks everything is in place
#
if [ $# -ne 1 ] ; then
    echo bacman $_bacman_ver
    echo "Usage: ./bacman <installed package name>"
    exit 1
fi
if [ ! -d $pac_db ] ; then
    echo There is no pacman database directory in $pac_db
    echo $pac_db is missing
    exit 1
fi
if [ ! -d $pac_cache ] ; then
    echo Warning, there is no pacman pkg cache directory
    echo $pac_cache is missing
    unset pac_cache
fi
if [ ! -d $pkg_dir ] ; then
    echo There is no package with this name, $pkg_name
    echo Maybe you are trying to pass the directory name, instead of the package name
    exit 1
fi
if [ -n $pac_cache ] && [ -f $pac_cache/${pkg_dir##*/}*.tar.gz ] ; then
    echo The package already exists in your cache
    read -n 1 -p 'Do you want to fetch it instead ? (y/N) '
    case $REPLY in
           y|Y)
           cp $pac_cache/${pkg_dir##*/}*.pkg.tar.gz .
           exit 0
        ;;
        *) ;;
    esac
fi
#
# Begin 
#
mkdir $work_dir/pkg
cd $work_dir/pkg || exit 1
#
# .PKGINFO stuff
#
echo 
echo Generating .PKGINFO metadata...
echo "# Generated by bacman $_bacman_ver"    > .PKGINFO
echo "# $(LC_ALL=C date)"            >> .PKGINFO
echo "#"                    >> .PKGINFO
for i in $(cat $pkg_dir/{desc,files,depends}) ; do
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
        case "$current" in
#desc
        %NAME%)
           echo "pkgname = $i"    >> .PKGINFO
           pkgname=$i
        ;;
        %VERSION%)
           echo "pkgver = $i"    >> .PKGINFO
           pkgver=$i
           ;;
        %DESC%)
           echo "pkgdesc = $i"    >> .PKGINFO
        ;;
        %URL%)
           echo "url = $i"    >> .PKGINFO
        ;;
        %LICENSE%)
           echo "license = $i"    >> .PKGINFO
        ;;
        %ARCH%)
           echo "arch = $i"    >> .PKGINFO
           arch=$i
        ;;
        %BUILDDATE%)
           echo "builddate = $i" >> .PKGINFO
        ;;
        %PACKAGER%)
           echo "packager = $i"    >> .PKGINFO
        ;;
        %SIZE%)
           echo "size = $i"    >> .PKGINFO
        ;;
        %GROUPS%)
           echo "group = $i"    >> .PKGINFO
        ;;
#files
        %BACKUP%)
           echo "backup = $i"   >> .PKGINFO
        ;;
#depends
                %DEPENDS%)
                   echo "depend = $i"   >> .PKGINFO
                ;;
                %OPTDEPENDS%)
                   echo "optdepend = $i" >> .PKGINFO
                ;;
                %CONFLICTS%)
                   echo "conflict = $i" >> .PKGINFO
                ;;
                %PROVIDES%)
                   echo "provide = $i"  >> .PKGINFO
                ;;
    esac
done
#
# Files stuff
#
echo Copying package files...
for i in $(cat $pkg_dir/files) ; do
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case $current in
        %FILES%)
           if [ -d /$i ]; then
            mkdir $i
           fi
           if [ -f /$i ]; then
            install -D /$i $i
           fi
        ;;
    esac
done
echo Adding install commands and changelogs, if any...
if [ -f $pkg_dir/install ] ; then
    cp $pkg_dir/install $work_dir/pkg/.install
fi
if  [ -f $pkg_dir/changelog ] ; then
    cp $pkg_dir/changelog $work_dir/pkg/.changelog
fi
#
# 
#
echo 
echo Generating the package...
bsdtar -czf ../"$pkgname-$pkgver-$arch.tar.gz" $(ls -A)
echo Removing temporary files...
cd $work_dir || exit 1
rm -r pkg/
exit 0
#
# End
#Last edited by carlocci (2008-05-26 23:20:49)
Offline

I just made a very quick testing, it does not seem to work bad.
You made a typo though, it is provides, not provide.
pacman roulette : pacman -S $(pacman -Slq | LANG=C sort -R | head -n $((RANDOM % 10)))
Offline

I am going to add a couple of suggestions that you may or may not consider to be useful....
You could change the builddate to be the date the package is remade on. Also, packager could take the value in /etc/makepkg.conf or default to something sensible. The size might have changed with any changed configuration files that you are repacking (but the difference is probably too small to care about).
Offline
You made a typo though, it is provides, not provide.
Thank you, the esses were a little bit confusing 
As suggested by Allan, I integrated some data from makepkg.conf (packager and PKGDEST), I might include the emptydirs flag and strip flag as soon as I figure out bash arrays. Even if the original idea was to create the exact same original package (I forgot about /etc  ).
 ).
I added more checks and warnings.
I thought about using /tmp and mktemp for the temporary pkg directory name, but I tried to mimic the behaviour of makepkg: I removed the line deleting pkg/
I added a correct size calculator
I'm thinking about setting a variable for each field and then writing them to the PKGCONFIG.
#!/bin/bash
#
#   bacman: recreate a package from a running system
#   This script rebuilds an already installed package using metadata
#   stored into the pacman database and system files
#
#   (c) 2008 - locci <carlocci_at_gmail_dot_com>
#   
#   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 <http://www.gnu.org/licenses/>.
#
_bacman_ver="0.1.½"
#
# Setting env variables
#
IFS=$'\n'
eval $(awk '/DBPath|CacheDir/ {print $1$2$3}' /etc/pacman.conf)
pac_db="${DBPath:-/var/lib/pacman/}/local"
pac_cache="${CacheDir:-/var/cache/pacman/pkg/}"
work_dir="$PWD"
pkg_name="$1"
pkg_dir="$(echo $pac_db/$pkg_name-[0-9]*)"
eval $(awk '/PKGDEST|CARCH|PACKAGER/ {print $1$2$3}' /etc/makepkg.conf)
pkg_dest="${PKGDEST:-$work_dir}"
pkg_arch=${CARCH:-'noarch'}
pkg_pkger=${PACKAGER:-'Unknown Packager'}
#
# Checks everything is in place
#
if [ $# -ne 1 ] ; then
    echo bacman $_bacman_ver
    echo "Usage: ./bacman <installed package name>"
    exit 1
fi
if [ ! -d "$pac_db" ] ; then
    echo There is no pacman database directory in $pac_db
    echo $pac_db is missing
    exit 1
fi
if [ ! -d "$pac_cache" ] ; then
    echo Warning, there is no pacman pkg cache directory
    echo $pac_cache is missing
    unset pac_cache
fi
if [ ! -d "$pkg_dir" ] ; then
    echo There is no package with this name, $pkg_name
    echo Maybe you are trying to pass the directory name, instead of the package name
    exit 1
fi
if [ -n "$pac_cache" ] && [ -f "$pac_cache"/"${pkg_dir##*/}"*.tar.gz ] ; then
    echo The package already exists in your cache
    read -n 1 -p 'Do you want to fetch it instead ? (y/N) '
    case $REPLY in
           y|Y)
           cp "$pac_cache"/"${pkg_dir##*/}"*.pkg.tar.gz "$pkg_dest"
           exit 0
        ;;
        *) echo ""
        ;;
    esac
fi
#
# Begin 
#
echo Packet: ${pkg_dir##*/}
mkdir "$work_dir"/pkg || exit 1
cd "$work_dir"/pkg || exit 1
#
# File copying
#
echo Copying package files...
for i in $(cat "$pkg_dir"/files) ; do
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case $current in
        %FILES%)
           if [ -d "/$i" ]; then
            mkdir "$i"
           elif [ -f "/$i" ]; then
            install -D "/$i" "$i"
           else
            echo "/$i" is missing: this might result in a broken package
           fi
        ;;
    esac
    pkg_size=$(du -sb | awk '{print $1}')
done
echo Adding install commands and changelogs, if any...
if [ -f "$pkg_dir/install" ] ; then
    cp "$pkg_dir/install" "$work_dir/pkg/.install"
fi
if  [ -f $pkg_dir/changelog ] ; then
    cp "$pkg_dir/changelog" "$work_dir/pkg/.changelog"
fi
#
# .PKGINFO stuff
#
echo 
echo Generating .PKGINFO metadata...
echo "# Generated by bacman $_bacman_ver"    > .PKGINFO
echo "# $(LC_ALL=C date)"            >> .PKGINFO
echo "#"                    >> .PKGINFO
for i in $(cat "$pkg_dir"/{desc,files,depends}) ; do
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
        case "$current" in
        %NAME%)                    #desc
           echo "pkgname = $i"    >> .PKGINFO
           pkgname=$i
        ;;
        %VERSION%)
           echo "pkgver = $i"    >> .PKGINFO
           pkgver=$i
           ;;
        %DESC%)
           echo "pkgdesc = $i"    >> .PKGINFO
        ;;
        %URL%)
           echo "url = $i"    >> .PKGINFO
        ;;
        %LICENSE%)
           echo "license = $i"    >> .PKGINFO
        ;;
        %ARCH%)
           echo "arch = $i"    >> .PKGINFO
        ;;
        %BUILDDATE%)
           echo "builddate = $(date -u "+%s")"    >> .PKGINFO
        ;;
        %PACKAGER%)
           echo "packager = $pkg_pkger"        >> .PKGINFO
        ;;
        %SIZE%)
           echo "size = $pkg_size"        >> .PKGINFO
        ;;
        %GROUPS%)
           echo "group = $i"    >> .PKGINFO
        ;;
        %BACKUP%)                #files
           echo "backup = $i"   >> .PKGINFO
        ;;
                %DEPENDS%)                #depends
                   echo "depend = $i"   >> .PKGINFO
                ;;
                %OPTDEPENDS%)
                   echo "optdepend = $i" >> .PKGINFO
                ;;
                %CONFLICTS%)
                   echo "conflict = $i" >> .PKGINFO
                ;;
                %PROVIDES%)
                   echo "provides = $i"  >> .PKGINFO
                ;;
    esac
done
#
# 
#
echo 
echo Generating the package...
bsdtar -czf "$pkg_dest/$pkgname-$pkgver-$pkg_arch.tar.gz" $(ls -A) || echo Cannot write to $pkg_dest: maybe disk is full or you do not have write access 
#echo Removing temporary files...
#cd $work_dir || exit 1
#rm -r pkg/
exit 0
#
# End
#edit: damned quotes, but now it supports spaces in the path!
edit2: minor bugfixes
Last edited by carlocci (2008-05-27 15:31:01)
Offline

shining wrote:You made a typo though, it is provides, not provide.
Thank you, the esses were a little bit confusing
As suggested by Allan, I integrated some data from makepkg.conf (packager and PKGDEST), I might include the emptydirs flag and strip flag as soon as I figure out bash arrays. Even if the original idea was to create the exact same original package (I forgot about /etc
).
I added more checks and warnings.
I thought about using /tmp and mktemp for the temporary pkg directory name, but I tried to mimic the behaviour of makepkg: I removed the line deleting pkg/
I added a correct size calculator
I'm thinking about setting a variable for each field and then writing them to the PKGCONFIG.
Nice job, I will try to test it again this evening.
Just a reminder for me : if we replace the repacman in pacman repo by this much better alternative,
and if we also fix the following problem : http://bugs.archlinux.org/task/10459#comment28645
then this script will need to be updated as well. But not for now.
Anyway, this script looks good as it is imo.
pacman roulette : pacman -S $(pacman -Slq | LANG=C sort -R | head -n $((RANDOM % 10)))
Offline

Gave this a quick spin and it looks great. I will sit down and give this good look over in the next couple of days and then I would be very keen for this to replace repacman in the contrib section of pacman (and thus added to the pacman-contrib package).
Again, this is some really nice work!
Offline

I noticed a few other problems, but now I am stuck on a really weird issue.
First, the bug fixes :
* the hidden metainfo files are all uppercase : PKGINFO / INSTALL / CHANGELOG
* fix backup field by stripping the md5sum
now the addition I made :
* add REPLACES : this will be stored in local database with pacman 3.2
* add FORCE field : same as above
Now, this is the problematic one, as FORCE is the only empty field.
I first thought I needed all empty lines to handle this, so I changed the loop to a : cat foo | while read i
Anyway, I don' t think this is a bad change.
Now the crazy issue :
pkgname and pkgver are correctly set when desc is parsed, and are added to .PKGINFO
but at the end of the script, when the package is generated, they are always empty!
This issue has driven me crazy for one hour, so I give up now... Help! 
patch :
--- repacman.orig    2008-05-28 14:53:30.000000000 +0200
+++ repacman    2008-05-28 17:39:42.000000000 +0200
@@ -25,7 +25,6 @@
 #
 # Setting env variables
 #
-IFS=$'\n'
 eval $(awk '/DBPath|CacheDir/ {print $1$2$3}' /etc/pacman.conf)
 pac_db="${DBPath:-/var/lib/pacman/}/local"
 pac_cache="${CacheDir:-/var/cache/pacman/pkg/}"
@@ -110,10 +109,10 @@
 
 echo Adding install commands and changelogs, if any...
 if [ -f "$pkg_dir/install" ] ; then
-    cp "$pkg_dir/install" "$work_dir/pkg/.install"
+    cp "$pkg_dir/install" "$work_dir/pkg/.INSTALL"
 fi
 if  [ -f $pkg_dir/changelog ] ; then
-    cp "$pkg_dir/changelog" "$work_dir/pkg/.changelog"
+    cp "$pkg_dir/changelog" "$work_dir/pkg/.CHANGELOG"
 fi
 
 #
@@ -125,7 +124,16 @@
 echo "# $(LC_ALL=C date)"            >> .PKGINFO
 echo "#"                    >> .PKGINFO
 
-for i in $(cat "$pkg_dir"/{desc,files,depends}) ; do
+cat "$pkg_dir"/{desc,files,depends} |
+while read i; do
+    if [[ -z "$i" ]]; then
+        continue;
+    fi
+
+    if [[ "$i" == "%FORCE%" ]] ; then
+        echo "force = true"    >> .PKGINFO
+        continue
+    fi
 
     if [[ "$i" =~ %[A-Z]*% ]] ; then
         current=$i
@@ -131,9 +139,11 @@
         current=$i
         continue
     fi
+
         case "$current" in
 
-        %NAME%)                    #desc
+        # desc
+        %NAME%)
            echo "pkgname = $i"    >> .PKGINFO
            pkgname=$i
         ;;
@@ -165,12 +175,18 @@
         %GROUPS%)
            echo "group = $i"    >> .PKGINFO
         ;;
+        %REPLACES%)
+        echo "replaces = $i"    >> .PKGINFO
+        ;;
 
-        %BACKUP%)                #files
-           echo "backup = $i"   >> .PKGINFO
+        # files
+        %BACKUP%)
+        # strip the md5sum after the tab
+        echo "backup = ${i%%    *}"   >> .PKGINFO
         ;;
 
-                %DEPENDS%)                #depends
+        # depends
+        %DEPENDS%)
                    echo "depend = $i"   >> .PKGINFO
                 ;;
                 %OPTDEPENDS%)full script :
#!/bin/bash
#
#   bacman: recreate a package from a running system
#   This script rebuilds an already installed package using metadata
#   stored into the pacman database and system files
#
#   (c) 2008 - locci <carlocci_at_gmail_dot_com>
#   
#   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 <http://www.gnu.org/licenses/>.
#
_bacman_ver="0.1.½"
#
# Setting env variables
#
eval $(awk '/DBPath|CacheDir/ {print $1$2$3}' /etc/pacman.conf)
pac_db="${DBPath:-/var/lib/pacman/}/local"
pac_cache="${CacheDir:-/var/cache/pacman/pkg/}"
work_dir="$PWD"
pkg_name="$1"
pkg_dir="$(echo $pac_db/$pkg_name-[0-9]*)"
eval $(awk '/PKGDEST|CARCH|PACKAGER/ {print $1$2$3}' /etc/makepkg.conf)
pkg_dest="${PKGDEST:-$work_dir}"
pkg_arch=${CARCH:-'noarch'}
pkg_pkger=${PACKAGER:-'Unknown Packager'}
#
# Checks everything is in place
#
if [ $# -ne 1 ] ; then
    echo bacman $_bacman_ver
    echo "Usage: ./bacman <installed package name>"
    exit 1
fi
if [ ! -d "$pac_db" ] ; then
    echo There is no pacman database directory in $pac_db
    echo $pac_db is missing
    exit 1
fi
if [ ! -d "$pac_cache" ] ; then
    echo Warning, there is no pacman pkg cache directory
    echo $pac_cache is missing
    unset pac_cache
fi
if [ ! -d "$pkg_dir" ] ; then
    echo There is no package with this name, $pkg_name
    echo Maybe you are trying to pass the directory name, instead of the package name
    exit 1
fi
if [ -n "$pac_cache" ] && [ -f "$pac_cache"/"${pkg_dir##*/}"*.tar.gz ] ; then
    echo The package already exists in your cache
    read -n 1 -p 'Do you want to fetch it instead ? (y/N) '
    case $REPLY in
        y|Y)
        cp "$pac_cache"/"${pkg_dir##*/}"*.pkg.tar.gz "$pkg_dest"
        exit 0
        ;;
        *) echo ""
        ;;
    esac
fi
#
# Begin 
#
echo Packet: ${pkg_dir##*/}
mkdir "$work_dir"/pkg || exit 1
cd "$work_dir"/pkg || exit 1
#
# File copying
#
echo Copying package files...
for i in $(cat "$pkg_dir"/files) ; do
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case $current in
        %FILES%)
        if [ -d "/$i" ]; then
            mkdir "$i"
        elif [ -f "/$i" ]; then
            install -D "/$i" "$i"
        else
            echo "/$i" is missing: this might result in a broken package
        fi
        ;;
    esac
    pkg_size=$(du -sb | awk '{print $1}')
done
echo Adding install commands and changelogs, if any...
if [ -f "$pkg_dir/install" ] ; then
    cp "$pkg_dir/install" "$work_dir/pkg/.INSTALL"
fi
if  [ -f $pkg_dir/changelog ] ; then
    cp "$pkg_dir/changelog" "$work_dir/pkg/.CHANGELOG"
fi
#
# .PKGINFO stuff
#
echo 
echo Generating .PKGINFO metadata...
echo "# Generated by bacman $_bacman_ver"    > .PKGINFO
echo "# $(LC_ALL=C date)"            >> .PKGINFO
echo "#"                    >> .PKGINFO
cat "$pkg_dir"/{desc,files,depends} |
while read i; do
    if [[ -z "$i" ]]; then
        continue;
    fi
    if [[ "$i" == "%FORCE%" ]] ; then
        echo "force = true"    >> .PKGINFO
        continue
    fi
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case "$current" in
        # desc
        %NAME%)
        echo "pkgname = $i"    >> .PKGINFO
        pkgname=$i
        ;;
        %VERSION%)
        echo "pkgver = $i"    >> .PKGINFO
        pkgver=$i
        ;;
        %DESC%)
        echo "pkgdesc = $i"    >> .PKGINFO
        ;;
        %URL%)
        echo "url = $i"    >> .PKGINFO
        ;;
        %LICENSE%)
        echo "license = $i"    >> .PKGINFO
        ;;
        %ARCH%)
        echo "arch = $i"    >> .PKGINFO
        ;;
        %BUILDDATE%)
        echo "builddate = $(date -u "+%s")"    >> .PKGINFO
        ;;
        %PACKAGER%)
        echo "packager = $pkg_pkger"        >> .PKGINFO
        ;;
        %SIZE%)
        echo "size = $pkg_size"        >> .PKGINFO
        ;;
        %GROUPS%)
        echo "group = $i"    >> .PKGINFO
        ;;
        %REPLACES%)
        echo "replaces = $i"    >> .PKGINFO
        ;;
        # files
        %BACKUP%)
        # strip the md5sum after the tab
        echo "backup = ${i%%    *}"   >> .PKGINFO
        ;;
        # depends
        %DEPENDS%)
        echo "depend = $i"   >> .PKGINFO
        ;;
        %OPTDEPENDS%)
        echo "optdepend = $i" >> .PKGINFO
        ;;
        %CONFLICTS%)
        echo "conflict = $i" >> .PKGINFO
        ;;
        %PROVIDES%)
        echo "provides = $i"  >> .PKGINFO
        ;;
    esac
done
#
# 
#
echo 
echo Generating the package...
bsdtar -czf "$pkg_dest/$pkgname-$pkgver-$pkg_arch.tar.gz" $(ls -A) || echo Cannot write to $pkg_dest: maybe disk is full or you do not have write access 
#echo Removing temporary files...
#cd $work_dir || exit 1
#rm -r pkg/
exit 0
#
# End
#pacman roulette : pacman -S $(pacman -Slq | LANG=C sort -R | head -n $((RANDOM % 10)))
Offline
Now the crazy issue :
pkgname and pkgver are correctly set when desc is parsed, and are added to .PKGINFO
but at the end of the script, when the package is generated, they are always empty!This issue has driven me crazy for one hour, so I give up now... Help!
NICE JOB, YOU RUINED IT! 
Thank you for your effort.
I think the problem is in the pipe you use in the main cycle which calls another shell and the variables created in the loop exist only in the subshell.
Actually I was dissatisfied with the IFS too. I think we can safely remove the two variables as we can take $name-$ver from the directory name in the database: I just wanted to be sure to get the right pkg and ver since I didn't know much about pacman db.
edit: here's the patch
--- bacman    2008-05-28 20:23:48.000000000 +0200
+++ bacman.new    2008-05-28 20:30:32.000000000 +0200
@@ -35,6 +35,7 @@
 pkg_dest="${PKGDEST:-$work_dir}"
 pkg_arch=${CARCH:-'noarch'}
 pkg_pkger=${PACKAGER:-'Unknown Packager'}
+pkg_namver="${pkg_dir##*/}"
 
 #
 # Checks everything is in place
@@ -62,12 +63,12 @@
     exit 1
 fi
 
-if [ -n "$pac_cache" ] && [ -f "$pac_cache"/"${pkg_dir##*/}"*.tar.gz ] ; then
+if [ -n "$pac_cache" ] && [ -f "$pac_cache"/"$pkg_namver"*.tar.gz ] ; then
     echo The package already exists in your cache
     read -n 1 -p 'Do you want to fetch it instead ? (y/N) '
     case $REPLY in
         y|Y)
-        cp "$pac_cache"/"${pkg_dir##*/}"*.pkg.tar.gz "$pkg_dest"
+        cp "$pac_cache"/"${pkg_namver##*/}"*.pkg.tar.gz "$pkg_dest"
         exit 0
         ;;
         *) echo ""
@@ -145,11 +146,9 @@
         # desc
         %NAME%)
         echo "pkgname = $i"    >> .PKGINFO
-        pkgname=$i
         ;;
         %VERSION%)
         echo "pkgver = $i"    >> .PKGINFO
-        pkgver=$i
         ;;
         %DESC%)
         echo "pkgdesc = $i"    >> .PKGINFO
@@ -207,7 +206,7 @@
 #
 echo 
 echo Generating the package...
-bsdtar -czf "$pkg_dest/$pkgname-$pkgver-$pkg_arch.tar.gz" $(ls -A) || echo Cannot write to $pkg_dest: maybe disk is full or you do not have write access 
+bsdtar -czf "$pkg_dest/$pkg_namver-$pkg_arch.tar.gz" $(ls -A) || echo Cannot write to $pkg_dest: maybe disk is full or you do not have write access 
 
 #echo Removing temporary files...
 #cd $work_dir || exit 1I wondered if there was a particular reason you placed %FORCE% outside of the case, I was planning of moving it into the case.
Thank you again for adding the unusual options!
Last edited by carlocci (2008-05-28 18:43:22)
Offline

shining wrote:Now the crazy issue :
pkgname and pkgver are correctly set when desc is parsed, and are added to .PKGINFO
but at the end of the script, when the package is generated, they are always empty!This issue has driven me crazy for one hour, so I give up now... Help!
NICE JOB, YOU RUINED IT!
Thank you for your effort.I think the problem is in the pipe you use in the main cycle which calls another shell and the variables created in the loop exist only in the subshell.
That is weird, I was totally not aware of that, but it would explain everything.
Actually I was dissatisfied with the IFS too. I think we can safely remove the two variables as we can take $name-$ver from the directory name in the database: I just wanted to be sure to get the right pkg and ver since I didn't know much about pacman db.
edit: here's the patch
Great, thanks! that should do the job.
I wondered if there was a particular reason you placed %FORCE% outside of the case, I was planning of moving it into the case.
Thank you again for adding the unusual options!
Hmm, I thought I needed to handle the empty fields separately, but looking at the final code, I always start by skipping empty lines so it seems like it does not have to be handled separately. Good point.
pacman roulette : pacman -S $(pacman -Slq | LANG=C sort -R | head -n $((RANDOM % 10)))
Offline

Ok it looks perfectly functional now. I am just sending the whole file again so that it is easier for others to pick up last version.
Now the goal is to make it appear there :
http://projects.archlinux.org/?p=pacman … ;f=contrib
so that we can remove the broken re-pacman script. At least this was my only motivation for fixing bacman, I was never really interested by the feature provided 
Anyway I will let carlocci and Allan work together on that now 
#!/bin/bash
#
#   bacman: recreate a package from a running system
#   This script rebuilds an already installed package using metadata
#   stored into the pacman database and system files
#
#   (c) 2008 - locci <carlocci_at_gmail_dot_com>
#   
#   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 <http://www.gnu.org/licenses/>.
#
_bacman_ver="0.1.1"
#
# Setting env variables
#
eval $(awk '/DBPath|CacheDir/ {print $1$2$3}' /etc/pacman.conf)
pac_db="${DBPath:-/var/lib/pacman/}/local"
pac_cache="${CacheDir:-/var/cache/pacman/pkg/}"
work_dir="$PWD"
pkg_name="$1"
pkg_dir="$(echo $pac_db/$pkg_name-[0-9]*)"
eval $(awk '/PKGDEST|CARCH|PACKAGER/ {print $1$2$3}' /etc/makepkg.conf)
pkg_dest="${PKGDEST:-$work_dir}"
pkg_arch=${CARCH:-'noarch'}
pkg_pkger=${PACKAGER:-'Unknown Packager'}
pkg_namver="${pkg_dir##*/}"
#
# Checks everything is in place
#
if [ $# -ne 1 ] ; then
    echo bacman $_bacman_ver
    echo "Usage: ./bacman <installed package name>"
    exit 1
fi
if [ ! -d "$pac_db" ] ; then
    echo There is no pacman database directory in $pac_db
    echo $pac_db is missing
    exit 1
fi
if [ ! -d "$pac_cache" ] ; then
    echo Warning, there is no pacman pkg cache directory
    echo $pac_cache is missing
    unset pac_cache
fi
if [ ! -d "$pkg_dir" ] ; then
    echo There is no package with this name, $pkg_name
    echo Maybe you are trying to pass the directory name, instead of the package name
    exit 1
fi
if [ -n "$pac_cache" ] && [ -f "$pac_cache"/"$pkg_namver"*.tar.gz ] ; then
    echo The package already exists in your cache
    read -n 1 -p 'Do you want to fetch it instead ? (y/N) '
    case $REPLY in
        y|Y)
        cp "$pac_cache"/"${pkg_namver##*/}"*.pkg.tar.gz "$pkg_dest"
        exit 0
        ;;
        *) echo ""
        ;;
    esac
fi
#
# Begin 
#
echo Package: ${pkg_dir##*/}
mkdir "$work_dir"/pkg || exit 1
cd "$work_dir"/pkg || exit 1
#
# File copying
#
echo Copying package files...
for i in $(cat "$pkg_dir"/files) ; do
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case $current in
        %FILES%)
        if [ -d "/$i" ]; then
            mkdir "$i"
        elif [ -f "/$i" ]; then
            install -D "/$i" "$i"
        else
            echo "/$i" is missing: this might result in a broken package
        fi
        ;;
    esac
    pkg_size=$(du -sb | awk '{print $1}')
done
echo Adding install commands and changelogs, if any...
if [ -f "$pkg_dir/install" ] ; then
    cp "$pkg_dir/install" "$work_dir/pkg/.INSTALL"
fi
if  [ -f $pkg_dir/changelog ] ; then
    cp "$pkg_dir/changelog" "$work_dir/pkg/.CHANGELOG"
fi
#
# .PKGINFO stuff
#
echo 
echo Generating .PKGINFO metadata...
echo "# Generated by bacman $_bacman_ver"    > .PKGINFO
echo "# $(LC_ALL=C date)"            >> .PKGINFO
echo "#"                    >> .PKGINFO
cat "$pkg_dir"/{desc,files,depends} |
while read i; do
    if [[ -z "$i" ]]; then
        continue;
    fi
    if [[ "$i" == "%FORCE%" ]] ; then
        echo "force = true"    >> .PKGINFO
        continue
    fi
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case "$current" in
        # desc
        %NAME%)
        echo "pkgname = $i"    >> .PKGINFO
        ;;
        %VERSION%)
        echo "pkgver = $i"    >> .PKGINFO
        ;;
        %DESC%)
        echo "pkgdesc = $i"    >> .PKGINFO
        ;;
        %URL%)
        echo "url = $i"    >> .PKGINFO
        ;;
        %LICENSE%)
        echo "license = $i"    >> .PKGINFO
        ;;
        %ARCH%)
        echo "arch = $i"    >> .PKGINFO
        ;;
        %BUILDDATE%)
        echo "builddate = $(date -u "+%s")"    >> .PKGINFO
        ;;
        %PACKAGER%)
        echo "packager = $pkg_pkger"        >> .PKGINFO
        ;;
        %SIZE%)
        echo "size = $pkg_size"        >> .PKGINFO
        ;;
        %GROUPS%)
        echo "group = $i"    >> .PKGINFO
        ;;
        %REPLACES%)
        echo "replaces = $i"    >> .PKGINFO
        ;;
        # files
        %BACKUP%)
        # strip the md5sum after the tab
        echo "backup = ${i%%    *}"   >> .PKGINFO
        ;;
        # depends
        %DEPENDS%)
        echo "depend = $i"   >> .PKGINFO
        ;;
        %OPTDEPENDS%)
        echo "optdepend = $i" >> .PKGINFO
        ;;
        %CONFLICTS%)
        echo "conflict = $i" >> .PKGINFO
        ;;
        %PROVIDES%)
        echo "provides = $i"  >> .PKGINFO
        ;;
    esac
done
#
# Generate the package 
#
echo 
echo Generating the package...
bsdtar -czf "$pkg_dest/$pkg_namver-$pkg_arch.tar.gz" $(ls -A) || echo Cannot write to $pkg_dest: maybe disk is full or you do not have write access 
exit 0
# vim: set ts=2 sw=2 noet:pacman roulette : pacman -S $(pacman -Slq | LANG=C sort -R | head -n $((RANDOM % 10)))
Offline

Anyway I will let carlocci and Allan work together on that now
So I'm going to have to do something! Here I thought I could get away with just saying I was going to do stuff...
Anyway, I see nothing more to add to the core functionality. Just a couple of tidy ups I think are necessary before it can make it into the official pacman contrib directory. I will post my changes in a few hours.
Offline

shining wrote:Anyway I will let carlocci and Allan work together on that now
So I'm going to have to do something! Here I thought I could get away with just saying I was going to do stuff...
Ahah, nice try indeed 
Anyway, I see nothing more to add to the core functionality. Just a couple of tidy ups I think are necessary before it can make it into the official pacman contrib directory. I will post my changes in a few hours.
Thanks, that is perfect.
pacman roulette : pacman -S $(pacman -Slq | LANG=C sort -R | head -n $((RANDOM % 10)))
Offline

Ok, here is some changes I would like to make...
1)Catch some commonly used flags at the top of the script. Also, change usage of "bacman" and the version variable throughout. I.e.,
readonly progname="bacman"
readonly progver="0.1.1"
if [ "$1" = "--help" -o "$1" = "-h" ] ; then
    echo "Usage: $progname <installed package name>"
    echo "Example: $progname kernel26"
    exit 0
fi
if [ "$1" = "--version" -o "$1" = "-v" ]; then
    echo "$progname version $version"
    echo "Copyright (C) 2008 locci"
    exit 0
fiThis will make the script more in line with the others in the pacman contrib directory
2) You do not need to remove whitespace when reading makepkg.conf. It is read by bash so reading the variables should be fine without this. It screws up my PACKAGER entry otherwise.
3) We should not do arch detection from makepkg.conf. It should come form the %ARCH% entry in the local database.
4) We can tidy up the error messages so they are a bit clearer/cleaner.
5) I am not so sure about using the $PWD/pkg directory. If one already exists there will be trouble. Given it is left in the directory after usage, that is likely to happen (e.g. bacman kernel26, bacman ipw3945). I think it should create a temporary directory for creating the package and remove it at the end.
6) Fix up the error message during the actual package generation including exiting with a error condition.
I will post a version with the changes made just as soon as Family Guy finishes on tv...
Offline

2) You do not need to remove whitespace when reading makepkg.conf. It is read by bash so reading the variables should be fine without this. It screws up my PACKAGER entry otherwise.
How are whitespace removed?
5) I am not so sure about using the $PWD/pkg directory. If one already exists there will be trouble. Given it is left in the directory after usage, that is likely to happen (e.g. bacman kernel26, bacman ipw3945). I think it should create a temporary directory for creating the package and remove it at the end.
Oops, have a look at the older versions, there was a block commented out for removing pkg/
All the other points look right.
pacman roulette : pacman -S $(pacman -Slq | LANG=C sort -R | head -n $((RANDOM % 10)))
Offline

Allan wrote:2) You do not need to remove whitespace when reading makepkg.conf. It is read by bash so reading the variables should be fine without this. It screws up my PACKAGER entry otherwise.
How are whitespace removed?
Currently is it like:
eval $(awk '/PKGDEST|CARCH|PACKAGER/ {print $1$2$3}' /etc/makepkg.conf)This makes my PACKAGER get extracted like: PACKAGER="AllanMcRae<mcrae_allan@hotmail.com>". Getting rid of the the "{print $1$2$3}" fixes this
Allan wrote:5) I am not so sure about using the $PWD/pkg directory. If one already exists there will be trouble. Given it is left in the directory after usage, that is likely to happen (e.g. bacman kernel26, bacman ipw3945). I think it should create a temporary directory for creating the package and remove it at the end.
Oops, have a look at the older versions, there was a block commented out for removing pkg/
From you comment, I'm not sure whether you are for or against that change... I think the script at least needs to create a unique working directory to avoid problems. Also, there is very little loss in removing pkg/ because you can just extract your newly created package.
Offline

This makes my PACKAGER get extracted like: PACKAGER="AllanMcRae<mcrae_allan@hotmail.com>". Getting rid of the the "{print $1$2$3}" fixes this
Ah indeed.
From you comment, I'm not sure whether you are for or against that change... I think the script at least needs to create a unique working directory to avoid problems. Also, there is very little loss in removing pkg/ because you can just extract your newly created package.
That is because I don't really have an opinion.
I used the pkg dir during debugging but I could indeed have used the package instead, so no problem.
About the location, I was not sure either how to handle this.
I thought about using /tmp and mktemp for the temporary pkg directory name, but I tried to mimic the behaviour of makepkg: I removed the line deleting pkg/
So after thinking a bit about this, I am not sure we need to follow makepkg behavior here. makepkg needs a package per directory, with a pkgbuild inside, so it makes sense to put the pkg/ and src/ dir in there.
But bacman can be run anywhere, so it is probably a good idea to use /tmp and mktemp and remove the temp dir afterward.
pacman roulette : pacman -S $(pacman -Slq | LANG=C sort -R | head -n $((RANDOM % 10)))
Offline

OK, here is the updated version.
#!/bin/bash
#
#   bacman: recreate a package from a running system
#   This script rebuilds an already installed package using metadata
#   stored into the pacman database and system files
#
#   (c) 2008 - locci <carlocci_at_gmail_dot_com>
#   
#   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 <http://www.gnu.org/licenses/>.
#
readonly progname="bacman"
readonly progver="0.1.2"
if [ "$1" = "--help" -o "$1" = "-h" ] ; then
    echo "Usage:   $progname <installed package name>"
    echo "Example: $progname kernel26"
    exit 0
fi
if [ "$1" = "--version" -o "$1" = "-v" ]; then
    echo "$progname version $version"
    echo "Copyright (C) 2008 locci"
    exit 0
fi
#
# Setting environmental variables
#
eval $(awk '/DBPath|CacheDir/ {print $1$2$3}' /etc/pacman.conf)
pac_db="${DBPath:-/var/lib/pacman/}/local"
pac_cache="${CacheDir:-/var/cache/pacman/pkg/}"
pkg_name="$1"
pkg_dir="$(echo $pac_db/$pkg_name-[0-9]*)"
eval $(awk '/PKGDEST|PACKAGER/' /etc/makepkg.conf)
pkg_dest="${PKGDEST:-$PWD}"
pkg_pkger=${PACKAGER:-'Unknown Packager'}
pkg_arch="unknown"
pkg_namver="${pkg_dir##*/}"
#
# Checks everything is in place
#
if [ $# -ne 1 ] ; then
    echo "Usage:   $progname <installed package name>"
    echo "Example: $progname kernel26"
    exit 1
fi
if [ ! -d "$pac_db" ] ; then
    echo Error: pacman database directory ${pac_db} not found
    exit 1
fi
if [ ! -d "$pac_cache" ] ; then
    echo Warning: pacman pkg cache directory ${pac_cache} not found
    unset pac_cache
fi
if [ ! -d "$pkg_dir" ] ; then
    echo Error: package ${pkg_name} not found in pacman database
    exit 1
fi
if [ -n "$pac_cache" ] && [ -f "$pac_cache"/"$pkg_namver"*.tar.gz ] ; then
    echo The package ${pkg_name} exists in your pacman cache
    read -n 1 -p 'Do you want to fetch it instead? (y/N) '
    case $REPLY in
        y|Y)
        cp "$pac_cache"/"${pkg_namver##*/}"*.pkg.tar.gz "$pkg_dest"
        exit 0
        ;;
        *) echo ""
        ;;
    esac
fi
#
# Begin 
#
echo Package: ${pkg_dir##*/}
work_dir=$(mktemp -d -p /tmp)
cd $work_dir || exit 1
#
# File copying
#
echo Copying package files...
for i in $(cat "$pkg_dir"/files) ; do
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case $current in
        %FILES%)
        if [ -d "/$i" ]; then
            mkdir "$i"
        elif [ -f "/$i" ]; then
            install -D "/$i" "$i"
        else
            echo "/$i" is missing: this might result in a broken package
        fi
        ;;
    esac
    pkg_size=$(du -sb | awk '{print $1}')
done
echo Adding install commands and changelogs, if any...
if [ -f "$pkg_dir/install" ] ; then
    cp "$pkg_dir/install" "$work_dir/.INSTALL"
fi
if  [ -f $pkg_dir/changelog ] ; then
    cp "$pkg_dir/changelog" "$work_dir/.CHANGELOG"
fi
#
# .PKGINFO stuff
#
echo 
echo Generating .PKGINFO metadata...
echo "# Generated by $progname $progver"    > .PKGINFO
echo "# $(LC_ALL=C date)"            >> .PKGINFO
echo "#"                    >> .PKGINFO
cat "$pkg_dir"/{desc,files,depends} |
while read i; do
    if [[ -z "$i" ]]; then
        continue;
    fi
    if [[ "$i" == "%FORCE%" ]] ; then
        echo "force = true"    >> .PKGINFO
        continue
    fi
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case "$current" in
        # desc
        %NAME%)
        echo "pkgname = $i"    >> .PKGINFO
        ;;
        %VERSION%)
        echo "pkgver = $i"    >> .PKGINFO
        ;;
        %DESC%)
        echo "pkgdesc = $i"    >> .PKGINFO
        ;;
        %URL%)
        echo "url = $i"    >> .PKGINFO
        ;;
        %LICENSE%)
        echo "license = $i"    >> .PKGINFO
        ;;
        %ARCH%)
        echo "arch = $i"    >> .PKGINFO
        pkg_arch=$i
        ;;
        %BUILDDATE%)
        echo "builddate = $(date -u "+%s")"    >> .PKGINFO
        ;;
        %PACKAGER%)
        echo "packager = $pkg_pkger"        >> .PKGINFO
        ;;
        %SIZE%)
        echo "size = $pkg_size"        >> .PKGINFO
        ;;
        %GROUPS%)
        echo "group = $i"    >> .PKGINFO
        ;;
        %REPLACES%)
        echo "replaces = $i"    >> .PKGINFO
        ;;
        # files
        %BACKUP%)
        # strip the md5sum after the tab
        echo "backup = ${i%%    *}"   >> .PKGINFO
        ;;
        # depends
        %DEPENDS%)
        echo "depend = $i"   >> .PKGINFO
        ;;
        %OPTDEPENDS%)
        echo "optdepend = $i" >> .PKGINFO
        ;;
        %CONFLICTS%)
        echo "conflict = $i" >> .PKGINFO
        ;;
        %PROVIDES%)
        echo "provides = $i"  >> .PKGINFO
        ;;
    esac
done
#
# Generate the package 
#
echo 
echo Generating the package...
ret=0
bsdtar -czf "$pkg_dest/$pkg_namver-$pkg_arch.tar.gz" $(ls -A) || ret=$?
if [ $ret -ne 0 ]; then
    echo Error: Unable to write package to $pkg_dest
    echo Maybe the disk is full or you do not have write access
    exit 1
fi
#rm -rf $work_dir
exit 0
# vim: set ts=2 sw=2 noet:There are still problems.....
It seem the reading of info from makepkg.conf does not work. In the .PKGINFO file I always get "Unknown Packager". I haven't actually checked any of the other fields that are read in from files yet as I have these set as default values.
There are problems running this as a user when packages do not have read permissions for a user. E.g. sudo.
Also, the setting of the pkg_arch within the case statement does not work.
Edit: Reading in the details from the files works when done one field at a time.
Edit2: I think the pkg_arch problem is reminiscent of a problem above....
Last edited by Allan (2008-05-29 14:23:46)
Offline

There are still problems.....
It seem the reading of info from makepkg.conf does not work. In the .PKGINFO file I always get "Unknown Packager". I haven't actually checked any of the other fields that are read in from files yet as I have these set as default values.
Edit: Reading in the details from the files works when done one field at a time.
I just figured it out : when you have some commented out fields, it will hide the others.
Either you take them one by one, or you don't grep the commented one (starting with #), or my favorite:
why don' t we simply source the whole makepkg.conf ?
There are problems running this as a user when packages do not have read permissions for a user. E.g. sudo.
I don' t see what we can do about this. install errors out with permission denied, which is explicit enough.
The user can manually run it again as root.
Also, the setting of the pkg_arch within the case statement does not work.
Same problem as with pkgname and pkgver, see above posts from me and carlocci.
That issue is problematic 
pacman roulette : pacman -S $(pacman -Slq | LANG=C sort -R | head -n $((RANDOM % 10)))
Offline

or my favorite: why don' t we simply source the whole makepkg.conf ?
We could do.  I have implemented the read one in at a time strategy below.  It is getting late at night here so if someone wants to look into this...  
Anyway, I don't see any further changes that need made.
Edit: some of that was stupid...
#!/bin/bash
#
#   bacman: recreate a package from a running system
#   This script rebuilds an already installed package using metadata
#   stored into the pacman database and system files
#
#   (c) 2008 - locci <carlocci_at_gmail_dot_com>
#   
#   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 <http://www.gnu.org/licenses/>.
#
readonly progname="bacman"
readonly progver="0.1.2"
if [ "$1" = "--help" -o "$1" = "-h" ] ; then
    echo "Usage:   $progname <installed package name>"
    echo "Example: $progname kernel26"
    exit 0
fi
if [ "$1" = "--version" -o "$1" = "-v" ]; then
    echo "$progname version $version"
    echo "Copyright (C) 2008 locci"
    exit 0
fi
#
# Setting environmental variables
#
eval $(awk '/DBPath/ {print $1$2$3}' /etc/pacman.conf)
pac_db="${DBPath:-/var/lib/pacman/}/local"
eval $(awk '/CacheDir/ {print $1$2$3}' /etc/pacman.conf)
pac_cache="${CacheDir:-/var/cache/pacman/pkg/}"
pkg_name="$1"
pkg_dir="$(echo $pac_db/$pkg_name-[0-9]*)"
eval $(awk '/CARCH/' /etc/makepkg.conf)
pkg_arch=${CARCH:-'unknown'}
eval $(awk '/PKGDEST/' /etc/makepkg.conf)
pkg_dest="${PKGDEST:-$PWD}"
eval $(awk '/PACKAGER/' /etc/makepkg.conf)
pkg_pkger=${PACKAGER:-'Unknown Packager'}
pkg_namver="${pkg_dir##*/}"
#
# Checks everything is in place
#
if [ $# -ne 1 ] ; then
    echo "Usage:   $progname <installed package name>"
    echo "Example: $progname kernel26"
    exit 1
fi
if [ ! -d "$pac_db" ] ; then
    echo Error: pacman database directory ${pac_db} not found
    exit 1
fi
if [ ! -d "$pac_cache" ] ; then
    echo Warning: pacman pkg cache directory ${pac_cache} not found
    unset pac_cache
fi
if [ ! -d "$pkg_dir" ] ; then
    echo Error: package ${pkg_name} not found in pacman database
    exit 1
fi
if [ -n "$pac_cache" ] && [ -f "$pac_cache"/"$pkg_namver"*.tar.gz ] ; then
    echo The package ${pkg_name} exists in your pacman cache
    read -n 1 -p 'Do you want to fetch it instead? (y/N) '
    case $REPLY in
        y|Y)
        cp "$pac_cache"/"${pkg_namver##*/}"*.pkg.tar.gz "$pkg_dest"
        exit 0
        ;;
        *) echo ""
        ;;
    esac
fi
#
# Begin 
#
echo Package: ${pkg_dir##*/}
work_dir=$(mktemp -d -p /tmp)
cd $work_dir || exit 1
#
# File copying
#
echo Copying package files...
for i in $(cat "$pkg_dir"/files) ; do
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case $current in
        %FILES%)
        if [ -d "/$i" ]; then
            mkdir "$i"
        elif [ -f "/$i" ]; then
            install -D "/$i" "$i"
        else
            echo "/$i" is missing: this might result in a broken package
        fi
        ;;
    esac
    pkg_size=$(du -sb | awk '{print $1}')
done
echo Adding install commands and changelogs, if any...
if [ -f "$pkg_dir/install" ] ; then
    cp "$pkg_dir/install" "$work_dir/.INSTALL"
fi
if  [ -f $pkg_dir/changelog ] ; then
    cp "$pkg_dir/changelog" "$work_dir/.CHANGELOG"
fi
#
# .PKGINFO stuff
#
echo 
echo Generating .PKGINFO metadata...
echo "# Generated by $progname $progver"    > .PKGINFO
echo "# $(LC_ALL=C date)"            >> .PKGINFO
echo "#"                    >> .PKGINFO
cat "$pkg_dir"/{desc,files,depends} |
while read i; do
    if [[ -z "$i" ]]; then
        continue;
    fi
    if [[ "$i" == "%FORCE%" ]] ; then
        echo "force = true"    >> .PKGINFO
        continue
    fi
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case "$current" in
        # desc
        %NAME%)
        echo "pkgname = $i"    >> .PKGINFO
        ;;
        %VERSION%)
        echo "pkgver = $i"    >> .PKGINFO
        ;;
        %DESC%)
        echo "pkgdesc = $i"    >> .PKGINFO
        ;;
        %URL%)
        echo "url = $i"    >> .PKGINFO
        ;;
        %LICENSE%)
        echo "license = $i"    >> .PKGINFO
        ;;
        %ARCH%)
        echo "arch = $i"    >> .PKGINFO
        ;;
        %BUILDDATE%)
        echo "builddate = $(date -u "+%s")"    >> .PKGINFO
        ;;
        %PACKAGER%)
        echo "packager = $pkg_pkger"        >> .PKGINFO
        ;;
        %SIZE%)
        echo "size = $pkg_size"        >> .PKGINFO
        ;;
        %GROUPS%)
        echo "group = $i"    >> .PKGINFO
        ;;
        %REPLACES%)
        echo "replaces = $i"    >> .PKGINFO
        ;;
        # files
        %BACKUP%)
        # strip the md5sum after the tab
        echo "backup = ${i%%    *}"   >> .PKGINFO
        ;;
        # depends
        %DEPENDS%)
        echo "depend = $i"   >> .PKGINFO
        ;;
        %OPTDEPENDS%)
        echo "optdepend = $i" >> .PKGINFO
        ;;
        %CONFLICTS%)
        echo "conflict = $i" >> .PKGINFO
        ;;
        %PROVIDES%)
        echo "provides = $i"  >> .PKGINFO
        ;;
    esac
done
#
# Generate the package 
#
echo 
echo Generating the package...
ret=0
bsdtar -czf "$pkg_dest/$pkg_namver-$pkg_arch.tar.gz" $(ls -A) || ret=$?
if [ $ret -ne 0 ]; then
    echo Error: Unable to write package to $pkg_dest
    echo Maybe the disk is full or you do not have write access
    exit 1
fi
#rm -rf $work_dir
exit 0
# vim: set ts=2 sw=2 noet:Last edited by Allan (2008-05-29 14:45:09)
Offline

shining wrote:or my favorite: why don' t we simply source the whole makepkg.conf ?
We could do. I have implemented the read one in at a time strategy below. It is getting late at night here so if someone wants to look into this...
Anyway, I don't see any further changes that need made.
Forget about sourcing, it is fine that way.
So the script is ready now, great 
pacman roulette : pacman -S $(pacman -Slq | LANG=C sort -R | head -n $((RANDOM % 10)))
Offline

I will make the patch which add this into the contrib directory and the description to the README file in the morning. I guess we remove repacman at the same time.
@carlocci: This is unless you wants to submit it yourself. Either way, you bask in the glory that is contributing to the pacman code base!
Offline
I addressed some bugs:
for example the file processing still had for i in $pac_db/blabla/files which doesn't work if the path to the files has spaces inside (without setting IFS=\n)
I added a usage function in order to remove a redundancy, I fixed some variables names, messed a bit with the main loop.
There are still some issues, for example pacman's database path and PKGDEST path can't have spaces inside.
I'm learning sed to fix this
#!/bin/bash
#
#   bacman: recreate a package from a running system
#   This script rebuilds an already installed package using metadata
#   stored into the pacman database and system files
#
#   (c) 2008 - locci <carlocci_at_gmail_dot_com>
#   
#   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 <http://www.gnu.org/licenses/>.
#
readonly progname="bacman"
readonly progver="0.1.2"
#
# User Friendliness
#
function usage(){
    echo "This program recreates a package using pacman's db and system files"
    echo "Usage:   $progname <installed package name>"
    echo "Example: $progname kernel26"
}
if [ $# -ne 1 ] ; then
    usage
    exit 1
fi
if [ "$1" = "--help" -o "$1" = "-h" ] ; then
    usage
    exit 0
fi
if [ "$1" = "--version" -o "$1" = "-v" ]; then
    echo "$progname version $version"
    echo "Copyright (C) 2008 locci"
    exit 0
fi
#
# Setting environmental variables
#
eval $(sed -nre 's:[[:space:]]*(DBPath|CacheDir)[[:space:]]*=[[:space:]]*([[:print:]]*):\1="\2":p' /etc/pacman.conf)
pac_db="${DBPath:-/var/lib/pacman/}/local"
pac_cache="${CacheDir:-/var/cache/pacman/pkg/}"
pkg_name="$1"
pkg_dir="$(echo $pac_db/$pkg_name-[0-9]*)"
eval $(sed -nre 's:[[:space:]]*(CARCH|PKGDEST|PACKAGER)[[:space:]]*=[[:space:]]*([[:print:]]*):\1=\2:p' /etc/makepkg.conf)
pkg_arch=${CARCH:-'unknown'}
pkg_dest="${PKGDEST:-$PWD}"
pkg_pkger=${PACKAGER:-'Unknown Packager'}
pkg_namver="${pkg_dir##*/}"
#
# Checks everything is in place
#
if [ ! -d "$pac_db" ] ; then
    echo Error: pacman database directory ${pac_db} not found
    exit 1
fi
if [ ! -d "$pac_cache" ] ; then
    echo Warning: pacman pkg cache directory ${pac_cache} not found
    unset pac_cache
fi
if [ ! -d "$pkg_dir" ] ; then
    echo Error: package ${pkg_name} not found in pacman database
    exit 1
fi
if [ -n "$pac_cache" ] && [ -f "$pac_cache"/"$pkg_namver"*.tar.gz ] ; then
    echo The package ${pkg_name} exists in your pacman cache
    read -n 1 -p 'Do you want to fetch it instead? (y/N) '
    case $REPLY in
        y|Y)
        cp "$pac_cache"/"$pkg_namver"*.pkg.tar.gz "$pkg_dest"
        exit 0
        ;;
        *) echo ""
        ;;
    esac
fi
#
# Begin 
#
echo Package: ${pkg_namver}
work_dir=$(mktemp -d -p /tmp)
cd $work_dir || exit 1
#
# File copying
#
echo Copying package files...
while read i; do
    if [ -z "$i" ] ; then
        continue
    fi
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case $current in
        %FILES%)
        if [ -d "/$i" ]; then
            mkdir "$i"
        elif [ -f "/$i" ]; then
            install -D "/$i" "$i"
        else
            echo "/$i" is missing: this might result in a broken package
        fi
        ;;
    esac
    pkg_size=$(du -sb | awk '{print $1}')
done
echo Adding install commands and changelogs, if any...
if [ -f "$pkg_dir/install" ] ; then
    cp "$pkg_dir/install" "$work_dir/.INSTALL"
fi
if  [ -f $pkg_dir/changelog ] ; then
    cp "$pkg_dir/changelog" "$work_dir/.CHANGELOG"
fi
#
# .PKGINFO stuff
#
echo 
echo Generating .PKGINFO metadata...
echo "# Generated by $progname $progver"    > .PKGINFO
echo "# $(LC_ALL=C date)"            >> .PKGINFO
echo "#"                    >> .PKGINFO
cat "$pkg_dir"/{desc,files,depends} |
while read i; do
    if [[ -z "$i" ]]; then
        continue;
    fi
    if [[ "$i" =~ %[A-Z]*% ]] ; then
        current=$i
        continue
    fi
    case "$current" in
        # desc
        %NAME%)
        echo "pkgname = $i"    >> .PKGINFO
        ;;
        %VERSION%)
        echo "pkgver = $i"    >> .PKGINFO
        ;;
        %DESC%)
        echo "pkgdesc = $i"    >> .PKGINFO
        ;;
        %URL%)
        echo "url = $i"    >> .PKGINFO
        ;;
        %LICENSE%)
        echo "license = $i"    >> .PKGINFO
        ;;
        %ARCH%)
        echo "arch = $i"    >> .PKGINFO
        ;;
        %BUILDDATE%)
        echo "builddate = $(date -u "+%s")"    >> .PKGINFO
        ;;
        %PACKAGER%)
        echo "packager = $pkg_pkger"        >> .PKGINFO
        ;;
        %SIZE%)
        echo "size = $pkg_size"        >> .PKGINFO
        ;;
        %GROUPS%)
        echo "group = $i"    >> .PKGINFO
        ;;
        %REPLACES%)
        echo "replaces = $i"    >> .PKGINFO
        ;;
        # files
        %BACKUP%)
        # strip the md5sum after the tab
        echo "backup = ${i%%    *}"   >> .PKGINFO
        ;;
        # depends
        %DEPENDS%)
        echo "depend = $i"   >> .PKGINFO
        ;;
        %OPTDEPENDS%)
        echo "optdepend = $i" >> .PKGINFO
        ;;
        %CONFLICTS%)
        echo "conflict = $i" >> .PKGINFO
        ;;
        %PROVIDES%)
        echo "provides = $i"  >> .PKGINFO
        ;;
                %FORCE%)
                echo "force = true" >> .PKGINFO
    esac
done
#
# Generate the package 
#
echo 
echo Generating the package...
ret=0
bsdtar -czf "$pkg_dest/$pkg_namver-$pkg_arch.tar.gz" $(ls -A) || ret=$?
if [ $ret -ne 0 ]; then
    echo Error: Unable to write package to $pkg_dest
    echo Maybe the disk is full or you do not have write access
    exit 1
fi
rm -rf $work_dir
exit 0
# vim: set ts=2 sw=2 noet:Allan, thank you: I finally understood what "# vim: set ts=2 sw=2 noet:" means
As for the arch detection from makepkg.conf Allan brought about, I thought there could be more than 1 arch declared in the desc file which could have been a problem.
Thanks for your effort.
@carlocci: This is unless you wants to submit it yourself. Either way, you bask in the glory that is contributing to the pacman code base!
That's awesome!
I'll submit the script in a couple of hours.
edit: sed learnt: REGEXP+sed = brain cancer
Last edited by carlocci (2008-05-29 17:48:28)
Offline