mirror of https://github.com/patacrep/patacrep.git
Engine for LaTeX songbooks
http://www.patacrep.com
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
4.2 KiB
132 lines
4.2 KiB
"""File system utilities."""
|
|
|
|
from contextlib import contextmanager
|
|
import glob
|
|
import importlib
|
|
import logging
|
|
import os
|
|
import posixpath
|
|
import re
|
|
import sys
|
|
|
|
LOGGER = logging.getLogger(__name__)
|
|
|
|
def recursive_find(root_directory, extensions):
|
|
"""Recursively find files with some extension, from a root_directory.
|
|
|
|
Return a list of files matching those conditions.
|
|
|
|
Arguments:
|
|
- `extensions`: list of accepted extensions.
|
|
- `root_directory`: root directory of the search.
|
|
"""
|
|
if not os.path.isdir(root_directory):
|
|
return []
|
|
|
|
matches = []
|
|
pattern = re.compile(r'.*\.({})$'.format('|'.join(extensions)))
|
|
with chdir(root_directory):
|
|
for root, __ignored, filenames in os.walk(os.curdir):
|
|
for filename in filenames:
|
|
if pattern.match(filename):
|
|
matches.append(os.path.join(root, filename))
|
|
return matches
|
|
|
|
def relpath(path, start=None):
|
|
"""Return relative filepath to path if a subpath of start."""
|
|
if start is None:
|
|
start = os.curdir
|
|
if os.path.abspath(path).startswith(os.path.abspath(start)):
|
|
return os.path.relpath(path, start)
|
|
else:
|
|
return os.path.abspath(path)
|
|
|
|
|
|
def path2posix(string):
|
|
""""Convert path from local format to posix format."""
|
|
if not string or string == "/":
|
|
return string
|
|
if os.path.splitdrive(string)[1] == "\\":
|
|
# Assuming DRIVE:\
|
|
return string[0:-1]
|
|
(head, tail) = os.path.split(string)
|
|
return posixpath.join(
|
|
path2posix(head),
|
|
tail)
|
|
|
|
@contextmanager
|
|
def chdir(path):
|
|
"""Locally change dir
|
|
|
|
Can be used as:
|
|
|
|
with chdir("some/directory"):
|
|
do_stuff()
|
|
"""
|
|
olddir = os.getcwd()
|
|
if path:
|
|
os.chdir(path)
|
|
yield
|
|
os.chdir(olddir)
|
|
else:
|
|
yield
|
|
|
|
def load_plugins(datadirs, subdir, variable, error):
|
|
"""Load all content plugins, and return a dictionary of those plugins.
|
|
|
|
A plugin is a .py file, submodule of `subdir`, located in one of the
|
|
directories of `datadirs`. It contains a dictionary `variable`. The return
|
|
value is the union of the dictionaries of the loaded plugins.
|
|
|
|
Arguments:
|
|
- datadirs: list of directories (as strings) in which files has to be
|
|
searched.
|
|
- subdir: modules (as a list of strings) files has to be submodules of
|
|
(e.g. if `subdir` is `['first', 'second']`, search files are of the form
|
|
`first/second/*.py`.
|
|
- variable: Name of the variable holding the dictionary.
|
|
- error: Error message raised if a key appears several times.
|
|
"""
|
|
plugins = {}
|
|
directory_list = (
|
|
[
|
|
os.path.join(datadir, "python", *subdir) #pylint: disable=star-args
|
|
for datadir in datadirs
|
|
]
|
|
+ [os.path.dirname(__file__)]
|
|
)
|
|
for directory in directory_list:
|
|
if not os.path.exists(directory):
|
|
LOGGER.debug(
|
|
"Ignoring non-existent directory '%s'.",
|
|
directory
|
|
)
|
|
continue
|
|
sys.path.append(directory)
|
|
for name in glob.glob(os.path.join(directory, *(subdir + ['*.py']))):
|
|
if name.endswith(".py") and os.path.basename(name) != "__init__.py":
|
|
if directory == os.path.dirname(__file__):
|
|
plugin = importlib.import_module(
|
|
'patacrep.{}.{}'.format(
|
|
".".join(subdir),
|
|
os.path.basename(name[:-len('.py')])
|
|
)
|
|
)
|
|
else:
|
|
plugin = importlib.import_module(
|
|
os.path.basename(name[:-len('.py')])
|
|
)
|
|
for (key, value) in getattr(plugin, variable, {}).items():
|
|
if key in plugins:
|
|
LOGGER.warning(
|
|
error.format(
|
|
filename=relpath(name),
|
|
key=key,
|
|
)
|
|
)
|
|
continue
|
|
plugins[key] = value
|
|
del sys.path[-1]
|
|
return plugins
|
|
|
|
|
|
|