From 0e0189f0ebbf0a19404628b01e65cbd54734feee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Roth?= Date: Mon, 2 Dec 2024 20:56:17 +0100 Subject: [PATCH] use yaml config file --- cmd/config_show.go | 22 ++- debian/aptly.conf.yaml | 339 +++++++++++++++++++++++++++++++++++++++++ man/aptly.1.ronn.tmpl | 1 + utils/config.go | 207 ++++++++++++++----------- 4 files changed, 479 insertions(+), 90 deletions(-) create mode 100644 debian/aptly.conf.yaml diff --git a/cmd/config_show.go b/cmd/config_show.go index 66adc8f0..56ab33e8 100644 --- a/cmd/config_show.go +++ b/cmd/config_show.go @@ -5,19 +5,30 @@ import ( "fmt" "github.com/smira/commander" + "gopkg.in/yaml.v3" ) func aptlyConfigShow(_ *commander.Command, _ []string) error { + show_yaml := context.Flags().Lookup("yaml").Value.Get().(bool) config := context.Config() - prettyJSON, err := json.MarshalIndent(config, "", " ") - if err != nil { - return fmt.Errorf("unable to dump the config file: %s", err) + if show_yaml { + yamlData, err := yaml.Marshal(&config) + if err != nil { + return fmt.Errorf("error marshaling to YAML: %s", err) + } + + fmt.Println(string(yamlData)) + } else { + prettyJSON, err := json.MarshalIndent(config, "", " ") + if err != nil { + return fmt.Errorf("unable to dump the config file: %s", err) + } + + fmt.Println(string(prettyJSON)) } - fmt.Println(string(prettyJSON)) - return nil } @@ -35,5 +46,6 @@ Example: `, } + cmd.Flag.Bool("yaml", false, "show yaml config") return cmd } diff --git a/debian/aptly.conf.yaml b/debian/aptly.conf.yaml new file mode 100644 index 00000000..89c70fa6 --- /dev/null +++ b/debian/aptly.conf.yaml @@ -0,0 +1,339 @@ +# Aptly Configuration File +########################### + +# Aptly storage directory for: +# - downloaded packages (`rootDir`/pool) +# - database (`rootDir`/db) +# - published repositories (`rootDir`/public) +root_dir: ~/.aptly + +# Number of attempts to open database if it's locked by other instance +# * -1 (no retry) +database_open_attempts: -1 + +# Log Level +# * debug +# * info +# * warning +# * error +log_level: info + +# Log Format +# * default (text) +# * json +log_format: default + +# Default Architectures +# empty list defaults to all available architectures +architectures: +# - amd64 + + +# Dependency following +####################### + +# Follow contents of `Suggests:` field when processing dependencies for the package +dep_follow_suggests: false + +# Follow contents of `Recommends:` field when processing dependencies for the package +dep_follow_recommends: false + +# When dependency looks like `package-a | package-b`, follow both variants always +dep_follow_allvariants: false + +# Follow dependency from binary package to source package +dep_follow_source: false + +# Log additional details while resolving dependencies (useful for debugging) +dep_verbose_resolve: false + + +# PPA +###### + +# Specify paramaters for short PPA url expansion +# empty defaults to output of `lsb_release` command +ppa_distributor_id: ubuntu + +# Codename for short PPA url expansion +ppa_codename: "" + +# OBSOLETE +# in aptly up to version 1.0.0, package files were stored in internal package pool +# with MD5-dervied path, since 1.1.0 package pool layout was changed; +# if option is enabled, aptly stops checking for legacy paths; +# by default option is enabled for new aptly installations and disabled when +# upgrading from older versions +skip_legacy_pool: true + + +# Aptly Server +############### + +# Serve published repos as well as API +serve_in_api_mode: false + +# Enable metrics for Prometheus client +enable_metrics_endpoint: false + +# Enable API documentation on /docs +enable_swagger_endpoint: false + +# OBSOLETE: use via url param ?_async=true +async_api: false + + +# Database +########### + +# Database backend +# Type must be one of: +# * leveldb (default) +# * etcd +database_backend: + type: leveldb + # Path to leveldb files + # empty dbPath defaults to `rootDir`/db + db_path: "" + + # type: etcd + # # URL to db server + # url: "127.0.0.1:2379" + + +# Mirroring +############ + +# Downloader +# * "default" +# * "grab" (more robust) +downloader: default + +# Number of parallel download threads to use when downloading packages +download_concurrency: 4 + +# Limit in kbytes/sec on download speed while mirroring remote repositories +download_limit: 0 + +# Number of retries for download attempts +download_retries: 0 + +# Download source packages per default +download_sourcepackages: false + + +# Signing +########## + +# GPG Provider +# * "internal" (Go internal implementation) +# * "gpg" (External `gpg` utility) +gpg_provider: gpg + +# Disable signing of published repositories +gpg_disable_sign: false + +# Disable signature verification of remote repositories +gpg_disable_verify: false + + +# Publishing +############# + +# Do not publish Contents files +skip_contents_publishing: false + +# Do not create bz2 files +skip_bz2_publishing: false + + +# Storage +########## + +# Filesystem publishing endpoints +# +# aptly defaults to publish to a single publish directory under `rootDir`/public. For +# a more advanced publishing strategy, you can define one or more filesystem endpoints in the +# `FileSystemPublishEndpoints` list of the aptly configuration file. Each endpoint has a name +# and the following associated settings. +# +# In order to publish to such an endpoint, specify the endpoint as `filesystem:endpoint-name` +# with `endpoint-name` as the name given in the aptly configuration file. For example: +# +# `aptly publish snapshot wheezy-main filesystem:test1:wheezy/daily` +# +filesystem_publish_endpoints: + # # Endpoint Name + # test1: + # # Directory for publishing + # root_dir: /opt/srv/aptly_public + # # File Link Method for linking files from the internal pool to the published directory + # # * hardlink + # # * symlink + # # * copy + # link_method: hardlink + # # File Copare Method for comparing existing links from the internal pool to the published directory + # # Only used when "linkMethod" is set to "copy" + # # * md5 (default: compare md5 sum) + # # * size (compare file size) + # verify_method: md5 + +# S3 Endpoint Support +# +# cloud storage). First, publishing +# endpoints should be described in aptly configuration file. Each endpoint has name +# and associated settings. +# +# In order to publish to S3, specify endpoint as `s3:endpoint-name:` before +# publishing prefix on the command line, e.g.: +# +# `aptly publish snapshot wheezy-main s3:test:` +# +s3_publish_endpoints: + # # Endpoint Name + # test: + # # Amazon region for S3 bucket + # region: us-east-1 + # # Bucket name + # bucket: test-bucket + # # Endpoint (optional) + # # When using S3-compatible cloud storage, specify hostname of service endpoint here, + # # region is ignored if endpoint is set (set region to some human-readable name) + # # (should be left blank for real Amazon S3) + # endpoint: "" + # # Prefix (optional) + # # publishing under specified prefix in the bucket, defaults to + # # no prefix (bucket root) + # prefix: "" + # # Default ACLs (optional) + # # assign ACL to published files: + # # * private (default, for use with apt S3 transport) + # # * public-read (public repository) + # # * none (don't set ACL) + # acl: private + # # Credentials (optional) + # # Amazon credentials to access S3 bucket. If not supplied, environment variables + # # `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `AWS_SESSION_TOKEN` are used + # access_key_id: "" + # secret_access_key: "" + # session_token: "" + # # Storage Class (optional) + # # Amazon S3 storage class, defaults to `STANDARD`. Other values + # # available: `REDUCED_REDUNDANCY` (lower price, lower redundancy) + # storage_class: STANDARD + # # Encryption Method (optional) + # # Server-side encryption method, defaults to none. Currently + # # the only available encryption method is `AES256` + # encryption_method: none + # # Plus Workaround (optional) + # # Workaround misbehavior in apt and Amazon S3 for files with `+` in filename by + # # creating two copies of package files with `+` in filename: one original + # # and another one with spaces instead of plus signs + # # With `plusWorkaround` enabled, package files with plus sign + # # would be stored twice. aptly might not cleanup files with spaces when published + # # repository is dropped or updated (switched) to new version of repository (snapshot) + # plus_workaround: false + # # Disable MultiDel (optional) + # # For S3-compatible cloud storages which do not support `MultiDel` S3 API, + # # enable this setting (file deletion would be slower with this setting enabled) + # disable_multidel: false + # # Force Signature v2 (optional) + # # Disable Signature V4 support, useful with non-AWS S3-compatible object stores + # # which do not support SigV4, shouldn't be enabled for AWS + # force_sigv2: false + # # Force VirtualHosted Style (optional) + # # Disable path style visit, useful with non-AWS S3-compatible object stores + # # which only support virtual hosted style + # force_virtualhosted_style: false + # # Debug (optional) + # # Enables detailed request/response dump for each S3 operation + # debug: false + +# Swift Endpoint Support +# +# aptly can publish a repository directly to OpenStack Swift. +# Each endpoint has name and associated settings. +# +# In order to publish to Swift, specify endpoint as `swift:endpoint-name:` before +# publishing prefix on the command line, e.g.: +# +# `aptly publish snapshot jessie-main swift:test:` +# +swift_publish_endpoints: + # # Endpoint Name + # test: + # # Container Name + # container: taylor1 + # # Prefix (optional) + # # Publish under specified prefix in the container, defaults to no prefix (container root) + # prefix: "" + # # Credentials (optional) + # # OpenStack credentials to access Keystone. If not supplied, environment variables `OS_USERNAME` and `OS_PASSWORD` are used + # username: "" + # password: "" + # # Domain (optional) + # # OpenStack domain + # domain: "" + # domain_id: "" + # # Tenant (optional) + # # OpenStack tenant (in order to use v2 authentication) + # tenant: "" + # tenant_id: "" + # tenant_domain: "" + # tenant_domain_id: "" + # # Auth URL (optional) + # # Full url of Keystone server (including port, and version). + # # Example `http://identity.example.com:5000/v2.0` + # auth_url: "" + +# Azure Endpoint Support +# +# aptly can be configured to publish repositories directly to Microsoft Azure Blob +# Storage. First, publishing endpoints should be described in the aptly +# configuration file. Each endpoint has its name and associated settings. +azure_publish_endpoints: + # # Endpoint Name + # test: + # # Container Name + # container: container1 + # # Prefix (optional) + # # Publishing under specified prefix in the container, defaults to no prefix (container root) + # prefix: "" + # # Credentials + # # Azure storage account access key to access blob storage + # account_name: "" + # account_key: "" + # # Endpoint URL + # # See: Azure documentation https://docs.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string + # # defaults to "https://.blob.core.windows.net" + # endpoint: "" + +# Package Pool +# +# Location for storing downloaded packages +# Type must be one of: +# * local +# * azure +packagepool_storage: + # Local Pool + type: local + # Local Pool Path + # empty path defaults to `rootDir`/pool + path: + + # # Azure Azure Blob Storage Pool + # type: azure + # # Container Name + # container: pool1 + # # Prefix (optional) + # # Publishing under specified prefix in the container, defaults to no prefix (container root) + # prefix: "" + # # Credentials + # # Azure storage account access key to access blob storage + # account_name: "" + # account_key: "" + # # Endpoint URL + # # See: Azure documentation https://docs.microsoft.com/en-us/azure/storage/common/storage-configure-connection-string + # # defaults to "https://.blob.core.windows.net" + # endpoint: "" + diff --git a/man/aptly.1.ronn.tmpl b/man/aptly.1.ronn.tmpl index 0b319c74..a04ac52d 100644 --- a/man/aptly.1.ronn.tmpl +++ b/man/aptly.1.ronn.tmpl @@ -48,6 +48,7 @@ Configuration file is stored in JSON format (default values shown below): "gpgProvider": "gpg", "downloadSourcePackages": false, "packagePoolStorage": { + "type": "local", "path": "$ROOTDIR/pool", "azure": { "accountName": "", diff --git a/utils/config.go b/utils/config.go index 20849450..d0e48e94 100644 --- a/utils/config.go +++ b/utils/config.go @@ -9,55 +9,54 @@ import ( "github.com/DisposaBoy/JsonConfigReader" "gopkg.in/yaml.v3" - ) // ConfigStructure is structure of main configuration type ConfigStructure struct { // nolint: maligned - RootDir string `json:"rootDir"` - DownloadConcurrency int `json:"downloadConcurrency"` - DownloadLimit int64 `json:"downloadSpeedLimit"` - DownloadRetries int `json:"downloadRetries"` - Downloader string `json:"downloader"` - DatabaseOpenAttempts int `json:"databaseOpenAttempts"` - Architectures []string `json:"architectures"` - DepFollowSuggests bool `json:"dependencyFollowSuggests"` - DepFollowRecommends bool `json:"dependencyFollowRecommends"` - DepFollowAllVariants bool `json:"dependencyFollowAllVariants"` - DepFollowSource bool `json:"dependencyFollowSource"` - DepVerboseResolve bool `json:"dependencyVerboseResolve"` - GpgDisableSign bool `json:"gpgDisableSign"` - GpgDisableVerify bool `json:"gpgDisableVerify"` - GpgProvider string `json:"gpgProvider"` - DownloadSourcePackages bool `json:"downloadSourcePackages"` - PackagePoolStorage PackagePoolStorage `json:"packagePoolStorage"` - SkipLegacyPool bool `json:"skipLegacyPool"` - PpaDistributorID string `json:"ppaDistributorID"` - PpaCodename string `json:"ppaCodename"` - SkipContentsPublishing bool `json:"skipContentsPublishing"` - SkipBz2Publishing bool `json:"skipBz2Publishing"` - FileSystemPublishRoots map[string]FileSystemPublishRoot `json:"FileSystemPublishEndpoints"` - S3PublishRoots map[string]S3PublishRoot `json:"S3PublishEndpoints"` - SwiftPublishRoots map[string]SwiftPublishRoot `json:"SwiftPublishEndpoints"` - AzurePublishRoots map[string]AzureEndpoint `json:"AzurePublishEndpoints"` - AsyncAPI bool `json:"AsyncAPI"` - EnableMetricsEndpoint bool `json:"enableMetricsEndpoint"` - LogLevel string `json:"logLevel"` - LogFormat string `json:"logFormat"` - ServeInAPIMode bool `json:"serveInAPIMode"` - DatabaseBackend DBConfig `json:"databaseBackend"` - EnableSwaggerEndpoint bool `json:"enableSwaggerEndpoint"` + RootDir string `json:"rootDir" yaml:"root_dir"` + DownloadConcurrency int `json:"downloadConcurrency" yaml:"download_concurrency"` + DownloadLimit int64 `json:"downloadSpeedLimit" yaml:"download_limit"` + DownloadRetries int `json:"downloadRetries" yaml:"download_retries"` + Downloader string `json:"downloader" yaml:"downloader"` + DatabaseOpenAttempts int `json:"databaseOpenAttempts" yaml:"database_open_attempts"` + Architectures []string `json:"architectures" yaml:"architectures"` + 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"` + GpgDisableSign bool `json:"gpgDisableSign" yaml:"gpg_disable_sign"` + GpgDisableVerify bool `json:"gpgDisableVerify" yaml:"gpg_disable_verify"` + GpgProvider string `json:"gpgProvider" yaml:"gpg_provider"` + DownloadSourcePackages bool `json:"downloadSourcePackages" yaml:"download_sourcepackages"` + PackagePoolStorage PackagePoolStorage `json:"packagePoolStorage" yaml:"packagepool_storage"` + SkipLegacyPool bool `json:"skipLegacyPool" yaml:"skip_legacy_pool"` + PpaDistributorID string `json:"ppaDistributorID" yaml:"ppa_distributor_id"` + PpaCodename string `json:"ppaCodename" yaml:"ppa_codename"` + SkipContentsPublishing bool `json:"skipContentsPublishing" yaml:"skip_contents_publishing"` + SkipBz2Publishing bool `json:"skipBz2Publishing" yaml:"skip_bz2_publishing"` + 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"` + AsyncAPI bool `json:"AsyncAPI" yaml:"async_api"` + EnableMetricsEndpoint bool `json:"enableMetricsEndpoint" yaml:"enable_metrics_endpoint"` + LogLevel string `json:"logLevel" yaml:"log_level"` + LogFormat string `json:"logFormat" yaml:"log_format"` + ServeInAPIMode bool `json:"serveInAPIMode" yaml:"serve_in_api_mode"` + DatabaseBackend DBConfig `json:"databaseBackend" yaml:"database_backend"` + EnableSwaggerEndpoint bool `json:"enableSwaggerEndpoint" yaml:"enable_swagger_endpoint"` } // DBConfig type DBConfig struct { - Type string `json:"type"` - URL string `json:"url"` - DbPath string `json:"dbPath"` + Type string `json:"type" yaml:"type"` + URL string `json:"url" yaml:"url"` + DbPath string `json:"dbPath" yaml:"db_path"` } type LocalPoolStorage struct { - Path string `json:"path,omitempty"` + Path string `json:"path,omitempty" yaml:"path,omitempty"` } type PackagePoolStorage struct { @@ -86,6 +85,26 @@ func (pool *PackagePoolStorage) UnmarshalJSON(data []byte) error { } } +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"` @@ -104,54 +123,72 @@ func (pool *PackagePoolStorage) MarshalJSON() ([]byte, error) { 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"` - LinkMethod string `json:"linkMethod"` - VerifyMethod string `json:"verifyMethod"` + 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"` - Bucket string `json:"bucket"` - Endpoint string `json:"endpoint"` - AccessKeyID string `json:"awsAccessKeyID"` - SecretAccessKey string `json:"awsSecretAccessKey"` - SessionToken string `json:"awsSessionToken"` - Prefix string `json:"prefix"` - ACL string `json:"acl"` - StorageClass string `json:"storageClass"` - EncryptionMethod string `json:"encryptionMethod"` - PlusWorkaround bool `json:"plusWorkaround"` - DisableMultiDel bool `json:"disableMultiDel"` - ForceSigV2 bool `json:"forceSigV2"` - ForceVirtualHostedStyle bool `json:"forceVirtualHostedStyle"` - Debug bool `json:"debug"` + Region string `json:"region" yaml:"region"` + Bucket string `json:"bucket" yaml:"bucket"` + Endpoint string `json:"endpoint" yaml:"endpoint"` + AccessKeyID string `json:"awsAccessKeyID" yaml:"access_key_id"` + SecretAccessKey string `json:"awsSecretAccessKey" yaml:"secret_access_key"` + SessionToken string `json:"awsSessionToken" yaml:"session_token"` + Prefix string `json:"prefix" yaml:"prefix"` + ACL string `json:"acl" yaml:"acl"` + 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 { - UserName string `json:"osname"` - Password string `json:"password"` - AuthURL string `json:"authurl"` - Tenant string `json:"tenant"` - TenantID string `json:"tenantid"` - Domain string `json:"domain"` - DomainID string `json:"domainid"` - TenantDomain string `json:"tenantdomain"` - TenantDomainID string `json:"tenantdomainid"` - Prefix string `json:"prefix"` - Container string `json:"container"` + UserName string `json:"osname" yaml:"username"` + Password string `json:"password" yaml:"password"` + AuthURL string `json:"authurl" yaml:"auth_url"` + 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"` + Prefix string `json:"prefix" yaml:"prefix"` + Container string `json:"container" yaml:"container"` } // AzureEndpoint describes single Azure publishing entry point type AzureEndpoint struct { - AccountName string `json:"accountName"` - AccountKey string `json:"accountKey"` - Container string `json:"container"` - Prefix string `json:"prefix"` - Endpoint string `json:"endpoint"` + AccountName string `json:"accountName" yaml:"account_name"` + AccountKey string `json:"accountKey" yaml:"account_key"` + Container string `json:"container" yaml:"container"` + Prefix string `json:"prefix" yaml:"prefix"` + Endpoint string `json:"endpoint" yaml:"endpoint"` } // Config is configuration for aptly, shared by all modules @@ -182,7 +219,7 @@ var Config = ConfigStructure{ AzurePublishRoots: map[string]AzureEndpoint{}, AsyncAPI: false, EnableMetricsEndpoint: false, - LogLevel: "debug", + LogLevel: "info", LogFormat: "default", ServeInAPIMode: false, EnableSwaggerEndpoint: false, @@ -196,18 +233,18 @@ func LoadConfig(filename string, config *ConfigStructure) error { } defer f.Close() - dec_json := json.NewDecoder(JsonConfigReader.New(f)) - if err = dec_json.Decode(&config); err != nil { - f.Seek(0, 0) - dec_yaml := yaml.NewDecoder(f) - if err = dec_yaml.Decode(&config); err != nil { - fmt.Errorf("config file %s is not valid yaml or json\n", filename) - } else { - fmt.Printf("config file %s format is yaml\n", filename) - } - } else { - fmt.Printf("config file %s format is json\n", filename) - } + dec_json := json.NewDecoder(JsonConfigReader.New(f)) + if err = dec_json.Decode(&config); err != nil { + f.Seek(0, 0) + dec_yaml := yaml.NewDecoder(f) + if err = dec_yaml.Decode(&config); err != nil { + fmt.Errorf("config file %s is not valid yaml or json\n", filename) + } else { + fmt.Printf("config file %s format is yaml\n", filename) + } + } else { + fmt.Printf("config file %s format is json\n", filename) + } return err }