Skip to content

Commit f718b82

Browse files
committed
Merge discvr-23.11 to develop
2 parents 9558a1d + b4bcf09 commit f718b82

File tree

11 files changed

+334
-67
lines changed

11 files changed

+334
-67
lines changed

SequenceAnalysis/pipeline_code/sequence_tools_install.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,13 +512,12 @@ then
512512

513513
wget $WGET_OPTS https://github.com/samtools/bcftools/releases/download/1.18/bcftools-1.18.tar.bz2
514514
tar xjvf bcftools-1.18.tar.bz2
515-
bzip2 bcftools-1.18.tar
516515
chmod 755 bcftools-1.18
517516
cd bcftools-1.18
518517
rm -f plugins/liftover.c
519518
wget $WGET_OPTS -P plugins https://raw.githubusercontent.com/freeseek/score/master/liftover.c
520519

521-
./configure CFLAGS="-g -Wall -O2 -std=c99"
520+
./configure
522521
make
523522

524523
install ./bcftools $LKTOOLS_DIR

SequenceAnalysis/src/org/labkey/sequenceanalysis/ScatterGatherUtils.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ public static void possiblyCacheSupportFiles(SequenceOutputHandler.JobContext ct
5454
try
5555
{
5656
FileUtils.copyFile(inputFile, localCopy);
57+
if (inputFile.getPath().toLowerCase().endsWith("vcf.gz"))
58+
{
59+
File inputFileIdx = new File(inputFile.getPath() + ".tbi");
60+
File localCopyIdx = new File(ScatterGatherUtils.getLocalCopyDir(ctx, true), inputFile.getName() + ".tbi");
61+
if (!inputFileIdx.exists())
62+
{
63+
throw new PipelineJobException("Unable to find file: " + inputFileIdx.getPath());
64+
}
65+
66+
FileUtils.copyFile(inputFileIdx, localCopyIdx);
67+
}
5768
FileUtils.touch(doneFile);
5869
}
5970
catch (IOException e)

SequenceAnalysis/src/org/labkey/sequenceanalysis/SequenceAnalysisMaintenanceTask.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ else if (!d.getFile().exists())
172172
{
173173
if (d != null && d.getFile() != null && d.getFile().exists())
174174
{
175-
log.error("ReadData marked as archived, but file exists: " + rd.getRowid() + ", " + rd.getFileId1() + ", " + d.getFile().getPath() + " for container: " + (c == null ? rd.getContainer() : c.getPath()));
175+
// NOTE: ultimately remove this:
176+
log.info("ReadData marked as archived, but file exists: " + rd.getRowid() + ", " + rd.getFileId1() + ", " + d.getFile().getPath() + " for container: " + (c == null ? rd.getContainer() : c.getPath()));
176177
}
177178
}
178179
}

SequenceAnalysis/src/org/labkey/sequenceanalysis/run/RestoreSraDataHandler.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -307,15 +307,18 @@ public void complete(PipelineJob job, List<Readset> readsets, List<SequenceOutpu
307307
boolean hasMetrics = new TableSelector(SequenceAnalysisSchema.getTable(SequenceAnalysisSchema.TABLE_QUALITY_METRICS), PageFlowUtil.set("RowId"), filter, null).exists();
308308
if (!hasMetrics)
309309
{
310+
job.getLogger().debug("No existing metrics found for: " + rd.getFileId1());
310311
List<Integer> toAdd = new ArrayList<>(rd.getFileId1());
311312
if (rd.getFileId2() != null)
312313
{
313314
toAdd.add(rd.getFileId2());
314315
}
315316

317+
job.getLogger().debug("adding metrics for " + toAdd.size() + " total fastq files");
316318
for (int dataId : toAdd)
317319
{
318320
//then delete/add:
321+
job.getLogger().debug("adding metrics for: " + dataId);
319322
ReadsetCreationTask.addQualityMetricsForReadset(rs, dataId, job, true);
320323
}
321324
}
@@ -332,15 +335,22 @@ public void complete(PipelineJob job, List<Readset> readsets, List<SequenceOutpu
332335
}
333336
}
334337

