go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/logdog/client/cmd/logdog_butler/subcommand_stream.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package main 16 17 import ( 18 "os" 19 20 "go.chromium.org/luci/common/errors" 21 "go.chromium.org/luci/common/flag/nestedflagset" 22 log "go.chromium.org/luci/common/logging" 23 "go.chromium.org/luci/logdog/client/butler" 24 "go.chromium.org/luci/logdog/client/butlerlib/streamproto" 25 "go.chromium.org/luci/logdog/common/types" 26 27 "github.com/maruel/subcommands" 28 ) 29 30 var subcommandStream = &subcommands.Command{ 31 UsageLine: "stream", 32 ShortDesc: "Serves a single input stream.", 33 LongDesc: "Configures and transmits a single stream from the command-line.", 34 CommandRun: func() subcommands.CommandRun { 35 cmd := &streamCommandRun{} 36 37 cmd.Flags.StringVar(&cmd.path, "source", "-", 38 "The path of the file to stream. If omitted, STDIN will be used") 39 40 streamFlag := &nestedflagset.FlagSet{} 41 cmd.stream.addFlags(&streamFlag.F) 42 cmd.Flags.Var(streamFlag, "stream", "Output stream parameters.") 43 return cmd 44 }, 45 } 46 47 type streamCommandRun struct { 48 subcommands.CommandRunBase 49 50 path string // The stream input path. 51 stream streamConfig // Stream configuration parameters. 52 } 53 54 // subcommands.Run 55 func (cmd *streamCommandRun) Run(app subcommands.Application, args []string, _ subcommands.Env) int { 56 a := app.(*application) 57 58 var ( 59 streamFile *os.File 60 defaultStreamName streamproto.StreamNameFlag 61 ) 62 if cmd.path == "-" { 63 defaultStreamName = "stdin" 64 streamFile = os.Stdin 65 } else { 66 streamName, err := types.MakeStreamName("file:", cmd.path) 67 if err != nil { 68 log.Fields{ 69 log.ErrorKey: err, 70 }.Errorf(a, "Failed to generate stream name.") 71 return runtimeErrorReturnCode 72 } 73 defaultStreamName = streamproto.StreamNameFlag(streamName) 74 75 file, err := os.Open(cmd.path) 76 if err != nil { 77 log.Fields{ 78 log.ErrorKey: err, 79 "path": cmd.path, 80 }.Errorf(a, "Failed to open input stream file.") 81 return runtimeErrorReturnCode 82 } 83 streamFile = file 84 } 85 if cmd.stream.Name == "" { 86 cmd.stream.Name = defaultStreamName 87 } 88 89 // We think everything should work. Configure our Output instance. 90 of, err := a.getOutputFactory() 91 if err != nil { 92 log.WithError(err).Errorf(a, "Failed to get output factory instance.") 93 return runtimeErrorReturnCode 94 } 95 output, err := of.configOutput(a) 96 if err != nil { 97 log.WithError(err).Errorf(a, "Failed to create output instance.") 98 return runtimeErrorReturnCode 99 } 100 defer output.Close() 101 102 // Instantiate our Processor. 103 err = a.runWithButler(output, func(b *butler.Butler) error { 104 if err := b.AddStream(streamFile, cmd.stream.properties()); err != nil { 105 return errors.Annotate(err, "failed to add stream").Err() 106 } 107 108 b.Activate() 109 return b.Wait() 110 }) 111 if err != nil { 112 logAnnotatedErr(a, err, "Failed to stream file.") 113 return runtimeErrorReturnCode 114 } 115 116 return 0 117 }