-
Notifications
You must be signed in to change notification settings - Fork 193
/
Copy pathNfcoreTemplate.groovy
executable file
·258 lines (231 loc) · 12.7 KB
/
NfcoreTemplate.groovy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
//
// This file holds several functions used within the nf-core pipeline template.
//
import org.yaml.snakeyaml.Yaml
class NfcoreTemplate {
//
// Check AWS Batch related parameters have been specified correctly
//
public static void awsBatch(workflow, params) {
if (workflow.profile.contains('awsbatch')) {
// Check params.awsqueue and params.awsregion have been set if running on AWSBatch
assert (params.awsqueue && params.awsregion) : "Specify correct --awsqueue and --awsregion parameters on AWSBatch!"
// Check outdir paths to be S3 buckets if running on AWSBatch
assert params.outdir.startsWith('s3:') : "Outdir not on S3 - specify S3 Bucket to run on AWSBatch!"
}
}
//
// Warn if a -profile or Nextflow config has not been provided to run the pipeline
//
public static void checkConfigProvided(workflow, log) {
if (workflow.profile == 'standard' && workflow.configFiles.size() <= 1) {
log.warn "[$workflow.manifest.name] You are attempting to run the pipeline without any custom configuration!\n\n" +
"This will be dependent on your local compute environment but can be achieved via one or more of the following:\n" +
" (1) Using an existing pipeline profile e.g. `-profile docker` or `-profile singularity`\n" +
" (2) Using an existing nf-core/configs for your Institution e.g. `-profile crick` or `-profile uppmax`\n" +
" (3) Using your own local custom config e.g. `-c /path/to/your/custom.config`\n\n" +
"Please refer to the quick start section and usage docs for the pipeline.\n "
}
}
//
// Construct and send completion email
//
public static void email(workflow, params, summary_params, projectDir, log, multiqc_report=[]) {
// Set up the e-mail variables
def subject = "[$workflow.manifest.name] Successful: $workflow.runName"
if (!workflow.success) {
subject = "[$workflow.manifest.name] FAILED: $workflow.runName"
}
def summary = [:]
for (group in summary_params.keySet()) {
summary << summary_params[group]
}
def misc_fields = [:]
misc_fields['Date Started'] = workflow.start
misc_fields['Date Completed'] = workflow.complete
misc_fields['Pipeline script file path'] = workflow.scriptFile
misc_fields['Pipeline script hash ID'] = workflow.scriptId
if (workflow.repository) misc_fields['Pipeline repository Git URL'] = workflow.repository
if (workflow.commitId) misc_fields['Pipeline repository Git Commit'] = workflow.commitId
if (workflow.revision) misc_fields['Pipeline Git branch/tag'] = workflow.revision
misc_fields['Nextflow Version'] = workflow.nextflow.version
misc_fields['Nextflow Build'] = workflow.nextflow.build
misc_fields['Nextflow Compile Timestamp'] = workflow.nextflow.timestamp
def email_fields = [:]
email_fields['version'] = workflow.manifest.version
email_fields['runName'] = workflow.runName
email_fields['success'] = workflow.success
email_fields['dateComplete'] = workflow.complete
email_fields['duration'] = workflow.duration
email_fields['exitStatus'] = workflow.exitStatus
email_fields['errorMessage'] = (workflow.errorMessage ?: 'None')
email_fields['errorReport'] = (workflow.errorReport ?: 'None')
email_fields['commandLine'] = workflow.commandLine
email_fields['projectDir'] = workflow.projectDir
email_fields['summary'] = summary << misc_fields
// On success try attach the multiqc report
def mqc_report = null
try {
if (workflow.success) {
mqc_report = multiqc_report.getVal()
if (mqc_report.getClass() == ArrayList && mqc_report.size() >= 1) {
if (mqc_report.size() > 1) {
log.warn "[$workflow.manifest.name] Found multiple reports from process 'MULTIQC', will use only one"
}
mqc_report = mqc_report[0]
}
}
} catch (all) {
if (multiqc_report) {
log.warn "[$workflow.manifest.name] Could not attach MultiQC report to summary email"
}
}
// Check if we are only sending emails on failure
def email_address = params.email
if (!params.email && params.email_on_fail && !workflow.success) {
email_address = params.email_on_fail
}
// Render the TXT template
def engine = new groovy.text.GStringTemplateEngine()
def tf = new File("$projectDir/assets/email_template.txt")
def txt_template = engine.createTemplate(tf).make(email_fields)
def email_txt = txt_template.toString()
// Render the HTML template
def hf = new File("$projectDir/assets/email_template.html")
def html_template = engine.createTemplate(hf).make(email_fields)
def email_html = html_template.toString()
// Render the sendmail template
def max_multiqc_email_size = params.max_multiqc_email_size as nextflow.util.MemoryUnit
def smail_fields = [ email: email_address, subject: subject, email_txt: email_txt, email_html: email_html, projectDir: "$projectDir", mqcFile: mqc_report, mqcMaxSize: max_multiqc_email_size.toBytes() ]
def sf = new File("$projectDir/assets/sendmail_template.txt")
def sendmail_template = engine.createTemplate(sf).make(smail_fields)
def sendmail_html = sendmail_template.toString()
// Send the HTML e-mail
Map colors = logColours(params.monochrome_logs)
if (email_address) {
try {
if (params.plaintext_email) { throw GroovyException('Send plaintext e-mail, not HTML') }
// Try to send HTML e-mail using sendmail
[ 'sendmail', '-t' ].execute() << sendmail_html
log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (sendmail)-"
} catch (all) {
// Catch failures and try with plaintext
def mail_cmd = [ 'mail', '-s', subject, '--content-type=text/html', email_address ]
if ( mqc_report.size() <= max_multiqc_email_size.toBytes() ) {
mail_cmd += [ '-A', mqc_report ]
}
mail_cmd.execute() << email_html
log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Sent summary e-mail to $email_address (mail)-"
}
}
// Write summary e-mail HTML to a file
def output_d = new File("${params.outdir}/pipeline_info/")
if (!output_d.exists()) {
output_d.mkdirs()
}
def output_hf = new File(output_d, "pipeline_report.html")
output_hf.withWriter { w -> w << email_html }
def output_tf = new File(output_d, "pipeline_report.txt")
output_tf.withWriter { w -> w << email_txt }
}
//
// Print pipeline summary on completion
//
public static void summary(workflow, params, log) {
Map colors = logColours(params.monochrome_logs)
if (workflow.success) {
if (workflow.stats.ignoredCount == 0) {
log.info "-${colors.purple}[$workflow.manifest.name]${colors.green} Pipeline completed successfully${colors.reset}-"
} else {
log.info "-${colors.purple}[$workflow.manifest.name]${colors.red} Pipeline completed successfully, but with errored process(es) ${colors.reset}-"
}
} else {
log.info "-${colors.purple}[$workflow.manifest.name]${colors.red} Pipeline completed with errors${colors.reset}-"
}
}
//
// ANSII Colours used for terminal logging
//
public static Map logColours(Boolean monochrome_logs) {
Map colorcodes = [:]
// Reset / Meta
colorcodes['reset'] = monochrome_logs ? '' : "\033[0m"
colorcodes['bold'] = monochrome_logs ? '' : "\033[1m"
colorcodes['dim'] = monochrome_logs ? '' : "\033[2m"
colorcodes['underlined'] = monochrome_logs ? '' : "\033[4m"
colorcodes['blink'] = monochrome_logs ? '' : "\033[5m"
colorcodes['reverse'] = monochrome_logs ? '' : "\033[7m"
colorcodes['hidden'] = monochrome_logs ? '' : "\033[8m"
// Regular Colors
colorcodes['black'] = monochrome_logs ? '' : "\033[0;30m"
colorcodes['red'] = monochrome_logs ? '' : "\033[0;31m"
colorcodes['green'] = monochrome_logs ? '' : "\033[0;32m"
colorcodes['yellow'] = monochrome_logs ? '' : "\033[0;33m"
colorcodes['blue'] = monochrome_logs ? '' : "\033[0;34m"
colorcodes['purple'] = monochrome_logs ? '' : "\033[0;35m"
colorcodes['cyan'] = monochrome_logs ? '' : "\033[0;36m"
colorcodes['white'] = monochrome_logs ? '' : "\033[0;37m"
// Bold
colorcodes['bblack'] = monochrome_logs ? '' : "\033[1;30m"
colorcodes['bred'] = monochrome_logs ? '' : "\033[1;31m"
colorcodes['bgreen'] = monochrome_logs ? '' : "\033[1;32m"
colorcodes['byellow'] = monochrome_logs ? '' : "\033[1;33m"
colorcodes['bblue'] = monochrome_logs ? '' : "\033[1;34m"
colorcodes['bpurple'] = monochrome_logs ? '' : "\033[1;35m"
colorcodes['bcyan'] = monochrome_logs ? '' : "\033[1;36m"
colorcodes['bwhite'] = monochrome_logs ? '' : "\033[1;37m"
// Underline
colorcodes['ublack'] = monochrome_logs ? '' : "\033[4;30m"
colorcodes['ured'] = monochrome_logs ? '' : "\033[4;31m"
colorcodes['ugreen'] = monochrome_logs ? '' : "\033[4;32m"
colorcodes['uyellow'] = monochrome_logs ? '' : "\033[4;33m"
colorcodes['ublue'] = monochrome_logs ? '' : "\033[4;34m"
colorcodes['upurple'] = monochrome_logs ? '' : "\033[4;35m"
colorcodes['ucyan'] = monochrome_logs ? '' : "\033[4;36m"
colorcodes['uwhite'] = monochrome_logs ? '' : "\033[4;37m"
// High Intensity
colorcodes['iblack'] = monochrome_logs ? '' : "\033[0;90m"
colorcodes['ired'] = monochrome_logs ? '' : "\033[0;91m"
colorcodes['igreen'] = monochrome_logs ? '' : "\033[0;92m"
colorcodes['iyellow'] = monochrome_logs ? '' : "\033[0;93m"
colorcodes['iblue'] = monochrome_logs ? '' : "\033[0;94m"
colorcodes['ipurple'] = monochrome_logs ? '' : "\033[0;95m"
colorcodes['icyan'] = monochrome_logs ? '' : "\033[0;96m"
colorcodes['iwhite'] = monochrome_logs ? '' : "\033[0;97m"
// Bold High Intensity
colorcodes['biblack'] = monochrome_logs ? '' : "\033[1;90m"
colorcodes['bired'] = monochrome_logs ? '' : "\033[1;91m"
colorcodes['bigreen'] = monochrome_logs ? '' : "\033[1;92m"
colorcodes['biyellow'] = monochrome_logs ? '' : "\033[1;93m"
colorcodes['biblue'] = monochrome_logs ? '' : "\033[1;94m"
colorcodes['bipurple'] = monochrome_logs ? '' : "\033[1;95m"
colorcodes['bicyan'] = monochrome_logs ? '' : "\033[1;96m"
colorcodes['biwhite'] = monochrome_logs ? '' : "\033[1;97m"
return colorcodes
}
//
// Does what is says on the tin
//
public static String dashedLine(monochrome_logs) {
Map colors = logColours(monochrome_logs)
return "-${colors.dim}----------------------------------------------------${colors.reset}-"
}
//
// nf-core logo
//
public static String logo(workflow, monochrome_logs) {
Map colors = logColours(monochrome_logs)
String.format(
"""\n
${dashedLine(monochrome_logs)}
${colors.green},--.${colors.black}/${colors.green},-.${colors.reset}
${colors.blue} ___ __ __ __ ___ ${colors.green}/,-._.--~\'${colors.reset}
${colors.blue} |\\ | |__ __ / ` / \\ |__) |__ ${colors.yellow}} {${colors.reset}
${colors.blue} | \\| | \\__, \\__/ | \\ |___ ${colors.green}\\`-._,-`-,${colors.reset}
${colors.green}`._,._,\'${colors.reset}
${colors.purple} ${workflow.manifest.name} v${workflow.manifest.version}${colors.reset}
${dashedLine(monochrome_logs)}
""".stripIndent()
)
}
}