#!/bin/bash

#################################################
## aptosmart
## (c) 2005, TeXpert for www.linux-club.de
##     idea: oc2pus
##     License: use this software on your own
##              risk, it works for me but there
##              are no guaranties about stability
##              or fitness of this software.
## ----------------------------------------------
##
## aptosmart: convert sources.list from apt to
##           smartpm channel files
##
##
## Version: 0.5
##
## Synopsis:
##       aptosmart [OPTIONS] DESTDIR
##
## Description:
##   read the sources.list and convert it to
##   channel-files for the smartpm. All
##   files will be saved in DESTDIR.
##
##   aptochan will read /etc/apt/sources.list
##   until an other source is specified. No
##   existing channels will be overwritten
##   until specified.
##
## Supported:
##      rpm and deb apt-repositories
##      over ftp://, http:// and local over file:/
##
## Options:
##   -s FILE   read FILE as sources.list instead of
##      /etc/apt/sources.list
##
##   -v   be verbose ;)
##
##    -f   overwrite existing channel files
##      
## ----------------------------------------------
## Changelog:
##      0.5 - bug-fix: corrected the apt-deb channel
##                     format (hell, why are they
##                     different from apt-rpm?)
##                     and changed the channel-names...
##            bug-fix: used numbers for multiple used
##                     aliases
##      0.4 - added filename-counter
##      0.3 - parser-bug-fix (generate generic-filenames
##                            for locale repositories)
##      0.2 - parser-addon (detect more URIs and duplicates)
##            parser-bug-fix (wrong typematch rpm-src)
##   0.1 - new software
#################################################



## ----------------------------------------------
VFLAG=off
FFLAG=off
SOURCE="/etc/apt/sources.list"
FORMAT= 
URL=   
PROTOCOL=   
DISTRI=
DEST=
declare -a HAVESEEN
declare -a USEDALIAS
declare -a USEDFILES

## ----------------------------------------------
SUPPORTEDPROTOCOLS="ftp http file" ## todo rsync
SUPPORTEDFORMATS="rpm deb"

## ----------------------------------------------
## usage output...
function usage {
  echo "use: $0 [-v] [-f] [-s SOURCE] DEST-DIRECTORY"
}

## ----------------------------------------------
## verbose-output-func
function verbose {
  if [ "$VFLAG" = "on" ] ; then echo "$1" ; fi
}

## ----------------------------------------------
## error-output-func
function error {
  echo "*** ERROR: $1"
  exit 1
}

## ----------------------------------------------
## warning-output-func
function warning {
  echo "*** WARNING: $1"
  echo "*** WARNING: $2"
}

