diff --git a/file_utils/dirpacker.py b/file_utils/dirpacker.py index 27de185..b2ebf75 100755 --- a/file_utils/dirpacker.py +++ b/file_utils/dirpacker.py @@ -36,6 +36,29 @@ from collections import defaultdict import math +class Bin: + """ Represents a bin (a volume) containing files and directories. + """ + def __init__(self, bin_id, total_size, files): + """bin_id is the bin's identifier, total_size the sum of the sizes of + all the files it contains, and files is a dictionary with file names + as the keys and sizes as values. + """ + self.id = bin_id + self.size = total_size + self.files = files + + def print(self): + """Displays the contents of the bin. + """ + print("\n### Bin #{} ###\n# List of files:".format(self.id)) + for filename, size in sorted(self.files.items()): + print("{} # {:.2f} MiB".format(filename, size)) + print("# This bin's size: {:.2f} MiB".format(self.size)) + sizefree = options.maxbinsize - self.size + print("# Free space: {:.2f} MiB".format(sizefree)) + + def du(basepath): """ Returns the size of the file of directory `basepath`, in MiB. """ @@ -51,10 +74,10 @@ def du(basepath): def create_bin(binnumber): """Creates a bin numbered `binnumber` from the global list of files and - sizes. + sizes, and returns it. """ - print("\n### Bin #{} ###\n# List of files:".format(binnumber)) binsize = 0 + files = {} for size in reversed(sorted(sizes.keys())): newbinsize = binsize + size # Try the next, smaller file if we would exceed the bin's maximum size @@ -62,8 +85,7 @@ def create_bin(binnumber): if newbinsize > options.maxbinsize: continue - filename = sizes[size].pop() - print("{} # {:.2f} MiB".format(filename, size)) + files[sizes[size].pop()] = size # Delete the size from the dictionary if its last file name was just # popped: if not len(sizes[size]): @@ -71,22 +93,23 @@ def create_bin(binnumber): binsize = newbinsize - print("# This bin's size: {:.2f} MiB".format(binsize)) - sizefree = options.maxbinsize - binsize - print("# Free space: {:.2f} MiB".format(sizefree)) + return Bin(binnumber, binsize, files) ### Parse command-line arguments ### arg_parser = argparse.ArgumentParser( description="Packs files and directories into fixed-size volumes", - epilog="For more information about this program, see the README file \ -provided with the distribution.") + epilog="For more information about this program, see the README file" + "provided with the distribution.") arg_parser.add_argument("-s", "--size", action="store", dest="maxbinsize", type=float, default=703, help="maximal size of each volume (bin), in MiB; the " - +"default is 703 MiB, i.e. the size of a 80-minute " - +"CD-ROM") + "default is 703 MiB, i.e. the size of a 80-minute " + "CD-ROM") +arg_parser.add_argument("-a", "--action", action="store", default="list", + help='action to be taken; can be "list" (default)' + ' or "move" (move input to per-volume directories)') arg_parser.add_argument("filenames", metavar="file", nargs="+", help="files or directories to pack") options = arg_parser.parse_args() @@ -115,14 +138,16 @@ print("# Total size of the input files: {:.2f} MiB".format(totalsize)) minbins = math.ceil(totalsize / options.maxbinsize) print("# Minimal (optimal) number of bins required: ", minbins) sizefree = minbins * options.maxbinsize - totalsize -print("# Total unused space with {} bins: {:.2f} MiB".format(minbins, sizefree)) +print("# Theoretical unused space with {} bins: {:.2f} MiB" + .format(minbins, sizefree)) ### Assemble the bins ### +bins = [] binnumber = 1 while len(sizes): - create_bin(binnumber) + bins.append(create_bin(binnumber)) binnumber += 1 binscreated = binnumber - 1 @@ -130,8 +155,26 @@ binscreated = binnumber - 1 ### Final statistics ### sizefree = binscreated * options.maxbinsize - totalsize -print("\n# Total unused space over the {} bins created: {:.2f} MiB" - .format(binscreated, sizefree)) +print("""\ +# {} bins created. +# Actual unused space over the {} bins created: {:.2f} MiB""" + .format(binscreated, binscreated, sizefree)) + + +### Execute the requested action ### + +if options.action == "list": + for b in bins: + b.print() +elif options.action == "move": + print('Action "move" is not implemented yet.') + exit(0) +else: + print('ERROR! Action "{}" is unknown.'.format(options.action)) + exit(1) + + +### Wrapping-up ### if (ignored_files): print("\n# WARNING! There were ignored files, see at the top of this log.")