| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // The following enables go generate to generate the doc.go file. |
| //go:generate go run $JIRI_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . |
| |
| package main |
| |
| import ( |
| "fmt" |
| "sort" |
| "time" |
| |
| "v.io/v23" |
| "v.io/v23/context" |
| "v.io/v23/naming" |
| "v.io/x/lib/cmdline" |
| "v.io/x/lib/set" |
| "v.io/x/lib/vlog" |
| "v.io/x/ref/lib/v23cmd" |
| _ "v.io/x/ref/runtime/factories/generic" |
| "v.io/x/ref/services/internal/binarylib" |
| "v.io/x/ref/services/internal/profiles" |
| "v.io/x/ref/services/repository" |
| ) |
| |
| var cmdBinaryTidy = &cmdline.Command{ |
| Runner: v23cmd.RunnerFunc(runBinaryTidy), |
| Name: "binary", |
| Short: "Binary sub-command tidies a specified binaryd", |
| Long: ` |
| Binary sub-command removes all binaries from a specified binaryd that |
| are not referenced by an applicationd envelope stored in the specified |
| applicationd. |
| `, |
| ArgsName: "<applicationd> <binaryd>", |
| ArgsLong: ` |
| <applicationd> is the name or endpoint of the applicationd instance |
| sourcing the envelopes. |
| <binaryd> is the name or endpoint of a binaryd instance to clean up. |
| `, |
| } |
| |
| // simpleGlob globs the provided endpoint as the namespace cmd does. |
| func mapGlob(ctx *context.T, pattern string, mapFunc func(string)) (error, []error) { |
| ctx, cancel := context.WithTimeout(ctx, time.Minute) |
| defer cancel() |
| |
| ns := v23.GetNamespace(ctx) |
| c, err := ns.Glob(ctx, pattern) |
| if err != nil { |
| vlog.Infof("ns.Glob(%q) failed: %v", pattern, err) |
| return err, nil |
| } |
| |
| errors := []*naming.GlobError{} |
| for res := range c { |
| switch v := res.(type) { |
| case *naming.GlobReplyEntry: |
| if v.Value.Name != "" { |
| mapFunc(v.Value.Name) |
| } |
| case *naming.GlobReplyError: |
| errors = append(errors, &v.Value) |
| } |
| } |
| |
| globErrors := make([]error, 0, len(errors)) |
| for _, err := range errors { |
| globErrors = append(globErrors, fmt.Errorf("Glob error: %s: %v\n", err.Name, err.Error)) |
| } |
| return nil, globErrors |
| } |
| |
| func logGlobErrors(env *cmdline.Env, errors []error) { |
| for _, err := range errors { |
| vlog.Errorf("Glob error: %v", err) |
| } |
| } |
| |
| // getProfileNames uses glob to extract the list of profile names |
| // available from the binary server specified by endpoint. |
| func getProfileNames(ctx *context.T, env *cmdline.Env, endpoint string) ([]string, error) { |
| profiles, err := profiles.GetKnownProfiles() |
| if err != nil { |
| return nil, err |
| } |
| |
| pnames := make([]string, 0, len(profiles)) |
| for _, p := range profiles { |
| pnames = append(pnames, p.Label) |
| } |
| return pnames, nil |
| } |
| |
| func getNames(ctx *context.T, env *cmdline.Env, endpoint string) ([]string, error) { |
| resultSet := make(map[string]struct{}) |
| err, errors := mapGlob(ctx, endpoint, func(s string) { |
| resultSet[s] = struct{}{} |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| logGlobErrors(env, errors) |
| s := set.String.ToSlice(resultSet) |
| sort.Strings(s) |
| return s, nil |
| } |
| |
| func runBinaryTidy(ctx *context.T, env *cmdline.Env, args []string) error { |
| if expected, got := 2, len(args); expected != got { |
| return env.UsageErrorf("match: incorrect number of arguments, expected %d, got %d", expected, got) |
| } |
| |
| appEndpoint, binEndpoint := args[0], args[1] |
| |
| profileNames, err := getProfileNames(ctx, env, binEndpoint) |
| if err != nil { |
| return err |
| } |
| |
| envelopeNames, err := getNames(ctx, env, naming.Join(appEndpoint, "...")) |
| if err != nil { |
| return err |
| } |
| |
| // Add every path in use to a set. Deletion scope is limited to |
| // only the binEndpoint. |
| bpaths := make(map[string]struct{}) |
| for _, en := range envelopeNames { |
| // convert an envelope name into an envelope. |
| ac := repository.ApplicationClient(en) |
| |
| for _, p := range profileNames { |
| e, err := ac.Match(ctx, []string{p}) |
| if err != nil { |
| // This error case is very noisy. |
| vlog.VI(2).Infof("applicationd.Match(%s, %s) failed: %v\n", en, p, err) |
| continue |
| } |
| |
| root, relative := naming.SplitAddressName(e.Binary.File) |
| if root == binEndpoint || root == "" { |
| bpaths[relative] = struct{}{} |
| } |
| for _, sf := range e.Packages { |
| root, relative := naming.SplitAddressName(sf.File) |
| if root == binEndpoint || root == "" { |
| bpaths[relative] = struct{}{} |
| } |
| } |
| } |
| } |
| |
| binaryNames, err := getNames(ctx, env, naming.Join(binEndpoint, "...")) |
| if err != nil { |
| return err |
| } |
| |
| deletionCandidates := make([]int, 0, len(binaryNames)-len(envelopeNames)) |
| for i, bn := range binaryNames { |
| _, relative := naming.SplitAddressName(bn) |
| if _, ok := bpaths[relative]; ok { |
| // relative is mentioned in an envelope. |
| continue |
| } |
| |
| if _, err := binarylib.Stat(ctx, bn); err != nil { |
| // This name is not a binary. |
| continue |
| } |
| deletionCandidates = append(deletionCandidates, i) |
| } |
| |
| for _, i := range deletionCandidates { |
| b := binaryNames[i] |
| if err := binarylib.Delete(ctx, b); err != nil { |
| vlog.Errorf("Couldn't delete binary %s: %v", b, err) |
| } |
| } |
| |
| return nil |
| } |
| |
| var cmdApplicationTidy = &cmdline.Command{ |
| Runner: v23cmd.RunnerFunc(runApplicationTidy), |
| Name: "application", |
| Short: "Application sub-command tidies a specified applicationd", |
| Long: ` |
| Application sub-command uses the Tidy RPC to clean up outdated |
| envelopes from the specified appilcationd. Call this before tidying a |
| binaryd instance for maximum tidiness. |
| `, |
| ArgsName: "<applicationd>", |
| ArgsLong: ` |
| <applicationd> is the name or endpoint of the applicationd instance |
| to tidy. |
| `, |
| } |
| |
| func runApplicationTidy(ctx *context.T, env *cmdline.Env, args []string) error { |
| vlog.Infof("runApplicationTidy") |
| if expected, got := 1, len(args); expected != got { |
| return env.UsageErrorf("match: incorrect number of arguments, expected %d, got %d", expected, got) |
| } |
| ac := repository.ApplicationClient(args[0]) |
| return ac.TidyNow(ctx) |
| } |
| |
| var cmdRoot = &cmdline.Command{ |
| Name: "tidy", |
| Short: "Tidy binary repositories", |
| Long: ` |
| Tidy tidies the Vanadium repository by removing unused |
| envelopes and binaries. |
| `, |
| Children: []*cmdline.Command{cmdBinaryTidy, cmdApplicationTidy}, |
| } |
| |
| func main() { |
| cmdline.HideGlobalFlagsExcept() |
| cmdline.Main(cmdRoot) |
| } |