| Index: go/src/infra/tools/cipd/builder.go
|
| diff --git a/go/src/infra/tools/cipd/builder.go b/go/src/infra/tools/cipd/builder.go
|
| deleted file mode 100644
|
| index f2ce0f0d07c9a95fcd9e29183416736d0381c3ee..0000000000000000000000000000000000000000
|
| --- a/go/src/infra/tools/cipd/builder.go
|
| +++ /dev/null
|
| @@ -1,174 +0,0 @@
|
| -// Copyright 2014 The Chromium 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 cipd
|
| -
|
| -import (
|
| - "archive/zip"
|
| - "bytes"
|
| - "fmt"
|
| - "io"
|
| - "io/ioutil"
|
| - "os"
|
| - "strings"
|
| - "time"
|
| -)
|
| -
|
| -// BuildInstanceOptions defines options for BuildInstance function.
|
| -type BuildInstanceOptions struct {
|
| - // List of files to add to the package.
|
| - Input []File
|
| - // Where to write the package file to.
|
| - Output io.Writer
|
| - // Package name, e.g. 'infra/tools/cipd'.
|
| - PackageName string
|
| -}
|
| -
|
| -// BuildInstance builds a new package instance for package named opts.PackageName
|
| -// by archiving input files (passed via opts.Input). The final binary is written
|
| -// to opts.Output. Some output may be written even if BuildInstance eventually
|
| -// returns an error.
|
| -func BuildInstance(opts BuildInstanceOptions) error {
|
| - err := ValidatePackageName(opts.PackageName)
|
| - if err != nil {
|
| - return err
|
| - }
|
| -
|
| - // Make sure no files are written to package service directory.
|
| - for _, f := range opts.Input {
|
| - if strings.HasPrefix(f.Name(), packageServiceDir+"/") {
|
| - return fmt.Errorf("Can't write to %s: %s", packageServiceDir, f.Name())
|
| - }
|
| - }
|
| -
|
| - // Generate the manifest file, add to the list of input files.
|
| - manifestFile, err := makeManifestFile(opts)
|
| - if err != nil {
|
| - return err
|
| - }
|
| - files := append(opts.Input, manifestFile)
|
| -
|
| - // Make sure filenames are unique.
|
| - seenNames := make(map[string]struct{}, len(files))
|
| - for _, f := range files {
|
| - _, seen := seenNames[f.Name()]
|
| - if seen {
|
| - return fmt.Errorf("File %s is provided twice", f.Name())
|
| - }
|
| - seenNames[f.Name()] = struct{}{}
|
| - }
|
| -
|
| - // Write the final zip file.
|
| - return zipInputFiles(files, opts.Output)
|
| -}
|
| -
|
| -// zipInputFiles deterministically builds a zip archive out of input files and
|
| -// writes it to the writer. Files are written in the order given.
|
| -func zipInputFiles(files []File, w io.Writer) error {
|
| - writer := zip.NewWriter(w)
|
| - defer writer.Close()
|
| -
|
| - // Reports zipping progress to the log each second.
|
| - lastReport := time.Time{}
|
| - progress := func(count int) {
|
| - if time.Since(lastReport) > time.Second {
|
| - lastReport = time.Now()
|
| - log.Infof("Zipping files: %d files left", len(files)-count)
|
| - }
|
| - }
|
| -
|
| - for i, in := range files {
|
| - progress(i)
|
| -
|
| - // Intentionally do not add timestamp or file mode to make zip archive
|
| - // deterministic. See also zip.FileInfoHeader() implementation.
|
| - fh := zip.FileHeader{
|
| - Name: in.Name(),
|
| - Method: zip.Deflate,
|
| - }
|
| -
|
| - mode := os.FileMode(0600)
|
| - if in.Executable() {
|
| - mode |= 0100
|
| - }
|
| - if in.Symlink() {
|
| - mode |= os.ModeSymlink
|
| - }
|
| - fh.SetMode(mode)
|
| -
|
| - dst, err := writer.CreateHeader(&fh)
|
| - if err != nil {
|
| - return err
|
| - }
|
| - if in.Symlink() {
|
| - err = zipSymlinkFile(dst, in)
|
| - } else {
|
| - err = zipRegularFile(dst, in)
|
| - }
|
| - if err != nil {
|
| - return err
|
| - }
|
| - }
|
| -
|
| - return nil
|
| -}
|
| -
|
| -func zipRegularFile(dst io.Writer, f File) error {
|
| - src, err := f.Open()
|
| - if err != nil {
|
| - return err
|
| - }
|
| - defer src.Close()
|
| - written, err := io.Copy(dst, src)
|
| - if err != nil {
|
| - return err
|
| - }
|
| - if uint64(written) != f.Size() {
|
| - return fmt.Errorf("File %s changed midway", f.Name())
|
| - }
|
| - return nil
|
| -}
|
| -
|
| -func zipSymlinkFile(dst io.Writer, f File) error {
|
| - target, err := f.SymlinkTarget()
|
| - if err != nil {
|
| - return err
|
| - }
|
| - // Symlinks are zipped as text files with target path. os.ModeSymlink bit in
|
| - // the header distinguishes them from regular files.
|
| - _, err = dst.Write([]byte(target))
|
| - return err
|
| -}
|
| -
|
| -////////////////////////////////////////////////////////////////////////////////
|
| -
|
| -type manifestFile []byte
|
| -
|
| -func (m *manifestFile) Name() string { return manifestName }
|
| -func (m *manifestFile) Size() uint64 { return uint64(len(*m)) }
|
| -func (m *manifestFile) Executable() bool { return false }
|
| -func (m *manifestFile) Symlink() bool { return false }
|
| -
|
| -func (m *manifestFile) SymlinkTarget() (string, error) {
|
| - return "", fmt.Errorf("Not a symlink: %s", m.Name())
|
| -}
|
| -
|
| -func (m *manifestFile) Open() (io.ReadCloser, error) {
|
| - return ioutil.NopCloser(bytes.NewReader(*m)), nil
|
| -}
|
| -
|
| -// makeManifestFile generates a package manifest file and returns it as
|
| -// File interface.
|
| -func makeManifestFile(opts BuildInstanceOptions) (File, error) {
|
| - buf := &bytes.Buffer{}
|
| - err := writeManifest(&Manifest{
|
| - FormatVersion: manifestFormatVersion,
|
| - PackageName: opts.PackageName,
|
| - }, buf)
|
| - if err != nil {
|
| - return nil, err
|
| - }
|
| - out := manifestFile(buf.Bytes())
|
| - return &out, nil
|
| -}
|
|
|