cmd/gendb: write entries by ID

Create a new directory in the database, called byID, and write one
file there for each osv.Entry, named by the Entry's ID. This provides
a way to quickly get an entry by ID, rather than by affected package.

Change-Id: I9971bbd5b5f8ef384f930915f6bcdc03d1dd05cf
Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/352890
Trust: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Julie Qiu <julie@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Vulndb-Deploy: Roland Shoemaker <bracewell@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
diff --git a/cmd/gendb/main.go b/cmd/gendb/main.go
index 86ffde4..54dac5d 100644
--- a/cmd/gendb/main.go
+++ b/cmd/gendb/main.go
@@ -51,6 +51,7 @@
 	}
 
 	jsonVulns := map[string][]osv.Entry{}
+	var entries []osv.Entry
 	for _, f := range yamlFiles {
 		if !strings.HasSuffix(f.Name(), ".yaml") {
 			continue
@@ -80,6 +81,7 @@
 		for _, path := range paths {
 			jsonVulns[path] = append(jsonVulns[path], entry)
 		}
+		entries = append(entries, entry)
 	}
 
 	index := make(osv.DBIndex, len(jsonVulns))
@@ -109,4 +111,20 @@
 	if err := os.WriteFile(filepath.Join(*jsonDir, "index.json"), indexJSON, 0644); err != nil {
 		failf("failed to write index: %s", err)
 	}
+
+	// Write a directory containing entries by ID.
+	idDir := filepath.Join(*jsonDir, "byID")
+	if err := os.MkdirAll(idDir, 0700); err != nil {
+		failf("failed to create directory %q: %v", idDir, err)
+	}
+	for _, e := range entries {
+		outPath := filepath.Join(idDir, e.ID+".json")
+		content, err := json.Marshal(e)
+		if err != nil {
+			failf("failed to marshal json: %v", err)
+		}
+		if err := os.WriteFile(outPath, content, 0644); err != nil {
+			failf("failed to write %q: %v", outPath, err)
+		}
+	}
 }