Repository: broadinstitute/picard
Issue: UpdateVcfSequenceDictionary cannot write index

@ronlevine looks like you introduced a bug, can you fix?  Try writing it to a file with `CREATE_INDEX=true`.  Since you wrapped it with an output stream :/.  I am curious as to why the change was made at all, since shouldn't `VariantContextWriterBuilder.determineOutputTypeFromFile` handle this? What was the original problem?

https://github.com/broadinstitute/picard/blob/master/src/main/java/picard/vcf/UpdateVcfSequenceDictionary.java#L92-L99

Changed files:
src/test/java/picard/vcf/UpdateVcfSequenceDictionaryTest.java, src/main/java/picard/vcf/UpdateVcfSequenceDictionary.java

diff --git a/src/main/java/picard/vcf/UpdateVcfSequenceDictionary.java b/src/main/java/picard/vcf/UpdateVcfSequenceDictionary.java
index d688bebad..eacba3d73 100644
--- a/src/main/java/picard/vcf/UpdateVcfSequenceDictionary.java
+++ b/src/main/java/picard/vcf/UpdateVcfSequenceDictionary.java
@@ -38,15 +38,12 @@ import htsjdk.variant.vcf.VCFFileReader;
 import htsjdk.variant.vcf.VCFHeader;
 import org.broadinstitute.barclay.argparser.Argument;
 import org.broadinstitute.barclay.help.DocumentedFeature;
-import picard.PicardException;
 import picard.cmdline.CommandLineProgram;
 import org.broadinstitute.barclay.argparser.CommandLineProgramProperties;
 import picard.cmdline.StandardOptionDefinitions;
 import picard.cmdline.programgroups.VariantManipulationProgramGroup;
 
 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.
