Test Failed
Branch feature/user-customizations (24e3d3)
by Shalom
03:23
created

inji.cli.cli_args()   B

Complexity

Conditions 5

Size

Total Lines 47
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 33
dl 0
loc 47
rs 8.6213
c 0
b 0
f 0
cc 5
nop 0
1
#!/usr/bin/env python3
2
3
# -*- coding: utf-8 -*-
4
5
# NAME
6
7
# inji - Render jina2 templates to stdout
8
9
import argparse
10
import atexit
11
import fnmatch
12
import json
13
import locale
14
import os
15
from setproctitle import setproctitle
16
import shutil
17
import signal
18
import sys
19
import tempfile
20
21
from .engine import TemplateEngine
22
from . import utils
23
24
def cli_args():
25
  parser = argparse.ArgumentParser(
26
      description='inji - render jinja templates'
27
    )
28
  required = parser.add_argument_group('required arguments')
29
30
  required.add_argument('-t', '-f', '--template',
31
    action = 'store',  required=False, type=utils.file_or_stdin,
32
    dest='template', default='-',
33
    help='/path/to/template.j2 (defaults to -)'
34
  )
35
36
  parser.add_argument('-j', '--json-config', '-c',
37
    action = 'store', required=False,
38
    type=lambda x: utils.json_parse(x),
39
    dest='json_string',
40
    help="-c '{ \"foo\": \"bar\", \"fred\": \"wilma\" }'"
41
  )
42
43
  parser.add_argument('-k', '--kv-config', '-d',
44
    action = 'store', required=False,
45
    type=lambda x: utils.kv_parse(x),
46
    dest='kv_pair',
47
    help='-d foo=bar -d fred=wilma'
48
  )
49
50
  parser.add_argument('-o', '--overlay-dir',
51
    action = 'append', required=False, type=lambda p, t='dir': utils.path(p, t),
52
    dest='overlay_dir', default=[],
53
    help='/path/to/overlay/'
54
  )
55
56
  parser.add_argument('-v', '-p', '--vars-file', '--vars',
57
    action = 'append', required=False, type=lambda p, t='file': utils.path(p, t),
58
    dest='vars_file', default=[],
59
    help='/path/to/vars.yaml'
60
  )
61
62
  parser.add_argument('--strict-mode', '-s',
63
    action = 'store', required=False, type=str,
64
    dest='undefined_variables_mode', default='strict',
65
    choices=[ 'strict', 'empty', 'keep',
66
              'StrictUndefined', 'Undefined', 'DebugUndefined' ],
67
    help='Refer to http://jinja.pocoo.org/docs/2.10/api/#undefined-types'
68
  )
69
70
  return parser.parse_args()
71
72
73
def sigint_handler(signum, frame):  # pragma: no cover # despite being covered
74
  """ Handle SIGINT, ctrl-c gracefully """
75
  signal.signal(signum, signal.SIG_IGN) # ignore subsequent ctrl-c's
76
  sys.exit( 128 + signal.SIGINT )       # 130 by convention
77
78
def main():
79
  """ Our main method """
80
81
  # cleanly handle ctrl-c's
82
  signal.signal(signal.SIGINT, sigint_handler)
83
84
  # set process name
85
  setproctitle('inji')
86
87
  args = cli_args()
88
89
  # this holds all the possible vars files we are told about or imply
90
  vars_files = []
91
92
  # context in the local configuration files - p5
93
  vars_files += fnmatch.filter(os.listdir('.'), "*inji.y*ml")
94
95
  # context in the overlay directories - p4
96
  for d in args.overlay_dir:
97
    files = list(utils.recursive_iglob(d, '*.y*ml'))
98
    if len(files):
99
      loc = locale.getlocale()
100
      locale.setlocale(locale.LC_ALL, 'C') # Using LC_ALL=C POSIX locale
101
      files.sort()                         # We force the sort collation of files
102
      locale.setlocale(locale.LC_ALL, loc) # And then reset it back
103
      vars_files += files
104
105
  # context from named vars files - p3
106
  vars_files += args.vars_file
107
108
  # This will hold the final vars dict merged from various available sources
109
  context = {}
110
  for file in vars_files:
111
    context.update(utils.read_context(file))
112
113
  # context from environment variables - p2
114
  context.update(os.environ)
115
116
  # context at the command line (either JSON or KV type) - p1
117
  if args.json_string:
118
    context.update(args.json_string)
119
120
  if args.kv_pair:
121
    context.update(args.kv_pair)
122
123
  if args.template == '-':
124
    # Template passed in via stdin. Create template as a tempfile and use it
125
    # instead but since includes are possible (though not likely), we have to do
126
    # this in an isolated tmpdir container to prevent inadvertent reading of
127
    # includes not meant to be read.
128
    tmpdir = tempfile.mkdtemp()
129
    atexit.register(shutil.rmtree, tmpdir)
130
131
    _, tmpfile = tempfile.mkstemp(prefix='stdin-', dir=tmpdir, text=True)
132
    atexit.register(os.remove, tmpfile)
133
134
    with open(tmpfile, "a+") as f:
135
      f.write(sys.stdin.read())
136
    args.template = tmpfile
137
138
  engine = TemplateEngine( undefined_variables_mode_behaviour=args.undefined_variables_mode )
139
  for block in engine.render( template=args.template,
140
                              context=context,
141
                            ):
142
    print(block)
143