You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
598 lines
22 KiB
Go
598 lines
22 KiB
Go
// Package config handles all the user-configuration. The fields here are
|
|
// all in PascalCase but in your actual config.yml they'll be in camelCase.
|
|
// You can view the default config with `lazydocker --config`.
|
|
// You can open your config file by going to the status panel (using left-arrow)
|
|
// and pressing 'o'.
|
|
// You can directly edit the file (e.g. in vim) by pressing 'e' instead.
|
|
// To see the final config after your user-specific options have been merged
|
|
// with the defaults, go to the 'about' tab in the status panel.
|
|
// Because of the way we merge your user config with the defaults you may need
|
|
// to be careful: if for example you set a `commandTemplates:` yaml key but then
|
|
// give it no child values, it will scrap all of the defaults and the app will
|
|
// probably crash.
|
|
package config
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/OpenPeeDeeP/xdg"
|
|
"github.com/jesseduffield/yaml"
|
|
)
|
|
|
|
// UserConfig holds all of the user-configurable options
|
|
type UserConfig struct {
|
|
// Gui is for configuring visual things like colors and whether we show or
|
|
// hide things
|
|
Gui GuiConfig `yaml:"gui,omitempty"`
|
|
|
|
// ConfirmOnQuit when enabled prompts you to confirm you want to quit when you
|
|
// hit esc or q when no confirmation panels are open
|
|
ConfirmOnQuit bool `yaml:"confirmOnQuit,omitempty"`
|
|
|
|
// Logs determines how we render/filter a container's logs
|
|
Logs LogsConfig `yaml:"logs,omitempty"`
|
|
|
|
// CommandTemplates determines what commands actually get called when we run
|
|
// certain commands
|
|
CommandTemplates CommandTemplatesConfig `yaml:"commandTemplates,omitempty"`
|
|
|
|
// CustomCommands determines what shows up in your custom commands menu when
|
|
// you press 'c'. You can use go templates to access three items on the
|
|
// struct: the DockerCompose command (defaulted to 'docker-compose'), the
|
|
// Service if present, and the Container if present. The struct types for
|
|
// those are found in the commands package
|
|
CustomCommands CustomCommands `yaml:"customCommands,omitempty"`
|
|
|
|
// BulkCommands are commands that apply to all items in a panel e.g.
|
|
// killing all containers, stopping all services, or pruning all images
|
|
BulkCommands CustomCommands `yaml:"bulkCommands,omitempty"`
|
|
|
|
// OS determines what defaults are set for opening files and links
|
|
OS OSConfig `yaml:"oS,omitempty"`
|
|
|
|
// Stats determines how long lazydocker will gather container stats for, and
|
|
// what stat info to graph
|
|
Stats StatsConfig `yaml:"stats,omitempty"`
|
|
|
|
// Replacements determines how we render an item's info
|
|
Replacements Replacements `yaml:"replacements,omitempty"`
|
|
|
|
// For demo purposes: any list item with one of these strings as a substring
|
|
// will be filtered out and not displayed.
|
|
// Not documented because it's subject to change
|
|
Ignore []string `yaml:"ignore,omitempty"`
|
|
}
|
|
|
|
// ThemeConfig is for setting the colors of panels and some text.
|
|
type ThemeConfig struct {
|
|
ActiveBorderColor []string `yaml:"activeBorderColor,omitempty"`
|
|
InactiveBorderColor []string `yaml:"inactiveBorderColor,omitempty"`
|
|
OptionsTextColor []string `yaml:"optionsTextColor,omitempty"`
|
|
}
|
|
|
|
// GuiConfig is for configuring visual things like colors and whether we show or
|
|
// hide things
|
|
type GuiConfig struct {
|
|
// ScrollHeight determines how many characters you scroll at a time when
|
|
// scrolling the main panel
|
|
ScrollHeight int `yaml:"scrollHeight,omitempty"`
|
|
|
|
// Language determines which language the GUI displayed.
|
|
Language string `yaml:"language,omitempty"`
|
|
|
|
// ScrollPastBottom determines whether you can scroll past the bottom of the
|
|
// main view
|
|
ScrollPastBottom bool `yaml:"scrollPastBottom,omitempty"`
|
|
|
|
// IgnoreMouseEvents is for when you do not want to use your mouse to interact
|
|
// with anything
|
|
IgnoreMouseEvents bool `yaml:"mouseEvents,omitempty"`
|
|
|
|
// Theme determines what colors and color attributes your panel borders have.
|
|
// I always set inactiveBorderColor to black because in my terminal it's more
|
|
// of a grey, but that doesn't work in your average terminal. I highly
|
|
// recommended finding a combination that works for you
|
|
Theme ThemeConfig `yaml:"theme,omitempty"`
|
|
|
|
// ShowAllContainers determines whether the Containers panel contains all the
|
|
// containers returned by `docker ps -a`, or just those containers that aren't
|
|
// directly linked to a service. It is probably desirable to enable this if
|
|
// you have multiple containers per service, but otherwise it can cause a lot
|
|
// of clutter
|
|
ShowAllContainers bool `yaml:"showAllContainers,omitempty"`
|
|
|
|
// ReturnImmediately determines whether you get the 'press enter to return to
|
|
// lazydocker' message after a subprocess has completed. You would set this to
|
|
// true if you often want to see the output of subprocesses before returning
|
|
// to lazydocker. I would default this to false but then people who want it
|
|
// set to true won't even know the config option exists.
|
|
ReturnImmediately bool `yaml:"returnImmediately,omitempty"`
|
|
|
|
// WrapMainPanel determines whether we use word wrap on the main panel
|
|
WrapMainPanel bool `yaml:"wrapMainPanel,omitempty"`
|
|
|
|
// LegacySortContainers determines if containers should be sorted using legacy approach.
|
|
// By default, containers are now sorted by status. This setting allows users to
|
|
// use legacy behaviour instead.
|
|
LegacySortContainers bool `yaml:"legacySortContainers,omitempty"`
|
|
|
|
// If 0.333, then the side panels will be 1/3 of the screen's width
|
|
SidePanelWidth float64 `yaml:"sidePanelWidth"`
|
|
|
|
// Determines whether we show the bottom line (the one containing keybinding
|
|
// info and the status of the app).
|
|
ShowBottomLine bool `yaml:"showBottomLine"`
|
|
|
|
// When true, increases vertical space used by focused side panel,
|
|
// creating an accordion effect
|
|
ExpandFocusedSidePanel bool `yaml:"expandFocusedSidePanel"`
|
|
}
|
|
|
|
// CommandTemplatesConfig determines what commands actually get called when we
|
|
// run certain commands
|
|
type CommandTemplatesConfig struct {
|
|
// RestartService is for restarting a service. docker-compose restart {{
|
|
// .Service.Name }} works but I prefer docker-compose up --force-recreate {{
|
|
// .Service.Name }}
|
|
RestartService string `yaml:"restartService,omitempty"`
|
|
|
|
// StartService is just like the above but for starting
|
|
StartService string `yaml:"startService,omitempty"`
|
|
|
|
// UpService ups the service (creates and starts)
|
|
UpService string `yaml:"upService,omitempty"`
|
|
|
|
// Runs "docker-compose up -d"
|
|
Up string `yaml:"up,omitempty"`
|
|
|
|
// downs everything
|
|
Down string `yaml:"down,omitempty"`
|
|
// downs and removes volumes
|
|
DownWithVolumes string `yaml:"downWithVolumes,omitempty"`
|
|
|
|
// DockerCompose is for your docker-compose command. You may want to combine a
|
|
// few different docker-compose.yml files together, in which case you can set
|
|
// this to "docker-compose -f foo/docker-compose.yml -f
|
|
// bah/docker-compose.yml". The reason that the other docker-compose command
|
|
// templates all start with {{ .DockerCompose }} is so that they can make use
|
|
// of whatever you've set in this value rather than you having to copy and
|
|
// paste it to all the other commands
|
|
DockerCompose string `yaml:"dockerCompose,omitempty"`
|
|
|
|
// StopService is the command for stopping a service
|
|
StopService string `yaml:"stopService,omitempty"`
|
|
|
|
// ServiceLogs get the logs for a service. This is actually not currently
|
|
// used; we just get the logs of the corresponding container. But we should
|
|
// probably support explicitly returning the logs of the service when you've
|
|
// selected the service, given that a service may have multiple containers.
|
|
ServiceLogs string `yaml:"serviceLogs,omitempty"`
|
|
|
|
// ViewServiceLogs is for when you want to view the logs of a service as a
|
|
// subprocess. This defaults to having no filter, unlike the in-app logs
|
|
// commands which will usually filter down to the last hour for the sake of
|
|
// performance.
|
|
ViewServiceLogs string `yaml:"viewServiceLogs,omitempty"`
|
|
|
|
// RebuildService is the command for rebuilding a service. Defaults to
|
|
// something along the lines of `{{ .DockerCompose }} up --build {{
|
|
// .Service.Name }}`
|
|
RebuildService string `yaml:"rebuildService,omitempty"`
|
|
|
|
// RecreateService is for force-recreating a service. I prefer this to
|
|
// restarting a service because it will also restart any dependent services
|
|
// and ensure they're running before trying to run the service at hand
|
|
RecreateService string `yaml:"recreateService,omitempty"`
|
|
|
|
// AllLogs is for showing what you get from doing `docker-compose logs`. It
|
|
// combines all the logs together
|
|
AllLogs string `yaml:"allLogs,omitempty"`
|
|
|
|
// ViewAllLogs is the command we use when you want to see all logs in a subprocess with no filtering
|
|
ViewAllLogs string `yaml:"viewAlLogs,omitempty"`
|
|
|
|
// DockerComposeConfig is the command for viewing the config of your docker
|
|
// compose. It basically prints out the yaml from your docker-compose.yml
|
|
// file(s)
|
|
DockerComposeConfig string `yaml:"dockerComposeConfig,omitempty"`
|
|
|
|
// CheckDockerComposeConfig is what we use to check whether we are in a
|
|
// docker-compose context. If the command returns an error then we clearly
|
|
// aren't in a docker-compose config and we then just hide the services panel
|
|
// and only show containers
|
|
CheckDockerComposeConfig string `yaml:"checkDockerComposeConfig,omitempty"`
|
|
|
|
// ServiceTop is the command for viewing the processes under a given service
|
|
ServiceTop string `yaml:"serviceTop,omitempty"`
|
|
}
|
|
|
|
// OSConfig contains config on the level of the os
|
|
type OSConfig struct {
|
|
// OpenCommand is the command for opening a file
|
|
OpenCommand string `yaml:"openCommand,omitempty"`
|
|
|
|
// OpenCommand is the command for opening a link
|
|
OpenLinkCommand string `yaml:"openLinkCommand,omitempty"`
|
|
}
|
|
|
|
// GraphConfig specifies how to make a graph of recorded container stats
|
|
type GraphConfig struct {
|
|
// Min sets the minimum value that you want to display. If you want to set
|
|
// this, you should also set MinType to "static". The reason for this is that
|
|
// if Min == 0, it's not clear if it has not been set (given that the
|
|
// zero-value of an int is 0) or if it's intentionally been set to 0.
|
|
Min float64 `yaml:"min,omitempty"`
|
|
|
|
// Max sets the maximum value that you want to display. If you want to set
|
|
// this, you should also set MaxType to "static". The reason for this is that
|
|
// if Max == 0, it's not clear if it has not been set (given that the
|
|
// zero-value of an int is 0) or if it's intentionally been set to 0.
|
|
Max float64 `yaml:"max,omitempty"`
|
|
|
|
// Height sets the height of the graph in ascii characters
|
|
Height int `yaml:"height,omitempty"`
|
|
|
|
// Caption sets the caption of the graph. If you want to show CPU Percentage
|
|
// you could set this to "CPU (%)"
|
|
Caption string `yaml:"caption,omitempty"`
|
|
|
|
// This is the path to the stat that you want to display. It is based on the
|
|
// RecordedStats struct in container_stats.go, so feel free to look there to
|
|
// see all the options available. Alternatively if you go into lazydocker and
|
|
// go to the stats tab, you'll see that same struct in JSON format, so you can
|
|
// just PascalCase the path and you'll have a valid path. E.g.
|
|
// ClientStats.blkio_stats -> "ClientStats.BlkioStats"
|
|
StatPath string `yaml:"statPath,omitempty"`
|
|
|
|
// This determines the color of the graph. This can be any color attribute,
|
|
// e.g. 'blue', 'green'
|
|
Color string `yaml:"color,omitempty"`
|
|
|
|
// MinType and MaxType are each one of "", "static". blank means the min/max
|
|
// of the data set will be used. "static" means the min/max specified will be
|
|
// used
|
|
MinType string `yaml:"minType,omitempty"`
|
|
|
|
// MaxType is just like MinType but for the max value
|
|
MaxType string `yaml:"maxType,omitempty"`
|
|
}
|
|
|
|
// StatsConfig contains the stuff relating to stats and graphs
|
|
type StatsConfig struct {
|
|
// Graphs contains the configuration for the stats graphs we want to show in
|
|
// the app
|
|
Graphs []GraphConfig
|
|
|
|
// MaxDuration tells us how long to collect stats for. Currently this defaults
|
|
// to "5m" i.e. 5 minutes.
|
|
MaxDuration time.Duration `yaml:"maxDuration,omitempty"`
|
|
}
|
|
|
|
// CustomCommands contains the custom commands that you might want to use on any
|
|
// given service or container
|
|
type CustomCommands struct {
|
|
// Containers contains the custom commands for containers
|
|
Containers []CustomCommand `yaml:"containers,omitempty"`
|
|
|
|
// Services contains the custom commands for services
|
|
Services []CustomCommand `yaml:"services,omitempty"`
|
|
|
|
// Images contains the custom commands for images
|
|
Images []CustomCommand `yaml:"images,omitempty"`
|
|
|
|
// Volumes contains the custom commands for volumes
|
|
Volumes []CustomCommand `yaml:"volumes,omitempty"`
|
|
|
|
// Networks contains the custom commands for networks
|
|
Networks []CustomCommand `yaml:"networks,omitempty"`
|
|
}
|
|
|
|
// Replacements contains the stuff relating to rendering a container's info
|
|
type Replacements struct {
|
|
// ImageNamePrefixes tells us how to replace a prefix in the Docker image name
|
|
ImageNamePrefixes map[string]string `yaml:"imageNamePrefixes,omitempty"`
|
|
}
|
|
|
|
// CustomCommand is a template for a command we want to run against a service or
|
|
// container
|
|
type CustomCommand struct {
|
|
// Name is the name of the command, purely for visual display
|
|
Name string `yaml:"name"`
|
|
|
|
// Attach tells us whether to switch to a subprocess to interact with the
|
|
// called program, or just read its output. If Attach is set to false, the
|
|
// command will run in the background. I'm open to the idea of having a third
|
|
// option where the output plays in the main panel.
|
|
Attach bool `yaml:"attach"`
|
|
|
|
// Shell indicates whether to invoke the Command on a shell or not.
|
|
// Example of a bash invoked command: `/bin/bash -c "{Command}".
|
|
Shell bool `yaml:"shell"`
|
|
|
|
// Command is the command we want to run. We can use the go templates here as
|
|
// well. One example might be `{{ .DockerCompose }} exec {{ .Service.Name }}
|
|
// /bin/sh`
|
|
Command string `yaml:"command"`
|
|
|
|
// ServiceNames is used to restrict this command to just one or more services.
|
|
// An example might be 'rails migrate' for your rails api service(s). This
|
|
// field has no effect on customcommands under the 'communications' part of
|
|
// the customCommand config.
|
|
ServiceNames []string `yaml:"serviceNames"`
|
|
|
|
// InternalFunction is the name of a function inside lazydocker that we want to run, as opposed to a command-line command. This is only used internally and can't be configured by the user
|
|
InternalFunction func() error `yaml:"-"`
|
|
}
|
|
|
|
type LogsConfig struct {
|
|
Timestamps bool `yaml:"timestamps,omitempty"`
|
|
Since string `yaml:"since,omitempty"`
|
|
Tail string `yaml:"tail,omitempty"`
|
|
}
|
|
|
|
// GetDefaultConfig returns the application default configuration NOTE (to
|
|
// contributors, not users): do not default a boolean to true, because false is
|
|
// the boolean zero value and this will be ignored when parsing the user's
|
|
// config
|
|
func GetDefaultConfig() UserConfig {
|
|
duration, err := time.ParseDuration("3m")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return UserConfig{
|
|
Gui: GuiConfig{
|
|
ScrollHeight: 2,
|
|
Language: "auto",
|
|
ScrollPastBottom: false,
|
|
IgnoreMouseEvents: false,
|
|
Theme: ThemeConfig{
|
|
ActiveBorderColor: []string{"green", "bold"},
|
|
InactiveBorderColor: []string{"default"},
|
|
OptionsTextColor: []string{"blue"},
|
|
},
|
|
ShowAllContainers: false,
|
|
ReturnImmediately: false,
|
|
WrapMainPanel: true,
|
|
LegacySortContainers: false,
|
|
SidePanelWidth: 0.3333,
|
|
ShowBottomLine: true,
|
|
ExpandFocusedSidePanel: false,
|
|
},
|
|
ConfirmOnQuit: false,
|
|
Logs: LogsConfig{
|
|
Timestamps: false,
|
|
Since: "60m",
|
|
Tail: "",
|
|
},
|
|
CommandTemplates: CommandTemplatesConfig{
|
|
DockerCompose: "docker-compose",
|
|
RestartService: "{{ .DockerCompose }} restart {{ .Service.Name }}",
|
|
StartService: "{{ .DockerCompose }} start {{ .Service.Name }}",
|
|
Up: "{{ .DockerCompose }} up -d",
|
|
Down: "{{ .DockerCompose }} down",
|
|
DownWithVolumes: "{{ .DockerCompose }} down --volumes",
|
|
UpService: "{{ .DockerCompose }} up -d {{ .Service.Name }}",
|
|
RebuildService: "{{ .DockerCompose }} up -d --build {{ .Service.Name }}",
|
|
RecreateService: "{{ .DockerCompose }} up -d --force-recreate {{ .Service.Name }}",
|
|
StopService: "{{ .DockerCompose }} stop {{ .Service.Name }}",
|
|
ServiceLogs: "{{ .DockerCompose }} logs --since=60m --follow {{ .Service.Name }}",
|
|
ViewServiceLogs: "{{ .DockerCompose }} logs --follow {{ .Service.Name }}",
|
|
AllLogs: "{{ .DockerCompose }} logs --tail=300 --follow",
|
|
ViewAllLogs: "{{ .DockerCompose }} logs",
|
|
DockerComposeConfig: "{{ .DockerCompose }} config",
|
|
CheckDockerComposeConfig: "{{ .DockerCompose }} config --quiet",
|
|
ServiceTop: "{{ .DockerCompose }} top {{ .Service.Name }}",
|
|
},
|
|
CustomCommands: CustomCommands{
|
|
Containers: []CustomCommand{},
|
|
Services: []CustomCommand{},
|
|
Images: []CustomCommand{},
|
|
Volumes: []CustomCommand{},
|
|
},
|
|
BulkCommands: CustomCommands{
|
|
Services: []CustomCommand{
|
|
{
|
|
Name: "up",
|
|
Command: "{{ .DockerCompose }} up -d",
|
|
},
|
|
{
|
|
Name: "up (attached)",
|
|
Command: "{{ .DockerCompose }} up",
|
|
Attach: true,
|
|
},
|
|
{
|
|
Name: "stop",
|
|
Command: "{{ .DockerCompose }} stop",
|
|
},
|
|
{
|
|
Name: "pull",
|
|
Command: "{{ .DockerCompose }} pull",
|
|
Attach: true,
|
|
},
|
|
{
|
|
Name: "build",
|
|
Command: "{{ .DockerCompose }} build --parallel --force-rm",
|
|
Attach: true,
|
|
},
|
|
{
|
|
Name: "down",
|
|
Command: "{{ .DockerCompose }} down",
|
|
},
|
|
{
|
|
Name: "down with volumes",
|
|
Command: "{{ .DockerCompose }} down --volumes",
|
|
},
|
|
{
|
|
Name: "down with images",
|
|
Command: "{{ .DockerCompose }} down --rmi all",
|
|
},
|
|
{
|
|
Name: "down with volumes and images",
|
|
Command: "{{ .DockerCompose }} down --volumes --rmi all",
|
|
},
|
|
},
|
|
Containers: []CustomCommand{},
|
|
Images: []CustomCommand{},
|
|
Volumes: []CustomCommand{},
|
|
},
|
|
OS: GetPlatformDefaultConfig(),
|
|
Stats: StatsConfig{
|
|
MaxDuration: duration,
|
|
Graphs: []GraphConfig{
|
|
{
|
|
Caption: "CPU (%)",
|
|
StatPath: "DerivedStats.CPUPercentage",
|
|
Color: "cyan",
|
|
},
|
|
{
|
|
Caption: "Memory (%)",
|
|
StatPath: "DerivedStats.MemoryPercentage",
|
|
Color: "green",
|
|
},
|
|
},
|
|
},
|
|
Replacements: Replacements{
|
|
ImageNamePrefixes: map[string]string{},
|
|
},
|
|
}
|
|
}
|
|
|
|
// AppConfig contains the base configuration fields required for lazydocker.
|
|
type AppConfig struct {
|
|
Debug bool `long:"debug" env:"DEBUG" default:"false"`
|
|
Version string `long:"version" env:"VERSION" default:"unversioned"`
|
|
Commit string `long:"commit" env:"COMMIT"`
|
|
BuildDate string `long:"build-date" env:"BUILD_DATE"`
|
|
Name string `long:"name" env:"NAME" default:"lazydocker"`
|
|
BuildSource string `long:"build-source" env:"BUILD_SOURCE" default:""`
|
|
UserConfig *UserConfig
|
|
ConfigDir string
|
|
ProjectDir string
|
|
}
|
|
|
|
// NewAppConfig makes a new app config
|
|
func NewAppConfig(name, version, commit, date string, buildSource string, debuggingFlag bool, composeFiles []string, projectDir string) (*AppConfig, error) {
|
|
configDir, err := findOrCreateConfigDir(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
userConfig, err := loadUserConfigWithDefaults(configDir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Pass compose files as individual -f flags to docker-compose
|
|
if len(composeFiles) > 0 {
|
|
userConfig.CommandTemplates.DockerCompose += " -f " + strings.Join(composeFiles, " -f ")
|
|
}
|
|
|
|
appConfig := &AppConfig{
|
|
Name: name,
|
|
Version: version,
|
|
Commit: commit,
|
|
BuildDate: date,
|
|
Debug: debuggingFlag || os.Getenv("DEBUG") == "TRUE",
|
|
BuildSource: buildSource,
|
|
UserConfig: userConfig,
|
|
ConfigDir: configDir,
|
|
ProjectDir: projectDir,
|
|
}
|
|
|
|
return appConfig, nil
|
|
}
|
|
|
|
func configDirForVendor(vendor string, projectName string) string {
|
|
envConfigDir := os.Getenv("CONFIG_DIR")
|
|
if envConfigDir != "" {
|
|
return envConfigDir
|
|
}
|
|
configDirs := xdg.New(vendor, projectName)
|
|
return configDirs.ConfigHome()
|
|
}
|
|
|
|
func configDir(projectName string) string {
|
|
legacyConfigDirectory := configDirForVendor("jesseduffield", projectName)
|
|
if _, err := os.Stat(legacyConfigDirectory); !os.IsNotExist(err) {
|
|
return legacyConfigDirectory
|
|
}
|
|
configDirectory := configDirForVendor("", projectName)
|
|
return configDirectory
|
|
}
|
|
|
|
func findOrCreateConfigDir(projectName string) (string, error) {
|
|
folder := configDir(projectName)
|
|
|
|
err := os.MkdirAll(folder, 0o755)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return folder, nil
|
|
}
|
|
|
|
func loadUserConfigWithDefaults(configDir string) (*UserConfig, error) {
|
|
config := GetDefaultConfig()
|
|
|
|
return loadUserConfig(configDir, &config)
|
|
}
|
|
|
|
func loadUserConfig(configDir string, base *UserConfig) (*UserConfig, error) {
|
|
fileName := filepath.Join(configDir, "config.yml")
|
|
|
|
if _, err := os.Stat(fileName); err != nil {
|
|
if os.IsNotExist(err) {
|
|
file, err := os.Create(fileName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
file.Close()
|
|
} else {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
content, err := ioutil.ReadFile(fileName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := yaml.Unmarshal(content, base); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return base, nil
|
|
}
|
|
|
|
// WriteToUserConfig allows you to set a value on the user config to be saved
|
|
// note that if you set a zero-value, it may be ignored e.g. a false or 0 or
|
|
// empty string this is because we are using the omitempty yaml directive so
|
|
// that we don't write a heap of zero values to the user's config.yml
|
|
func (c *AppConfig) WriteToUserConfig(updateConfig func(*UserConfig) error) error {
|
|
userConfig, err := loadUserConfig(c.ConfigDir, &UserConfig{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := updateConfig(userConfig); err != nil {
|
|
return err
|
|
}
|
|
|
|
file, err := os.OpenFile(c.ConfigFilename(), os.O_WRONLY|os.O_CREATE, 0o666)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return yaml.NewEncoder(file).Encode(userConfig)
|
|
}
|
|
|
|
// ConfigFilename returns the filename of the current config file
|
|
func (c *AppConfig) ConfigFilename() string {
|
|
return filepath.Join(c.ConfigDir, "config.yml")
|
|
}
|