kkonganti@11
|
1 // Hold methods to print:
|
kkonganti@11
|
2 // 1. Colored logo.
|
kkonganti@11
|
3 // 2. Summary of parameters.
|
kkonganti@11
|
4 // 3. Single dashed line.
|
kkonganti@11
|
5 // 4. Double dashed line.
|
kkonganti@11
|
6 //
|
kkonganti@11
|
7
|
kkonganti@11
|
8 import groovy.json.JsonSlurper
|
kkonganti@11
|
9 import nextflow.config.ConfigParser
|
kkonganti@11
|
10 // import groovy.json.JsonOutput
|
kkonganti@11
|
11
|
kkonganti@11
|
12 // ASCII logo
|
kkonganti@11
|
13 def pipelineBanner() {
|
kkonganti@11
|
14
|
kkonganti@11
|
15 def padding = (params.pad) ?: 30
|
kkonganti@11
|
16 Map fgcolors = getANSIColors()
|
kkonganti@11
|
17
|
kkonganti@11
|
18 def banner = [
|
kkonganti@11
|
19 name: "${fgcolors.magenta}${workflow.manifest.name}${fgcolors.reset}",
|
kkonganti@11
|
20 author: "${fgcolors.cyan}${workflow.manifest.author}${fgcolors.reset}",
|
kkonganti@11
|
21 // workflow: "${fgcolors.magenta}${params.pipeline}${fgcolors.reset}",
|
kkonganti@11
|
22 version: "${fgcolors.green}${workflow.manifest.version}${fgcolors.reset}",
|
kkonganti@11
|
23 center: "${fgcolors.green}${params.center}${fgcolors.reset}",
|
kkonganti@11
|
24 pad: padding
|
kkonganti@11
|
25 ]
|
kkonganti@11
|
26
|
kkonganti@11
|
27 manifest = addPadding(banner)
|
kkonganti@11
|
28
|
kkonganti@11
|
29 return """${fgcolors.white}${dashedLine(type: '=')}${fgcolors.magenta}
|
kkonganti@11
|
30 (o)
|
kkonganti@11
|
31 ___ _ __ _ _ __ ___ ___
|
kkonganti@11
|
32 / __|| '_ \\ | || '_ \\ / _ \\/ __|
|
kkonganti@11
|
33 | (__ | |_) || || |_) || __/\\__ \\
|
kkonganti@11
|
34 \\___|| .__/ |_|| .__/ \\___||___/
|
kkonganti@11
|
35 | | | |
|
kkonganti@11
|
36 |_| |_|${fgcolors.reset}
|
kkonganti@11
|
37 ${dashedLine()}
|
kkonganti@11
|
38 ${fgcolors.blue}A collection of modular pipelines at CFSAN, FDA.${fgcolors.reset}
|
kkonganti@11
|
39 ${dashedLine()}
|
kkonganti@11
|
40 ${manifest}
|
kkonganti@11
|
41 ${dashedLine(type: '=')}
|
kkonganti@11
|
42 """.stripIndent()
|
kkonganti@11
|
43 }
|
kkonganti@11
|
44
|
kkonganti@11
|
45 // Add padding to keys so that
|
kkonganti@11
|
46 // they indent nicely on the
|
kkonganti@11
|
47 // terminal
|
kkonganti@11
|
48 def addPadding(values) {
|
kkonganti@11
|
49
|
kkonganti@11
|
50 def pad = (params.pad) ?: 30
|
kkonganti@11
|
51 values.pad = pad
|
kkonganti@11
|
52
|
kkonganti@11
|
53 def padding = values.pad.toInteger()
|
kkonganti@11
|
54 def nocapitalize = values.nocapitalize
|
kkonganti@11
|
55 def stopnow = values.stopNow
|
kkonganti@11
|
56 def help = values.help
|
kkonganti@11
|
57
|
kkonganti@11
|
58 values.removeAll {
|
kkonganti@11
|
59 k, v -> [
|
kkonganti@11
|
60 'nocapitalize',
|
kkonganti@11
|
61 'pad',
|
kkonganti@11
|
62 'stopNow',
|
kkonganti@11
|
63 'help'
|
kkonganti@11
|
64 ].contains(k)
|
kkonganti@11
|
65 }
|
kkonganti@11
|
66
|
kkonganti@11
|
67 values.keySet().each { k ->
|
kkonganti@11
|
68 v = values[k]
|
kkonganti@11
|
69 s = params.linewidth - (pad + 5)
|
kkonganti@11
|
70 if (v.toString().size() > s && !stopnow) {
|
kkonganti@11
|
71 def sen = ''
|
kkonganti@11
|
72 // v.toString().findAll(/.{1,${s}}\b(?:\W*|\s*)/).each {
|
kkonganti@11
|
73 // sen += ' '.multiply(padding + 2) + it + '\n'
|
kkonganti@11
|
74 // }
|
kkonganti@11
|
75 v.toString().eachMatch(/.{1,${s}}(?=.*)\b|\w+/) {
|
kkonganti@11
|
76 sen += ' '.multiply(padding + 2) + it.trim() + '\n'
|
kkonganti@11
|
77 }
|
kkonganti@11
|
78 values[k] = (
|
kkonganti@11
|
79 help ? sen.replaceAll(/^(\n|\s)*/, '') : sen.trim()
|
kkonganti@11
|
80 )
|
kkonganti@11
|
81 } else {
|
kkonganti@11
|
82 values[k] = (help ? v + "\n" : v)
|
kkonganti@11
|
83 }
|
kkonganti@11
|
84 k = k.replaceAll(/\./, '_')
|
kkonganti@11
|
85 }
|
kkonganti@11
|
86
|
kkonganti@11
|
87 return values.findResults {
|
kkonganti@11
|
88 k, v -> nocapitalize ?
|
kkonganti@11
|
89 k.padRight(padding) + ': ' + v :
|
kkonganti@11
|
90 k.capitalize().padRight(padding) + ': ' + v
|
kkonganti@11
|
91 }.join("\n")
|
kkonganti@11
|
92 }
|
kkonganti@11
|
93
|
kkonganti@11
|
94 // Method for error messages
|
kkonganti@11
|
95 def stopNow(msg) {
|
kkonganti@11
|
96
|
kkonganti@11
|
97 Map fgcolors = getANSIColors()
|
kkonganti@11
|
98 Map errors = [:]
|
kkonganti@11
|
99
|
kkonganti@11
|
100 if (msg == null) {
|
kkonganti@11
|
101 msg = "Unknown error"
|
kkonganti@11
|
102 }
|
kkonganti@11
|
103
|
kkonganti@11
|
104 errors['stopNow'] = true
|
kkonganti@11
|
105 errors["${params.cfsanpipename} - ${params.pipeline} - ERROR"] = """
|
kkonganti@11
|
106 ${fgcolors.reset}${dashedLine()}
|
kkonganti@11
|
107 ${fgcolors.red}${msg}${fgcolors.reset}
|
kkonganti@11
|
108 ${dashedLine()}
|
kkonganti@11
|
109 """.stripIndent()
|
kkonganti@11
|
110 // println dashedLine() // defaults to stdout
|
kkonganti@11
|
111 // log.info addPadding(errors) // prints to stdout
|
kkonganti@11
|
112 exit 1, "\n" + dashedLine() +
|
kkonganti@11
|
113 "${fgcolors.red}\n" + addPadding(errors)
|
kkonganti@11
|
114 }
|
kkonganti@11
|
115
|
kkonganti@11
|
116 // Method to validate 4 required parameters
|
kkonganti@11
|
117 // if input for entry point is FASTQ files
|
kkonganti@11
|
118 def validateParamsForFASTQ() {
|
kkonganti@11
|
119 switch (params) {
|
kkonganti@11
|
120 case { params.metadata == null && params.input == null }:
|
kkonganti@11
|
121 stopNow("Either metadata CSV file with 5 required columns\n" +
|
kkonganti@11
|
122 "in order: sample, fq1, fq2, strandedness, single_end or \n" +
|
kkonganti@11
|
123 "input directory of only FASTQ files (gzipped or unzipped) should be provided\n" +
|
kkonganti@11
|
124 "using --metadata or --input options.\n" +
|
kkonganti@11
|
125 "None of these two options were provided!")
|
kkonganti@11
|
126 break
|
kkonganti@11
|
127 case { params.metadata != null && params.input != null }:
|
kkonganti@11
|
128 stopNow("Either metadata or input directory of FASTQ files\n" +
|
kkonganti@11
|
129 "should be provided using --metadata or --input options.\n" +
|
kkonganti@11
|
130 "Using both these options is not allowed!")
|
kkonganti@11
|
131 break
|
kkonganti@11
|
132 case { params.output == null }:
|
kkonganti@11
|
133 stopNow("Please mention output directory to store all results " +
|
kkonganti@11
|
134 "using --output option!")
|
kkonganti@11
|
135 break
|
kkonganti@11
|
136 }
|
kkonganti@11
|
137 return 1
|
kkonganti@11
|
138 }
|
kkonganti@11
|
139
|
kkonganti@11
|
140 // Method to print summary of parameters
|
kkonganti@11
|
141 // before running
|
kkonganti@11
|
142 def summaryOfParams() {
|
kkonganti@11
|
143
|
kkonganti@11
|
144 def pipeline_specific_config = new ConfigParser().setIgnoreIncludes(true).parse(
|
kkonganti@11
|
145 file("${params.workflowsconf}${params.fs}${params.pipeline}.config").text
|
kkonganti@11
|
146 )
|
kkonganti@11
|
147 Map fgcolors = getANSIColors()
|
kkonganti@11
|
148 Map globalparams = [:]
|
kkonganti@11
|
149 Map localparams = params.subMap(
|
kkonganti@11
|
150 pipeline_specific_config.params.keySet().toList() + params.logtheseparams
|
kkonganti@11
|
151 )
|
kkonganti@11
|
152
|
kkonganti@11
|
153 if (localparams !instanceof Map) {
|
kkonganti@11
|
154 stopNow("Need a Map of paramters. We got: " + localparams.getClass())
|
kkonganti@11
|
155 }
|
kkonganti@11
|
156
|
kkonganti@11
|
157 if (localparams.size() != 0) {
|
kkonganti@11
|
158 localparams['nocapitalize'] = true
|
kkonganti@11
|
159 globalparams['nocapitalize'] = true
|
kkonganti@11
|
160 globalparams['nextflow_version'] = "${nextflow.version}"
|
kkonganti@11
|
161 globalparams['nextflow_build'] = "${nextflow.build}"
|
kkonganti@11
|
162 globalparams['nextflow_timestamp'] = "${nextflow.timestamp}"
|
kkonganti@11
|
163 globalparams['workflow_projectDir'] = "${workflow.projectDir}"
|
kkonganti@11
|
164 globalparams['workflow_launchDir'] = "${workflow.launchDir}"
|
kkonganti@11
|
165 globalparams['workflow_workDir'] = "${workflow.workDir}"
|
kkonganti@11
|
166 globalparams['workflow_container'] = "${workflow.container}"
|
kkonganti@11
|
167 globalparams['workflow_containerEngine'] = "${workflow.containerEngine}"
|
kkonganti@11
|
168 globalparams['workflow_runName'] = "${workflow.runName}"
|
kkonganti@11
|
169 globalparams['workflow_sessionId'] = "${workflow.sessionId}"
|
kkonganti@11
|
170 globalparams['workflow_profile'] = "${workflow.profile}"
|
kkonganti@11
|
171 globalparams['workflow_start'] = "${workflow.start}"
|
kkonganti@11
|
172 globalparams['workflow_commandLine'] = "${workflow.commandLine}"
|
kkonganti@11
|
173 return """${dashedLine()}
|
kkonganti@11
|
174 Summary of the current workflow (${fgcolors.magenta}${params.pipeline}${fgcolors.reset}) parameters
|
kkonganti@11
|
175 ${dashedLine()}
|
kkonganti@11
|
176 ${addPadding(localparams)}
|
kkonganti@11
|
177 ${dashedLine()}
|
kkonganti@11
|
178 ${fgcolors.cyan}N E X T F L O W${fgcolors.reset} - ${fgcolors.magenta}${params.cfsanpipename}${fgcolors.reset} - Runtime metadata
|
kkonganti@11
|
179 ${dashedLine()}
|
kkonganti@11
|
180 ${addPadding(globalparams)}
|
kkonganti@11
|
181 ${dashedLine()}""".stripIndent()
|
kkonganti@11
|
182 }
|
kkonganti@11
|
183 return 1
|
kkonganti@11
|
184 }
|
kkonganti@11
|
185
|
kkonganti@11
|
186 // Method to display
|
kkonganti@11
|
187 // Return dashed line either '-'
|
kkonganti@11
|
188 // type or '=' type
|
kkonganti@11
|
189 def dashedLine(Map defaults = [:]) {
|
kkonganti@11
|
190
|
kkonganti@11
|
191 Map fgcolors = getANSIColors()
|
kkonganti@11
|
192 def line = [color: 'white', type: '-']
|
kkonganti@11
|
193
|
kkonganti@11
|
194 if (!defaults.isEmpty()) {
|
kkonganti@11
|
195 line.putAll(defaults)
|
kkonganti@11
|
196 }
|
kkonganti@11
|
197
|
kkonganti@11
|
198 return fgcolors."${line.color}" +
|
kkonganti@11
|
199 "${line.type}".multiply(params.linewidth) +
|
kkonganti@11
|
200 fgcolors.reset
|
kkonganti@11
|
201 }
|
kkonganti@11
|
202
|
kkonganti@11
|
203 // Return slurped keys parsed from JSON
|
kkonganti@11
|
204 def slurpJson(file) {
|
kkonganti@11
|
205 def slurped = null
|
kkonganti@11
|
206 def jsonInst = new JsonSlurper()
|
kkonganti@11
|
207
|
kkonganti@11
|
208 try {
|
kkonganti@11
|
209 slurped = jsonInst.parse(new File ("${file}"))
|
kkonganti@11
|
210 }
|
kkonganti@11
|
211 catch (Exception e) {
|
kkonganti@11
|
212 log.error 'Please check your JSON schema. Invalid JSON file: ' + file
|
kkonganti@11
|
213 }
|
kkonganti@11
|
214
|
kkonganti@11
|
215 // Declare globals for the nanofactory
|
kkonganti@11
|
216 // workflow.
|
kkonganti@11
|
217 return [keys: slurped.keySet().toList(), cparams: slurped]
|
kkonganti@11
|
218 }
|
kkonganti@11
|
219
|
kkonganti@11
|
220 // Default help text in a map if the entry point
|
kkonganti@11
|
221 // to a pipeline is FASTQ files.
|
kkonganti@11
|
222 def fastqEntryPointHelp() {
|
kkonganti@11
|
223
|
kkonganti@11
|
224 Map helptext = [:]
|
kkonganti@11
|
225 Map fgcolors = getANSIColors()
|
kkonganti@11
|
226
|
kkonganti@11
|
227 helptext['Workflow'] = "${fgcolors.magenta}${params.pipeline}${fgcolors.reset}"
|
kkonganti@11
|
228 helptext['Author'] = "${fgcolors.cyan}${params.workflow_built_by}${fgcolors.reset}"
|
kkonganti@11
|
229 helptext['Version'] = "${fgcolors.green}${params.workflow_version}${fgcolors.reset}\n"
|
kkonganti@11
|
230 helptext['Usage'] = "cpipes --pipeline ${params.pipeline} [options]\n"
|
kkonganti@11
|
231 helptext['Required'] = ""
|
kkonganti@11
|
232 helptext['--input'] = "Absolute path to directory containing FASTQ files. " +
|
kkonganti@11
|
233 "The directory should contain only FASTQ files as all the " +
|
kkonganti@11
|
234 "files within the mentioned directory will be read. " +
|
kkonganti@11
|
235 "Ex: --input /path/to/fastq_pass"
|
kkonganti@11
|
236 helptext['--output'] = "Absolute path to directory where all the pipeline " +
|
kkonganti@11
|
237 "outputs should be stored. Ex: --output /path/to/output"
|
kkonganti@11
|
238 helptext['Other options'] = ""
|
kkonganti@11
|
239 helptext['--metadata'] = "Absolute path to metadata CSV file containing five " +
|
kkonganti@11
|
240 "mandatory columns: sample,fq1,fq2,strandedness,single_end. The fq1 and fq2 " +
|
kkonganti@11
|
241 "columns contain absolute paths to the FASTQ files. This option can be used in place " +
|
kkonganti@11
|
242 "of --input option. This is rare. Ex: --metadata samplesheet.csv"
|
kkonganti@11
|
243 helptext['--fq_suffix'] = "The suffix of FASTQ files (Unpaired reads or R1 reads or Long reads) if " +
|
kkonganti@11
|
244 "an input directory is mentioned via --input option. Default: ${params.fq_suffix}"
|
kkonganti@11
|
245 helptext['--fq2_suffix'] = "The suffix of FASTQ files (Paired-end reads or R2 reads) if an input directory is mentioned via " +
|
kkonganti@11
|
246 "--input option. Default: ${params.fq2_suffix}"
|
kkonganti@11
|
247 helptext['--fq_filter_by_len'] = "Remove FASTQ reads that are less than this many bases. " +
|
kkonganti@11
|
248 "Default: ${params.fq_filter_by_len}"
|
kkonganti@11
|
249 helptext['--fq_strandedness'] = "The strandedness of the sequencing run. This is mostly needed " +
|
kkonganti@11
|
250 "if your sequencing run is RNA-SEQ. For most of the other runs, it is probably safe to use " +
|
kkonganti@11
|
251 "unstranded for the option. Default: ${params.fq_strandedness}"
|
kkonganti@11
|
252 helptext['--fq_single_end'] = "SINGLE-END information will be auto-detected but this option forces " +
|
kkonganti@11
|
253 "PAIRED-END FASTQ files to be treated as SINGLE-END so only read 1 information is included in " +
|
kkonganti@11
|
254 "auto-generated samplesheet. Default: ${params.fq_single_end}"
|
kkonganti@11
|
255 helptext['--fq_filename_delim'] = "Delimiter by which the file name is split to obtain sample name. " +
|
kkonganti@11
|
256 "Default: ${params.fq_filename_delim}"
|
kkonganti@11
|
257 helptext['--fq_filename_delim_idx'] = "After splitting FASTQ file name by using the --fq_filename_delim option," +
|
kkonganti@11
|
258 " all elements before this index (1-based) will be joined to create final sample name." +
|
kkonganti@11
|
259 " Default: ${params.fq_filename_delim_idx}"
|
kkonganti@11
|
260
|
kkonganti@11
|
261 return helptext
|
kkonganti@11
|
262 }
|
kkonganti@11
|
263
|
kkonganti@11
|
264 // Show concise help text if configured within the main workflow.
|
kkonganti@11
|
265 def conciseHelp(def tool = null) {
|
kkonganti@11
|
266 Map fgcolors = getANSIColors()
|
kkonganti@11
|
267
|
kkonganti@11
|
268 tool ?= "fastp"
|
kkonganti@11
|
269 tools = tool?.tokenize(',')
|
kkonganti@11
|
270
|
kkonganti@11
|
271 return """
|
kkonganti@11
|
272 ${dashedLine()}
|
kkonganti@11
|
273 Show configurable CLI options for each tool within ${fgcolors.magenta}${params.pipeline}${fgcolors.reset}
|
kkonganti@11
|
274 ${dashedLine()}
|
kkonganti@11
|
275 Ex: cpipes --pipeline ${params.pipeline} --help
|
kkonganti@11
|
276 """ + (tools.size() > 1 ? "Ex: cpipes --pipeline ${params.pipeline} --help ${tools[0]}"
|
kkonganti@11
|
277 + """
|
kkonganti@11
|
278 Ex: cpipes --pipeline ${params.pipeline} --help ${tools[0]},${tools[1]}
|
kkonganti@11
|
279 ${dashedLine()}""".stripIndent() : """Ex: cpipes --pipeline ${params.pipeline} --help ${tool}
|
kkonganti@11
|
280 ${dashedLine()}""".stripIndent())
|
kkonganti@11
|
281
|
kkonganti@11
|
282 }
|
kkonganti@11
|
283
|
kkonganti@11
|
284 // Wrap help text with the following options
|
kkonganti@11
|
285 def wrapUpHelp() {
|
kkonganti@11
|
286
|
kkonganti@11
|
287 return [
|
kkonganti@11
|
288 'Help options' : "",
|
kkonganti@11
|
289 '--help': "Display this message.\n",
|
kkonganti@11
|
290 'help': true,
|
kkonganti@11
|
291 'nocapitalize': true
|
kkonganti@11
|
292 ]
|
kkonganti@11
|
293 }
|
kkonganti@11
|
294
|
kkonganti@11
|
295 // Method to send email on workflow complete.
|
kkonganti@11
|
296 def sendMail() {
|
kkonganti@11
|
297
|
kkonganti@11
|
298 if (params.user_email == null) {
|
kkonganti@11
|
299 return 1
|
kkonganti@11
|
300 }
|
kkonganti@11
|
301
|
kkonganti@11
|
302 def pad = (params.pad) ?: 30
|
kkonganti@11
|
303 def contact_emails = [
|
kkonganti@11
|
304 stakeholder: (params.workflow_blueprint_by ?: 'Not defined'),
|
kkonganti@11
|
305 author: (params.workflow_built_by ?: 'Not defined')
|
kkonganti@11
|
306 ]
|
kkonganti@11
|
307 def msg = """
|
kkonganti@11
|
308 ${pipelineBanner()}
|
kkonganti@11
|
309 ${summaryOfParams()}
|
kkonganti@11
|
310 ${params.cfsanpipename} - ${params.pipeline}
|
kkonganti@11
|
311 ${dashedLine()}
|
kkonganti@11
|
312 Please check the following directory for N E X T F L O W
|
kkonganti@11
|
313 reports. You can view the HTML files directly by double clicking
|
kkonganti@11
|
314 them on your workstation.
|
kkonganti@11
|
315 ${dashedLine()}
|
kkonganti@11
|
316 ${params.tracereportsdir}
|
kkonganti@11
|
317 ${dashedLine()}
|
kkonganti@11
|
318 Please send any bug reports to CFSAN Dev Team or the author or
|
kkonganti@11
|
319 the stakeholder of the current pipeline.
|
kkonganti@11
|
320 ${dashedLine()}
|
kkonganti@11
|
321 Error messages (if any)
|
kkonganti@11
|
322 ${dashedLine()}
|
kkonganti@11
|
323 ${workflow.errorMessage}
|
kkonganti@11
|
324 ${workflow.errorReport}
|
kkonganti@11
|
325 ${dashedLine()}
|
kkonganti@11
|
326 Contact emails
|
kkonganti@11
|
327 ${dashedLine()}
|
kkonganti@11
|
328 ${addPadding(contact_emails)}
|
kkonganti@11
|
329 ${dashedLine()}
|
kkonganti@11
|
330 Thank you for using ${params.cfsanpipename} - ${params.pipeline}!
|
kkonganti@11
|
331 ${dashedLine()}
|
kkonganti@11
|
332 """.stripIndent()
|
kkonganti@11
|
333
|
kkonganti@11
|
334 def mail_cmd = [
|
kkonganti@11
|
335 'sendmail',
|
kkonganti@11
|
336 '-f', 'noreply@gmail.com',
|
kkonganti@11
|
337 '-F', 'noreply',
|
kkonganti@11
|
338 '-t', "${params.user_email}"
|
kkonganti@11
|
339 ]
|
kkonganti@11
|
340
|
kkonganti@11
|
341 def email_subject = "${params.cfsanpipename} - ${params.pipeline}"
|
kkonganti@11
|
342 Map fgcolors = getANSIColors()
|
kkonganti@11
|
343
|
kkonganti@11
|
344 if (workflow.success) {
|
kkonganti@11
|
345 email_subject += ' completed successfully!'
|
kkonganti@11
|
346 }
|
kkonganti@11
|
347 else if (!workflow.success) {
|
kkonganti@11
|
348 email_subject += ' has failed!'
|
kkonganti@11
|
349 }
|
kkonganti@11
|
350
|
kkonganti@11
|
351 try {
|
kkonganti@11
|
352 ['env', 'bash'].execute() << """${mail_cmd.join(' ')}
|
kkonganti@11
|
353 Subject: ${email_subject}
|
kkonganti@11
|
354 Mime-Version: 1.0
|
kkonganti@11
|
355 Content-Type: text/html
|
kkonganti@11
|
356 <pre>
|
kkonganti@11
|
357 ${msg.replaceAll(/\x1b\[[0-9;]*m/, '')}
|
kkonganti@11
|
358 </pre>
|
kkonganti@11
|
359 """.stripIndent()
|
kkonganti@11
|
360 } catch (all) {
|
kkonganti@11
|
361 def warning_msg = "${fgcolors.yellow}${params.cfsanpipename} - ${params.pipeline} - WARNING"
|
kkonganti@11
|
362 .padRight(pad) + ':'
|
kkonganti@11
|
363 log.info """
|
kkonganti@11
|
364 ${dashedLine()}
|
kkonganti@11
|
365 ${warning_msg}
|
kkonganti@11
|
366 ${dashedLine()}
|
kkonganti@11
|
367 Could not send mail with the sendmail command!
|
kkonganti@11
|
368 ${dashedLine()}
|
kkonganti@11
|
369 """.stripIndent()
|
kkonganti@11
|
370 }
|
kkonganti@11
|
371 return 1
|
kkonganti@11
|
372 }
|
kkonganti@11
|
373
|
kkonganti@11
|
374 // Set ANSI colors for any and all
|
kkonganti@11
|
375 // STDOUT or STDERR
|
kkonganti@11
|
376 def getANSIColors() {
|
kkonganti@11
|
377
|
kkonganti@11
|
378 Map fgcolors = [:]
|
kkonganti@11
|
379
|
kkonganti@11
|
380 fgcolors['reset'] = "\033[0m"
|
kkonganti@11
|
381 fgcolors['black'] = "\033[0;30m"
|
kkonganti@11
|
382 fgcolors['red'] = "\033[0;31m"
|
kkonganti@11
|
383 fgcolors['green'] = "\033[0;32m"
|
kkonganti@11
|
384 fgcolors['yellow'] = "\033[0;33m"
|
kkonganti@11
|
385 fgcolors['blue'] = "\033[0;34m"
|
kkonganti@11
|
386 fgcolors['magenta'] = "\033[0;35m"
|
kkonganti@11
|
387 fgcolors['cyan'] = "\033[0;36m"
|
kkonganti@11
|
388 fgcolors['white'] = "\033[0;37m"
|
kkonganti@11
|
389
|
kkonganti@11
|
390 return fgcolors
|
kkonganti@11
|
391 }
|