161 lines
4.2 KiB
Go
161 lines
4.2 KiB
Go
// Copyright 2019 The Chromium OS 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 main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
var errNoSuchCmdlineArg = errors.New("no such commandline argument")
|
|
|
|
// Removes one flag from `builder`, assuming that a value follows the flag. Two formats are
|
|
// supported for this: `--foo=bar` and `--foo bar`. In either case, "bar" will be returned as the
|
|
// `value`.
|
|
//
|
|
// If no flag is found on the commandline, this returns the `errNoSuchCmdlineArg` error. `builder`
|
|
// is unmodified if this error is returned, but its contents are unspecified if any other error is
|
|
// returned.
|
|
//
|
|
// In the case of multiple such flags, only the first encountered will be removed.
|
|
func removeOneUserCmdlineFlagWithValue(builder *commandBuilder, flagName string) (flagValue string, err error) {
|
|
const (
|
|
searchingForFlag uint8 = iota
|
|
searchingForValue
|
|
searchComplete
|
|
)
|
|
|
|
flagRequiresAValue := func() error { return newUserErrorf("flag %q requires a value", flagName) }
|
|
searchState := searchingForFlag
|
|
builder.transformArgs(func(arg builderArg) string {
|
|
if err != nil {
|
|
return arg.value
|
|
}
|
|
|
|
switch searchState {
|
|
case searchingForFlag:
|
|
if !arg.fromUser {
|
|
return arg.value
|
|
}
|
|
|
|
if arg.value == flagName {
|
|
searchState = searchingForValue
|
|
return ""
|
|
}
|
|
|
|
isArgEq := strings.HasPrefix(arg.value, flagName) && arg.value[len(flagName)] == '='
|
|
if !isArgEq {
|
|
return arg.value
|
|
}
|
|
|
|
flagValue = arg.value[len(flagName)+1:]
|
|
searchState = searchComplete
|
|
return ""
|
|
|
|
case searchingForValue:
|
|
if !arg.fromUser {
|
|
err = flagRequiresAValue()
|
|
return arg.value
|
|
}
|
|
|
|
flagValue = arg.value
|
|
searchState = searchComplete
|
|
return ""
|
|
|
|
case searchComplete:
|
|
return arg.value
|
|
|
|
default:
|
|
panic(fmt.Sprintf("unknown search state: %v", searchState))
|
|
}
|
|
})
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
switch searchState {
|
|
case searchingForFlag:
|
|
return "", errNoSuchCmdlineArg
|
|
|
|
case searchingForValue:
|
|
return "", flagRequiresAValue()
|
|
|
|
case searchComplete:
|
|
return flagValue, nil
|
|
|
|
default:
|
|
panic(fmt.Sprintf("unknown search state: %v", searchState))
|
|
}
|
|
}
|
|
|
|
func processGomaCccFlags(builder *commandBuilder, inheritFromEnv bool) (gomaUsed bool, err error) {
|
|
gomaPath, err := removeOneUserCmdlineFlagWithValue(builder, "--gomacc-path")
|
|
if err != nil && err != errNoSuchCmdlineArg {
|
|
return false, err
|
|
}
|
|
|
|
if inheritFromEnv && (err == errNoSuchCmdlineArg || gomaPath == "") {
|
|
gomaPath, _ = builder.env.getenv("GOMACC_PATH")
|
|
}
|
|
|
|
if gomaPath != "" {
|
|
if _, err := os.Lstat(gomaPath); err == nil {
|
|
builder.wrapPath(gomaPath)
|
|
return true, nil
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func processRewrapperCcFlags(builder *commandBuilder) (rewrapperUsed bool, err error) {
|
|
rewrapperPath, pathErr := removeOneUserCmdlineFlagWithValue(builder, "--rewrapper-path")
|
|
if pathErr != nil && pathErr != errNoSuchCmdlineArg {
|
|
return false, err
|
|
}
|
|
|
|
rewrapperCfg, cfgErr := removeOneUserCmdlineFlagWithValue(builder, "--rewrapper-cfg")
|
|
if cfgErr != nil && cfgErr != errNoSuchCmdlineArg {
|
|
return false, err
|
|
}
|
|
|
|
if pathErr == errNoSuchCmdlineArg {
|
|
if cfgErr != errNoSuchCmdlineArg {
|
|
return false, newUserErrorf("--rewrapper-path must be specified if --rewrapper-cfg is")
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
if cfgErr == errNoSuchCmdlineArg {
|
|
return false, newUserErrorf("--rewrapper-cfg must be specified if --rewrapper-path is")
|
|
}
|
|
|
|
// It's unclear that we should have a similar fallback to gomacc if --rewrapper-path doesn't
|
|
// exist, so don't until it's obviously necessary.
|
|
builder.wrapPath(rewrapperPath, "-cfg", rewrapperCfg)
|
|
return true, nil
|
|
}
|
|
|
|
func processRemoteBuildFlags(builder *commandBuilder) (remoteBuildUsed bool, err error) {
|
|
rewrapperUsed, err := processRewrapperCcFlags(builder)
|
|
if err != nil {
|
|
return rewrapperUsed, err
|
|
}
|
|
|
|
inheritGomaFromEnv := !rewrapperUsed
|
|
gomaUsed, err := processGomaCccFlags(builder, inheritGomaFromEnv)
|
|
remoteBuildUsed = gomaUsed || rewrapperUsed
|
|
if err != nil {
|
|
return remoteBuildUsed, err
|
|
}
|
|
|
|
if gomaUsed && rewrapperUsed {
|
|
return true, newUserErrorf("rewrapper and gomacc are mutually exclusive")
|
|
}
|
|
return remoteBuildUsed, nil
|
|
}
|