[file_utils] dirpacker: --move, --prefix, -v/-q
dirpacker can now create a directory for each volume and move the corresponding files in it (option --move). The option --prefix allows the user to specify a custom prefix for the volumes' names. The options -v (--verbose) and -q (--quiet) enable or disable displaying the list of volumes.
This commit is contained in:
parent
e382dace97
commit
ace92010ec
|
@ -11,10 +11,15 @@ The particularity of this program, compared for example to datapacker
|
||||||
instead of regular files only. The files inside a directory won't be
|
instead of regular files only. The files inside a directory won't be
|
||||||
separated on several archives, they will be on the same volume.
|
separated on several archives, they will be on the same volume.
|
||||||
|
|
||||||
Note: I kept the datapacker's terminology, a volume is also called a
|
Note: I kept the datapacker's terminology in which a volume is also
|
||||||
bin.
|
called a bin.
|
||||||
|
|
||||||
To see the usage, call the program with -h.
|
By default, dirpacker displays a list of bins and the files they
|
||||||
|
would contain, along with the size of each file and some statistics.
|
||||||
|
With the option --move, a directory will be created for each volume and
|
||||||
|
the files will be moved to the corresponding volume.
|
||||||
|
|
||||||
|
To see the full usage, call the program with -h.
|
||||||
|
|
||||||
|
|
||||||
# mvparent.sh #
|
# mvparent.sh #
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
@ -51,13 +52,23 @@ class Bin:
|
||||||
def print(self):
|
def print(self):
|
||||||
"""Displays the contents of the bin.
|
"""Displays the contents of the bin.
|
||||||
"""
|
"""
|
||||||
print("\n### Bin #{} ###\n# List of files:".format(self.id))
|
print("\n### {} ###\n# List of files:".format(self.name()))
|
||||||
for filename, size in sorted(self.files.items()):
|
for filename, size in sorted(self.files.items()):
|
||||||
print("{} # {:.2f} MiB".format(filename, size))
|
print("{} # {:.2f} MiB".format(filename, size))
|
||||||
print("# This bin's size: {:.2f} MiB".format(self.size))
|
print("# This bin's size: {:.2f} MiB".format(self.size))
|
||||||
sizefree = options.maxbinsize - self.size
|
sizefree = options.maxbinsize - self.size
|
||||||
print("# Free space: {:.2f} MiB".format(sizefree))
|
print("# Free space: {:.2f} MiB".format(sizefree))
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
"""Returns the bin's name'
|
||||||
|
"""
|
||||||
|
return "{}{:02}".format(options.prefix, b.id)
|
||||||
|
|
||||||
|
def list_files(self):
|
||||||
|
"""Returns a list of the files contained in the bin.
|
||||||
|
"""
|
||||||
|
return list(self.files.keys())
|
||||||
|
|
||||||
|
|
||||||
def du(basepath):
|
def du(basepath):
|
||||||
""" Returns the size of the file of directory `basepath`, in MiB.
|
""" Returns the size of the file of directory `basepath`, in MiB.
|
||||||
|
@ -107,9 +118,14 @@ arg_parser.add_argument("-s", "--size", action="store", dest="maxbinsize",
|
||||||
help="maximal size of each volume (bin), in MiB; the "
|
help="maximal size of each volume (bin), in MiB; the "
|
||||||
"default is 703 MiB, i.e. the size of a 80-minute "
|
"default is 703 MiB, i.e. the size of a 80-minute "
|
||||||
"CD-ROM")
|
"CD-ROM")
|
||||||
arg_parser.add_argument("-a", "--action", action="store", default="list",
|
arg_parser.add_argument("--prefix", action="store", default="bin_",
|
||||||
help='action to be taken; can be "list" (default)'
|
help="prefix of a bin's name (default: \"bin_\")")
|
||||||
' or "move" (move input to per-volume directories)')
|
arg_parser.add_argument("--move", action="store_true",
|
||||||
|
help="move input to per-volume directories")
|
||||||
|
arg_parser.add_argument("-v", "--verbose", action="store_true", default=True,
|
||||||
|
help="be verbose (this is the default)")
|
||||||
|
arg_parser.add_argument("-q", "--quiet", action="store_false", dest="verbose",
|
||||||
|
help="print only warnings and errors")
|
||||||
arg_parser.add_argument("filenames", metavar="file", nargs="+",
|
arg_parser.add_argument("filenames", metavar="file", nargs="+",
|
||||||
help="files or directories to pack")
|
help="files or directories to pack")
|
||||||
options = arg_parser.parse_args()
|
options = arg_parser.parse_args()
|
||||||
|
@ -117,7 +133,8 @@ options = arg_parser.parse_args()
|
||||||
|
|
||||||
### Preliminary statistics ###
|
### Preliminary statistics ###
|
||||||
|
|
||||||
print("# Maximum size of a bin: {:.2f} MiB".format(options.maxbinsize))
|
if options.verbose:
|
||||||
|
print("# Maximum size of a bin: {:.2f} MiB".format(options.maxbinsize))
|
||||||
|
|
||||||
# Compute the size of all the files
|
# Compute the size of all the files
|
||||||
sizes = defaultdict(list)
|
sizes = defaultdict(list)
|
||||||
|
@ -134,12 +151,13 @@ for filename in options.filenames:
|
||||||
sizes[size].append(filename)
|
sizes[size].append(filename)
|
||||||
totalsize += size
|
totalsize += size
|
||||||
|
|
||||||
print("# Total size of the input files: {:.2f} MiB".format(totalsize))
|
if options.verbose:
|
||||||
minbins = math.ceil(totalsize / options.maxbinsize)
|
print("# Total size of the input files: {:.2f} MiB".format(totalsize))
|
||||||
print("# Minimal (optimal) number of bins required: ", minbins)
|
minbins = math.ceil(totalsize / options.maxbinsize)
|
||||||
sizefree = minbins * options.maxbinsize - totalsize
|
print("# Minimal (optimal) number of bins required: ", minbins)
|
||||||
print("# Theoretical unused space with {} bins: {:.2f} MiB"
|
sizefree = minbins * options.maxbinsize - totalsize
|
||||||
.format(minbins, sizefree))
|
print("# Theoretical unused space with {} bins: {:.2f} MiB"
|
||||||
|
.format(minbins, sizefree))
|
||||||
|
|
||||||
|
|
||||||
### Assemble the bins ###
|
### Assemble the bins ###
|
||||||
|
@ -154,24 +172,41 @@ binscreated = binnumber - 1
|
||||||
|
|
||||||
### Final statistics ###
|
### Final statistics ###
|
||||||
|
|
||||||
sizefree = binscreated * options.maxbinsize - totalsize
|
if options.verbose:
|
||||||
print("""\
|
sizefree = binscreated * options.maxbinsize - totalsize
|
||||||
|
print("""\
|
||||||
# {} bins created.
|
# {} bins created.
|
||||||
# Actual unused space over the {} bins created: {:.2f} MiB"""
|
# Actual unused space over the {} bins created: {:.2f} MiB"""
|
||||||
.format(binscreated, binscreated, sizefree))
|
.format(binscreated, binscreated, sizefree))
|
||||||
|
|
||||||
|
|
||||||
### Execute the requested action ###
|
### Execute the requested action ###
|
||||||
|
|
||||||
if options.action == "list":
|
|
||||||
|
# Print the contents of the bins
|
||||||
|
if options.verbose:
|
||||||
for b in bins:
|
for b in bins:
|
||||||
b.print()
|
b.print()
|
||||||
elif options.action == "move":
|
|
||||||
print('Action "move" is not implemented yet.')
|
# Move the files
|
||||||
exit(0)
|
if options.move:
|
||||||
else:
|
for b in bins:
|
||||||
print('ERROR! Action "{}" is unknown.'.format(options.action))
|
dirname = b.name()
|
||||||
exit(1)
|
if os.path.exists(dirname) and not os.path.isdir(dirname):
|
||||||
|
print('# WARNING! File "{}" exists but is not a directory:'
|
||||||
|
' skipping bin #{}.'
|
||||||
|
.format(dirname, b.id))
|
||||||
|
continue
|
||||||
|
# Create the target directory:
|
||||||
|
try:
|
||||||
|
os.makedirs(dirname, exist_ok=True)
|
||||||
|
except FileExistsError:
|
||||||
|
print('# WARNING! Directory "{}" already exists with different'
|
||||||
|
' permissions (mode). Proceeding anyway.'
|
||||||
|
.format(dirname))
|
||||||
|
# Move the files in the directory:
|
||||||
|
for filename in b.list_files():
|
||||||
|
shutil.move(filename, dirname)
|
||||||
|
|
||||||
|
|
||||||
### Wrapping-up ###
|
### Wrapping-up ###
|
||||||
|
|
Loading…
Reference in New Issue