[manifest] Sort packages before writing manifest.

CIPD package features broke the stability of the `jiri snapshot` because
they were not sorted before writing. This adds that sort.

Change-Id: Ia7d49d916d49459a5af87d82d26cbc0fe0dc9373
Reviewed-on: https://fuchsia-review.googlesource.com/c/jiri/+/484277
Reviewed-by: Haowei Wu <haowei@google.com>
Reviewed-by: Anirudh Mathukumilli <rudymathu@google.com>
Commit-Queue: Nathan Mulcahey <nmulcahey@google.com>
diff --git a/project/manifest.go b/project/manifest.go
index 196996f..f50abfc 100644
--- a/project/manifest.go
+++ b/project/manifest.go
@@ -163,12 +163,13 @@
 		}
 		projects = append(projects, project)
 	}
-	// Sort the projects and hooks to ensure that the output of "jiri
-	// snapshot" is deterministic.  Sorting the hooks by name allows
+	// Sort the packages, projects and hooks to ensure that the output of
+	// "jiri snapshot" is deterministic.  Sorting the hooks by name allows
 	// some control over the ordering of the hooks in case that is
 	// necessary.
 	sort.Sort(ProjectsByPath(projects))
 	m.Projects = projects
+	sort.Sort(PackagesByKey(m.Packages))
 	sort.Sort(HooksByName(m.Hooks))
 	data, err := m.ToBytes()
 	if err != nil {
@@ -510,6 +511,20 @@
 	ManifestPath string `xml:"-"`
 }
 
+// PackagesByKey implements the Sort interface. It sorts Packages by
+// the synthesized PackageKey.
+type PackagesByKey []Package
+
+func (packages PackagesByKey) Len() int {
+	return len(packages)
+}
+func (packages PackagesByKey) Swap(i, j int) {
+	packages[i], packages[j] = packages[j], packages[i]
+}
+func (packages PackagesByKey) Less(i, j int) bool {
+	return packages[i].Key() < packages[j].Key()
+}
+
 type PackageKey string
 
 type Packages map[PackageKey]Package