From f196cb16b24a8e86710c1be5da6f4cf81d4eb90e Mon Sep 17 00:00:00 2001 From: Ron Levine Date: Sat, 28 Jan 2017 09:17:14 -0500 Subject: [PATCH] UpdateVcfSequenceDictionary handles stdout --- .../vcf/UpdateVcfSequenceDictionary.java | 13 ++++- .../vcf/UpdateVcfSequenceDictionaryTest.java | 47 ++++++++++++++++--- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/main/java/picard/vcf/UpdateVcfSequenceDictionary.java b/src/main/java/picard/vcf/UpdateVcfSequenceDictionary.java index b68f96c9f2..06e77ded19 100644 --- a/src/main/java/picard/vcf/UpdateVcfSequenceDictionary.java +++ b/src/main/java/picard/vcf/UpdateVcfSequenceDictionary.java @@ -36,6 +36,7 @@ import htsjdk.variant.variantcontext.writer.VariantContextWriterBuilder; import htsjdk.variant.vcf.VCFFileReader; import htsjdk.variant.vcf.VCFHeader; +import picard.PicardException; import picard.cmdline.CommandLineProgram; import picard.cmdline.CommandLineProgramProperties; import picard.cmdline.Option; @@ -43,6 +44,8 @@ import picard.cmdline.programgroups.VcfOrBcf; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; /** * Takes a VCF file and a Sequence Dictionary (from a variety of file types) and updates the Sequence Dictionary in VCF. @@ -56,7 +59,7 @@ programGroup = VcfOrBcf.class ) public class UpdateVcfSequenceDictionary extends CommandLineProgram { - @Option(shortName = StandardOptionDefinitions.INPUT_SHORT_NAME, doc = "Input VCF") + @Option(shortName = StandardOptionDefinitions.INPUT_SHORT_NAME, doc = "Input VCF") public File INPUT; @Option(shortName = StandardOptionDefinitions.OUTPUT_SHORT_NAME, doc = "Output VCF to be written.") @@ -89,7 +92,13 @@ protected int doWork() { if (CREATE_INDEX) builder.setOption(Options.INDEX_ON_THE_FLY); - final VariantContextWriter vcfWriter = builder.setOutputFile(OUTPUT).build(); + try { + builder.setOutputStream(new FileOutputStream(OUTPUT)); + } catch (final FileNotFoundException ex ) { + throw new PicardException("Could not open " + OUTPUT.getAbsolutePath() + ": " + ex.getMessage(), ex); + } + + final VariantContextWriter vcfWriter = builder.build(); fileHeader.setSequenceDictionary(samSequenceDictionary); vcfWriter.writeHeader(fileHeader); diff --git a/src/test/java/picard/vcf/UpdateVcfSequenceDictionaryTest.java b/src/test/java/picard/vcf/UpdateVcfSequenceDictionaryTest.java index 3f8f4d9bb9..d26d459708 100644 --- a/src/test/java/picard/vcf/UpdateVcfSequenceDictionaryTest.java +++ b/src/test/java/picard/vcf/UpdateVcfSequenceDictionaryTest.java @@ -28,8 +28,13 @@ import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; +import org.testng.annotations.DataProvider; import java.io.File; +import java.io.FileDescriptor; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; /** * @author George Grant @@ -37,28 +42,58 @@ public class UpdateVcfSequenceDictionaryTest { private static final File TEST_DATA_PATH = new File("testdata/picard/vcf/"); private static final File OUTPUT_DATA_PATH = IOUtil.createTempDir("UpdateVcfSequenceDictionaryTest", null); + private static final File STD_OUT_FILE = new File(OUTPUT_DATA_PATH, "stdout.vcf"); + private static final String STD_OUT_NAME = "/dev/stdout"; @AfterClass public void teardown() { IOUtil.deleteDirectoryTree(OUTPUT_DATA_PATH); } - @Test - public void testUpdateVcfSequenceDictionary() { - final File input = new File(TEST_DATA_PATH, "vcfFormatTest.vcf"); + @DataProvider(name = "OutputFiles") + public static Object[][] outputFies() { + + return new Object[][] { + {OUTPUT_DATA_PATH + "updateVcfSequenceDictionaryTest-delete-me.vcf"}, + {STD_OUT_NAME} + }; + } + + @Test(dataProvider = "OutputFiles") + public void testUpdateVcfSequenceDictionary(final String outputFileName) throws IOException, NoSuchFieldException, IllegalAccessException { + File input = new File(TEST_DATA_PATH, "vcfFormatTest.vcf"); // vcfFormatTest.bad_dict.vcf is a vcf with two (2) ##contig lines deleted final File samSequenceDictionaryVcf = new File(TEST_DATA_PATH, "vcfFormatTest.bad_dict.vcf"); - final File outputFile = new File(OUTPUT_DATA_PATH, "updateVcfSequenceDictionaryTest-delete-me.vcf"); - + File outputFile = new File(outputFileName); outputFile.deleteOnExit(); final UpdateVcfSequenceDictionary updateVcfSequenceDictionary = new UpdateVcfSequenceDictionary(); + + if (outputFileName.equals(STD_OUT_NAME)) { + + final FileOutputStream stream = new FileOutputStream(STD_OUT_FILE); + + // Ugliness required to write to a stream given as a string on the commandline. + // Since the actual fd number is private inside FileDescriptor, needs reflection + // in order to pull it out. + + final Field fdField = FileDescriptor.class.getDeclaredField("fd"); + fdField.setAccessible(true); + updateVcfSequenceDictionary.OUTPUT = new File("/dev/fd/" + fdField.getInt(stream.getFD())); + + } else { + final FileOutputStream stream = null; + updateVcfSequenceDictionary.OUTPUT = outputFile; + } updateVcfSequenceDictionary.INPUT = input; updateVcfSequenceDictionary.SEQUENCE_DICTIONARY = samSequenceDictionaryVcf; - updateVcfSequenceDictionary.OUTPUT = outputFile; Assert.assertEquals(updateVcfSequenceDictionary.instanceMain(new String[0]), 0); + if (outputFileName.equals(STD_OUT_NAME)) { + outputFile = STD_OUT_FILE; + } + IOUtil.assertFilesEqual(samSequenceDictionaryVcf, outputFile); // A little extra checking.