Test Failed
Branch feature/user-customizations (ad1d9d)
by Shalom
06:11 queued 02:27
created

inji.cli.pkg_location()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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