From 85ce9841eb695861579bba7d9706110ed601f799 Mon Sep 17 00:00:00 2001 From: Chris Down Date: Tue, 31 Oct 2023 00:09:22 +0000 Subject: [PATCH] Allow FIFOs to be used as config files There are some config options which have no equivalent command line option. Some may want to set these options dynamically or on a one-off basis where a static config file is not ideal, and one very easy way to do that is using process substitution: linkchecker --config <(printf '%s\n' '[filtering]' 'ignorewarnings=http-redirected') ... This, however, does not work in the current code because these are typically implemented as FIFOs, which don't pass the `os.path.isfile` check: WARNING linkcheck.cmdline 2023-10-31 00:12:09,678 MainThread Unreadable config file: '/dev/fd/63' Allow reading FIFOs as config input so that this is possible. `fileutil.is_readable` also now doesn't check if the path leads to a regular file: this is only used as part of cookie and config file input, and in both cases that's not really relevant. --- linkcheck/command/linkchecker.py | 2 +- linkcheck/configuration/__init__.py | 2 +- linkcheck/fileutil.py | 9 +++++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/linkcheck/command/linkchecker.py b/linkcheck/command/linkchecker.py index 00cdf578..f4c5ff47 100644 --- a/linkcheck/command/linkchecker.py +++ b/linkcheck/command/linkchecker.py @@ -135,7 +135,7 @@ def linkchecker(): files = [] if options.configfile: path = configuration.normpath(options.configfile) - if os.path.isfile(path): + if fileutil.is_valid_config_source(path): files.append(path) else: log.warn( diff --git a/linkcheck/configuration/__init__.py b/linkcheck/configuration/__init__.py index 1a8f82f0..09214851 100644 --- a/linkcheck/configuration/__init__.py +++ b/linkcheck/configuration/__init__.py @@ -222,7 +222,7 @@ class Configuration(dict): # filter invalid files filtered_cfiles = [] for cfile in cfiles: - if not os.path.isfile(cfile): + if not fileutil.is_valid_config_source(cfile): log.warn(LOG_CHECK, _("Configuration file %r does not exist."), cfile) elif not fileutil.is_readable(cfile): log.warn(LOG_CHECK, _("Configuration file %r is not readable."), cfile) diff --git a/linkcheck/fileutil.py b/linkcheck/fileutil.py index eb9bb91e..db574500 100644 --- a/linkcheck/fileutil.py +++ b/linkcheck/fileutil.py @@ -89,8 +89,8 @@ def is_tty(fp): @lru_cache(128) def is_readable(filename): - """Check if file is a regular file and is readable.""" - return os.path.isfile(filename) and os.access(filename, os.R_OK) + """Check if file is readable.""" + return os.access(filename, os.R_OK) def is_accessable_by_others(filename): @@ -103,3 +103,8 @@ def is_writable_by_others(filename): """Check if file or directory is world writable.""" mode = os.stat(filename)[stat.ST_MODE] return mode & stat.S_IWOTH + + +def is_valid_config_source(filename): + """Check if the file is a valid config file.""" + return os.path.isfile(filename) or stat.S_ISFIFO(os.stat(filename).st_mode)