blob: 5260bc5b1ef2cdab75b41af113dabec7c390c9fc [file] [log] [blame]
// Copyright 2015 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package main
import (
"errors"
"fmt"
"log"
"os"
"path/filepath"
"time"
"github.com/golang/protobuf/proto"
"github.com/maruel/subcommands"
"github.com/luci/luci-go/client/archiver"
"github.com/luci/luci-go/client/internal/common"
"github.com/luci/luci-go/client/isolate"
"github.com/luci/luci-go/common/auth"
"github.com/luci/luci-go/common/data/text/units"
logpb "github.com/luci/luci-go/common/eventlog/proto"
"github.com/luci/luci-go/common/isolatedclient"
)
func cmdArchive(defaultAuthOpts auth.Options) *subcommands.Command {
return &subcommands.Command{
UsageLine: "archive <options>",
ShortDesc: "creates a .isolated file and uploads the tree to an isolate server.",
LongDesc: "All the files listed in the .isolated file are put in the isolate server cache",
CommandRun: func() subcommands.CommandRun {
c := archiveRun{}
c.commonServerFlags.Init(defaultAuthOpts)
c.isolateFlags.Init(&c.Flags)
c.loggingFlags.Init(&c.Flags)
return &c
},
}
}
type archiveRun struct {
commonServerFlags
isolateFlags
loggingFlags loggingFlags
}
func (c *archiveRun) Parse(a subcommands.Application, args []string) error {
if err := c.commonServerFlags.Parse(); err != nil {
return err
}
cwd, err := os.Getwd()
if err != nil {
return err
}
if err := c.isolateFlags.Parse(cwd, RequireIsolatedFile); err != nil {
return err
}
if len(args) != 0 {
return errors.New("position arguments not expected")
}
return nil
}
func (c *archiveRun) main(a subcommands.Application, args []string) error {
out := os.Stdout
prefix := "\n"
if c.defaultFlags.Quiet {
prefix = ""
}
start := time.Now()
client, err := c.createAuthClient()
if err != nil {
return err
}
ctx := c.defaultFlags.MakeLoggingContext(os.Stderr)
arch := archiver.New(ctx, isolatedclient.New(nil, client, c.isolatedFlags.ServerURL, c.isolatedFlags.Namespace, nil, nil), out)
common.CancelOnCtrlC(arch)
item := isolate.Archive(arch, &c.ArchiveOptions)
item.WaitForHashed()
if err = item.Error(); err != nil {
fmt.Printf("%s%s %s\n", prefix, filepath.Base(c.Isolate), err)
} else {
fmt.Printf("%s%s %s\n", prefix, item.Digest(), filepath.Base(c.Isolate))
}
if err2 := arch.Close(); err == nil {
err = err2
}
stats := arch.Stats()
if !c.defaultFlags.Quiet {
duration := time.Since(start)
fmt.Fprintf(os.Stderr, "Hits : %5d (%s)\n", stats.TotalHits(), stats.TotalBytesHits())
fmt.Fprintf(os.Stderr, "Misses : %5d (%s)\n", stats.TotalMisses(), stats.TotalBytesPushed())
fmt.Fprintf(os.Stderr, "Duration: %s\n", units.Round(duration, time.Millisecond))
}
end := time.Now()
archiveDetails := &logpb.IsolateClientEvent_ArchiveDetails{
HitCount: proto.Int64(int64(stats.TotalHits())),
MissCount: proto.Int64(int64(stats.TotalMisses())),
HitBytes: proto.Int64(int64(stats.TotalBytesHits())),
MissBytes: proto.Int64(int64(stats.TotalBytesPushed())),
}
if item.Error() != nil {
archiveDetails.IsolateHash = []string{string(item.Digest())}
}
eventlogger := NewLogger(ctx, c.loggingFlags.EventlogEndpoint)
op := logpb.IsolateClientEvent_LEGACY_ARCHIVE.Enum()
if err := eventlogger.logStats(ctx, op, start, end, archiveDetails); err != nil {
log.Printf("Failed to log to eventlog: %v", err)
}
return err
}
func (c *archiveRun) Run(a subcommands.Application, args []string, _ subcommands.Env) int {
if err := c.Parse(a, args); err != nil {
fmt.Fprintf(a.GetErr(), "%s: %s\n", a.GetName(), err)
return 1
}
cl, err := c.defaultFlags.StartTracing()
if err != nil {
fmt.Fprintf(a.GetErr(), "%s: %s\n", a.GetName(), err)
return 1
}
defer cl.Close()
if err := c.main(a, args); err != nil {
fmt.Fprintf(a.GetErr(), "%s: %s\n", a.GetName(), err)
return 1
}
return 0
}