blob: 075ad9eac6e11da7300828e28e7f37e6fd5fe1f9 [file] [log] [blame]
// Copyright 2020 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 artifactory
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sort"
pm "go.fuchsia.dev/fuchsia/src/sys/pkg/bin/pm/build"
tools "go.fuchsia.dev/fuchsia/tools/build"
)
// BlobsUpload parses all the package manifests in the build and returns an
// Upload for all the blobs.
func BlobsUpload(mods *tools.Modules, destination string) (Upload, error) {
return blobsUpload(mods, destination)
}
func blobsUpload(mods pkgManifestsModules, destination string) (Upload, error) {
// Obtain the absolute paths.
packageManifestList := filepath.Join(mods.BuildDir(), mods.PackageManifestsLocation()[0])
manifests, err := tools.LoadPackageManifests(packageManifestList)
// It's ok for package manifests to not exist, this happens on e.g. SDK-only builders.
if _, err := os.Stat(packageManifestList); os.IsNotExist(err) {
return Upload{
Compress: true,
Contents: []byte("[]"),
Destination: destination,
}, nil
}
if err != nil {
return Upload{}, fmt.Errorf("failed to load list of package manifests: %s", err)
}
absolutePaths := make([]string, len(manifests))
for _, path := range manifests {
absolutePaths = append(absolutePaths, filepath.Join(mods.BuildDir(), path))
}
// Obtain a list of blobs.
blobs, err := loadBlobsFromPackageManifests(absolutePaths)
if err != nil {
return Upload{}, fmt.Errorf("failed to parse blobs: %w", err)
}
// Convert blobs list to json.
blobsJSON, err := json.Marshal(blobs)
if err != nil {
return Upload{}, fmt.Errorf("failed to marshal blobs to json: %w", err)
}
return Upload{
Compress: true,
Contents: blobsJSON,
Destination: destination,
}, nil
}
// loadBlobsFromPackageManifests collects the blobs from the provided package manifests.
func loadBlobsFromPackageManifests(paths []string) ([]pm.PackageBlobInfo, error) {
// The same blob might appear in multiple package manifests.
seen := map[pm.PackageBlobInfo]bool{}
for _, path := range paths {
// It's ok for package manifests to not exist.
if _, err := os.Stat(path); os.IsNotExist(err) {
continue
}
// Collect the blobs from this package manifest.
pkgManifest, err := pm.LoadPackageManifest(path)
if err != nil {
return nil, fmt.Errorf("failed to parse package manifest: %w", err)
}
for _, blob := range pkgManifest.Blobs {
if _, ok := seen[blob]; !ok {
seen[blob] = true
}
}
}
// Convert back to a regular list, sort by hash so it's deterministic.
var blobs []pm.PackageBlobInfo
for blob := range seen {
blobs = append(blobs, blob)
}
sort.Slice(blobs, func(i, j int) bool {
return blobs[i].Merkle.String() < blobs[j].Merkle.String()
})
return blobs, nil
}
type pkgManifestsModules interface {
BuildDir() string
PackageManifestsLocation() []string
}