[dump_breapad_symbols] use tarutil for Tar archive creation.

Delete main_test.go since it no longer adds value.

Change-Id: Ifab10e4f72c3d2bb723f8b6d9ed1114dfd4fddf4
diff --git a/cmd/dump_breakpad_symbols/main.go b/cmd/dump_breakpad_symbols/main.go
index 1b1eb87..a239786 100755
--- a/cmd/dump_breakpad_symbols/main.go
+++ b/cmd/dump_breakpad_symbols/main.go
@@ -15,7 +15,6 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"log"
 	"os"
 	"os/exec"
@@ -25,6 +24,7 @@
 
 	"fuchsia.googlesource.com/tools/breakpad"
 	"fuchsia.googlesource.com/tools/elflib"
+	"fuchsia.googlesource.com/tools/tarutil"
 )
 
 const usage = `usage: dump_breakpad_symbols [options] file1 file2 ... fileN
@@ -67,12 +67,6 @@
 	tarFilepath  string
 )
 
-// ExecDumpSyms runs the beakpad `dump_syms` command and returns the output.
-type ExecDumpSyms = func(args []string) ([]byte, error)
-
-// CreateFile returns an io.ReadWriteCloser for the file at the given path.
-type CreateFile = func(path string) (io.ReadWriteCloser, error)
-
 func init() {
 	flag.Usage = func() {
 		fmt.Fprint(os.Stderr, usage)
@@ -94,15 +88,6 @@
 }
 
 func execute(ctx context.Context) error {
-	// Callback to run breakpad `dump_syms` command.
-	execDumpSyms := func(args []string) ([]byte, error) {
-		return exec.Command(dumpSymsPath, args...).Output()
-	}
-
-	// Callback to create new files.
-	createFile := func(path string) (io.ReadWriteCloser, error) {
-		return os.Create(path)
-	}
 	// Open the input files for reading.  In practice there are very few files,
 	// so it's fine to open them all at once.
 	var inputReaders []io.Reader
@@ -117,7 +102,7 @@
 	}
 
 	// Process the IDsFiles.
-	summary := processIdsFiles(inputReaders, outdir, execDumpSyms, createFile)
+	summary := processIdsFiles(inputReaders, outdir)
 
 	// Write the Ninja dep file.
 	depfile := depfile{outputPath: tarFilepath, inputPaths: inputPaths}
@@ -133,22 +118,29 @@
 		return fmt.Errorf("wrote 0 bytes to %q", depFilepath)
 	}
 
-	// Create and open tarball.
-	tarFile, err := os.Create(tarFilepath)
+	// Write the tar archive containing all symbol files.
+	tarfd, err := os.Create(tarFilepath)
 	if err != nil {
-		return fmt.Errorf("could not create file %s: %v", tarFilepath, err)
+		return fmt.Errorf("failed to create %q: %v", tarFilepath, err)
 	}
-	defer tarFile.Close()
-
-	// Collect Breakpad symbol files generated by the build to a tarball.
-	if err := writeTarball(tarFile, summary, outdir); err != nil {
-		return fmt.Errorf("failed to generate tarball %s: %v", tarFilepath, err)
+	gzw := gzip.NewWriter(tarfd)
+	defer gzw.Close()
+	tw := tar.NewWriter(gzw)
+	for _, fp := range summary {
+		fd, err := os.Open(fp)
+		if err != nil {
+			return err
+		}
+		defer fd.Close()
+		if err := tarutil.TarReader(tw, fd, fp); err != nil {
+			return fmt.Errorf("failed to archive %q: %v", fp, err)
+		}
 	}
 	return nil
 }
 
 // processIdsFiles dumps symbol data for each executable in a set of ids files.
-func processIdsFiles(idsFiles []io.Reader, outdir string, execDumpSyms ExecDumpSyms, createFile CreateFile) map[string]string {
+func processIdsFiles(idsFiles []io.Reader, outdir string) map[string]string {
 	// Binary paths we've already seen.  Duplicates are skipped.
 	visited := make(map[string]bool)
 	binaryToSymbolFile := make(map[string]string)
@@ -173,7 +165,7 @@
 			// Record that we've seen this binary path.
 			visited[binaryPath] = true
 
-			symbolFilepath, err := generateSymbolFile(binaryPath, createFile, execDumpSyms)
+			symbolFilepath, err := generateSymbolFile(binaryPath)
 			if err != nil {
 				log.Println(err)
 				continue
@@ -187,9 +179,9 @@
 	return binaryToSymbolFile
 }
 
-func generateSymbolFile(path string, createFile CreateFile, execDumpSyms ExecDumpSyms) (outputPath string, err error) {
+func generateSymbolFile(path string) (outputPath string, err error) {
 	outputPath = createSymbolFilepath(outdir, path)
-	output, err := execDumpSyms([]string{path})
+	output, err := exec.Command(dumpSymsPath, path).Output()
 	if err != nil {
 		return "", fmt.Errorf("failed to generate symbol data for %s: %v", path, err)
 	}
@@ -217,7 +209,7 @@
 	// Ensure the module section specifies this is a Fuchsia binary instead of Linux
 	// binary, which is the default for the dump_syms tool.
 	symbolFile.ModuleSection.OS = "Fuchsia"
-	symbolFd, err := createFile(outputPath)
+	symbolFd, err := os.Create(outputPath)
 	if err != nil {
 		return "", fmt.Errorf("failed to create symbol file %s: %v", outputPath, err)
 	}
@@ -287,38 +279,3 @@
 
 	return absPath
 }
-
-func writeTarball(w io.Writer, summary map[string]string, parentDir string) error {
-	gw := gzip.NewWriter(w)
-	defer gw.Close()
-	// Create a tarWriter to perform the tarring task.
-	tw := tar.NewWriter(gw)
-	defer tw.Close()
-
-	// Iterate through the summary file, writting each symbol file to the tarball buffer.
-	for _, file := range summary {
-		data, err := ioutil.ReadFile(file)
-		if err != nil {
-			return fmt.Errorf("failed to read the symbol data file %s: %v", file, err)
-		}
-
-		// Add a file with its relative path instead of absolute path to the tarball.
-		rel, err := filepath.Rel(parentDir, file)
-		if err != nil {
-			return fmt.Errorf("failed to get the relative path from %s to %s: %v", parentDir, file, err)
-		}
-		hdr := &tar.Header{
-			Name: rel,
-			Mode: 0600,
-			Size: int64(len(data)),
-		}
-		if err := tw.WriteHeader(hdr); err != nil {
-			return fmt.Errorf("failed to write header for tarball: %v", err)
-		}
-		if _, err := tw.Write([]byte(data)); err != nil {
-			return fmt.Errorf("failed to write contents for tarball: %v", err)
-		}
-	}
-
-	return nil
-}
diff --git a/cmd/dump_breakpad_symbols/main_test.go b/cmd/dump_breakpad_symbols/main_test.go
deleted file mode 100644
index a382c1b..0000000
--- a/cmd/dump_breakpad_symbols/main_test.go
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2018 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-package main
-
-import (
-	"archive/tar"
-	"bytes"
-	"compress/gzip"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"testing"
-)
-
-// FakeFile is a file-like io.ReadWriteCloser for testing.
-type FakeFile struct {
-	path string
-	*bytes.Buffer
-}
-
-// The filepath of this FakeFile.
-func (f *FakeFile) Name() string {
-	return f.path
-}
-
-// Close implements io.WriteCloser.
-func (f *FakeFile) Close() error {
-	// Noop
-	return nil
-}
-
-func NewFakeFile(path string, contents string) *FakeFile {
-	return &FakeFile{
-		Buffer: bytes.NewBuffer([]byte(contents)),
-		path:   path,
-	}
-}
-
-func checkTarContents(contents []byte, expectedTarFileContents map[string][]byte) error {
-	var contentsBuffer bytes.Buffer
-	contentsBuffer.Write(contents)
-	// Open and iterate through the files in the archive.
-	gzf, err := gzip.NewReader(&contentsBuffer)
-	if err != nil {
-		return fmt.Errorf("reading tarball failed, %v", err)
-	}
-
-	tr := tar.NewReader(gzf)
-	actualTarFileContents := make(map[string][]byte)
-	for {
-		hdr, err := tr.Next()
-		if err == io.EOF {
-			break // End of archive.
-		}
-		if err != nil {
-			return fmt.Errorf("reading tarball failed, %v", err)
-		}
-		actualData := make([]byte, hdr.Size)
-		if _, err := tr.Read(actualData); err != nil && err != io.EOF {
-			return fmt.Errorf("reading tarball data failed, %v", err)
-		}
-		actualTarFileContents[hdr.Name] = actualData
-	}
-
-	for expectedFileName, expectedFileContents := range expectedTarFileContents {
-		actualFileContents, exist := actualTarFileContents[expectedFileName]
-		if !exist {
-			return fmt.Errorf("expecting %s to be found in tarball but not found", expectedFileName)
-		}
-		if !bytes.Equal(actualFileContents, expectedFileContents) {
-			return fmt.Errorf("expecting contents in %s to be found same but not", expectedFileName)
-		}
-	}
-	return nil
-}
-
-func TestRunCommand(t *testing.T) {
-	// Expects dump_breakpad_symbols to produce the specified summary and
-	// ninja depfile from the given input sources.
-	expectOutputs := func(t *testing.T, inputs []*FakeFile, expectedDepFile string, expectedTarFileContents map[string][]byte, outDir string) {
-		tarFile := NewFakeFile("breakpad_symbols.tar.gz", "")
-
-		// Callback to mock executing the breakpad dump_syms binary.
-		execDumpSyms := func(args []string) ([]byte, error) {
-			return []byte("FAKE_SYMBOL_DATA_LINE_1\nFAKE_SYMBOL_DATA_LINE_2"), nil
-		}
-
-		// Callback to perform file I/O.
-		createFile := func(path string) (io.ReadWriteCloser, error) {
-			return NewFakeFile(path, ""), nil
-		}
-
-		// Convert input files from `[]FakeFile` to `[]io.Reader`.
-		fileReaders := make([]io.Reader, len(inputs))
-		for i := range inputs {
-			fileReaders[i] = inputs[i]
-		}
-
-		// Process the input files.
-		summary := processIdsFiles(fileReaders, outDir, execDumpSyms, createFile)
-
-		// Write the tarball file.
-		if err := writeTarball(tarFile, summary, outDir); err != nil {
-			t.Fatalf("failed to write tarball %s: %v", tarFile.Name(), err)
-		}
-
-		// Extract input filepaths.
-		inputPaths := make([]string, len(inputs))
-		for i := range inputs {
-			inputPaths[i] = inputs[i].Name()
-		}
-
-		// Expect matching tarball.
-		actualTarFile, err := ioutil.ReadAll(tarFile)
-		if err != nil {
-			t.Fatal(err)
-		}
-		if err := checkTarContents(actualTarFile, expectedTarFileContents); err != nil {
-			t.Fatalf("%v", err)
-		}
-	}
-
-	t.Run("should produce an emtpy summary if no data is provided", func(t *testing.T) {
-		inputSources := []*FakeFile{
-			NewFakeFile("idsA.txt", ""),
-			NewFakeFile("idsB.txt", ""),
-		}
-		expectedDepFile := fmt.Sprintf("breakpad_symbols.tar.gz: %s %s\n", "idsA.txt", "idsB.txt")
-		expectOutputs(t, inputSources, expectedDepFile, make(map[string][]byte), "out/")
-	})
-}
-
-// No tests to verify the output of dump_syms. Assume it does the right thing.