@@ -89,13 +86,7 @@ public class UpdateVcfSequenceDictionary extends CommandLineProgram {
         if (CREATE_INDEX)
             builder.setOption(Options.INDEX_ON_THE_FLY);
 
-        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();
+        final VariantContextWriter vcfWriter = builder.setOutputFile(OUTPUT).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 ee66cad94..c441b9767 100644
--- a/src/test/java/picard/vcf/UpdateVcfSequenceDictionaryTest.java
+++ b/src/test/java/picard/vcf/UpdateVcfSequenceDictionaryTest.java
@@ -30,17 +30,17 @@ 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.io.*;
 import java.lang.reflect.Field;
 
-/**
- * @author George Grant
- */
+
 public class UpdateVcfSequenceDictionaryTest {
     private static final File TEST_DATA_PATH = new File("testdata/picard/vcf/");
+    private static final File INPUT_FILE = new File(TEST_DATA_PATH, "vcfFormatTest.vcf");
+
+    // vcfFormatTest.bad_dict.vcf is a vcf with two (2) ##contig lines deleted
+    private final File SAM_SEQUENCE_DICTIONARY_VCF = new File(TEST_DATA_PATH, "vcfFormatTest.bad_dict.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";
@@ -54,23 +54,41 @@ public class UpdateVcfSequenceDictionaryTest {
     public static Object[][] outputFies() {
 
         return new Object[][] {
-                {OUTPUT_DATA_PATH + "updateVcfSequenceDictionaryTest-delete-me.vcf"},
+                {OUTPUT_DATA_PATH + "updateVcfSequenceDictionaryTest-delete-me"  + IOUtil.COMPRESSED_VCF_FILE_EXTENSION},
+                {OUTPUT_DATA_PATH + "updateVcfSequenceDictionaryTest-delete-me" + IOUtil.VCF_FILE_EXTENSION},
                 {STD_OUT_NAME}
         };
     }
 
+    /**
+     * Utility for unzipping a zipped file's contents into a human readable, unzipped file
+     *
+     * @param zippedFile    input zipped file
+     * @param unzippedFile  unzipped file
+     * @throws IOException
+     */
+    private void unzipFile(final File zippedFile, final File unzippedFile) throws IOException {
+        final InputStream gzInputStream = IOUtil.openFileForReading(zippedFile);
+        final FileOutputStream fileOutputStream = new FileOutputStream(unzippedFile.getAbsolutePath());
+        final byte[] buffer = new byte[1024];
+        int len;
+        while ((len = gzInputStream.read(buffer)) > 0) {
+            fileOutputStream.write(buffer, 0, len);
+        }
+        gzInputStream.close();
+        fileOutputStream.close();
+    }
+
     @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");
         File outputFile = new File(outputFileName);
         outputFile.deleteOnExit();
 
         final UpdateVcfSequenceDictionary updateVcfSequenceDictionary = new UpdateVcfSequenceDictionary();
 
+        updateVcfSequenceDictionary.INPUT = INPUT_FILE;
+        updateVcfSequenceDictionary.SEQUENCE_DICTIONARY = SAM_SEQUENCE_DICTIONARY_VCF;
         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.
@@ -80,25 +98,67 @@ public class UpdateVcfSequenceDictionaryTest {
             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;
 
         Assert.assertEquals(updateVcfSequenceDictionary.instanceMain(new String[0]), 0);
 
         if (outputFileName.equals(STD_OUT_NAME)) {
             outputFile = STD_OUT_FILE;
         }
+        else if (outputFileName.endsWith(IOUtil.COMPRESSED_VCF_FILE_EXTENSION)) {
+            // Output is a gzipped vcf, unzip it
+            File unzippedOutputFile = new File(OUTPUT_DATA_PATH + ".out.vcf");
+            unzippedOutputFile.deleteOnExit();
+            unzipFile(outputFile, unzippedOutputFile);
+            outputFile = unzippedOutputFile;
+        }
 
-        IOUtil.assertFilesEqual(samSequenceDictionaryVcf, outputFile);
+        IOUtil.assertFilesEqual(SAM_SEQUENCE_DICTIONARY_VCF, outputFile);
 
         // A little extra checking.
-        Assert.assertEquals(SAMSequenceDictionaryExtractor.extractDictionary(input.toPath()).size(), 84);
-        Assert.assertEquals(SAMSequenceDictionaryExtractor.extractDictionary(samSequenceDictionaryVcf.toPath()).size(), 82);
+        Assert.assertEquals(SAMSequenceDictionaryExtractor.extractDictionary(INPUT_FILE.toPath()).size(), 84);
+        Assert.assertEquals(SAMSequenceDictionaryExtractor.extractDictionary(SAM_SEQUENCE_DICTIONARY_VCF.toPath()).size(), 82);
         Assert.assertEquals(SAMSequenceDictionaryExtractor.extractDictionary(outputFile.toPath()).size(), 82);
     }
-}
+
+
+    private String classPath = "\\"" + System.getProperty("java.class.path") + "\\" ";
+
+    @Test
+    public void testCaptureStdout() throws IOException {
+        final File outputFile = File.createTempFile("UpdateVcfSequenceDictionaryTest.output.", ".vcf");
+        outputFile.deleteOnExit();
+
+        String[] command = {
+                "/bin/bash",
+                "-c",
+                "java -Dpicard.useLegacyParser=false -classpath " +
+                        classPath +
+                        "picard.cmdline.PicardCommandLine " +
+                        "UpdateVcfSequenceDictionary " +
+                        "-I " + INPUT_FILE.getAbsolutePath() + " " +
+                        "-O /dev/stdout " +
+                        "-SD " + SAM_SEQUENCE_DICTIONARY_VCF.getAbsolutePath()
+        };
+
+        try {
+            ProcessBuilder processBuilder = new ProcessBuilder(command);
+            processBuilder.inheritIO();
+            processBuilder.redirectOutput(outputFile);
+
+            Process process = processBuilder.start();
+            Assert.assertEquals(process.waitFor(), 0);
+
+            IOUtil.assertFilesEqual(SAM_SEQUENCE_DICTIONARY_VCF, outputFile);
+
+            // A little extra checking.
+            Assert.assertEquals(SAMSequenceDictionaryExtractor.extractDictionary(INPUT_FILE.toPath()).size(), 84);
+            Assert.assertEquals(SAMSequenceDictionaryExtractor.extractDictionary(SAM_SEQUENCE_DICTIONARY_VCF.toPath()).size(), 82);
+            Assert.assertEquals(SAMSequenceDictionaryExtractor.extractDictionary(outputFile.toPath()).size(), 82);
+        } catch (Exception e) {
+            Assert.fail("Failure executing UpdateVcfSequenceDictionary", e);
+        }
+    }
+}
\\ No newline at end of file