blob: e8ecd86381ed5c1441a9692dd5654c81085b9dca [file] [log] [blame]
// Copyright 2019 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 packages
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"go.fuchsia.dev/fuchsia/src/sys/pkg/bin/pm/build"
"go.fuchsia.dev/fuchsia/src/sys/pkg/lib/far/go"
)
type FileData []byte
type Package struct {
merkle string
repo *Repository
contents build.MetaContents
}
// newPackage extracts out a package from the repository.
func newPackage(ctx context.Context, repo *Repository, merkle string) (Package, error) {
// Need to parse out the package meta.far to find the package contents.
blob, err := repo.OpenBlob(ctx, merkle)
if err != nil {
return Package{}, err
}
defer blob.Close()
f, err := far.NewReader(blob)
if err != nil {
return Package{}, err
}
defer f.Close()
b, err := f.ReadFile("meta/contents")
if err != nil {
return Package{}, err
}
contents, err := build.ParseMetaContents(bytes.NewReader(b))
if err != nil {
return Package{}, err
}
return Package{
merkle: merkle,
repo: repo,
contents: contents,
}, nil
}
// Merkle returns the meta.far merkle.
func (p *Package) Merkle() string {
return p.merkle
}
// Open opens a file in the package.
func (p *Package) Open(ctx context.Context, path string) (*os.File, error) {
merkle, ok := p.contents[path]
if !ok {
return nil, os.ErrNotExist
}
return p.repo.OpenBlob(ctx, merkle.String())
}
// ReadFile reads a file from a package.
func (p *Package) ReadFile(ctx context.Context, path string) ([]byte, error) {
r, err := p.Open(ctx, path)
if err != nil {
return nil, err
}
return ioutil.ReadAll(r)
}
func (p *Package) Expand(ctx context.Context, dir string) error {
for path := range p.contents {
data, err := p.ReadFile(ctx, path)
if err != nil {
return fmt.Errorf("invalid path. %w", err)
}
realPath := filepath.Join(dir, path)
if err := os.MkdirAll(filepath.Dir(realPath), 0755); err != nil {
return fmt.Errorf("could not create parent directories for %s, %w", realPath, err)
}
if err = ioutil.WriteFile(realPath, data, 0644); err != nil {
return fmt.Errorf("could not export %s to %s. %w", path, realPath, err)
}
}
blob, err := p.repo.OpenBlob(ctx, p.merkle)
if err != nil {
return fmt.Errorf("failed to open meta.far blob. %w", err)
}
defer blob.Close()
f, err := far.NewReader(blob)
if err != nil {
return fmt.Errorf("failed to open reader on blob. %w", err)
}
defer f.Close()
for _, path := range f.List() {
data, err := f.ReadFile(path)
if err != nil {
fmt.Errorf("failed to read %s. %w", path, err)
}
realPath := filepath.Join(dir, path)
if err := os.MkdirAll(filepath.Dir(realPath), 0755); err != nil {
return fmt.Errorf("could not create parent directories for %s, %w", realPath, err)
}
if err = ioutil.WriteFile(realPath, data, 0644); err != nil {
fmt.Errorf("failed to write file %s. %w", realPath, err)
}
}
return nil
}