diff --git a/README.md b/README.md index 568a50be..c2aa7e08 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ If possible, try building with clang as your compiler, this will make DwarFS significantly faster. If you have both gcc and clang installed, use: - # cmake .. -DWITH_TESTS=1 -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ + # CC=clang CXX=clang++ cmake .. -DWITH_TESTS=1 To build with experimental Lua support, you need to install both `lua` and `luabind`. The latter isn't very well maintained and I @@ -231,6 +231,23 @@ Installing is as easy as: Though you don't have to install the tools to play with them. +### Experimental Python Scripting Support + +You can build `mkdwarfs` with experimental support for Python +scripting: + + # cmake .. -DWITH_TESTS=1 -DWITH_PYTHON=1 + +This also requires Boost.Python. If you have multiple Python +versions installed, you can explicitly specify the version to +build against: + + # cmake .. -DWITH_TESTS=1 -DWITH_PYTHON=1 -DWITH_PYTHON_VERSION=3.8 + +Note that only Python 3 is supported. You can take a look at +[scripts/example.py](scripts/example.py) to get an idea for +what can currently be done with the interface. + ## Usage Please check out the man pages for [mkdwarfs](doc/mkdwarfs.md) diff --git a/doc/mkdwarfs.md b/doc/mkdwarfs.md index bc8e3cb9..b065a618 100644 --- a/doc/mkdwarfs.md +++ b/doc/mkdwarfs.md @@ -167,6 +167,14 @@ Most other options are concerned with compression tuning: Show program help, including defaults, compression level detail and supported compression algorithms. +If experimental Python support was compiled into `mkdwarfs`, you can use the +following option to enable customizations via the scripting interface: + + * `--script=`*file*[`:`*class*[`(`arguments`...)`]]: + Specify the Python script to load. The class name is optional if there's + a class named `mkdwarfs` in the script. It is also possible to pass + arguments to the constuctor. + ## TIPS & TRICKS ### Compression Ratio vs Decompression Speed diff --git a/scripts/example.py b/scripts/example.py index ee38bddb..93d724fd 100644 --- a/scripts/example.py +++ b/scripts/example.py @@ -1,24 +1,72 @@ class mkdwarfs(object): + """ + The class defining mkdwarfs customization. + + If this is named `mkdwarfs`, you only have to specify the path to + the script file with `--script`. You can define multiple classes in + a single script, in which case you'll have to pass the class name + in addition to the script path as `--script :`. If the + class has a custom contructor, it is also possible to pass arguments + to the constuctor from the command line. + + All methods are optional. If you want to define methods beyond the + ones specified below, make sure you start their names with an + underscore, otherwise there will be a warning to ensure you don't + accidentally mistype the names of the methods. + + You can use the global `logger` object for logging. + """ def __init__(self): + """ + Optional constructor + """ logger.info("this is python!") def configure(self, config): + """ + Configuration + + This will be called early and allows you to change the default + for or even override (command line) parameters. Only a small + number of parameters are currently supported. + """ + # Enable similarity hash computation, useful if you actually + # want to use it in the `order` method. config.enable_similarity() config.set_order(file_order_mode.script, set_mode.override) config.set_remove_empty_dirs(True, set_mode.default) def filter(self, entry): + """ + Filtering + + This will be called for every file system entry. If you return + `False`, the entry will be skipped. + """ logger.debug(f"filter: {entry.path()} [{entry.type()}]") if entry.type() == 'directory' and entry.name() == 'dev': return False return True def transform(self, entry): + """ + Transformation + + This will be called for every entry that has not been filtered, + and allows you to change certain attributes, such as permissions, + ownership, or timestamps. + """ logger.debug(f"transform {entry.path()}") entry.set_permissions(entry.permissions() & 0o7555) return entry def order(self, inodes): + """ + Inode Ordering + + This will be called for every regular file inode, after all + entries have been scanned and files have been deduplicated. + """ logger.info("order") for i in inodes: logger.debug(f"inode: {i.similarity_hash()} {i.size()} {i.refcount()}")