## ----------------------------------------------
## process repository line
function processline {
  if [ $# -lt 4 ]
  then   
    warning "wrong format in line" "====> skipping \"$*\"..."
    return 1
  fi
  local TEMP="$*"

  # check fmt
  FORMAT=$1  ; shift
  SUPPORTED=1
  for f in $SUPPORTEDFORMATS
  do
    if [ "$f" = "$FORMAT" ]
    then
      SUPPORTED=0
      break
    fi
  done
  if [ $SUPPORTED -eq 1 ]
  then
      warning "format \"$FORMAT\" is not yet supported." "====> skipping \"$TEMP\"..."
      return 1
  fi

  #check url 
  URL=$1    ; shift
  PROTOCOL="$(echo $URL | sed -e 's/\([^:]*\).*/\1/')"

  SUPPORTED=1
  for f in $SUPPORTEDPROTOCOLS
  do
    if [ "$f" = "$PROTOCOL" ]
    then
      SUPPORTED=0
      break
    fi
  done

  if [ $SUPPORTED -eq 1 ]
  then
      warning "protocol \"$PROTOCOL\" is not yet supported." "====> skipping \"$TEMP\"..."
      return 1
  fi

  DISTRI=$1 ; shift
  unset PACKAGES
  while [ -n "$1" ]
  do
    PACKAGES[${#PACKAGES[@]}]=$1
    shift
  done 
 
  return 0
}

## ----------------------------------------------
## process repository line
function processpackage {
  local PACKAGE=$1
  local DOMAIN=""
  if [ "$PROTOCOL" = "file" ]
  then
    DOMAIN="local_repository"
  else
    DOMAIN=$(echo "$URL" | sed -e 's#[^/]*/*\([^/]*\).*#\1#' -e 's/\./_/g' )
  fi
 
  local SEENENTRY="${FORMAT}_${URL}_${DISTRI}_${PACKAGE}"

  for s in ${HAVESEEN[@]}
  do
    if [ "$SEENENTRY" = "$s" ]
    then
      warning "found duplicate entry" "====> skipping \"${FORMAT} ${URL} ${DISTRI} ${PACKAGE}\""
      return
    fi
  done
  HAVESEEN[${#HAVESEEN[@]}]=$SEENENTRY
 
  local CNLFILE="${PACKAGE}--${DOMAIN}"
  local COUNT=1
  for u in ${USEDFILES[@]}
  do
    if [ "$u" = "$CNLFILE" ] ; then let "COUNT += 1" ; fi
  done

  USEDFILES[${#USEDFILES[@]}]=$CNLFILE
 
  if [ $COUNT -eq 1 ]
  then
    CNLFILE="$DEST/${CNLFILE}.channel"
  else
    CNLFILE="$DEST/${CNLFILE}-($COUNT).channel" 
  fi
 
  if [ -e "$CNLFILE" ] && [ "$FFLAG" = "off" ]
  then
    error "channelfile \"$CNLFILE\" exists use the force luke. --> EXIT"   
  fi
  if  [ -e "$CNLFILE" ]
  then
    if [ -w "$CNLFILE" ]
    then
      rm -rf "$CNLFILE"
    else
      error "channelfile \"$CNLFILE\" exists and is write protected --> EXIT"   
    fi
  fi

  local CNLNAME="${PACKAGE}-apt" 
  COUNT=1
  for a in ${USEDALIAS[@]}
  do
    if [ "$a" = "$CNLNAME" ] ; then let "COUNT += 1" ; fi
  done

  USEDALIAS[${#USEDALIAS[@]}]=$CNLNAME
 
  if [ $COUNT -eq 1 ]
  then
    CNLNAME="[${CNLNAME}]" 
  else
    CNLNAME="[${CNLNAME}-${COUNT}]" 
  fi
 
  local NAME="'$PACKAGE' ${FORMAT}-repository on:$URL"
  local BASEURL=""
  if [ "$FORMAT" = "rpm" ]
  then
    if [ "${URL:$((${#URL}-1))}" = "/" ] ; then URL="${URL:0:$((${#URL}-1))}" ; fi
    if [ "${DISTRI:0:1}" = "/" ] ; then DISTRI="${DISTRI:1}" ; fi
    BASEURL="${URL}/${DISTRI}"
  fi

  ## check protocol
  local TYPE=
  if [ "$PROTOCOL" = "file" ]
  then
    TYPE="${FORMAT}-dir"
  else
    TYPE="apt-${FORMAT}"
  fi
  local OUTPUT="$CNLNAME\ntype = $TYPE\nname = $NAME\n"
  if [ "$FORMAT" = "rpm" ]
  then
   OUTPUT="${OUTPUT}baseurl = $BASEURL\n"
  elif [ "$FORMAT" = "deb" ]
  then
   OUTPUT="${OUTPUT}baseurl = $URL\ndistribution = $DISTRI\n"
  fi

  OUTPUT="${OUTPUT}components = $PACKAGE\n"

  verbose "   writing \"$CNLFILE\" for components: $PACKAGE"
  echo -e "$OUTPUT" > $CNLFILE
  verbose "   finished $PACKAGE"
}

## ----------------------------------------------
## read shell options
echo "$0 - starting"
while getopts vfs: OPT
do
    case "$OPT" in
      v)  VFLAG=on;;
      f)  FFLAG=on;;
      s)  SOURCE="$OPTARG";;
      \?)   # unknown flag
           echo >&2 \
     usage
     exit 1;;
    esac
done
shift `expr $OPTIND - 1`
verbose "verbose is \"$VFLAG\""
verbose "force-overwrite is \"$FFLAG\""

## ---------------------------------------------
## sanity-checks
verbose " starting sanity checks"
if [ $# != 1 ]
then
  usage
  error "no destination given -> EXIT!"
fi
DEST="$1"
if [ ! -e "$SOURCE" ]
then
  usage
  error "$SOURCE does not exist! -> EXIT"
fi
if [ ! -r "$SOURCE" ]
then
  usage
  error "$SOURCE not readable! -> EXIT"
fi
if [ ! -d "$DEST" ]
then
  usage
  error "$DEST is no directory! -> EXIT"
fi
if [ ! -w "$DEST" ]
then
  usage
  error "$DEST is not writable! -> EXIT"
fi
if [ "${DEST:$((${#DEST}-1))}" = "/" ] ; then DEST="${DEST:0:$((${#DEST}-1))}" ; fi
verbose " finished sanity checks"

## ---------------------------------------------
## read source
verbose " reading '$SOURCE'"
while read LINE
do
  if [ -z "$LINE" ] ; then continue ; fi
  if [ "${LINE:0:1}" == "#" ] ; then continue ; fi
  verbose "  processing \"$LINE\""
  processline $LINE
  if [ $? -eq 1 ] ; then continue ; fi
  for i in $(seq 0 $(( ${#PACKAGES[@]} - 1 )) )
  do
    verbose "   processing package \"${PACKAGES[$i]}\""
    processpackage "${PACKAGES[$i]}"
  done
done < "$SOURCE"
echo "$0 - finished successful"
################################################# 

