blob: 76fb55c120b6db923a9dcbef393b117e076e9293 [file] [log] [blame]
package cos
import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
log "github.com/golang/glog"
"github.com/pkg/errors"
"cos.googlesource.com/cos/tools.git/src/pkg/utils"
)
const (
cosToolsGCS = "cos-tools"
chromiumOSSDKGCS = "chromiumos-sdk"
kernelInfo = "kernel_info"
kernelSrcArchive = "kernel-src.tar.gz"
kernelHeaders = "kernel-headers.tgz"
toolchainURL = "toolchain_url"
toolchainArchive = "toolchain.tar.xz"
toolchainEnv = "toolchain_env"
crosKernelRepo = "https://chromium.googlesource.com/chromiumos/third_party/kernel"
)
// ArtifactsDownloader defines the interface to download COS artifacts.
type ArtifactsDownloader interface {
DownloadKernelSrc(destDir string) error
DownloadToolchainEnv(destDir string) error
DownloadToolchain(destDir string) error
DownloadKernelHeaders(destDir string) error
DownloadArtifact(destDir, artifact string) error
GetArtifact(artifact string) ([]byte, error)
}
// GCSDownloader is the struct downloading COS artifacts from GCS bucket.
type GCSDownloader struct {
envReader *EnvReader
gcsDownloadBucket string
gcsDownloadPrefix string
}
// NewGCSDownloader creates a GCSDownloader instance.
func NewGCSDownloader(e *EnvReader, bucket, prefix string) *GCSDownloader {
// Use cos-tools as the default GCS bucket.
if bucket == "" {
bucket = cosToolsGCS
}
// Use build number as the default GCS download prefix.
if prefix == "" {
prefix = e.BuildNumber()
}
return &GCSDownloader{e, bucket, prefix}
}
// DownloadKernelSrc downloads COS kernel sources to destination directory.
func (d *GCSDownloader) DownloadKernelSrc(destDir string) error {
return d.DownloadArtifact(destDir, kernelSrcArchive)
}
// DownloadToolchainEnv downloads toolchain compilation environment variables to destination directory.
func (d *GCSDownloader) DownloadToolchainEnv(destDir string) error {
return d.DownloadArtifact(destDir, toolchainEnv)
}
// DownloadToolchain downloads toolchain package to destination directory.
func (d *GCSDownloader) DownloadToolchain(destDir string) error {
downloadURL, err := d.getToolchainURL()
if err != nil {
return errors.Wrap(err, "failed to download toolchain")
}
outputPath := filepath.Join(destDir, toolchainArchive)
if err := utils.DownloadContentFromURL(downloadURL, outputPath, toolchainArchive); err != nil {
return errors.Wrap(err, "failed to download toolchain")
}
return nil
}
// DownloadKernelHeaders downloads COS kernel headers to destination directory.
func (d *GCSDownloader) DownloadKernelHeaders(destDir string) error {
return d.DownloadArtifact(destDir, kernelHeaders)
}
// GetArtifact gets an artifact from GCS buckets and returns its content.
func (d *GCSDownloader) GetArtifact(artifactPath string) ([]byte, error) {
tmpDir, err := ioutil.TempDir("", "tmp")
if err != nil {
return nil, errors.Wrap(err, "failed to create temp dir")
}
defer os.RemoveAll(tmpDir)
if err = d.DownloadArtifact(tmpDir, artifactPath); err != nil {
return nil, errors.Wrapf(err, "failed to download artifact %s", artifactPath)
}
content, err := ioutil.ReadFile(filepath.Join(tmpDir, filepath.Base(artifactPath)))
if err != nil {
return nil, errors.Wrapf(err, "failed to read file %s", filepath.Join(tmpDir, artifactPath))
}
return content, nil
}
// DownloadArtifact downloads an artifact from the GCS prefix configured in GCSDownloader.
func (d *GCSDownloader) DownloadArtifact(destDir, artifactPath string) error {
gcsPath := path.Join(d.gcsDownloadPrefix, artifactPath)
if err := utils.DownloadFromGCS(destDir, d.gcsDownloadBucket, gcsPath); err != nil {
return errors.Errorf("failed to download %s from gs://%s/%s", artifactPath, d.gcsDownloadBucket, gcsPath)
}
return nil
}
func (d *GCSDownloader) getToolchainURL() (string, error) {
// First, check if the toolchain path is available locally
tcPath := d.envReader.ToolchainPath()
if tcPath != "" {
log.V(2).Info("Found toolchain path file locally")
return fmt.Sprintf("https://storage.googleapis.com/%s/%s", chromiumOSSDKGCS, tcPath), nil
}
// Next, check if the toolchain path is available in GCS.
tmpDir, err := ioutil.TempDir("", "temp")
if err != nil {
return "", errors.Wrap(err, "failed to create tmp dir")
}
defer os.RemoveAll(tmpDir)
if err := d.DownloadArtifact(tmpDir, toolchainURL); err != nil {
return "", err
}
toolchainURLContent, err := ioutil.ReadFile(filepath.Join(tmpDir, toolchainURL))
if err != nil {
return "", errors.Wrap(err, "failed to read toolchain URL file")
}
return string(toolchainURLContent), nil
}