#!/bin/bash # Script to convert all files (tarballs in any format; just recognized # by 'tar') within an 'odir' to a unified '.tar.lz' format. # # The inputs are assumed to be formatted with 'NAME_VERSION', and only for # the names, we are currently assuming '.tar.*' (for the 'sed' # command). Please modify/generalize accordingly. # # It will unpack the source in a certain empty directory with the # 'tmpunpack' suffix, and rename the top directory to the requested format # of NAME-VERSION also. So irrespective of the name of the top original # tarball directory, the resulting tarball's top directory will have a name # formatting of NAME-VERSION. # # Discussion: https://savannah.nongnu.org/task/?15699 # # Copyright (C) 2022-2025 Mohammad Akhlaghi <mohammad@akhlaghi.org> # Copyright (C) 2022-2025 Pedram Ashofteh Ardakani <pedramardakani@pm.me> # Released under GNU GPLv3+ # Abort the script in case of an error. set -e # Default arguments odir= idir= quiet= basedir=$PWD scriptname=$0 # The --help output print_help() { cat <<EOF Usage: $scriptname [OPTIONS] Low-level script to create maneage-standard tarballs. -o, --output-dir Target directory to write the packed tarballs. Current: $odir -i, --input-dir Directory containing original tarballs. Current: $idir -q, --quiet Suppress logging information. Only print the final packed file and its sha512sum. Maneage URL: https://maneage.org Report bugs: https://savannah.nongnu.org/bugs/?group=reproduce EOF } # Functions to check option values and complain if necessary. on_off_option_error() { if [ x"$2" = x ]; then echo "$scriptname: '$1' doesn't take any values" else echo "$scriptname: '$1' (or '$2') doesn't take any values" fi exit 1 } check_v() { if [ x"$2" = x ]; then cat <<EOF $scriptname: option '$1' requires an argument. Try '$scriptname --help' for more information EOF exit 1; fi } option_given_and_valid() { dirname="$1" optionlong="$2" optionshort="$3" if [ x"$dirname" = x ]; then cat <<EOF $scriptname: no '--$optionlong' (or '-$optionshort') given: use this for identifying the directory containing the input tarballs EOF exit 1 else dirname=$(echo "$dirname" | sed 's|/$||'); # Remove possible trailing slash if [ ! -d "$dirname" ]; then cat <<EOF $scriptname: '$dirname' that is given to '--$optionlong' (or '-$optionshort') couldn't be opened EOF exit 1 else outdir=$(realpath $dirname) fi fi ogvout=$outdir } # Parse the arguments while [ $# -gt 0 ] do case $1 in # Input and Output directories -i|--input-dir) idir="$2"; check_v "$1" "$idir"; shift;shift;; -i=*|--input-dir=*) idir="${1#*=}"; check_v "$1" "$idir"; shift;; -i*) idir=$(echo "$1" | sed -e's/-i//'); check_v "$1" "$idir"; shift;; -o|--output-dir) odir="$2"; check_v "$1" "$odir"; shift;shift;; -o=*|--output-dir=*) odir="${1#*=}"; check_v "$1" "$odir"; shift;; -o*) odir=$(echo "$1" | sed -e's/-o//'); check_v "$1" "$odir"; shift;; # Operating mode options -?|--help) print_help; exit 0;; -'?'*|--help=*) on_off_option_error --help -?;; -q|--quiet) quiet=1; shift;; -q*|--quiet=*) on_off_option_error --quiet -q;; *) echo "$scriptname: unknown option '$1'"; exit 1;; esac done # Basic sanity checks # # Make sure the input and output directories are given. Also extract # the absolute path to input and output directories and remove any # possible trailing '/'. Working with a relative path is a great # source of confusion and unwanted side-effects like moving/removing # files by accident. option_given_and_valid "$idir" "input-dir" "i" && idir=$ogvout option_given_and_valid "$odir" "output-dir" "o" && odir=$ogvout # Unpack and pack all files in the '$idir' # ---------------------------------------- allfiles=$(ls $idir | sort) # Let user know number of tarballs if its not in quiet mode if [ -z $quiet ]; then nfiles=$(ls $idir | wc -l) echo "Found $nfiles file(s) in '$idir/'" fi # Process all files for f in $allfiles; do # Extract the name and version (while replacing any possible '_' with # '-' because some software separate name and version with '_'). name=$(echo $(basename $f) \ | sed -e 's/.tar.*//' -e's/_/-/') # Lzip will not be available to unpack Lzip itself, so just use Tar. if [[ $name =~ ^lzip ]]; then outname=$name.tar else outname=$name.tar.lz fi # Skip previously packed files if [ -f $odir/$outname ]; then # Print the info message if not in quiet mode if [ -z $quiet ]; then echo "$scriptname: $odir/$outname: already present in output directory" fi # skip this file continue else # Print the info message if not in quiet mode if [ -z $quiet ]; then echo "$scriptname: processing '$idir/$f'" fi fi # Create a temporary directory name tmpdir=$odir/$name-tmpunpack # If the temporary directory exists, mkdir will throw an error. The # developer needs to intervene manually to fix the issue. mkdir $tmpdir # Move into the temporary directory # --------------------------------- # # The default output directory for all the following commands: $tmpdir cd $tmpdir # Unpack tar -xf $idir/$f # Make sure the unpacked tarball is contained within a directory with # the clean program name if [ ! -d "$name" ]; then mv * $name/ fi # Put the current date on all the files because some packagers will not # add dates to their release tarballs, resulting in dates of the # Unix-time zero'th second (1970-01-01 at 00:00:00)! # -print0 is needed for those tarballs that has paths with spaces. For # the same reason it's needed also `xargs -0`. (`xargs` is needed also # for large tarballs such as gcc's) find "$name"/ -type f -print0 | xargs -0 touch # Pack with recommended options tar -c -Hustar --owner=root --group=root \ -f $name.tar $name/ # Lzip will not be available when unpacking Lzip, so we just use Tar. if [[ ! $name =~ ^lzip ]]; then lzip -9 $name.tar fi # Move the compressed file from the temporary directory to the target # output directory mv $outname $odir/ # Print the sha512sum along with the filename for a quick reference echo $(sha512sum $odir/$outname) # Clean up the temporary directory rm -rf $tmpdir done