| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This file contains flag definitions for the config_parser package as well |
| // as all the functions which make direct use of these flags. |
| // TODO(fxbug.dev/87114): Refactor and test. This is half of the logic that was ripped out |
| // config_parser_main.go and it still needs to be refactored. |
| package config_parser |
| |
| import ( |
| "flag" |
| "fmt" |
| "time" |
| ) |
| |
| var ( |
| repoUrls flagList |
| configDirs flagList |
| configFile = flag.String("config_file", "", "File containing the config for a single project. Exactly one of 'repo_url', 'config_file' or 'config_dir' must be specified.") |
| customerId = flag.Int64("customer_id", -1, "Customer Id for the config to be read. Must be set if and only if 'config_file' is set.") |
| projectId = flag.Int64("project_id", -1, "Project Id for the config to be read. Must be set if and only if 'config_file' is set.") |
| gitTimeoutSec = flag.Int64("git_timeout", 60, "How many seconds should I wait on git commands?") |
| ) |
| |
| type flagList []string |
| |
| func (f *flagList) String() string { |
| return fmt.Sprintf("%q", *f) |
| } |
| |
| func (f *flagList) Set(value string) error { |
| *f = append(*f, value) |
| return nil |
| } |
| |
| // Initialization function that is run before any main(). |
| func init() { |
| flag.Var(&repoUrls, "repo_url", "URL of the repository containing the config, can be specified multiple times. Exactly one of 'repo_url', 'config_file' or 'config_dir' must be specified.") |
| flag.Var(&configDirs, "config_dir", "Directory containing the config, can be specified multiple times. Exactly one of 'repo_url', 'config_file' or 'config_dir' must be specified.") |
| } |
| |
| // checkFlags verifies that the specified flags are compatible with each other. |
| func checkFlags() error { |
| if (len(repoUrls) == 0) == (len(configDirs) == 0) == (*configFile == "") { |
| return fmt.Errorf("Exactly one of 'repo_url', 'config_file' and 'config_dir' must be set.") |
| } |
| |
| if *configFile == "" && len(configDirs) == 0 && (*customerId >= 0 || *projectId >= 0) { |
| return fmt.Errorf("'customer_id' and 'project_id' must be set if and only if 'config_file' or 'config_dir' are set.") |
| } |
| |
| if *configFile != "" && (*customerId < 0 || *projectId < 0) { |
| return fmt.Errorf("If 'config_file' is set, both 'customer_id' and 'project_id' must be set.") |
| } |
| |
| return nil |
| } |
| |
| // appendNewCustomers adds the new project configs to the list, verifying that |
| // none of their customers overlap with existing customers. |
| func appendNewCustomers(existingCustomers map[uint32]string, configs []ProjectConfigData, newConfigs ...ProjectConfigData) (map[uint32]string, []ProjectConfigData, error) { |
| for _, config := range newConfigs { |
| if customerName, ok := existingCustomers[config.CustomerId]; ok { |
| return nil, nil, fmt.Errorf("Duplicate customer ID %v for customers %s and %s", config.CustomerId, customerName, config.CustomerName) |
| } |
| } |
| configs = append(configs, newConfigs...) |
| for _, config := range newConfigs { |
| existingCustomers[config.CustomerId] = config.CustomerName |
| } |
| return existingCustomers, configs, nil |
| } |
| |
| // ParseProjectConfigDataFromFlags uses the specified flags to find the |
| // specified registry, read and parse it. |
| func ParseProjectConfigDataFromFlags() ([]ProjectConfigData, error) { |
| if err := checkFlags(); err != nil { |
| return nil, err |
| } |
| |
| existingCustomers := make(map[uint32]string) |
| configs := []ProjectConfigData{} |
| var pc ProjectConfigData |
| var err error |
| if len(repoUrls) != 0 { |
| gitTimeout := time.Duration(*gitTimeoutSec) * time.Second |
| var repoConfigs []ProjectConfigData |
| for _, repoUrl := range repoUrls { |
| if repoConfigs, err = ReadConfigFromRepo(repoUrl, gitTimeout); err != nil { |
| return nil, err |
| } |
| if existingCustomers, configs, err = appendNewCustomers(existingCustomers, configs, repoConfigs...); err != nil { |
| return nil, err |
| } |
| } |
| } else if *configFile != "" { |
| version := CobaltVersion1 |
| if pc, err = ReadConfigFromYaml(*configFile, uint32(*customerId), uint32(*projectId), CobaltVersion(version)); err != nil { |
| return nil, err |
| } |
| if existingCustomers, configs, err = appendNewCustomers(existingCustomers, configs, pc); err != nil { |
| return nil, err |
| } |
| } else if *customerId >= 0 && *projectId >= 0 { |
| for _, configDir := range configDirs { |
| if pc, err = ReadProjectConfigDataFromDir(configDir, uint32(*customerId), uint32(*projectId)); err != nil { |
| return nil, err |
| } |
| if existingCustomers, configs, err = appendNewCustomers(existingCustomers, configs, pc); err != nil { |
| return nil, err |
| } |
| } |
| } else { |
| var dirConfigs []ProjectConfigData |
| for _, configDir := range configDirs { |
| if dirConfigs, err = ReadConfigFromDir(configDir); err != nil { |
| return nil, err |
| } |
| if existingCustomers, configs, err = appendNewCustomers(existingCustomers, configs, dirConfigs...); err != nil { |
| return nil, err |
| } |
| } |
| } |
| return configs, err |
| } |
| |
| // GetConfigFilesListFromFlags returns a list of all the files that comprise |
| // the registry being parsed. This can be used to generate a depfile. |
| func GetConfigFilesListFromFlags() ([]string, error) { |
| if err := checkFlags(); err != nil { |
| return nil, err |
| } |
| if *configFile != "" { |
| return []string{*configFile}, nil |
| } else if len(configDirs) != 0 { |
| files := []string{} |
| var dirFiles []string |
| var err error |
| for _, configDir := range configDirs { |
| dirFiles, err = GetConfigFilesListFromConfigDir(configDir) |
| files = append(files, dirFiles...) |
| } |
| return files, err |
| } |
| return nil, fmt.Errorf("-dep_file requires -config_dir or -config_file") |
| } |