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