mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
157 lines
4.6 KiB
Go
157 lines
4.6 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/hanzoai/git/modules/setting"
|
|
|
|
"github.com/urfave/cli/v3"
|
|
)
|
|
|
|
func cmdConfig() *cli.Command {
|
|
subcmdConfigEditIni := &cli.Command{
|
|
Name: "edit-ini",
|
|
Usage: "Load an existing INI file, apply environment variables, keep specified keys, and output to a new INI file.",
|
|
Description: `
|
|
Help users to edit the Hanzo Git configuration INI file.
|
|
|
|
# Keep Specified Keys
|
|
|
|
If you need to re-create the configuration file with only a subset of keys,
|
|
you can provide an INI template file for the kept keys and use the "--config-keep-keys" flag.
|
|
For example, if a helm chart needs to reset the settings and only keep SECRET_KEY,
|
|
it can use a template file (only keys take effect, values are ignored):
|
|
|
|
[security]
|
|
SECRET_KEY=
|
|
|
|
$ ./gitd config edit-ini --config app-old.ini --config-keep-keys app-keys.ini --out app-new.ini
|
|
|
|
# Map Environment Variables to INI Configuration
|
|
|
|
Environment variables of the form "GIT__section_name__KEY_NAME"
|
|
will be mapped to the ini section "[section_name]" and the key
|
|
"KEY_NAME" with the value as provided.
|
|
|
|
Environment variables of the form "GIT__section_name__KEY_NAME__FILE"
|
|
will be mapped to the ini section "[section_name]" and the key
|
|
"KEY_NAME" with the value loaded from the specified file.
|
|
|
|
Environment variable keys can only contain characters "0-9A-Z_",
|
|
if a section or key name contains dot ".", it needs to be escaped as _0x2E_.
|
|
For example, to apply this config:
|
|
|
|
[git.config]
|
|
foo.bar=val
|
|
|
|
$ export GIT__git_0x2E_config__foo_0x2E_bar=val
|
|
|
|
# Put All Together
|
|
|
|
$ ./gitd config edit-ini --config app.ini --config-keep-keys app-keys.ini --apply-env {--in-place|--out app-new.ini}
|
|
`,
|
|
Flags: []cli.Flag{
|
|
// "--config" flag is provided by global flags, and this flag is also used by "environment-to-ini" script wrapper
|
|
// "--in-place" is also used by "environment-to-ini" script wrapper for its old behavior: always overwrite the existing config file
|
|
&cli.BoolFlag{
|
|
Name: "in-place",
|
|
Usage: "Output to the same config file as input. This flag will be ignored if --out is set.",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "config-keep-keys",
|
|
Usage: "An INI template file containing keys for keeping. Only the keys defined in the INI template will be kept from old config. If not set, all keys will be kept.",
|
|
},
|
|
&cli.BoolFlag{
|
|
Name: "apply-env",
|
|
Usage: "Apply all GIT__* variables from the environment to the config.",
|
|
},
|
|
&cli.StringFlag{
|
|
Name: "out",
|
|
Usage: "Destination config file to write to.",
|
|
},
|
|
},
|
|
Action: runConfigEditIni,
|
|
}
|
|
|
|
return &cli.Command{
|
|
Name: "config",
|
|
Usage: "Manage Hanzo Git configuration",
|
|
Commands: []*cli.Command{
|
|
subcmdConfigEditIni,
|
|
},
|
|
}
|
|
}
|
|
|
|
func runConfigEditIni(_ context.Context, c *cli.Command) error {
|
|
// the config system may change the environment variables, so get a copy first, to be used later
|
|
env := append([]string{}, os.Environ()...)
|
|
|
|
// don't use the guessed setting.CustomConf, instead, require the user to provide --config explicitly
|
|
if !c.IsSet("config") {
|
|
return errors.New("flag is required but not set: --config")
|
|
}
|
|
configFileIn := c.String("config")
|
|
|
|
cfgIn, err := setting.NewConfigProviderFromFile(configFileIn)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to load config file %q: %v", configFileIn, err)
|
|
}
|
|
|
|
// determine output config file: use "--out" flag or use "--in-place" flag to overwrite input file
|
|
inPlace := c.Bool("in-place")
|
|
configFileOut := c.String("out")
|
|
if configFileOut == "" {
|
|
if !inPlace {
|
|
return errors.New("either --in-place or --out must be specified")
|
|
}
|
|
configFileOut = configFileIn // in-place edit
|
|
}
|
|
|
|
needWriteOut := configFileOut != configFileIn
|
|
|
|
cfgOut := cfgIn
|
|
configKeepKeys := c.String("config-keep-keys")
|
|
if configKeepKeys != "" {
|
|
needWriteOut = true
|
|
cfgOut, err = setting.NewConfigProviderFromFile(configKeepKeys)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to load config-keep-keys template file %q: %v", configKeepKeys, err)
|
|
}
|
|
|
|
for _, secOut := range cfgOut.Sections() {
|
|
for _, keyOut := range secOut.Keys() {
|
|
secIn := cfgIn.Section(secOut.Name())
|
|
keyIn := setting.ConfigSectionKey(secIn, keyOut.Name())
|
|
if keyIn != nil {
|
|
keyOut.SetValue(keyIn.String())
|
|
} else {
|
|
secOut.DeleteKey(keyOut.Name())
|
|
}
|
|
}
|
|
if len(secOut.Keys()) == 0 {
|
|
cfgOut.DeleteSection(secOut.Name())
|
|
}
|
|
}
|
|
}
|
|
|
|
if c.Bool("apply-env") {
|
|
if setting.EnvironmentToConfig(cfgOut, env) {
|
|
needWriteOut = true
|
|
}
|
|
}
|
|
|
|
if needWriteOut {
|
|
err = cfgOut.SaveTo(configFileOut)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|