#!/usr/bin/perl use strict; use warnings; use Getopt::Long; my $VERSION="1.0d"; my $date="2004/06/04"; my $units; sub get_real_cap { $_=shift; die "Invalid capacity format '$_'" if(!/^(\d+(?:\.\d*)?)([kmgKMG]?)/); my $cap=$1; $units=uc $2; return int $cap*1024 if $units eq 'K'; return int $cap*1024*1024 if $units eq 'M'; return int $cap*1024*1024*1024 if $units eq 'G'; } sub get_human_size { $_=shift; $_=sprintf("%.2f",$_/1024) if $units eq 'K'; $_=sprintf("%.2f",$_/(1024*1024)) if $units eq 'M'; $_=sprintf("%.2f",$_/(1024*1024*1024)) if $units eq 'G'; return $_.$units; } my $my_cap="4485M"; my ($start_time,$end_time); my @ftable; my $nr_files=0; my $nr_combinations; my $nr_large=0; # Objects that are larger than media my $total_size=0; my $fl_all=0; sub usage { my $ec=shift; print<<EOH; lorry $VERSION, written by Ondra Havel, $date -help give this help -size <sz> optimize for given size (default $my_cap) K,M,G suffixes are recognized -all process all files, do multiple volumes EOH exit defined $ec ? $ec : 0; } $start_time=time; GetOptions("help"=>\&usage,"size=s"=>\$my_cap,"all"=>\$fl_all); my $real_cap=get_real_cap $my_cap; print STDERR "Optimizing for capacity $my_cap ($real_cap bytes)\n"; for (@ARGV) { next if /^\.\.?$/; next if ! -e $_; s/`/\\`/g; my $s=`du -sb "$_"`; chomp $s; $s=~s/^(\d+).*/$1/; if($s>$real_cap) { $nr_large++; next; } push(@ftable,{name=>$_, size=>$s}); $total_size+=$s; $nr_files++; } print STDERR "Warning $nr_large objects were rejected because of large size.\n" if $nr_large; if(!$nr_files) { print STDERR "Nothing to do\n"; exit 0; } print STDERR "Processing $nr_files objects, total size @{[ get_human_size $total_size ]}.\n"; if($total_size<=$real_cap) { print STDERR "Nothing to do media capacity not exceeded.\n"; print "${$_}{'name'}\n" for (@ftable); exit 0; } sub do_combine { my($my_idx,$my_limit,$my_res)=@_; return 0 if $my_idx==scalar @ftable; $nr_combinations++; my $ret0=[]; my $s0=do_combine($my_idx+1,$my_limit,$ret0); my $my_size=$ftable[$my_idx]{'size'}; if($my_size<=$my_limit) { my $s1; my $ret1=[]; $s1=$my_size+do_combine($my_idx+1,$my_limit-$my_size,$ret1); if($s1>$s0) { push @{$my_res},$my_idx; push @{$my_res},@{$ret1}; return $s1; } } push @{$my_res},@{$ret0}; return $s0; } while(scalar @ftable) { my $myres=[]; $nr_combinations=0; my $gsize=do_combine 0,$real_cap,$myres; for(@{$myres}) { print "$ftable[$_]{'name'}\n"; $ftable[$_]=''; } my $eff=sprintf("%.2f",100*$gsize/$real_cap); print STDERR "$nr_combinations combinations considered, $gsize/$real_cap ($eff%, ".($real_cap-$gsize)." bytes left)\n"; last if !$fl_all; print "\n"; @ftable=grep(!/^$/,@ftable); } $end_time=time; $end_time-=$start_time; if($end_time) { my $days=int($end_time/86400); $end_time%=86400; my $hours=int($end_time/3600); $end_time%=3600; my $mins=int($end_time/60); my $secs=$end_time % 60; print STDERR "Elapsed time: "; print STDERR "$days days " if $days; print STDERR "$hours hours " if $hours or $days; print STDERR "$mins minutes " if $mins or $hours or $days; print STDERR "$secs seconds\n"; }