diff --git a/linkcheck/command/linkchecker.py b/linkcheck/command/linkchecker.py index f4c5ff47..139a7cf8 100644 --- a/linkcheck/command/linkchecker.py +++ b/linkcheck/command/linkchecker.py @@ -135,11 +135,14 @@ def linkchecker(): files = [] if options.configfile: path = configuration.normpath(options.configfile) - if fileutil.is_valid_config_source(path): - files.append(path) + if not fileutil.is_valid_config_source(path): + raise LinkCheckerError( + _("Config file %s does not exist.") % options.configfile) + elif not fileutil.is_readable(path): + raise LinkCheckerError( + _("Could not read config file %s.") % options.configfile) else: - log.warn( - LOG_CMDLINE, _("Unreadable config file: %r"), options.configfile) + files.append(path) config.read(files=files) except LinkCheckerError as msg: # config error diff --git a/linkcheck/command/setup_config.py b/linkcheck/command/setup_config.py index a85bd310..da6c36d1 100644 --- a/linkcheck/command/setup_config.py +++ b/linkcheck/command/setup_config.py @@ -187,8 +187,6 @@ def setup_config(config, options): if options.verbose: config["verbose"] = True config["warnings"] = True - if options.cookiefile is not None: - config["cookiefile"] = options.cookiefile if constructauth: config.add_auth(pattern=".+", user=_username, password=_password) # read missing passwords @@ -204,8 +202,11 @@ def setup_config(config, options): if options.useragent is not None: config["useragent"] = options.useragent if options.cookiefile is not None: - if fileutil.is_readable(options.cookiefile): - config["cookiefile"] = options.cookiefile + if not fileutil.is_valid_config_source(options.cookiefile): + print_usage( + _("Cookie file %s does not exist.") % options.cookiefile) + elif not fileutil.is_readable(options.cookiefile): + print_usage( + _("Could not read cookie file %s") % options.cookiefile) else: - msg = _("Could not read cookie file %s") % options.cookiefile - log.error(LOG_CMDLINE, msg) + config["cookiefile"] = options.cookiefile diff --git a/linkcheck/configuration/confparse.py b/linkcheck/configuration/confparse.py index 9d9ff875..45b6026d 100644 --- a/linkcheck/configuration/confparse.py +++ b/linkcheck/configuration/confparse.py @@ -57,6 +57,9 @@ class LCConfigParser(RawConfigParser): assert isinstance(files, list), "Invalid file list %r" % files try: self.read_ok = super().read(files) + if not self.sections(): + raise LinkCheckerError( + _("configuration files %s contain no sections.") % files) if len(self.read_ok) < len(files): failed_files = set(files) - set(self.read_ok) log.warn( diff --git a/linkcheck/cookies.py b/linkcheck/cookies.py index 5e17ef29..b97e8018 100644 --- a/linkcheck/cookies.py +++ b/linkcheck/cookies.py @@ -21,6 +21,8 @@ from http.cookiejar import split_header_words import email import requests +from . import LinkCheckerError + def from_file(filename): """Parse cookie data from a text file in HTTP header format. @@ -40,6 +42,8 @@ def from_file(filename): lines.append(line) if lines: entries.extend(from_headers("\r\n".join(lines))) + if not entries: + raise LinkCheckerError(_("No entries found")) return entries diff --git a/linkcheck/director/aggregator.py b/linkcheck/director/aggregator.py index cace9edf..75f46269 100644 --- a/linkcheck/director/aggregator.py +++ b/linkcheck/director/aggregator.py @@ -45,8 +45,14 @@ def new_request_session(config, cookies): {"User-Agent": config["useragent"]} ) if config["cookiefile"]: - for cookie in from_file(config["cookiefile"]): - session.cookies.set_cookie(cookie) + try: + for cookie in from_file(config["cookiefile"]): + session.cookies.set_cookie(cookie) + except Exception as msg: + log.error( + LOG_CHECK, + _("Could not parse cookie file: %s. %s"), config["cookiefile"], msg + ) return session diff --git a/linkcheck/fileutil.py b/linkcheck/fileutil.py index db574500..22572ec1 100644 --- a/linkcheck/fileutil.py +++ b/linkcheck/fileutil.py @@ -107,4 +107,5 @@ def is_writable_by_others(filename): 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) + return os.path.exists(filename) and ( + os.path.isfile(filename) or stat.S_ISFIFO(os.stat(filename).st_mode)) diff --git a/tests/configuration/data/config.empty b/tests/configuration/data/config.empty new file mode 100644 index 00000000..e69de29b diff --git a/tests/configuration/test_config.py b/tests/configuration/test_config.py index 0529b71f..b36ef09d 100644 --- a/tests/configuration/test_config.py +++ b/tests/configuration/test_config.py @@ -191,3 +191,13 @@ class TestConfig(TestBase): # blacklist logger section self.assertEqual(config["failures"]["filename"], "blacklist") self.assertEqual(config["failures"]["encoding"], "utf-8") + + def test_confparse_empty(self): + config = linkcheck.configuration.Configuration() + files = [get_file("config.empty")] + self.assertRaises(linkcheck.LinkCheckerError, config.read, files) + + def test_confparse_missing(self): + config = linkcheck.configuration.Configuration() + files = [get_file("no_such_config")] + self.assertRaises(linkcheck.LinkCheckerError, config.read, files) diff --git a/tests/test_cookies.py b/tests/test_cookies.py index 78f29bfa..ebe8fc46 100644 --- a/tests/test_cookies.py +++ b/tests/test_cookies.py @@ -18,6 +18,7 @@ Test cookie routines. """ import os +from pathlib import Path import linkcheck.cookies import linkcheck.configuration @@ -80,3 +81,10 @@ class TestCookies(TestBase): aggregate.add_request_session() session = aggregate.get_request_session() self.assertEqual({c.name for c in session.cookies}, {"om", "multiple", "are"}) + + def test_empty_cookie_file(self): + self.assertRaises( + linkcheck.LinkCheckerError, + linkcheck.cookies.from_file, + Path(__file__).parent / "configuration/data/config.empty", + ) diff --git a/tests/test_linkchecker.py b/tests/test_linkchecker.py index e105a848..5ab06832 100644 --- a/tests/test_linkchecker.py +++ b/tests/test_linkchecker.py @@ -40,3 +40,6 @@ class TestLinkchecker(unittest.TestCase): run_with_options([option]) # unknown option self.assertRaises(OSError, run_with_options, ["--imadoofus"]) + # non-existent FILENAMEs + self.assertRaises(OSError, run_with_options, ["--config", "no_such_file"]) + self.assertRaises(OSError, run_with_options, ["--cookiefile", "no_such_file"])