335-
Container target = job.getContainer().isWorkbook() ? job.getContainer().getParent() : job.getContainer();
336-
TableInfo ti = QueryService.get().getUserSchema(job.getUser(), target, SequenceAnalysisSchema.SCHEMA_NAME).getTable(SequenceAnalysisSchema.TABLE_READ_DATA);
337-
try
338+
if (!rows.isEmpty())
338339
{
339-
ti.getUpdateService().updateRows(job.getUser(), target, rows, rows, null, null);
340+
Container target = job.getContainer().isWorkbook() ? job.getContainer().getParent() : job.getContainer();
341+
TableInfo ti = QueryService.get().getUserSchema(job.getUser(), target, SequenceAnalysisSchema.SCHEMA_NAME).getTable(SequenceAnalysisSchema.TABLE_READ_DATA);
342+
try
343+
{
344+
ti.getUpdateService().updateRows(job.getUser(), target, rows, rows, null, null);
345+
}
346+
catch (InvalidKeyException | BatchValidationException | QueryUpdateServiceException | SQLException e)
347+
{
348+
throw new PipelineJobException(e);
349+
}
340350
}
341-
catch (InvalidKeyException | BatchValidationException | QueryUpdateServiceException | SQLException e)
351+
else
342352
{
343-
throw new PipelineJobException(e);
353+
job.getLogger().debug("There were no readdata rows to update");
344354
}
345355
}
346356

