diff --git a/muppet/puppet/strings/__init__.py b/muppet/puppet/strings/__init__.py index 25c0650c18860d1ac0802055b3a8fd9148a89600..fabaf14c048874d76b4c28040fb0f05f1c1cdba0 100644 --- a/muppet/puppet/strings/__init__.py +++ b/muppet/puppet/strings/__init__.py @@ -34,6 +34,7 @@ from typing import ( from dataclasses import dataclass, field import logging from .internal import Deserializable +import re logger = logging.getLogger(__name__) @@ -370,14 +371,42 @@ def puppet_strings(path: str) -> bytes: >>> PuppetStrings.from_json(puppet_strings("/etc/puppetlabs/code/modules/stdlib")) """ - # TODO adding an --out flag (to not stdout) causes warnings to be - # printed to stdout. Warnings - - cmd = subprocess.run('puppet strings generate --format json'.split(' '), - cwd=path, - check=True, - stdout=subprocess.PIPE) - return cmd.stdout + # All this extra weird stuff with tempfiles and pipes since puppet + # strings output errors on stdout, and only if the --out flag + # isn't used. + import tempfile + + tmpfile = tempfile.NamedTemporaryFile() + + cmd = subprocess.Popen( + ['puppet', 'strings', 'generate', + '--format', 'json', + '--out', tmpfile.name], + cwd=path, + stdout=subprocess.PIPE, + text=True, + ) + + if not cmd.stdout: + # TODO better error? + raise Exception(cmd.returncode) + + for line in cmd.stdout: + line = line.strip() + # These debug levels are by best effort, and based on the + # enum found here: + # https://github.com/puppetlabs/puppet-strings/blob/afe75151f8b47ce33433c488e22ca508aa48ac7c/spec/unit/puppet-strings/yard/handlers/ruby/rsapi_handler_spec.rb#L105 + # Expected formatting from observing the output. + if m := re.match(r'^\[(\w+)]: (.*)', line): + match m[1]: + case "debug": logger.debug(m[2]) + case "warn": logger.warning(m[2]) + case "error": logger.error(m[2]) + case _: logger.warning(line) + else: + logger.info(line) + + return tmpfile.read() class HasDocstring(Protocol):