{"__v":0,"_id":"5835a51dca60af0f00ee15e3","category":{"project":"55faf11ba62ba1170021a9a7","version":"55faf11ba62ba1170021a9aa","_id":"57ff5c5dc135231700aed806","__v":0,"sync":{"url":"","isSync":false},"reference":false,"createdAt":"2016-10-13T10:05:17.381Z","from_sync":false,"order":15,"slug":"tool-wrapping-troubleshooting","title":"TOOL WRAPPING TIPS AND TRICKS"},"parentDoc":null,"project":"55faf11ba62ba1170021a9a7","user":"5767bc73bb15f40e00a28777","version":{"__v":37,"_id":"55faf11ba62ba1170021a9aa","project":"55faf11ba62ba1170021a9a7","createdAt":"2015-09-17T16:58:03.490Z","releaseDate":"2015-09-17T16:58:03.490Z","categories":["55faf11ca62ba1170021a9ab","55faf8f4d0e22017005b8272","55faf91aa62ba1170021a9b5","55faf929a8a7770d00c2c0bd","55faf932a8a7770d00c2c0bf","55faf94b17b9d00d00969f47","55faf958d0e22017005b8274","55faf95fa8a7770d00c2c0c0","55faf96917b9d00d00969f48","55faf970a8a7770d00c2c0c1","55faf98c825d5f19001fa3a6","55faf99aa62ba1170021a9b8","55faf99fa62ba1170021a9b9","55faf9aa17b9d00d00969f49","55faf9b6a8a7770d00c2c0c3","55faf9bda62ba1170021a9ba","5604570090ee490d00440551","5637e8b2fbe1c50d008cb078","5649bb624fa1460d00780add","5671974d1b6b730d008b4823","5671979d60c8e70d006c9760","568e8eef70ca1f0d0035808e","56d0a2081ecc471500f1795e","56d4a0adde40c70b00823ea3","56d96b03dd90610b00270849","56fbb83d8f21c817002af880","573c811bee2b3b2200422be1","576bc92afb62dd20001cda85","5771811e27a5c20e00030dcd","5785191af3a10c0e009b75b0","57bdf84d5d48411900cd8dc0","57ff5c5dc135231700aed806","5804caf792398f0f00e77521","58458b4fba4f1c0f009692bb","586d3c287c6b5b2300c05055","58ef66d88646742f009a0216","58f5d52d7891630f00fe4e77"],"is_deprecated":false,"is_hidden":false,"is_beta":true,"is_stable":true,"codename":"","version_clean":"1.0.0","version":"1.0"},"updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-11-23T14:18:05.953Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":3,"body":"This page provides examples of expressions that are entered in the Tool Editor when wrapping a tool for use on the CGC. Expressions can be used to dynamically set different tool properties such as the base command, arguments, secondary files, metadata, output file names, etc. Dynamic expressions commonly use the `$self` and `$job` predefined objects, which are determined at runtime and denote properties of the tool's inputs or outputs in a given execution and the ongoing tool execution (the job). The expressions are entered anywhere in the Tool Editor where the **</>** symbol is present. For general information about expressions, please refer to [dynamic expressions in tool descriptions](doc:dynamic-expressions-in-tool-descriptions).\n\n### Capture the name and content of an input file\n\nThe following expression picks out the name of the data file input for each execution of the tool. The dynamic expression will be based on the `$job` object; in particular, we will use the `inputs` property of the `$job` object. There is no property of the `inputs` for file name, but there is a property, `path`, which refers to the file path of the input to the tool in any given execution. Using string manipulation on the path object we can obtain the file name. In particular, we will use the following JavaScript expression:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"$job.inputs.<input_port__ID_for_data_file>.path.split('/').slice(-1)[0]\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nIn this expression, you should replace `<input_port_ID_for_data_file>` with the ID for the input port that the data file goes into. This expression will then take the path of the input to the specified port, split the path on '/', and then select the last slice of the split list. This should be the file name, at the end of the path.\n\nTo refer to the content of the file, use the following expression:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"$job.inputs.<input_ID_for_data_file>\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nAs before, `<input_ID_for_data_file>` refers to the ID of the input port that the data file gets inputted to. This expression will pick out the file object that is inputted there, and set it to the content of the file named in the expression above.\n\n### Name output files based on the Sample ID metadata field of input files\n\nThe expression below is used to name an output file of a tool based on the value in the **Sample ID** metadata field obtained from the input files. As some tools allow you to specify the output file name as a command line argument, this expression can be used to define the argument value in the [**Arguments** section](doc:general-tool-information#arg) of the Tool Editor’s **General** tab.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  input_files = [].concat($job.inputs.<input_port_ID>)\\n  filename = input_files[0].path.split('/').slice(-1)[0];\\n   \\n  if (input_files[0].metadata && input_files[0].metadata.sample_id)\\n  {\\n    filebase = input_files[0].metadata.sample_id\\n  }\\n  else\\n  {\\n    filebase = \\\"sample_unknown\\\"\\n  }\\n \\n  return filebase.concat(\\\"<file_extension>\\\")\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe expression works as follows:\n\nThe following two lines of code get the file name(s) from the input file or array of files.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"input_files = [].concat($job.inputs.<input_port_ID>)\\nfilename = input_files[0].path.split('/').slice(-1)[0];\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nMake sure to replace `<input_port_ID>` value with the the corresponding port ID of your app.\n\nThe next part of the expression checks whether the input file has a value set in the **Sample ID** metadata field. If there is a value, it is used as the base name of the output file. Otherwise, the base name will be `sample_unknown`.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"if (input_files[0].metadata && input_files[0].metadata.sample_id)\\n  {\\n    filebase = input_files[0].metadata.sample_id\\n  }\\n  else\\n  {\\n    filebase = \\\"sample_unknown\\\"\\n  }\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nFinally, the extension is appended to the base name of the file:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"return filebase.concat(\\\"<file_extension>\\\")\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nMake sure to replace `<file_extension>` with the extension of the tool's output file, including the dot (for example **.bam**).\n\n### Name output files based on input file names\n\nThe following expression will retrieve the name of the input file for the job and return it as the name of the output file. This expression can also be used with tools that allow output file name to be defined through a command line argument. It is entered as the argument value in the [**Arguments** section](doc:general-tool-information#arg) of the Tool Editor’s **General** tab.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  reads = [].concat($job.inputs.<input_port_ID>)\\n  file_path = reads[0].path\\n  filename = file_path.split('/').slice(-1)[0]\\n  filebase = filename.split('.').slice(0, 1).join('.')\\n  out_name = filebase.concat(\\\"<file_extension>\\\")\\n  return out_name \\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe expression works as follows:\n\nThe following two lines of code get the file name(s) from the file or array of files that have been provided as the input.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"reads = [].concat($job.inputs.<input_port_ID>)\\nfile_path = reads[0].path\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nIn this part of the expression, make sure to replace `<input_port_ID>` with the the corresponding port ID of your app.\n\nThe next part of the expression extracts the name of the input file. This will be used as the base name of the output file:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"filename = file_path.split('/').slice(-1)[0]\\nfilebase = filename.split('.').slice(0, 1).join('.')\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe last part of the expression appends the extension to the base name and returns the full name of the output file:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"out_name = filebase.concat(\\\"<file_extension>\\\")\\nreturn out_name\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nYou need to replace `<file_extension>` in the code to match the extension you need for your output file. The extension should also include the dot (for example **.fastq**).\n\n### Set metadata fields of output files based on inputs for paired end 1 and 2\n\nThis expression is used to copy the values in the **Paired-end** metadata field from input files for a given job to their corresponding paired-end output files.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  filename = $self.path.split('/').slice(-1)[0]\\n  filebase = filename.split('.').slice(0, -3).join('.')\\n   \\n  reads = [].concat($job.inputs.<input_port_ID>)\\n \\n  for (i=0; i<reads.length; i++)\\n  {\\n    input_filename = reads[i].path.split('/').slice(-1)[0]\\n    input_filebase = input_filename.split('.').slice(0, -1).join('.')\\n       \\n    if (filebase==input_filebase && $job.inputs.<input_port_ID>[i].metadata && $job.inputs.<input_port__ID>[i].metadata.paired_end)\\n    {\\n      return $job.inputs.<input_port_ID>[i].metadata.paired_end\\n    }\\n  }\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe expression is entered in the **Metadata Value** field on the output port's setup screen. The **Metadata Key** value needs to be `paired_end`.\n\nThe code is analyzed below:\n\nThe following two lines extract the base name of the output file on the output port:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"filename = $self.path.split('/').slice(-1)[0]\\nfilebase = filename.split('.').slice(0, -3).join('.')\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe expression assumes that the file extension includes three dot-separated portions, such as `<base_name>.pe_1.fastq.gz`. The `slice(0, -3)` method in the second line above is used to extract the part of the file name before `.pe_1.fastq.gz`, but can be adjusted to match the file naming convention for your tool's input paired-end files. For example, if the naming convention is `<base_name>.fastq`, the method needs to be `slice(0, -1)`.\n\nThe next line creates an array containing the paths of the input file(s):\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"reads = [].concat($job.inputs.<input_port_ID>)\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nMake sure to replace `<input_port_ID>` with the actual ID of the input port for paired-end files.\n\nFinally, there is a for loop that iterates through the array of input file paths and gets the base name of each of the files:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"for (i=0; i<reads.length; i++)\\n  {\\n    input_filename = reads[i].path.split('/').slice(-1)[0]\\n    input_filebase = input_filename.split('.').slice(0, -1).join('.')\\n       \\n    if (filebase==input_filebase && $job.inputs.<input_port_ID>[i].metadata && $job.inputs.<input_port__ID>[i].metadata.paired_end)\\n    {\\n      return $job.inputs.<input_port__ID>[i].metadata.paired_end\\n    }\\n  }\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nOnce it finds the input file whose name matches the name of the output file, it checks whether the input file has metadata and has a value in the **Paired-end** metadata field. If there is a value, the expression evaluates to that value, which becomes the **Paired-end** metadata value for the output file.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Even if you have properly entered the expression and replaced all placeholders with proper values, you might still get an error message when you save the expression. This warning is incorrect and it is a known bug on the CGC.\"\n}\n[/block]\n### Order input reads based on paired-end metadata\n\nSome tools, such as **BWA MEM Bundle** require paired-end input reads to be ordered in the correct sequence (paired-end 1 first, followed by paired-end 2). This expression will automatically order the input reads based on the values entered in the `paired_end` metadata field:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n if($job.inputs.input_reads[0] instanceof Array){\\n input_reads = $job.inputs.input_reads[0]\\n } else {\\n input_reads = $job.inputs.input_reads = [].concat($job.inputs.input_reads)\\n }\\n read_metadata = input_reads[0].metadata\\n if(!read_metadata) read_metadata = []\\n  \\n order = 0\\n  \\n if(read_metadata == []){ order = 0 }\\n else if('paired_end' in read_metadata){\\n pe1 = read_metadata.paired_end\\n if(pe1 != 1) order = 1\\n }\\n if (input_reads.length == 1){\\n   return input_reads[0].path\\n }\\n else if (input_reads.length == 2){\\n   if (order == 0) return input_reads[0].path + ' ' + input_reads[1].path\\n   else return input_reads[1].path + ' ' + input_reads[0].path\\n }\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe expression works as follows:\n\nThe first code block checks whether the input is an array or array of arrays and returns the correct value containing the input reads:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n if($job.inputs.input_reads[0] instanceof Array){\\n input_reads = $job.inputs.input_reads[0]\\n } else {\\n input_reads = $job.inputs.input_reads = [].concat($job.inputs.input_reads)\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe following part reads metadata from the first supplied input read. If there is no metadata, assigns an empty array to the `read_metadata` variable:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"read_metadata = input_reads[0].metadata\\nif(!read_metadata) read_metadata = []\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe `order` flag is used to mark the order of input reads. The starting assumption is that the reads are ordered correctly, which is denoted by assigning the value `0` to `order`.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"order = 0\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe following code block starts by checking whether the first input read has any assigned metadata values. If it finds no values, no sorting can be done based on metadata and it assumes that the reads are in correct order (`order = 0`). Otherwise, it checks whether paired-end 1 corresponds to the first given read:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"if(read_metadata == []){ order = 0 }\\n else if('paired_end' in read_metadata){\\n pe1 = read_metadata.paired_end\\n if(pe1 != 1) order = 1 // change order\\n }\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nFinally, the expression checks how many reads there are and returns them in the correct order. If only one input read is present, this read is returned as there is no need for ordering. If there are two input reads, they are returned in the correct order based on the value of the `order` flag.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"if (input_reads.length == 1){\\n   return input_reads[0].path\\n }\\n else if (input_reads.length == 2){\\n   if (order == 0) return input_reads[0].path + ' ' + input_reads[1].path\\n   else return input_reads[1].path + ' ' + input_reads[0].path\\n }\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\n### Configure a tool to unpack a TAR archive provided as its input\n\nIn some cases, input files taken by a tool come in the form of a TAR archive. TAR archives can be produced by e.g. aligner indexers, which are a set of indexing tools that index reference files and output an archive containing the reference and the index file(s). A tool that needs to use the files from a TAR archive can be configured to unpack it.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"Prerequisite: In order to simplify the process of unpacking the archive using the expression below, the tool's input port that takes the archive file will have the **Stage Input** > **Link** option configured. This will make the TAR archive available directly in the tool's working directory. Learn more about (Stage Input)[doc:tool-input-ports#section-stage-input] and see [how to configure the Stage Input option](doc:make-files-available-in-your-tools-working-directory) for a tool.\"\n}\n[/block]\n1. Navigate to the **Apps** tab in your project.\n2. Click the pencil icon next to the tool you want to configure.\n3. Navigate to the **General** tab in the Tool Editor.\n4. Click **+** in the **Base Command** section. If the field(s) in the **Base Command** section have already been populated, copy the content of each field to the first blank field below it, until the very first field in the section becomes blank.\n5. Click **</>** next to the first field.\n6. Paste the following code:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  var index_files_bundle = $job.inputs.<input_port_ID>.path.split('/').slice(-1)\\n  return 'tar -xf ' + index_files_bundle + ' ; '\\n}\",\n      \"language\": \"javascript\"\n    }\n  ]\n}\n[/block]\nThe first line of the expression retrieves the name of the archive file using the [$job object](doc:dynamic-expressions-in-tool-descriptions#section-the-job-object). The second line appends the retrieved file name to the command that will unpack the archive file.\n\nPlease make sure to replace `<input_port_ID>` in the above code with the ID value of your tool's input port that takes the archive file.\n7. Click **Save**.\n8. Click **Save** in the top-right corner of the Tool Editor.\nYour tool is now configured to unpack a TAR archive it receives as its input.","excerpt":"","slug":"javascript-cookbook","type":"basic","title":"JavaScript Cookbook"}

JavaScript Cookbook


This page provides examples of expressions that are entered in the Tool Editor when wrapping a tool for use on the CGC. Expressions can be used to dynamically set different tool properties such as the base command, arguments, secondary files, metadata, output file names, etc. Dynamic expressions commonly use the `$self` and `$job` predefined objects, which are determined at runtime and denote properties of the tool's inputs or outputs in a given execution and the ongoing tool execution (the job). The expressions are entered anywhere in the Tool Editor where the **</>** symbol is present. For general information about expressions, please refer to [dynamic expressions in tool descriptions](doc:dynamic-expressions-in-tool-descriptions). ### Capture the name and content of an input file The following expression picks out the name of the data file input for each execution of the tool. The dynamic expression will be based on the `$job` object; in particular, we will use the `inputs` property of the `$job` object. There is no property of the `inputs` for file name, but there is a property, `path`, which refers to the file path of the input to the tool in any given execution. Using string manipulation on the path object we can obtain the file name. In particular, we will use the following JavaScript expression: [block:code] { "codes": [ { "code": "$job.inputs.<input_port__ID_for_data_file>.path.split('/').slice(-1)[0]", "language": "javascript" } ] } [/block] In this expression, you should replace `<input_port_ID_for_data_file>` with the ID for the input port that the data file goes into. This expression will then take the path of the input to the specified port, split the path on '/', and then select the last slice of the split list. This should be the file name, at the end of the path. To refer to the content of the file, use the following expression: [block:code] { "codes": [ { "code": "$job.inputs.<input_ID_for_data_file>", "language": "javascript" } ] } [/block] As before, `<input_ID_for_data_file>` refers to the ID of the input port that the data file gets inputted to. This expression will pick out the file object that is inputted there, and set it to the content of the file named in the expression above. ### Name output files based on the Sample ID metadata field of input files The expression below is used to name an output file of a tool based on the value in the **Sample ID** metadata field obtained from the input files. As some tools allow you to specify the output file name as a command line argument, this expression can be used to define the argument value in the [**Arguments** section](doc:general-tool-information#arg) of the Tool Editor’s **General** tab. [block:code] { "codes": [ { "code": "{\n input_files = [].concat($job.inputs.<input_port_ID>)\n filename = input_files[0].path.split('/').slice(-1)[0];\n \n if (input_files[0].metadata && input_files[0].metadata.sample_id)\n {\n filebase = input_files[0].metadata.sample_id\n }\n else\n {\n filebase = \"sample_unknown\"\n }\n \n return filebase.concat(\"<file_extension>\")\n}", "language": "javascript" } ] } [/block] The expression works as follows: The following two lines of code get the file name(s) from the input file or array of files. [block:code] { "codes": [ { "code": "input_files = [].concat($job.inputs.<input_port_ID>)\nfilename = input_files[0].path.split('/').slice(-1)[0];", "language": "javascript" } ] } [/block] Make sure to replace `<input_port_ID>` value with the the corresponding port ID of your app. The next part of the expression checks whether the input file has a value set in the **Sample ID** metadata field. If there is a value, it is used as the base name of the output file. Otherwise, the base name will be `sample_unknown`. [block:code] { "codes": [ { "code": "if (input_files[0].metadata && input_files[0].metadata.sample_id)\n {\n filebase = input_files[0].metadata.sample_id\n }\n else\n {\n filebase = \"sample_unknown\"\n }", "language": "javascript" } ] } [/block] Finally, the extension is appended to the base name of the file: [block:code] { "codes": [ { "code": "return filebase.concat(\"<file_extension>\")", "language": "javascript" } ] } [/block] Make sure to replace `<file_extension>` with the extension of the tool's output file, including the dot (for example **.bam**). ### Name output files based on input file names The following expression will retrieve the name of the input file for the job and return it as the name of the output file. This expression can also be used with tools that allow output file name to be defined through a command line argument. It is entered as the argument value in the [**Arguments** section](doc:general-tool-information#arg) of the Tool Editor’s **General** tab. [block:code] { "codes": [ { "code": "{\n reads = [].concat($job.inputs.<input_port_ID>)\n file_path = reads[0].path\n filename = file_path.split('/').slice(-1)[0]\n filebase = filename.split('.').slice(0, 1).join('.')\n out_name = filebase.concat(\"<file_extension>\")\n return out_name \n}", "language": "javascript" } ] } [/block] The expression works as follows: The following two lines of code get the file name(s) from the file or array of files that have been provided as the input. [block:code] { "codes": [ { "code": "reads = [].concat($job.inputs.<input_port_ID>)\nfile_path = reads[0].path", "language": "javascript" } ] } [/block] In this part of the expression, make sure to replace `<input_port_ID>` with the the corresponding port ID of your app. The next part of the expression extracts the name of the input file. This will be used as the base name of the output file: [block:code] { "codes": [ { "code": "filename = file_path.split('/').slice(-1)[0]\nfilebase = filename.split('.').slice(0, 1).join('.')", "language": "javascript" } ] } [/block] The last part of the expression appends the extension to the base name and returns the full name of the output file: [block:code] { "codes": [ { "code": "out_name = filebase.concat(\"<file_extension>\")\nreturn out_name", "language": "javascript" } ] } [/block] You need to replace `<file_extension>` in the code to match the extension you need for your output file. The extension should also include the dot (for example **.fastq**). ### Set metadata fields of output files based on inputs for paired end 1 and 2 This expression is used to copy the values in the **Paired-end** metadata field from input files for a given job to their corresponding paired-end output files. [block:code] { "codes": [ { "code": "{\n filename = $self.path.split('/').slice(-1)[0]\n filebase = filename.split('.').slice(0, -3).join('.')\n \n reads = [].concat($job.inputs.<input_port_ID>)\n \n for (i=0; i<reads.length; i++)\n {\n input_filename = reads[i].path.split('/').slice(-1)[0]\n input_filebase = input_filename.split('.').slice(0, -1).join('.')\n \n if (filebase==input_filebase && $job.inputs.<input_port_ID>[i].metadata && $job.inputs.<input_port__ID>[i].metadata.paired_end)\n {\n return $job.inputs.<input_port_ID>[i].metadata.paired_end\n }\n }\n}", "language": "javascript" } ] } [/block] The expression is entered in the **Metadata Value** field on the output port's setup screen. The **Metadata Key** value needs to be `paired_end`. The code is analyzed below: The following two lines extract the base name of the output file on the output port: [block:code] { "codes": [ { "code": "filename = $self.path.split('/').slice(-1)[0]\nfilebase = filename.split('.').slice(0, -3).join('.')", "language": "javascript" } ] } [/block] The expression assumes that the file extension includes three dot-separated portions, such as `<base_name>.pe_1.fastq.gz`. The `slice(0, -3)` method in the second line above is used to extract the part of the file name before `.pe_1.fastq.gz`, but can be adjusted to match the file naming convention for your tool's input paired-end files. For example, if the naming convention is `<base_name>.fastq`, the method needs to be `slice(0, -1)`. The next line creates an array containing the paths of the input file(s): [block:code] { "codes": [ { "code": "reads = [].concat($job.inputs.<input_port_ID>)", "language": "javascript" } ] } [/block] Make sure to replace `<input_port_ID>` with the actual ID of the input port for paired-end files. Finally, there is a for loop that iterates through the array of input file paths and gets the base name of each of the files: [block:code] { "codes": [ { "code": "for (i=0; i<reads.length; i++)\n {\n input_filename = reads[i].path.split('/').slice(-1)[0]\n input_filebase = input_filename.split('.').slice(0, -1).join('.')\n \n if (filebase==input_filebase && $job.inputs.<input_port_ID>[i].metadata && $job.inputs.<input_port__ID>[i].metadata.paired_end)\n {\n return $job.inputs.<input_port__ID>[i].metadata.paired_end\n }\n }", "language": "javascript" } ] } [/block] Once it finds the input file whose name matches the name of the output file, it checks whether the input file has metadata and has a value in the **Paired-end** metadata field. If there is a value, the expression evaluates to that value, which becomes the **Paired-end** metadata value for the output file. [block:callout] { "type": "info", "body": "Even if you have properly entered the expression and replaced all placeholders with proper values, you might still get an error message when you save the expression. This warning is incorrect and it is a known bug on the CGC." } [/block] ### Order input reads based on paired-end metadata Some tools, such as **BWA MEM Bundle** require paired-end input reads to be ordered in the correct sequence (paired-end 1 first, followed by paired-end 2). This expression will automatically order the input reads based on the values entered in the `paired_end` metadata field: [block:code] { "codes": [ { "code": "{\n if($job.inputs.input_reads[0] instanceof Array){\n input_reads = $job.inputs.input_reads[0]\n } else {\n input_reads = $job.inputs.input_reads = [].concat($job.inputs.input_reads)\n }\n read_metadata = input_reads[0].metadata\n if(!read_metadata) read_metadata = []\n \n order = 0\n \n if(read_metadata == []){ order = 0 }\n else if('paired_end' in read_metadata){\n pe1 = read_metadata.paired_end\n if(pe1 != 1) order = 1\n }\n if (input_reads.length == 1){\n return input_reads[0].path\n }\n else if (input_reads.length == 2){\n if (order == 0) return input_reads[0].path + ' ' + input_reads[1].path\n else return input_reads[1].path + ' ' + input_reads[0].path\n }\n}", "language": "javascript" } ] } [/block] The expression works as follows: The first code block checks whether the input is an array or array of arrays and returns the correct value containing the input reads: [block:code] { "codes": [ { "code": "{\n if($job.inputs.input_reads[0] instanceof Array){\n input_reads = $job.inputs.input_reads[0]\n } else {\n input_reads = $job.inputs.input_reads = [].concat($job.inputs.input_reads)\n}", "language": "javascript" } ] } [/block] The following part reads metadata from the first supplied input read. If there is no metadata, assigns an empty array to the `read_metadata` variable: [block:code] { "codes": [ { "code": "read_metadata = input_reads[0].metadata\nif(!read_metadata) read_metadata = []", "language": "javascript" } ] } [/block] The `order` flag is used to mark the order of input reads. The starting assumption is that the reads are ordered correctly, which is denoted by assigning the value `0` to `order`. [block:code] { "codes": [ { "code": "order = 0", "language": "javascript" } ] } [/block] The following code block starts by checking whether the first input read has any assigned metadata values. If it finds no values, no sorting can be done based on metadata and it assumes that the reads are in correct order (`order = 0`). Otherwise, it checks whether paired-end 1 corresponds to the first given read: [block:code] { "codes": [ { "code": "if(read_metadata == []){ order = 0 }\n else if('paired_end' in read_metadata){\n pe1 = read_metadata.paired_end\n if(pe1 != 1) order = 1 // change order\n }", "language": "javascript" } ] } [/block] Finally, the expression checks how many reads there are and returns them in the correct order. If only one input read is present, this read is returned as there is no need for ordering. If there are two input reads, they are returned in the correct order based on the value of the `order` flag. [block:code] { "codes": [ { "code": "if (input_reads.length == 1){\n return input_reads[0].path\n }\n else if (input_reads.length == 2){\n if (order == 0) return input_reads[0].path + ' ' + input_reads[1].path\n else return input_reads[1].path + ' ' + input_reads[0].path\n }\n}", "language": "javascript" } ] } [/block] ### Configure a tool to unpack a TAR archive provided as its input In some cases, input files taken by a tool come in the form of a TAR archive. TAR archives can be produced by e.g. aligner indexers, which are a set of indexing tools that index reference files and output an archive containing the reference and the index file(s). A tool that needs to use the files from a TAR archive can be configured to unpack it. [block:callout] { "type": "warning", "body": "Prerequisite: In order to simplify the process of unpacking the archive using the expression below, the tool's input port that takes the archive file will have the **Stage Input** > **Link** option configured. This will make the TAR archive available directly in the tool's working directory. Learn more about (Stage Input)[doc:tool-input-ports#section-stage-input] and see [how to configure the Stage Input option](doc:make-files-available-in-your-tools-working-directory) for a tool." } [/block] 1. Navigate to the **Apps** tab in your project. 2. Click the pencil icon next to the tool you want to configure. 3. Navigate to the **General** tab in the Tool Editor. 4. Click **+** in the **Base Command** section. If the field(s) in the **Base Command** section have already been populated, copy the content of each field to the first blank field below it, until the very first field in the section becomes blank. 5. Click **</>** next to the first field. 6. Paste the following code: [block:code] { "codes": [ { "code": "{\n var index_files_bundle = $job.inputs.<input_port_ID>.path.split('/').slice(-1)\n return 'tar -xf ' + index_files_bundle + ' ; '\n}", "language": "javascript" } ] } [/block] The first line of the expression retrieves the name of the archive file using the [$job object](doc:dynamic-expressions-in-tool-descriptions#section-the-job-object). The second line appends the retrieved file name to the command that will unpack the archive file. Please make sure to replace `<input_port_ID>` in the above code with the ID value of your tool's input port that takes the archive file. 7. Click **Save**. 8. Click **Save** in the top-right corner of the Tool Editor. Your tool is now configured to unpack a TAR archive it receives as its input.