Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Config File Handling #156

Merged
merged 5 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 64 additions & 36 deletions cmd/iceberg/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (

"github.com/apache/iceberg-go"
"github.com/apache/iceberg-go/catalog"
"github.com/apache/iceberg-go/config"
"github.com/apache/iceberg-go/table"
"github.com/docopt/docopt-go"
)
Expand Down Expand Up @@ -58,54 +59,63 @@ Options:
--uri TEXT specify the catalog URI
--output TYPE output type (json/text) [default: text]
--credential TEXT specify credentials for the catalog
--warehouse TEXT specify the warehouse to use`
--warehouse TEXT specify the warehouse to use
--config TEXT specify the path to the configuration file`

type Config struct {
List bool `docopt:"list"`
Describe bool `docopt:"describe"`
Schema bool `docopt:"schema"`
Spec bool `docopt:"spec"`
Uuid bool `docopt:"uuid"`
Location bool `docopt:"location"`
Props bool `docopt:"properties"`
Drop bool `docopt:"drop"`
Files bool `docopt:"files"`
Rename bool `docopt:"rename"`

Get bool `docopt:"get"`
Set bool `docopt:"set"`
Remove bool `docopt:"remove"`

Namespace bool `docopt:"namespace"`
Table bool `docopt:"table"`

RenameFrom string `docopt:"<from>"`
RenameTo string `docopt:"<to>"`

Parent string `docopt:"PARENT"`
Ident string `docopt:"IDENTIFIER"`
TableID string `docopt:"TABLE_ID"`
PropName string `docopt:"PROPNAME"`
Value string `docopt:"VALUE"`

Catalog string `docopt:"--catalog"`
URI string `docopt:"--uri"`
Output string `docopt:"--output"`
History bool `docopt:"--history"`
Cred string `docopt:"--credential"`
Warehouse string `docopt:"--warehouse"`
Config string `docopt:"--config"`
}

func main() {
args, err := docopt.ParseArgs(usage, os.Args[1:], iceberg.Version())
if err != nil {
log.Fatal(err)
}

cfg := struct {
List bool `docopt:"list"`
Describe bool `docopt:"describe"`
Schema bool `docopt:"schema"`
Spec bool `docopt:"spec"`
Uuid bool `docopt:"uuid"`
Location bool `docopt:"location"`
Props bool `docopt:"properties"`
Drop bool `docopt:"drop"`
Files bool `docopt:"files"`
Rename bool `docopt:"rename"`

Get bool `docopt:"get"`
Set bool `docopt:"set"`
Remove bool `docopt:"remove"`

Namespace bool `docopt:"namespace"`
Table bool `docopt:"table"`

RenameFrom string `docopt:"<from>"`
RenameTo string `docopt:"<to>"`

Parent string `docopt:"PARENT"`
Ident string `docopt:"IDENTIFIER"`
TableID string `docopt:"TABLE_ID"`
PropName string `docopt:"PROPNAME"`
Value string `docopt:"VALUE"`

Catalog string `docopt:"--catalog"`
URI string `docopt:"--uri"`
Output string `docopt:"--output"`
History bool `docopt:"--history"`
Cred string `docopt:"--credential"`
Warehouse string `docopt:"--warehouse"`
}{}
cfg := Config{}

if err := args.Bind(&cfg); err != nil {
log.Fatal(err)
}
Comment on lines 110 to 112
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we probably add an option to specify the config file if they want something other than the default .iceberg-go.yaml?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zeroshade I have added --config option to specify the path to the configuration file.


fileCfg := config.ParseConfig(config.LoadConfig(cfg.Config), "default")
if fileCfg != nil {
mergeConf(fileCfg, &cfg)
}

var output Output
switch strings.ToLower(cfg.Output) {
case "text":
Expand Down Expand Up @@ -341,3 +351,21 @@ func properties(output Output, cat catalog.Catalog, args propCmd) {
}
}
}

func mergeConf(fileConf *config.CatalogConfig, resConfig *Config) {
if len(resConfig.Catalog) == 0 {
resConfig.Catalog = fileConf.Catalog
}
if len(resConfig.URI) == 0 {
resConfig.URI = fileConf.URI
}
if len(resConfig.Output) == 0 {
resConfig.Output = fileConf.Output
}
if len(resConfig.Cred) == 0 {
resConfig.Cred = fileConf.Credential
}
if len(resConfig.Warehouse) == 0 {
resConfig.Warehouse = fileConf.Warehouse
}
}
71 changes: 71 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package config

import (
"os"
"path/filepath"

"gopkg.in/yaml.v3"
)

const cfgFile = ".iceberg-go.yaml"

type Config struct {
Catalogs map[string]CatalogConfig `yaml:"catalog"`
}

type CatalogConfig struct {
Catalog string `yaml:"catalog"`
URI string `yaml:"uri"`
Output string `yaml:"output"`
Credential string `yaml:"credential"`
Warehouse string `yaml:"warehouse"`
}

func LoadConfig(configPath string) []byte {
var path string
if len(configPath) > 0 {
path = configPath
} else {
homeDir, err := os.UserHomeDir()
if err != nil {
return nil

}
path = filepath.Join(homeDir, cfgFile)
}
file, err := os.ReadFile(path)
if err != nil {
return nil
}
return file
}

func ParseConfig(file []byte, catalogName string) *CatalogConfig {
var config Config
err := yaml.Unmarshal(file, &config)
if err != nil {
return nil
}
res, ok := config.Catalogs[catalogName]
if !ok {
return nil
}
return &res
}
85 changes: 85 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package config

import (
"testing"

"github.com/stretchr/testify/assert"
)

var testArgs = []struct {
file []byte
catName string
expected *CatalogConfig
}{
// config file does not exist
{nil, "default", nil},
// config does not have default catalog
{[]byte(`
catalog:
custom-catalog:
catalog: rest
uri: http://localhost:8181/
output: text
credential: client-id:client-secret
warehouse: catalog_name
`), "default", nil},
// default catalog
{[]byte(`
catalog:
default:
catalog: rest
uri: http://localhost:8181/
output: text
credential: client-id:client-secret
warehouse: catalog_name
`), "default",
&CatalogConfig{
Catalog: "rest",
URI: "http://localhost:8181/",
Output: "text",
Credential: "client-id:client-secret",
Warehouse: "catalog_name",
}},
// custom catalog
{[]byte(`
catalog:
custom-catalog:
catalog: rest
uri: http://localhost:8181/
output: text
credential: client-id:client-secret
warehouse: catalog_name
`), "custom-catalog",
&CatalogConfig{
Catalog: "rest",
URI: "http://localhost:8181/",
Output: "text",
Credential: "client-id:client-secret",
Warehouse: "catalog_name",
}},
}

func TestParseConfig(t *testing.T) {
for _, tt := range testArgs {
actual := ParseConfig([]byte(tt.file), tt.catName)

assert.Equal(t, tt.expected, actual)
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ require (
github.com/twmb/murmur3 v1.1.8
github.com/wolfeidau/s3iofs v1.5.2
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0
gopkg.in/yaml.v3 v3.0.1
)

require (
Expand Down Expand Up @@ -87,5 +88,4 @@ require (
golang.org/x/text v0.18.0 // indirect
golang.org/x/tools v0.25.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading