mirror of
https://github.com/MillironX/taxprofiler.git
synced 2024-12-22 14:58:17 +00:00
336 lines
16 KiB
Groovy
Executable file
336 lines
16 KiB
Groovy
Executable file
//
|
|
// 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 "
|
|
}
|
|
}
|
|
|
|
//
|
|
// Generate version string
|
|
//
|
|
public static String version(workflow) {
|
|
String version_string = ""
|
|
|
|
if (workflow.manifest.version) {
|
|
def prefix_v = workflow.manifest.version[0] != 'v' ? 'v' : ''
|
|
version_string += "${prefix_v}${workflow.manifest.version}"
|
|
}
|
|
|
|
if (workflow.commitId) {
|
|
def git_shortsha = workflow.commitId.substring(0, 7)
|
|
version_string += "-g${git_shortsha}"
|
|
}
|
|
|
|
return version_string
|
|
}
|
|
|
|
//
|
|
// 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'] = NfcoreTemplate.version(workflow)
|
|
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 }
|
|
}
|
|
|
|
//
|
|
// Construct and send a notification to a web server as JSON
|
|
// e.g. Microsoft Teams and Slack
|
|
//
|
|
public static void IM_notification(workflow, params, summary_params, projectDir, log) {
|
|
def hook_url = params.hook_url
|
|
|
|
def summary = [:]
|
|
for (group in summary_params.keySet()) {
|
|
summary << summary_params[group]
|
|
}
|
|
|
|
def misc_fields = [:]
|
|
misc_fields['start'] = workflow.start
|
|
misc_fields['complete'] = workflow.complete
|
|
misc_fields['scriptfile'] = workflow.scriptFile
|
|
misc_fields['scriptid'] = workflow.scriptId
|
|
if (workflow.repository) misc_fields['repository'] = workflow.repository
|
|
if (workflow.commitId) misc_fields['commitid'] = workflow.commitId
|
|
if (workflow.revision) misc_fields['revision'] = workflow.revision
|
|
misc_fields['nxf_version'] = workflow.nextflow.version
|
|
misc_fields['nxf_build'] = workflow.nextflow.build
|
|
misc_fields['nxf_timestamp'] = workflow.nextflow.timestamp
|
|
|
|
def msg_fields = [:]
|
|
msg_fields['version'] = NfcoreTemplate.version(workflow)
|
|
msg_fields['runName'] = workflow.runName
|
|
msg_fields['success'] = workflow.success
|
|
msg_fields['dateComplete'] = workflow.complete
|
|
msg_fields['duration'] = workflow.duration
|
|
msg_fields['exitStatus'] = workflow.exitStatus
|
|
msg_fields['errorMessage'] = (workflow.errorMessage ?: 'None')
|
|
msg_fields['errorReport'] = (workflow.errorReport ?: 'None')
|
|
msg_fields['commandLine'] = workflow.commandLine.replaceFirst(/ +--hook_url +[^ ]+/, "")
|
|
msg_fields['projectDir'] = workflow.projectDir
|
|
msg_fields['summary'] = summary << misc_fields
|
|
|
|
// Render the JSON template
|
|
def engine = new groovy.text.GStringTemplateEngine()
|
|
// Different JSON depending on the service provider
|
|
// Defaults to "Adaptive Cards" (https://adaptivecards.io), except Slack which has its own format
|
|
def json_path = hook_url.contains("hooks.slack.com") ? "slackreport.json" : "adaptivecard.json"
|
|
def hf = new File("$projectDir/assets/${json_path}")
|
|
def json_template = engine.createTemplate(hf).make(msg_fields)
|
|
def json_message = json_template.toString()
|
|
|
|
// POST
|
|
def post = new URL(hook_url).openConnection();
|
|
post.setRequestMethod("POST")
|
|
post.setDoOutput(true)
|
|
post.setRequestProperty("Content-Type", "application/json")
|
|
post.getOutputStream().write(json_message.getBytes("UTF-8"));
|
|
def postRC = post.getResponseCode();
|
|
if (! postRC.equals(200)) {
|
|
log.warn(post.getErrorStream().getText());
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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.yellow} 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 workflow_version = NfcoreTemplate.version(workflow)
|
|
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} ${workflow_version}${colors.reset}
|
|
${dashedLine(monochrome_logs)}
|
|
""".stripIndent()
|
|
)
|
|
}
|
|
}
|