blob: 29f471f71405d3682ab15dd6d51a53ebbe6af30f [file] [log] [blame]
Sergey Kolekonovba203982016-12-21 18:32:17 +04001package com.mirantis.mk
2
3/**
4 *
5 * Python functions
6 *
7 */
8
9/**
10 * Install python virtualenv
11 *
Vladislav Naumov11103862017-07-19 17:02:39 +030012 * @param path Path to virtualenv
13 * @param python Version of Python (python/python3)
14 * @param reqs Environment requirements in list format
15 * @param reqs_path Environment requirements path in str format
Sergey Kolekonovba203982016-12-21 18:32:17 +040016 */
Tomáš Kukrál69c25452017-07-27 14:59:40 +020017def setupVirtualenv(path, python = 'python2', reqs=[], reqs_path=null, clean=false) {
18 def common = new com.mirantis.mk.Common()
19
Jakub Josef068f0be2017-04-18 14:34:59 +020020 def virtualenv_cmd = "virtualenv ${path} --python ${python}"
Tomáš Kukrál69c25452017-07-27 14:59:40 +020021
22 if (clean) {
23 common.infoMsg("Cleaning venv directory " + path)
24 sh("rm -rf \"${path}\"")
25 }
26
27 common.infoMsg("[Python ${path}] Setup ${python} environment")
Sergey Kolekonovba203982016-12-21 18:32:17 +040028 sh(returnStdout: true, script: virtualenv_cmd)
Vladislav Naumov11103862017-07-19 17:02:39 +030029 if (reqs_path==null) {
30 def args = ""
31 for (req in reqs) {
32 args = args + "${req}\n"
33 }
34 writeFile file: "${path}/requirements.txt", text: args
35 reqs_path = "${path}/requirements.txt"
Sergey Kolekonovba203982016-12-21 18:32:17 +040036 }
Vladislav Naumov11103862017-07-19 17:02:39 +030037 runVirtualenvCommand(path, "pip install -r ${reqs_path}")
Sergey Kolekonovba203982016-12-21 18:32:17 +040038}
39
40/**
41 * Run command in specific python virtualenv
42 *
43 * @param path Path to virtualenv
44 * @param cmd Command to be executed
45 */
46def runVirtualenvCommand(path, cmd) {
Tomáš Kukrál69c25452017-07-27 14:59:40 +020047 def common = new com.mirantis.mk.Common()
48
Jakub Josef0164dc12017-03-28 16:33:46 +020049 virtualenv_cmd = ". ${path}/bin/activate > /dev/null; ${cmd}"
Tomáš Kukrál69c25452017-07-27 14:59:40 +020050 common.infoMsg("[Python ${path}] Run command ${cmd}")
Sergey Kolekonovba203982016-12-21 18:32:17 +040051 output = sh(
52 returnStdout: true,
53 script: virtualenv_cmd
54 ).trim()
55 return output
56}
57
Ales Komarekd874d482016-12-26 10:33:29 +010058
59/**
60 * Install docutils in isolated environment
61 *
62 * @param path Path where virtualenv is created
63 */
64def setupDocutilsVirtualenv(path) {
65 requirements = [
66 'docutils',
67 ]
68 setupVirtualenv(path, 'python2', requirements)
69}
70
71
Sergey Kolekonovba203982016-12-21 18:32:17 +040072@NonCPS
73def loadJson(rawData) {
74 return new groovy.json.JsonSlurperClassic().parseText(rawData)
75}
76
77/**
78 * Parse content from markup-text tables to variables
79 *
80 * @param tableStr String representing the table
81 * @param mode Either list (1st row are keys) or item (key, value rows)
82 * @param format Format of the table
83 */
Ales Komarekd874d482016-12-26 10:33:29 +010084def parseTextTable(tableStr, type = 'item', format = 'rest', path = none) {
Ales Komarek0e558ee2016-12-23 13:02:55 +010085 parserFile = "${env.WORKSPACE}/textTableParser.py"
86 parserScript = """import json
87import argparse
88from docutils.parsers.rst import tableparser
89from docutils import statemachine
90
91def parse_item_table(raw_data):
92 i = 1
93 pretty_raw_data = []
94 for datum in raw_data:
95 if datum != "":
96 if datum[3] != ' ' and i > 4:
97 pretty_raw_data.append(raw_data[0])
98 if i == 3:
99 pretty_raw_data.append(datum.replace('-', '='))
100 else:
101 pretty_raw_data.append(datum)
102 i += 1
103 parser = tableparser.GridTableParser()
104 block = statemachine.StringList(pretty_raw_data)
105 docutils_data = parser.parse(block)
106 final_data = {}
107 for line in docutils_data[2]:
108 key = ' '.join(line[0][3]).strip()
109 value = ' '.join(line[1][3]).strip()
110 if key != "":
111 try:
112 value = json.loads(value)
113 except:
114 pass
115 final_data[key] = value
116 i+=1
117 return final_data
118
119def parse_list_table(raw_data):
120 i = 1
121 pretty_raw_data = []
122 for datum in raw_data:
123 if datum != "":
124 if datum[3] != ' ' and i > 4:
125 pretty_raw_data.append(raw_data[0])
126 if i == 3:
127 pretty_raw_data.append(datum.replace('-', '='))
128 else:
129 pretty_raw_data.append(datum)
130 i += 1
131 parser = tableparser.GridTableParser()
132 block = statemachine.StringList(pretty_raw_data)
133 docutils_data = parser.parse(block)
134 final_data = []
135 keys = []
136 for line in docutils_data[1]:
137 for item in line:
138 keys.append(' '.join(item[3]).strip())
139 for line in docutils_data[2]:
140 final_line = {}
141 key = ' '.join(line[0][3]).strip()
142 value = ' '.join(line[1][3]).strip()
143 if key != "":
144 try:
145 value = json.loads(value)
146 except:
147 pass
148 final_data[key] = value
149 i+=1
150 return final_data
151
152def parse_list_table(raw_data):
153 i = 1
154 pretty_raw_data = []
155 for datum in raw_data:
156 if datum != "":
157 if datum[3] != ' ' and i > 4:
158 pretty_raw_data.append(raw_data[0])
159 if i == 3:
160 pretty_raw_data.append(datum.replace('-', '='))
161 else:
162 pretty_raw_data.append(datum)
163 i += 1
164 parser = tableparser.GridTableParser()
165 block = statemachine.StringList(pretty_raw_data)
166 docutils_data = parser.parse(block)
167 final_data = []
168 keys = []
169 for line in docutils_data[1]:
170 for item in line:
171 keys.append(' '.join(item[3]).strip())
172 for line in docutils_data[2]:
173 final_line = {}
174 i = 0
175 for item in line:
176 value = ' '.join(item[3]).strip()
177 try:
178 value = json.loads(value)
179 except:
180 pass
181 final_line[keys[i]] = value
182 i += 1
183 final_data.append(final_line)
184 return final_data
185
186def read_table_file(file):
187 table_file = open(file, 'r')
Ales Komarekc000c152016-12-23 15:32:54 +0100188 raw_data = table_file.read().split('\\n')
Ales Komarek0e558ee2016-12-23 13:02:55 +0100189 table_file.close()
190 return raw_data
191
192parser = argparse.ArgumentParser()
193parser.add_argument('-f','--file', help='File with table data', required=True)
194parser.add_argument('-t','--type', help='Type of table (list/item)', required=True)
195args = vars(parser.parse_args())
196
197raw_data = read_table_file(args['file'])
198
199if args['type'] == 'list':
200 final_data = parse_list_table(raw_data)
201else:
202 final_data = parse_item_table(raw_data)
203
204print json.dumps(final_data)
205"""
206 writeFile file: parserFile, text: parserScript
Sergey Kolekonovba203982016-12-21 18:32:17 +0400207 tableFile = "${env.WORKSPACE}/prettytable.txt"
208 writeFile file: tableFile, text: tableStr
Ales Komarekd874d482016-12-26 10:33:29 +0100209
210 cmd = "python ${parserFile} --file '${tableFile}' --type ${type}"
211 if (path) {
Ales Komarekc6d28dd2016-12-28 12:59:38 +0100212 rawData = runVirtualenvCommand(path, cmd)
Ales Komarekd874d482016-12-26 10:33:29 +0100213 }
214 else {
215 rawData = sh (
216 script: cmd,
217 returnStdout: true
218 ).trim()
219 }
Sergey Kolekonovba203982016-12-21 18:32:17 +0400220 data = loadJson(rawData)
221 echo("[Parsed table] ${data}")
222 return data
223}
224
225/**
226 * Install cookiecutter in isolated environment
227 *
228 * @param path Path where virtualenv is created
229 */
230def setupCookiecutterVirtualenv(path) {
231 requirements = [
232 'cookiecutter',
Jakub Josef4df78272017-04-26 14:36:36 +0200233 'jinja2==2.8.1',
234 'PyYAML==3.12'
Sergey Kolekonovba203982016-12-21 18:32:17 +0400235 ]
236 setupVirtualenv(path, 'python2', requirements)
237}
238
239/**
240 * Generate the cookiecutter templates with given context
241 *
Jakub Josef4e10c372017-04-26 14:13:50 +0200242 * @param template template
243 * @param context template context
244 * @param path Path where virtualenv is created (optional)
245 * @param templatePath path to cookiecutter template repo (optional)
Sergey Kolekonovba203982016-12-21 18:32:17 +0400246 */
Jakub Josef4e10c372017-04-26 14:13:50 +0200247def buildCookiecutterTemplate(template, context, outputDir = '.', path = null, templatePath = ".") {
Tomáš Kukráldad7b462017-03-27 13:53:05 +0200248 configFile = "default_config.yaml"
249 configString = "default_context:\n"
Tomáš Kukrál6de85042017-04-12 17:49:05 +0200250 writeFile file: configFile, text: context
Jakub Josef4e61cc02017-04-26 14:29:09 +0200251 command = ". ${path}/bin/activate; if [ -f ${templatePath}/generate.py ]; then python ${templatePath}/generate.py --config-file ${configFile} --template ${template} --output-dir ${outputDir}; else cookiecutter --config-file ${configFile} --output-dir ${outputDir} --overwrite-if-exists --verbose --no-input ${template}; fi"
Sergey Kolekonovba203982016-12-21 18:32:17 +0400252 output = sh (returnStdout: true, script: command)
253 echo("[Cookiecutter build] Output: ${output}")
254}
255
256/**
257 * Install jinja rendering in isolated environment
258 *
259 * @param path Path where virtualenv is created
260 */
261def setupJinjaVirtualenv(path) {
262 requirements = [
263 'jinja2-cli',
264 'pyyaml',
265 ]
266 setupVirtualenv(path, 'python2', requirements)
267}
268
269/**
270 * Generate the Jinja templates with given context
271 *
272 * @param path Path where virtualenv is created
273 */
274def jinjaBuildTemplate (template, context, path = none) {
275 contextFile = "jinja_context.yml"
276 contextString = ""
277 for (parameter in context) {
278 contextString = "${contextString}${parameter.key}: ${parameter.value}\n"
279 }
280 writeFile file: contextFile, text: contextString
281 cmd = "jinja2 ${template} ${contextFile} --format=yaml"
282 data = sh (returnStdout: true, script: cmd)
283 echo(data)
284 return data
285}
Oleg Grigorovbec45582017-09-12 20:29:24 +0300286
287/**
288 * Install salt-pepper in isolated environment
289 *
290 * @param path Path where virtualenv is created
291 */
292def setupPepperVirtualenv(path) {
293 requirements = ['salt-pepper']
294 setupVirtualenv(path, 'python2', requirements)
295}