package utils import ( "encoding/json" "fmt" "os" "path/filepath" "strings" "github.com/DisposaBoy/JsonConfigReader" "gopkg.in/yaml.v3" ) // ConfigStructure is structure of main configuration type ConfigStructure struct { // nolint: maligned <<<<<<< HEAD // General RootDir string `json:"rootDir" yaml:"root_dir"` LogLevel string `json:"logLevel" yaml:"log_level"` LogFormat string `json:"logFormat" yaml:"log_format"` DatabaseOpenAttempts int `json:"databaseOpenAttempts" yaml:"database_open_attempts"` Architectures []string `json:"architectures" yaml:"architectures"` SkipLegacyPool bool `json:"skipLegacyPool" yaml:"skip_legacy_pool"` // OBSOLETE // Dependency following DepFollowSuggests bool `json:"dependencyFollowSuggests" yaml:"dep_follow_suggests"` DepFollowRecommends bool `json:"dependencyFollowRecommends" yaml:"dep_follow_recommends"` DepFollowAllVariants bool `json:"dependencyFollowAllVariants" yaml:"dep_follow_all_variants"` DepFollowSource bool `json:"dependencyFollowSource" yaml:"dep_follow_source"` DepVerboseResolve bool `json:"dependencyVerboseResolve" yaml:"dep_verboseresolve"` // PPA PpaDistributorID string `json:"ppaDistributorID" yaml:"ppa_distributor_id"` PpaCodename string `json:"ppaCodename" yaml:"ppa_codename"` // Server ServeInAPIMode bool `json:"serveInAPIMode" yaml:"serve_in_api_mode"` EnableMetricsEndpoint bool `json:"enableMetricsEndpoint" yaml:"enable_metrics_endpoint"` EnableSwaggerEndpoint bool `json:"enableSwaggerEndpoint" yaml:"enable_swagger_endpoint"` AsyncAPI bool `json:"AsyncAPI" yaml:"async_api"` // OBSOLETE // Database DatabaseBackend DBConfig `json:"databaseBackend" yaml:"database_backend"` // Mirroring Downloader string `json:"downloader" yaml:"downloader"` DownloadConcurrency int `json:"downloadConcurrency" yaml:"download_concurrency"` DownloadLimit int64 `json:"downloadSpeedLimit" yaml:"download_limit"` DownloadRetries int `json:"downloadRetries" yaml:"download_retries"` DownloadSourcePackages bool `json:"downloadSourcePackages" yaml:"download_sourcepackages"` // Signing GpgProvider string `json:"gpgProvider" yaml:"gpg_provider"` GpgDisableSign bool `json:"gpgDisableSign" yaml:"gpg_disable_sign"` GpgDisableVerify bool `json:"gpgDisableVerify" yaml:"gpg_disable_verify"` // Publishing SkipContentsPublishing bool `json:"skipContentsPublishing" yaml:"skip_contents_publishing"` SkipBz2Publishing bool `json:"skipBz2Publishing" yaml:"skip_bz2_publishing"` // Storage FileSystemPublishRoots map[string]FileSystemPublishRoot `json:"FileSystemPublishEndpoints" yaml:"filesystem_publish_endpoints"` S3PublishRoots map[string]S3PublishRoot `json:"S3PublishEndpoints" yaml:"s3_publish_endpoints"` SwiftPublishRoots map[string]SwiftPublishRoot `json:"SwiftPublishEndpoints" yaml:"swift_publish_endpoints"` AzurePublishRoots map[string]AzureEndpoint `json:"AzurePublishEndpoints" yaml:"azure_publish_endpoints"` PackagePoolStorage PackagePoolStorage `json:"packagePoolStorage" yaml:"packagepool_storage"` // Authentication UseAuth bool `json:"useAuth"` Auth AAuth `json:"Auth"` } // DBConfig type DBConfig struct { Type string `json:"type" yaml:"type"` DbPath string `json:"dbPath" yaml:"db_path"` URL string `json:"url" yaml:"url"` } type LocalPoolStorage struct { Path string `json:"path,omitempty" yaml:"path,omitempty"` } type PackagePoolStorage struct { Local *LocalPoolStorage Azure *AzureEndpoint } var AZURE = "azure" var LOCAL = "local" func (pool *PackagePoolStorage) UnmarshalJSON(data []byte) error { var discriminator struct { Type string `json:"type"` } if err := json.Unmarshal(data, &discriminator); err != nil { return err } switch discriminator.Type { case AZURE: pool.Azure = &AzureEndpoint{} return json.Unmarshal(data, &pool.Azure) case LOCAL, "": pool.Local = &LocalPoolStorage{} return json.Unmarshal(data, &pool.Local) default: return fmt.Errorf("unknown pool storage type: %s", discriminator.Type) } } func (pool *PackagePoolStorage) UnmarshalYAML(unmarshal func(interface{}) error) error { var discriminator struct { Type string `yaml:"type"` } if err := unmarshal(&discriminator); err != nil { return err } switch discriminator.Type { case AZURE: pool.Azure = &AzureEndpoint{} return unmarshal(&pool.Azure) case LOCAL, "": pool.Local = &LocalPoolStorage{} return unmarshal(&pool.Local) default: return fmt.Errorf("unknown pool storage type: %s", discriminator.Type) } } func (pool *PackagePoolStorage) MarshalJSON() ([]byte, error) { var wrapper struct { Type string `json:"type,omitempty"` *LocalPoolStorage *AzureEndpoint } if pool.Azure != nil { wrapper.Type = "azure" wrapper.AzureEndpoint = pool.Azure } else if pool.Local.Path != "" { wrapper.Type = "local" wrapper.LocalPoolStorage = pool.Local } return json.Marshal(wrapper) } func (pool PackagePoolStorage) MarshalYAML() (interface{}, error) { var wrapper struct { Type string `yaml:"type,omitempty"` *LocalPoolStorage `yaml:",inline"` *AzureEndpoint `yaml:",inline"` } if pool.Azure != nil { wrapper.Type = "azure" wrapper.AzureEndpoint = pool.Azure } else if pool.Local.Path != "" { wrapper.Type = "local" wrapper.LocalPoolStorage = pool.Local } return wrapper, nil } // FileSystemPublishRoot describes single filesystem publishing entry point type FileSystemPublishRoot struct { RootDir string `json:"rootDir" yaml:"root_dir"` LinkMethod string `json:"linkMethod" yaml:"link_method"` VerifyMethod string `json:"verifyMethod" yaml:"verify_method"` } // S3PublishRoot describes single S3 publishing entry point type S3PublishRoot struct { Region string `json:"region" yaml:"region"` Bucket string `json:"bucket" yaml:"bucket"` Prefix string `json:"prefix" yaml:"prefix"` ACL string `json:"acl" yaml:"acl"` AccessKeyID string `json:"awsAccessKeyID" yaml:"access_key_id"` SecretAccessKey string `json:"awsSecretAccessKey" yaml:"secret_access_key"` SessionToken string `json:"awsSessionToken" yaml:"session_token"` Endpoint string `json:"endpoint" yaml:"endpoint"` StorageClass string `json:"storageClass" yaml:"storage_class"` EncryptionMethod string `json:"encryptionMethod" yaml:"encryption_method"` PlusWorkaround bool `json:"plusWorkaround" yaml:"plus_workaround"` DisableMultiDel bool `json:"disableMultiDel" yaml:"disable_multidel"` ForceSigV2 bool `json:"forceSigV2" yaml:"force_sigv2"` ForceVirtualHostedStyle bool `json:"forceVirtualHostedStyle" yaml:"force_virtualhosted_style"` Debug bool `json:"debug" yaml:"debug"` } // SwiftPublishRoot describes single OpenStack Swift publishing entry point type SwiftPublishRoot struct { Container string `json:"container" yaml:"container"` Prefix string `json:"prefix" yaml:"prefix"` UserName string `json:"osname" yaml:"username"` Password string `json:"password" yaml:"password"` Tenant string `json:"tenant" yaml:"tenant"` TenantID string `json:"tenantid" yaml:"tenant_id"` Domain string `json:"domain" yaml:"domain"` DomainID string `json:"domainid" yaml:"domain_id"` TenantDomain string `json:"tenantdomain" yaml:"tenant_domain"` TenantDomainID string `json:"tenantdomainid" yaml:"tenant_domain_id"` AuthURL string `json:"authurl" yaml:"auth_url"` } // AzureEndpoint describes single Azure publishing entry point type AzureEndpoint struct { Container string `json:"container" yaml:"container"` Prefix string `json:"prefix" yaml:"prefix"` AccountName string `json:"accountName" yaml:"account_name"` AccountKey string `json:"accountKey" yaml:"account_key"` Endpoint string `json:"endpoint" yaml:"endpoint"` } type AAuth struct { Type string `json:"authType"` Server string `json:"server"` LdapDN string `json:"ldapDN"` LdapFilter string `json:"ldapFilter"` SecureTLS bool `json:"secureTLS"` } // Config is configuration for aptly, shared by all modules var Config = ConfigStructure{ RootDir: filepath.Join(os.Getenv("HOME"), ".aptly"), LogFile: "", UseAuth: false, // should we enable auth DownloadConcurrency: 4, DownloadLimit: 0, Downloader: "default", DatabaseOpenAttempts: -1, Architectures: []string{}, DepFollowSuggests: false, DepFollowRecommends: false, DepFollowAllVariants: false, DepFollowSource: false, GpgProvider: "gpg", GpgDisableSign: false, GpgDisableVerify: false, DownloadSourcePackages: false, PackagePoolStorage: PackagePoolStorage{ Local: &LocalPoolStorage{Path: ""}, }, SkipLegacyPool: false, PpaDistributorID: "ubuntu", PpaCodename: "", FileSystemPublishRoots: map[string]FileSystemPublishRoot{}, S3PublishRoots: map[string]S3PublishRoot{}, SwiftPublishRoots: map[string]SwiftPublishRoot{}, AzurePublishRoots: map[string]AzureEndpoint{}, AsyncAPI: false, EnableMetricsEndpoint: false, LogLevel: "info", LogFormat: "default", ServeInAPIMode: false, EnableSwaggerEndpoint: false, Auth: AAuth{}, } // LoadConfig loads configuration from json file func LoadConfig(filename string, config *ConfigStructure) error { f, err := os.Open(filename) if err != nil { return err } defer f.Close() decJSON := json.NewDecoder(JsonConfigReader.New(f)) if err = decJSON.Decode(&config); err != nil { f.Seek(0, 0) decYAML := yaml.NewDecoder(f) if err2 := decYAML.Decode(&config); err2 != nil { err = fmt.Errorf("invalid yaml (%s) or json (%s)", err2, err) } else { err = nil } } return err } // SaveConfig write configuration to json file func SaveConfig(filename string, config *ConfigStructure) error { f, err := os.Create(filename) if err != nil { return err } defer f.Close() encoded, err := json.MarshalIndent(&config, "", " ") if err != nil { return err } _, err = f.Write(encoded) return err } // SaveConfigRaw write configuration to file func SaveConfigRaw(filename string, conf []byte) error { f, err := os.Create(filename) if err != nil { return err } defer f.Close() _, err = f.Write(conf) return err } // SaveConfigYAML write configuration to yaml file func SaveConfigYAML(filename string, config *ConfigStructure) error { f, err := os.Create(filename) if err != nil { return err } defer f.Close() yamlData, err := yaml.Marshal(&config) if err != nil { return fmt.Errorf("error marshaling to YAML: %s", err) } _, err = f.Write(yamlData) return err } // GetRootDir returns the RootDir with expanded ~ as home directory func (conf *ConfigStructure) GetRootDir() string { return strings.Replace(conf.RootDir, "~", os.Getenv("HOME"), 1) }