<commit_before>package storeconfig

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	stdlog "log"
	"os"

	"github.com/abronan/valkeyrie/store"
	"github.com/containous/flaeg"
	"github.com/containous/staert"
	"github.com/containous/traefik/acme"
	"github.com/containous/traefik/cluster"
	"github.com/containous/traefik/cmd"
	"github.com/containous/traefik/log"
)

// NewCmd builds a new StoreConfig command
func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfiguration *cmd.TraefikConfiguration) *flaeg.Command {
	return &flaeg.Command{
		Name:                  "storeconfig",
		Description:           `Store the static traefik configuration into a Key-value stores. Traefik will not start.`,
		Config:                traefikConfiguration,
		DefaultPointersConfig: traefikPointersConfiguration,
		Metadata: map[string]string{
			"parseAllSources": "true",
		},
	}
}

// Run store config in KV
func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) func() error {
	return func() error {
		if kv == nil {
			return fmt.Errorf("error using command storeconfig, no Key-value store defined")
		}

		fileConfig := traefikConfiguration.GlobalConfiguration.File
		if fileConfig != nil {
			traefikConfiguration.GlobalConfiguration.File = nil
			if len(fileConfig.Filename) == 0 && len(fileConfig.Directory) == 0 {
				fileConfig.Filename = traefikConfiguration.ConfigFile
			}
		}

		jsonConf, err := json.Marshal(traefikConfiguration.GlobalConfiguration)
		if err != nil {
			return err
		}
		stdlog.Printf("Storing configuration: %s\n", jsonConf)

		err = kv.StoreConfig(traefikConfiguration.GlobalConfiguration)
		if err != nil {
			return err
		}

		if fileConfig != nil {
			jsonConf, err = json.Marshal(fileConfig)
			if err != nil {
				return err
			}

			stdlog.Printf("Storing file configuration: %s\n", jsonConf)
			config, err := fileConfig.BuildConfiguration()
			if err != nil {
				return err
			}

			stdlog.Print("Writing config to KV")
			err = kv.StoreConfig(config)
			if err != nil {
				return err
			}
		}

		if traefikConfiguration.GlobalConfiguration.ACME != nil {
			account := &acme.Account{}

			// Migrate ACME data from file to KV store if needed
			if len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
				account, err = migrateACMEData(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
				if err != nil {
					return err
				}
			}

			// Check to see if ACME account object is already in kv store
			if traefikConfiguration.GlobalConfiguration.ACME.OverrideCertificates {

				// Store the ACME Account into the KV Store
				// Certificates in KV Store will be overridden
				meta := cluster.NewMetadata(account)
				err = meta.Marshall()
				if err != nil {
					return err
				}

				source := staert.KvSource{
					Store:  kv,
					Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage,
				}

				err = source.StoreConfig(meta)
				if err != nil {
					return err
				}
			}

			// Force to delete storagefile
			return kv.Delete(kv.Prefix + "/acme/storagefile")
		}
		return nil
	}
}

// migrateACMEData allows migrating data from acme.json file to KV store in function of the file format
func migrateACMEData(fileName string) (*acme.Account, error) {

	f, err := os.Open(fileName)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	file, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	// Check if the storage file is not empty before to get data
	account := &acme.Account{}
	if len(file) > 0 {
		accountFromNewFormat, err := acme.FromNewToOldFormat(fileName)
		if err != nil {
			return nil, err
		}
<commit_msg> StoreConfig always initializes the account if it is missing<commit_after>package storeconfig

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	stdlog "log"
	"os"

	"github.com/abronan/valkeyrie/store"
	"github.com/containous/flaeg"
	"github.com/containous/staert"
	"github.com/containous/traefik/acme"
	"github.com/containous/traefik/cluster"
	"github.com/containous/traefik/cmd"
	"github.com/containous/traefik/log"
)

// NewCmd builds a new StoreConfig command
func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfiguration *cmd.TraefikConfiguration) *flaeg.Command {
	return &flaeg.Command{
		Name:                  "storeconfig",
		Description:           `Store the static traefik configuration into a Key-value stores. Traefik will not start.`,
		Config:                traefikConfiguration,
		DefaultPointersConfig: traefikPointersConfiguration,
		Metadata: map[string]string{
			"parseAllSources": "true",
		},
	}
}

// Run store config in KV
func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) func() error {
	return func() error {
		if kv == nil {
			return fmt.Errorf("error using command storeconfig, no Key-value store defined")
		}

		fileConfig := traefikConfiguration.GlobalConfiguration.File
		if fileConfig != nil {
			traefikConfiguration.GlobalConfiguration.File = nil
			if len(fileConfig.Filename) == 0 && len(fileConfig.Directory) == 0 {
				fileConfig.Filename = traefikConfiguration.ConfigFile
			}
		}

		jsonConf, err := json.Marshal(traefikConfiguration.GlobalConfiguration)
		if err != nil {
			return err
		}
		stdlog.Printf("Storing configuration: %s\n", jsonConf)

		err = kv.StoreConfig(traefikConfiguration.GlobalConfiguration)
		if err != nil {
			return err
		}

		if fileConfig != nil {
			jsonConf, err = json.Marshal(fileConfig)
			if err != nil {
				return err
			}

			stdlog.Printf("Storing file configuration: %s\n", jsonConf)
			config, err := fileConfig.BuildConfiguration()
			if err != nil {
				return err
			}

			stdlog.Print("Writing config to KV")
			err = kv.StoreConfig(config)
			if err != nil {
				return err
			}
		}

		if traefikConfiguration.GlobalConfiguration.ACME != nil {
			account := &acme.Account{}

			// Migrate ACME data from file to KV store if needed
			if len(traefikConfiguration.GlobalConfiguration.ACME.StorageFile) > 0 {
				account, err = migrateACMEData(traefikConfiguration.GlobalConfiguration.ACME.StorageFile)
				if err != nil {
					return err
				}
			}

			accountInitialized, err := keyExists(kv, traefikConfiguration.GlobalConfiguration.ACME.Storage)
			if err != nil {
				return err
			}

			// Check to see if ACME account object is already in kv store
			if traefikConfiguration.GlobalConfiguration.ACME.OverrideCertificates || !accountInitialized {

				// Store the ACME Account into the KV Store
				// Certificates in KV Store will be overridden
				meta := cluster.NewMetadata(account)
				err = meta.Marshall()
				if err != nil {
					return err
				}

				source := staert.KvSource{
					Store:  kv,
					Prefix: traefikConfiguration.GlobalConfiguration.ACME.Storage,
				}

				err = source.StoreConfig(meta)
				if err != nil {
					return err
				}
			}

			// Force to delete storagefile
			return kv.Delete(kv.Prefix + "/acme/storagefile")
		}
		return nil
	}
}

func keyExists(source *staert.KvSource, key string) (bool, error) {
	list, err := source.List(key, nil)
	if err != nil {
		return false, err
	}

	return len(list) > 0, nil
}

// migrateACMEData allows migrating data from acme.json file to KV store in function of the file format
func migrateACMEData(fileName string) (*acme.Account, error) {

	f, err := os.Open(fileName)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	file, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	// Check if the storage file is not empty before to get data
	account := &acme.Account{}
	if len(file) > 0 {
		accountFromNewFormat, err := acme.FromNewToOldFormat(fileName)
		if err != nil {
			return nil, err
		}

{'fraction_non_alphanumeric': 0.10385216033315982, 'fraction_numerical': 0.0011712649661634565, 'mean_word_length': 3.4014891179839633, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5261389', 'n_tokens_mistral': 2834, 'n_tokens_neox': 2450, 'n_words': 644}