App-BinPackUtils

 view release on metacpan or  search on metacpan

lib/App/BinPackUtils.pm  view on Meta::CPAN

    for my $item (@{ $args{items} }) {
        if (ref $item eq 'ARRAY') {
            $bp->add_item(label => $item->[0], size => $item->[1]);
        } else {
            my @item = split /\s*,\s*/, $item;
            $bp->add_item(label => $item[0], size => $item[1]);
        }
    }
    my @bins = $bp->pack_bins;
    [200, "OK", $args{num_bins} ? scalar(@bins) : \@bins];
}

$SPEC{bin_files} = {
    v => 1.1,
    summary => 'Put files into bins of certain size (or number of items)',
    args => {
        %argopt_bin_size,
        %argopt_bin_max_items,
        bin_prefix => {
            schema => 'filename*',
            default => 'bin',
        },
        %arg0_files,
        %argopt_dereference_files,
        %argopt_move,
        %argopt_num_bins,
    },
    args_rels => {
        req_one => [qw/bin_size bin_max_items/],
    },
    deps => {
        prog => 'du',
    },
    examples => [
        {
            summary => 'Put at most 100MB in each bin, move the files',
            src => 'bin-files --bin-size 100MB --move *.jpg',
            src_plang => 'bash',
            test => 0,
            'x.doc.show_result' => 0,
        },
        {
            summary => 'Put at most 1000 files in each bin, move the files',
            src => 'bin-files --bin-max-items 1000 --move *.jpg',
            src_plang => 'bash',
            test => 0,
            'x.doc.show_result' => 0,
        },
    ],
};
sub bin_files {
    require String::ShellQuote;

    my %args = @_;
    my $bin_size = $args{bin_size};
    my $bin_max_items = $args{bin_max_items};
    my $bin_prefix = $args{bin_prefix} // "bin";

    my @items;
    for my $file (@{ $args{files} }) {
        return [404, "File '$file' does not exist"] unless -e $file;

        if (defined $bin_size) {
            my $cmd = "du ".($args{dereference_files} ? "-D " : "")."--apparent-size -sb ".
                String::ShellQuote::shell_quote($file);
            my $out = `$cmd`;
            my $size;
            if ($out =~ /\A(\d+)/) {
                $size = $1;
            } else {
                return [500, "Cannot find the size of '$file': $!"];
            }
            push @items, [$file, $size];
        } else {
            push @items, [$file, 1];
        }
    }

    my $res = pack_bins(bin_size => $bin_size // $bin_max_items, items => \@items);
    return $res unless $res->[0] == 200;

    # reformat as a single 2D table
    my @rows;
    my $bin_num = 0;
    my %bin_names;
    for my $bin (@{ $res->[2] }) {
        $bin_num++;
        for my $item (@{ $bin->{items} }) {
            my $bin_name = "$bin_prefix$bin_num";
            $bin_names{$bin_name}++;
            push @rows, {
                bin => $bin_name,
                file=>$item->{label},
                size=>$item->{size},
            };
        }
    }

    if ($args{move}) {
        # create all the directories for bins
        for my $bin_name (sort keys %bin_names) {
            return [412, "Directory $bin_name must not already exist"]
                if -d $bin_name;
            log_info "Creating directory $bin_name ...";
            mkdir $bin_name or return [500, "Can't create directory $bin_name: $!"];
        }
        # move files to bins
        for my $row (@rows) {
            log_info "Moving '$row->{file}' to $row->{bin} ...";
            rename($row->{file}, "$row->{bin}/$row->{file}") or do {
                log_warn "Can't move '$row->{file}' to $row->{bin}/: $!, skipped";
            };
        }
    }

    [200, "OK", $args{num_bins} ? scalar(keys %bin_names) : \@rows];
}

$SPEC{bin_files_into_dvds} = {
    v => 1.1,
    summary => 'Put files into DVD bins',



( run in 2.609 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )