|
| 1 | +"""``hcl2tojson`` CLI entry point — convert HCL2 files to JSON.""" |
| 2 | +import argparse |
| 3 | +import json |
| 4 | +import os |
| 5 | +from typing import IO, Optional, TextIO |
| 6 | + |
| 7 | +from hcl2 import load |
| 8 | +from hcl2.utils import SerializationOptions |
| 9 | +from hcl2.version import __version__ |
| 10 | +from .helpers import ( |
| 11 | + HCL_SKIPPABLE, |
| 12 | + _convert_single_file, |
| 13 | + _convert_directory, |
| 14 | + _convert_stdin, |
| 15 | +) |
| 16 | + |
| 17 | + |
| 18 | +def _hcl_to_json( |
| 19 | + in_file: TextIO, |
| 20 | + out_file: IO, |
| 21 | + options: SerializationOptions, |
| 22 | + json_indent: Optional[int] = None, |
| 23 | +) -> None: |
| 24 | + data = load(in_file, serialization_options=options) |
| 25 | + json.dump(data, out_file, indent=json_indent) |
| 26 | + |
| 27 | + |
| 28 | +def main(): |
| 29 | + """The ``hcl2tojson`` console_scripts entry point.""" |
| 30 | + parser = argparse.ArgumentParser( |
| 31 | + description="Convert HCL2 files to JSON", |
| 32 | + ) |
| 33 | + parser.add_argument( |
| 34 | + "-s", dest="skip", action="store_true", help="Skip un-parsable files" |
| 35 | + ) |
| 36 | + parser.add_argument( |
| 37 | + "PATH", |
| 38 | + help='The file or directory to convert (use "-" for stdin)', |
| 39 | + ) |
| 40 | + parser.add_argument( |
| 41 | + "OUT_PATH", |
| 42 | + nargs="?", |
| 43 | + help="The path to write output to. Optional for single file (defaults to stdout)", |
| 44 | + ) |
| 45 | + parser.add_argument("--version", action="version", version=__version__) |
| 46 | + |
| 47 | + # SerializationOptions flags |
| 48 | + parser.add_argument( |
| 49 | + "--with-meta", |
| 50 | + action="store_true", |
| 51 | + help="Add meta parameters like __start_line__ and __end_line__", |
| 52 | + ) |
| 53 | + parser.add_argument( |
| 54 | + "--with-comments", |
| 55 | + action="store_true", |
| 56 | + help="Include comments in the output", |
| 57 | + ) |
| 58 | + parser.add_argument( |
| 59 | + "--wrap-objects", |
| 60 | + action="store_true", |
| 61 | + help="Wrap object values as an inline HCL2", |
| 62 | + ) |
| 63 | + parser.add_argument( |
| 64 | + "--wrap-tuples", |
| 65 | + action="store_true", |
| 66 | + help="Wrap tuple values an inline HCL2", |
| 67 | + ) |
| 68 | + parser.add_argument( |
| 69 | + "--no-explicit-blocks", |
| 70 | + action="store_true", |
| 71 | + help="Disable explicit block markers", |
| 72 | + ) |
| 73 | + parser.add_argument( |
| 74 | + "--no-preserve-heredocs", |
| 75 | + action="store_true", |
| 76 | + help="Convert heredocs to plain strings", |
| 77 | + ) |
| 78 | + parser.add_argument( |
| 79 | + "--force-parens", |
| 80 | + action="store_true", |
| 81 | + help="Force parentheses around all operations", |
| 82 | + ) |
| 83 | + parser.add_argument( |
| 84 | + "--no-preserve-scientific", |
| 85 | + action="store_true", |
| 86 | + help="Convert scientific notation to standard floats", |
| 87 | + ) |
| 88 | + |
| 89 | + # JSON output formatting |
| 90 | + parser.add_argument( |
| 91 | + "--json-indent", |
| 92 | + type=int, |
| 93 | + default=2, |
| 94 | + metavar="N", |
| 95 | + help="JSON indentation width (default: 2)", |
| 96 | + ) |
| 97 | + |
| 98 | + args = parser.parse_args() |
| 99 | + |
| 100 | + options = SerializationOptions( |
| 101 | + with_meta=args.with_meta, |
| 102 | + with_comments=args.with_comments, |
| 103 | + wrap_objects=args.wrap_objects, |
| 104 | + wrap_tuples=args.wrap_tuples, |
| 105 | + explicit_blocks=not args.no_explicit_blocks, |
| 106 | + preserve_heredocs=not args.no_preserve_heredocs, |
| 107 | + force_operation_parentheses=args.force_parens, |
| 108 | + preserve_scientific_notation=not args.no_preserve_scientific, |
| 109 | + ) |
| 110 | + json_indent = args.json_indent |
| 111 | + |
| 112 | + def convert(in_file, out_file): |
| 113 | + _hcl_to_json(in_file, out_file, options, json_indent=json_indent) |
| 114 | + |
| 115 | + if args.PATH == "-": |
| 116 | + _convert_stdin(convert) |
| 117 | + elif os.path.isfile(args.PATH): |
| 118 | + _convert_single_file( |
| 119 | + args.PATH, args.OUT_PATH, convert, args.skip, HCL_SKIPPABLE |
| 120 | + ) |
| 121 | + elif os.path.isdir(args.PATH): |
| 122 | + _convert_directory( |
| 123 | + args.PATH, |
| 124 | + args.OUT_PATH, |
| 125 | + convert, |
| 126 | + args.skip, |
| 127 | + HCL_SKIPPABLE, |
| 128 | + in_extensions={".tf", ".hcl"}, |
| 129 | + out_extension=".json", |
| 130 | + ) |
| 131 | + else: |
| 132 | + raise RuntimeError(f"Invalid Path: {args.PATH}") |
0 commit comments