SequenceAnalysis/src/org/labkey/sequenceanalysis/run/analysis/LofreqAnalysis.java

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public class LofreqAnalysis extends AbstractCommandPipelineStep<LofreqAnalysis.L
9494
{
9595
public static final String CATEGORY = "Lowfreq VCF";
9696

97-
public LofreqAnalysis(PipelineStepProvider provider, PipelineContext ctx)
97+
public LofreqAnalysis(PipelineStepProvider<?> provider, PipelineContext ctx)
9898
{
9999
super(provider, ctx, new LofreqWrapper(ctx.getLogger()));
100100
}
@@ -108,7 +108,7 @@ public Provider()
108108
{{
109109
put("extensions", Arrays.asList("gtf", "gff", "gbk"));
110110
put("width", 400);
111-
put("allowBlank", false);
111+
put("allowBlank", true);
112112
}}, null),
113113
ToolParameterDescriptor.create("minCoverage", "Min Coverage For Consensus", "If provided, a consensus will only be called over regions with at least this depth", "ldk-integerfield", new JSONObject(){{
114114
put("minValue", 0);
@@ -212,7 +212,6 @@ public Output performAnalysisPerSampleRemote(Readset rs, File inputBam, Referenc
212212

213213
File outputVcfRaw = new File(outputDir, FileUtil.getBaseName(inputBam) + ".lofreq.vcf.gz");
214214
File outputVcfFiltered = new File(outputDir, FileUtil.getBaseName(inputBam) + ".lofreq.filtered.vcf.gz");
215-
File outputVcfSnpEff = new File(outputDir, FileUtil.getBaseName(inputBam) + ".lofreq.snpeff.vcf.gz");
216215

217216
//LoFreq call
218217
getWrapper().execute(inputBam, outputVcfRaw, referenceGenome.getWorkingFastaFile(), SequencePipelineService.get().getMaxThreads(getPipelineCtx().getLogger()));
@@ -222,6 +221,9 @@ public Output performAnalysisPerSampleRemote(Readset rs, File inputBam, Referenc
222221
output.addIntermediateFile(outputVcfRaw);
223222
output.addIntermediateFile(new File(outputVcfRaw.getPath() + ".tbi"));
224223

224+
output.addIntermediateFile(outputVcfFiltered);
225+
output.addIntermediateFile(new File(outputVcfFiltered.getPath() + ".tbi"));
226+
225227
//Add depth for downstream use:
226228
File coverageOut = new File(outputDir, SequenceAnalysisService.get().getUnzippedBaseName(outputVcfRaw.getName()) + ".coverage");
227229
runDepthOfCoverage(getPipelineCtx(), output, outputDir, referenceGenome, inputBam, coverageOut);
@@ -438,24 +440,35 @@ public Output performAnalysisPerSampleRemote(Readset rs, File inputBam, Referenc
438440
}
439441

440442
//SnpEff:
443+
File activeVCF = outputVcfFiltered;
441444
Integer geneFileId = getProvider().getParameterByName(SNPEffStep.GENE_PARAM).extractValue(getPipelineCtx().getJob(), getProvider(), getStepIdx(), Integer.class);
442-
File snpEffBaseDir = SNPEffStep.checkOrCreateIndex(getPipelineCtx().getSequenceSupport(), getPipelineCtx().getLogger(), referenceGenome, geneFileId);
445+
if (geneFileId != null)
446+
{
447+
File outputVcfSnpEff = new File(outputDir, FileUtil.getBaseName(inputBam) + ".lofreq.snpeff.vcf.gz");
443448

444-
SnpEffWrapper snpEffWrapper = new SnpEffWrapper(getPipelineCtx().getLogger());
445-
snpEffWrapper.runSnpEff(referenceGenome.getGenomeId(), geneFileId, snpEffBaseDir, outputVcfFiltered, outputVcfSnpEff, null);
449+
File snpEffBaseDir = SNPEffStep.checkOrCreateIndex(getPipelineCtx().getSequenceSupport(), getPipelineCtx().getLogger(), referenceGenome, geneFileId);
450+
SnpEffWrapper snpEffWrapper = new SnpEffWrapper(getPipelineCtx().getLogger());
451+
snpEffWrapper.runSnpEff(referenceGenome.getGenomeId(), geneFileId, snpEffBaseDir, outputVcfFiltered, outputVcfSnpEff, null);
446452

447-
try
448-
{
449-
SequenceAnalysisService.get().ensureVcfIndex(outputVcfSnpEff, getPipelineCtx().getLogger());
453+
try
454+
{
455+
SequenceAnalysisService.get().ensureVcfIndex(outputVcfSnpEff, getPipelineCtx().getLogger());
456+
}
457+
catch (IOException e)
458+
{
459+
throw new PipelineJobException(e);
460+
}
461+
462+
output.addIntermediateFile(outputVcfSnpEff);
463+
output.addIntermediateFile(new File(outputVcfSnpEff.getPath() + ".tbi"));
464+
465+
activeVCF = outputVcfSnpEff;
450466
}
451-
catch (IOException e)
467+
else
452468
{
453-
throw new PipelineJobException(e);
469+
getPipelineCtx().getLogger().info("No GTF provided, skipping SnpEff");
454470
}
455471

456-
output.addIntermediateFile(outputVcfFiltered);
457-
output.addIntermediateFile(new File(outputVcfFiltered.getPath() + ".tbi"));
458-
459472
double minFractionForConsensus = getProvider().getParameterByName("minFractionForConsensus").extractValue(getPipelineCtx().getJob(), getProvider(), getStepIdx(), Double.class, 0.0);
460473

461474
Integer primerDataId = getProvider().getParameterByName("primerBedFile").extractValue(getPipelineCtx().getJob(), getProvider(), getStepIdx(), Integer.class);
@@ -508,7 +521,7 @@ public Output performAnalysisPerSampleRemote(Readset rs, File inputBam, Referenc
508521
SAMSequenceDictionary dict = SAMSequenceDictionaryExtractor.extractDictionary(referenceGenome.getSequenceDictionary().toPath());
509522
VariantContextWriterBuilder writerBuilderConsensus = new VariantContextWriterBuilder().setOutputFile(loFreqConsensusVcf).setReferenceDictionary(dict);
510523
VariantContextWriterBuilder writerBuilderAll = new VariantContextWriterBuilder().setOutputFile(loFreqAllVcf).setReferenceDictionary(dict);
511-
try (VCFFileReader reader = new VCFFileReader(outputVcfSnpEff);CloseableIterator<VariantContext> it = reader.iterator();VariantContextWriter writerConsensus = writerBuilderConsensus.build();VariantContextWriter writerAll = writerBuilderAll.build())
524+
try (VCFFileReader reader = new VCFFileReader(activeVCF);CloseableIterator<VariantContext> it = reader.iterator();VariantContextWriter writerConsensus = writerBuilderConsensus.build();VariantContextWriter writerAll = writerBuilderAll.build())
512525
{
513526
VCFHeader header = reader.getFileHeader();
514527

@@ -706,8 +719,6 @@ public Output performAnalysisPerSampleRemote(Readset rs, File inputBam, Referenc
706719
getPipelineCtx().getLogger().warn("Consensus ambiguities from bcftools and lofreq did not match: " + bcfToolsConsensusNs + " / " + lofreqConsensusNs);
707720
}
708721

709-
output.addIntermediateFile(outputVcfSnpEff);
710-
output.addIntermediateFile(new File(outputVcfSnpEff.getPath() + ".tbi"));
711722
output.addSequenceOutput(coverageOut, "Depth of Coverage: " + rs.getName(), "Depth of Coverage", rs.getReadsetId(), null, referenceGenome.getGenomeId(), null);
712723
output.addSequenceOutput(consensusFastaLoFreq, "Consensus: " + rs.getName(), "Viral Consensus Sequence", rs.getReadsetId(), null, referenceGenome.getGenomeId(), description);
713724

jbrowse/src/client/JBrowse/VariantSearch/components/FilterForm.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ const FilterForm = (props: FilterFormProps ) => {
265265
<InputLabel id="value-select-label">Value</InputLabel>
266266
<Select
267267
labelId="value-select-label"
268+
id={`value-select-${index}`}
268269
value={filter.value}
269270
onChange={(event) =>
270271
handleFilterChange(index, "value", event.target.value)
@@ -305,6 +306,7 @@ const FilterForm = (props: FilterFormProps ) => {
305306
<InputLabel id="value-select-label">Value</InputLabel>
306307
<Select
307308
labelId="value-select-label"
309+
id={`value-select-${index}`}
308310
value={filter.value}
309311
disabled={filter.operator === "is empty" || filter.operator === "is not empty"}
310312
onChange={(event) =>
@@ -321,6 +323,7 @@ const FilterForm = (props: FilterFormProps ) => {
321323
) : (
322324
<TextFieldMinWidth
323325
label="Value"
326+
id={`value-select-${index}`}
324327
sx={ highlightedInputs[index]?.value ? highlightedSx : null }
325328
value={filter.value}
326329
disabled={filter.operator === "is empty" || filter.operator === "is not empty"}

jbrowse/src/org/labkey/jbrowse/JBrowseLuceneSearch.java

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public class JBrowseLuceneSearch
6060
private final JBrowseSession _session;
6161
private final JsonFile _jsonFile;
6262
private final User _user;
63+
private final String[] specialStartPatterns = {"*:* -", "+", "-"};
6364

6465
private JBrowseLuceneSearch(final JBrowseSession session, final JsonFile jsonFile, User u)
6566
{
@@ -105,7 +106,7 @@ private String tryUrlDecode(String input) {
105106
//special case for urls containing +; this isn't necessary for strings sent from the client-side, but URLs
106107
//sent via unit tests autodecode, and strings containing + rather than the URL-encoded symbol are unsafe
107108
//to pass through URLDecoded.decode
108-
if(input.contains("+")) {
109+
if (input.contains("+")) {
109110
return input;
110111
}
111112

@@ -115,6 +116,19 @@ private String tryUrlDecode(String input) {
115116
}
116117
}
117118

119+
public String extractFieldName(String queryString) {
120+
// Check if the query starts with any of the start patterns
121+
for (String pattern : specialStartPatterns) {
122+
if (queryString.startsWith(pattern)) {
123+
queryString = queryString.substring(pattern.length()).trim();
124+
break;
125+
}
126+
}
127+
128+
// Split the remaining string by ':' and return the first part (field name)
129+
String[] parts = queryString.split(":", 2);
130+
return parts.length > 0 ? parts[0].trim() : null;
131+
}
118132

119133
public JSONObject doSearch(User u, String searchString, final int pageSize, final int offset) throws IOException, ParseException
120134
{
@@ -180,18 +194,7 @@ public JSONObject doSearch(User u, String searchString, final int pageSize, fina
180194
String queryString = tokenizer.nextToken();
181195
Query query = null;
182196

183-
// Type is defined by the first field in the lucene query
184-
// "First" field is defined by getting the first consecutive string of ASCII characters or underscores terminated by a colon
185-
// we might just want to return the field(s) in the form instead
186-
Pattern pattern = Pattern.compile("[\\p{ASCII}&&[^\\s:*+-]][\\p{ASCII}&&[^:\\p{Punct}*]]*:");
187-
188-
Matcher matcher = pattern.matcher(queryString);
189-
190-
String fieldName = null;
191-
if (matcher.find())
192-
{
193-
fieldName = matcher.group().substring(0, matcher.group().length() - 1);
194-
}
197+
String fieldName = extractFieldName(queryString);
195198

196199
if (VARIABLE_SAMPLES.equals(fieldName))
197200
{
@@ -202,7 +205,7 @@ public JSONObject doSearch(User u, String searchString, final int pageSize, fina
202205
{
203206
query = queryParser.parse(queryString);
204207
}
205-
else if(numericQueryParserFields.contains(fieldName))
208+
else if (numericQueryParserFields.contains(fieldName))
206209
{
207210
try
208211
{
@@ -212,7 +215,8 @@ else if(numericQueryParserFields.contains(fieldName))
212215
{
213216
e.printStackTrace();
214217
}
215-
} else
218+
}
219+
else
216220
{
217221
throw new IllegalArgumentException("No such field(s), or malformed query.");
218222
}

jbrowse/src/org/labkey/jbrowse/model/JsonFile.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -964,10 +964,32 @@ public File prepareResource(User u, Logger log, boolean throwIfNotPrepared, bool
964964
}
965965
else if (existingLuceneDir != null && existingLuceneDir.exists())
966966
{
967+
// Note: this could exist, but be an empty folder:
968+
if (luceneDir.exists())
969+
{
970+
log.info("Deleting existing lucene index dir: " + luceneDir.getPath());
971+
try
972+
{
973+
FileUtils.deleteDirectory(luceneDir);
974+
}
975+
catch (IOException e)
976+
{
977+
throw new PipelineJobException(e);
978+
}
979+
}
980+
967981
log.debug("Creating symlink to existing index: " + existingLuceneDir.getPath());
982+
log.debug("Symlink target: " + luceneDir.getPath());
983+
968984
try
969985
{
970-
Files.createSymbolicLink(existingLuceneDir.toPath(), existingLuceneDir.toPath());
986+
if (!luceneDir.getParentFile().exists())
987+
{
988+
log.debug("Creating parent directories: " + luceneDir.getParentFile().getPath());
989+
FileUtil.mkdirs(luceneDir.getParentFile());
990+
}
991+
992+
Files.createSymbolicLink(luceneDir.toPath(), existingLuceneDir.toPath());
971993
}
972994
catch (IOException e)
973995
{

0 commit comments

Comments
 (0)