[pm][expand] Write more metadata files

When expanding an archived package, also generate and write the merkle
root of the meta.far (meta.far.merkle) and the blob metadata file
(blobs.json) so the prebuilt_package template/script don't need to parse
the meta/contents file to generate a correct blobs.json file.

Test: build topaz, verify generated outputs of chromium
Change-Id: I6bd01c01fe08bb2169a16b640f6cc539a08bdc04
diff --git a/go/src/pm/cmd/pm/expand/expand.go b/go/src/pm/cmd/pm/expand/expand.go
index cff3712..a28176f 100644
--- a/go/src/pm/cmd/pm/expand/expand.go
+++ b/go/src/pm/cmd/pm/expand/expand.go
@@ -11,6 +11,7 @@
 	"flag"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"log"
 	"os"
 	"path/filepath"
@@ -20,6 +21,7 @@
 	"sync/atomic"
 
 	"fuchsia.googlesource.com/far"
+	"fuchsia.googlesource.com/merkle"
 	"fuchsia.googlesource.com/pm/build"
 	"fuchsia.googlesource.com/pm/pkg"
 )
@@ -66,7 +68,7 @@
 		return err
 	}
 
-	if err := writeMetaAndManifest(pkgArchive, outputDir); err != nil {
+	if err := writeMetadataAndManifest(pkgArchive, outputDir); err != nil {
 		return err
 	}
 
@@ -77,27 +79,96 @@
 	return nil
 }
 
+func merkleFor(b []byte) (build.MerkleRoot, error) {
+	var res build.MerkleRoot
+
+	var tree merkle.Tree
+	if _, err := tree.ReadFrom(bytes.NewReader(b)); err != nil {
+		return res, err
+	}
+
+	copy(res[:], tree.Root())
+
+	return res, nil
+}
+
 // Extract the meta.far to the `outputDir`, and write out a package manifest
 // into `$outputDir/package.manifest`. for it. The format of the manifest is:
 //
 //     $PKG_NAME.$PKG_VERSION=$outputDir/meta.far
-func writeMetaAndManifest(pkgArchive *far.Reader, outputDir string) error {
+func writeMetadataAndManifest(pkgArchive *far.Reader, outputDir string) error {
 	// First, extract the package info from the archive, or error out if
 	// the meta.far is malformed.
-	p, err := extractMetaPackage(pkgArchive)
+	pkgMetaBytes, err := pkgArchive.ReadFile(metaFar)
 	if err != nil {
 		return err
 	}
 
+	pkgMetaMerkle, err := merkleFor(pkgMetaBytes)
+	if err != nil {
+		return err
+	}
+
+	pkgMeta, err := far.NewReader(bytes.NewReader(pkgMetaBytes))
+	if err != nil {
+		return err
+	}
+
+	p, err := readMetaPackage(pkgMeta)
+	if err != nil {
+		return err
+	}
+
+	contents, err := readMetaContents(pkgMeta)
+	if err != nil {
+		return err
+	}
+
+	blobs := make([]build.PackageBlobInfo, 0, len(contents)+1)
+
+	blobs = append(blobs, build.PackageBlobInfo{
+		SourcePath: filepath.Join(outputDir, metaFar),
+		Path:       "meta/",
+		Merkle:     pkgMetaMerkle,
+		Size:       uint64(len(pkgMetaBytes)),
+	})
+
+	for path, merkle := range contents {
+		blobs = append(blobs, build.PackageBlobInfo{
+			SourcePath: filepath.Join(outputDir, "blobs", merkle.String()),
+			Path:       path,
+			Merkle:     merkle,
+			Size:       pkgArchive.GetSize(merkle.String()),
+		})
+	}
+
 	if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
 		return err
 	}
 
-	if err := writeEntry(pkgArchive, outputDir, metaFar); err != nil {
+	// Write meta.far
+	if err := ioutil.WriteFile(filepath.Join(outputDir, metaFar), pkgMetaBytes, 0666); err != nil {
 		return err
 	}
 
-	f, err := os.Create(filepath.Join(outputDir, "package.manifest"))
+	// Write meta.far.merkle
+	if err := ioutil.WriteFile(filepath.Join(outputDir, metaFar+".merkle"), []byte(pkgMetaMerkle.String()), 0666); err != nil {
+		return err
+	}
+
+	// Write blobs.json
+	f, err := os.Create(filepath.Join(outputDir, "blobs.json"))
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	if err := json.NewEncoder(f).Encode(blobs); err != nil {
+		return err
+	}
+
+	// Write package.manifest
+	f, err = os.Create(filepath.Join(outputDir, "package.manifest"))
 	if err != nil {
 		return err
 	}
@@ -112,17 +183,7 @@
 }
 
 // Extract the meta-package from the archive.
-func extractMetaPackage(pkgArchive *far.Reader) (*pkg.Package, error) {
-	b, err := pkgArchive.ReadFile(metaFar)
-	if err != nil {
-		return nil, err
-	}
-
-	pkgMeta, err := far.NewReader(bytes.NewReader(b))
-	if err != nil {
-		return nil, err
-	}
-
+func readMetaPackage(pkgMeta *far.Reader) (*pkg.Package, error) {
 	pkgJSON, err := pkgMeta.ReadFile("meta/package")
 	if err != nil {
 		return nil, err
@@ -136,6 +197,16 @@
 	return &p, nil
 }
 
+// Extract the meta-contents from the archive.
+func readMetaContents(pkgMeta *far.Reader) (build.MetaContents, error) {
+	b, err := pkgMeta.ReadFile("meta/contents")
+	if err != nil {
+		return nil, err
+	}
+
+	return build.ParseMetaContents(bytes.NewReader(b))
+}
+
 // Extract out all the blobs into the `outputDir`, and write out a blob
 // manifest into `$outputDir/blobs.manifest`. The format of the manifest is:
 //