1// Copyright 2019 The Pigweed Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); you may not 4// use this file except in compliance with the License. You may obtain a copy of 5// the License at 6// 7// https://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, WITHOUT 11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12// License for the specific language governing permissions and limitations under 13// the License. 14package main 15 16import ( 17 "errors" 18 "flag" 19 "fmt" 20 "io/ioutil" 21 "log" 22 23 "google.golang.org/protobuf/encoding/prototext" 24 "pigweed/pw_target_runner" 25 26 pb "pigweed/proto/pw_target_runner/exec_server_config_pb" 27) 28 29// ServerOptions contains command-line options for the server. 30type ServerOptions struct { 31 // Path to a server configuration file. 32 config string 33 34 // Port on which to run. 35 port int 36} 37 38// configureServerFromFile sets up the server with workers specified in a 39// config file. The file contains a pw.target_runner.ServerConfig protobuf 40// message in canonical protobuf text format. 41func configureServerFromFile(s *pw_target_runner.Server, filepath string) error { 42 content, err := ioutil.ReadFile(filepath) 43 if err != nil { 44 return err 45 } 46 47 var config pb.ServerConfig 48 if err := prototext.Unmarshal(content, &config); err != nil { 49 return err 50 } 51 52 log.Printf("Parsed server configuration from %s\n", filepath) 53 54 runners := config.GetRunner() 55 if runners == nil { 56 return nil 57 } 58 59 // Create an exec worker for each of the runner messages listed in the 60 // config and register them with the server. 61 for i, runner := range runners { 62 // Build the complete command for the worker from its "command" 63 // and "args" fields in the proto message. The command is 64 // required; arguments are optional. 65 cmd := []string{runner.GetCommand()} 66 if cmd[0] == "" { 67 msg := fmt.Sprintf( 68 "ServerConfig.runner[%d] does not specify a command; skipping\n", i) 69 return errors.New(msg) 70 } 71 72 if args := runner.GetArgs(); args != nil { 73 cmd = append(cmd, args...) 74 } 75 76 worker := pw_target_runner.NewExecDeviceRunner(i, cmd) 77 s.RegisterWorker(worker) 78 79 log.Printf( 80 "Registered ExecDeviceRunner %s with args %v\n", 81 cmd[0], 82 cmd[1:]) 83 } 84 85 return nil 86} 87 88func main() { 89 configPtr := flag.String("config", "", "Path to server configuration file") 90 portPtr := flag.Int("port", 8080, "Server port") 91 92 flag.Parse() 93 94 server := pw_target_runner.NewServer() 95 96 if *configPtr != "" { 97 if err := configureServerFromFile(server, *configPtr); err != nil { 98 log.Fatalf("Failed to parse config file %s: %v", *configPtr, err) 99 } 100 } 101 102 if err := server.Bind(*portPtr); err != nil { 103 log.Fatal(err) 104 } 105 106 if err := server.Serve(); err != nil { 107 log.Fatalf("Failed to start server: %v", err) 108 } 109} 110