Non dovremmo dimenticare che l'essenza del compito è davvero abbastanza semplice; come messo in un tutorial su Haskell (che è scritto attorno all'elaborazione della soluzione per questa attività, perfezionata in modo incrementale)
Ora pensiamo per un momento a come funzionerà il nostro programma ed esprimiamolo in pseudocodice:
main = Read list of directories and their sizes.
Decide how to fit them on CD-Rs.
Print solution.
Sembra ragionevole? Così ho pensato.
Semplifichiamo un po 'la nostra vita e supponiamo per ora che calcoleremo le dimensioni delle directory da qualche parte al di fuori del nostro programma (ad esempio, con " du -sb *
") e leggeremo queste informazioni da stdin.
(dalla guida degli autostoppisti a Haskell, capitolo 1 )
(Inoltre, nella tua domanda, vorresti essere in grado di modificare (modificare) i layout del disco risultanti e quindi utilizzare uno strumento per masterizzarli.)
Puoi riutilizzare (adattare e riutilizzare) una semplice variante del programma da quel tutorial Haskell per dividere la tua raccolta di file.
Purtroppo, nel l' distribute
attrezzo che ho accennato qui in un'altra risposta , la semplicità del compito essenziale la divisione non è compensata dalla complessità e gonfiore dell'interfaccia utente di distribute
(perché è stato scritto per combinare diversi compiti, anche se eseguita in più fasi, ma ancora combinato non nel modo più pulito a cui potrei pensare ora).
Per aiutarti a fare un po 'di uso del suo codice, ecco un estratto dal codice bash distribute
(alla riga 380 ) che serve a fare questo compito "essenziale" di dividere una raccolta di file:
# Splitting:
function splitMirrorDir() {
if [[ ! -d "$THIS_BASES_DIR/$BASE/$type" ]]; then
echo $"No base fixed for $type" >&2
exit 1
fi
# Getting the list of all suitable files:
local -a allFiles
let 'no = 0' ||:
allFiles=()
# no points to the next free position in allFiles
# allFiles contains the constructed list
for p in "$THIS_BASES_DIR/$BASE/$type"/*.rpm; do
if [[ ! -e "$p" ]]; then
# fail on non-existent files
echo $"Package file doesn't exist: " "$p" >&2
return 1
fi
if [[ "$ONLY_REAL_FILES" == "yes" && ! -f "$p" ]]; then
continue
fi
if [[ "$DIFF_TO_BASE" ]]; then
older_copy="$DIFF_TO_BASE/$type/${p##*/}" # using shell param expansion instead of `basename' to speed up
if [[ -h "$older_copy" || -a "$older_copy" ]]; then
continue
fi
fi
allFiles[$(( no++ ))]="$p"
done
readonly -a allFiles
# Splitting the list of all files into future disks:
#
local -a filesToEat allSizes
let 'no = 0' ||:
filesToEat=()
allSizes=($(getSize "${allFiles[@]}"))
readonly -a allSizes
# allSizes contains the sizes corrsponding to allFiles
# filesToEat hold the constructed list of files to put on the current disk
# no points to the next free position in filesToEat
# totalSize should hold the sum of the sizes
# of the files already put into filesToEat;
# it is set and reset externally.
for p in "${allFiles[@]}"; do
if (( totalsize + ${allSizes[$(( no ))]} > CDVOLUME )); then
eatFiles "${filesToEat[@]}"
filesToEat=()
finishCD
startTypedCD
fi
let "totalsize += ${allSizes[$(( no ))]}" ||:
filesToEat[$(( no++ ))]="$p"
done
eatFiles "${filesToEat[@]}"
}
function eatFiles() {
#{ oldIFS="$IFS"; IFS=$'\n'; echo "$FUNCNAME: args: " "$*" | head >&2; IFS="$oldIFS"; }
zeroDelimited "$@" | xargs -0 --no-run-if-empty \
cp -s \
--target-dir="$THIS_LAYOUTS_DIR/cd$(( cdN ))/$PREFIX/$type$DOT_SUFFIX"/ \
--
}
function startTypedCD() {
# set -x
mkdir -p "$THIS_LAYOUTS_DIR/cd$(( cdN ))/$PREFIX/$type$DOT_SUFFIX"
start_action $" %s with %s" "$(( cdN ))" "$type"
# set +x
}
function finishCD() {
( leggi di più dopo la riga 454 )
Si noti che la eatFiles
funzione prepara i layout dei dischi futuri come alberi in cui le foglie sono collegamenti simbolici ai file reali. Quindi, soddisfa i tuoi requisiti che dovresti essere in grado di modificare i layout prima della masterizzazione. L' mkisofs
utilità ha un'opzione per seguire i collegamenti simbolici, che è effettivamente impiegato nel codice della mia mkiso
funzione .
Lo script presentato (che puoi prendere e riscrivere in base alle tue esigenze, ovviamente!) Segue l'idea più semplice: sommare le dimensioni dei file (o, più precisamente, i pacchetti nel caso di distribute
) proprio nell'ordine in cui sono stati elencati, don non fare alcun riarrangiamento.
La "Guida degli autostoppisti a Haskell" prende più seriamente il problema dell'ottimizzazione e suggerisce varianti di programma che tenterebbero di riorganizzare i file in modo intelligente, in modo che si adattino meglio ai dischi (e richiedano meno dischi):
Già abbastanza preliminari. andiamo a fare un po 'di cd.
Come forse avrai già riconosciuto, il nostro problema è classico. Si chiama "problema dello zaino"
( cercalo su Google , se non sai già di cosa si tratta. Ci sono più di 100000 link).
partiamo dalla soluzione golosa ...
(leggi di più nel capitolo 3 e oltre.)
Altri strumenti intelligenti
Mi è stato anche detto che Debian usa uno strumento per rendere i suoi CD di distribuzione più intelligenti delle mie distribute
raccolte di pacchetti wrt: i suoi risultati sono più belli perché si preoccupano delle dipendenze tra pacchetti e proverebbero a fare la raccolta di pacchetti che va avanti il primo disco chiuso in dipendenze, cioè nessun pacchetto dal 1o disco dovrebbe richiedere un pacchetto da un altro disco (o almeno, direi, il numero di tali dipendenze dovrebbe essere ridotto al minimo).