Skip to content

Commit a28c2b3

Browse files
authored
Merge pull request #982 from kaleido-io/sharedstorage
Misc cleanup for 1.0 branch
2 parents b039fb3 + 92c2fc1 commit a28c2b3

File tree

11 files changed

+563
-2
lines changed

11 files changed

+563
-2
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ lint: ${LINT}
2323
${MOCKERY}:
2424
$(VGO) install github.com/vektra/mockery/cmd/mockery@latest
2525
${LINT}:
26-
$(VGO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
26+
$(VGO) install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.2
2727
ffcommon:
2828
$(eval WSCLIENT_PATH := $(shell $(VGO) list -f '{{.Dir}}' github.com/hyperledger/firefly-common/pkg/wsclient))
2929

ffconfig/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# FireFly configuration tool
2+
3+
A tool for managing and migrating config files for Hyperledger FireFly.
4+
5+
## Installation
6+
7+
If you have a local Go development environment, and you have included `${GOPATH}/bin` in your path, you can install with:
8+
9+
```sh
10+
go install github.com/hyperledger/firefly/ffconfig@latest
11+
```
12+
13+
## Usage
14+
15+
### Migration
16+
17+
Parse a config file to find any deprecated items that should be updated to the latest config syntax.
18+
The updated config will be written to stdout (or a file specified with `-o`).
19+
```
20+
ffconfig migrate -f firefly.core.yml [-o new.yml]
21+
```
22+
23+
You may optionally specify `--from` and `--to` versions to run a subset of the migrations.
24+
25+
View the source code for all current migrations at [migrate/migrations.go](migrate/migrations.go).

ffconfig/main.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Copyright © 2022 Kaleido, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package main
18+
19+
import (
20+
"fmt"
21+
"io/ioutil"
22+
"os"
23+
24+
"github.com/hyperledger/firefly/ffconfig/migrate"
25+
"github.com/spf13/cobra"
26+
)
27+
28+
var rootCmd = &cobra.Command{
29+
Use: "ffconfig",
30+
Short: "FireFly configuration tool",
31+
Long: "Tool for managing and migrating config files for Hyperledger FireFly",
32+
RunE: func(cmd *cobra.Command, args []string) error {
33+
return fmt.Errorf("a command is required")
34+
},
35+
}
36+
37+
var migrateCommand = &cobra.Command{
38+
Use: "migrate",
39+
Short: "Migrate a config file to the current version",
40+
RunE: func(cmd *cobra.Command, args []string) error {
41+
cfg, err := ioutil.ReadFile(cfgFile)
42+
if err != nil {
43+
return err
44+
}
45+
out, err := migrate.Run(cfg, fromVersion, toVersion)
46+
if err != nil {
47+
return err
48+
}
49+
if outFile == "" {
50+
fmt.Print(string(out))
51+
return nil
52+
}
53+
return ioutil.WriteFile(outFile, out, 0600)
54+
},
55+
}
56+
57+
var cfgFile string
58+
var outFile string
59+
var fromVersion string
60+
var toVersion string
61+
62+
func init() {
63+
rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "f", "firefly.core.yml", "config file")
64+
migrateCommand.PersistentFlags().StringVarP(&outFile, "out", "o", "", "output file (if unspecified, write to stdout)")
65+
migrateCommand.PersistentFlags().StringVar(&fromVersion, "from", "", "from version (optional, such as 1.0.0)")
66+
migrateCommand.PersistentFlags().StringVar(&toVersion, "to", "", "to version (optional, such as 1.1.0)")
67+
rootCmd.AddCommand(migrateCommand)
68+
}
69+
70+
func main() {
71+
if err := rootCmd.Execute(); err != nil {
72+
fmt.Fprintf(os.Stderr, "%s\n", err)
73+
os.Exit(1)
74+
}
75+
os.Exit(0)
76+
}

ffconfig/migrate/config.go

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
// Copyright © 2022 Kaleido, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package migrate
18+
19+
import (
20+
"fmt"
21+
"io"
22+
)
23+
24+
type ConfigItem struct {
25+
value interface{}
26+
parent *ConfigItem
27+
name string
28+
writer io.Writer
29+
}
30+
31+
type ConfigItemIterator struct {
32+
items []*ConfigItem
33+
}
34+
35+
func NewConfigItem(value interface{}, writer io.Writer) *ConfigItem {
36+
return &ConfigItem{value: value, writer: writer}
37+
}
38+
39+
func (c *ConfigItem) hasChild(name string) (exists bool) {
40+
if v, ok := c.value.(map[interface{}]interface{}); ok {
41+
_, exists = v[name]
42+
}
43+
return exists
44+
}
45+
46+
func (c *ConfigItem) deleteChild(name string) {
47+
if v, ok := c.value.(map[interface{}]interface{}); ok {
48+
delete(v, name)
49+
}
50+
}
51+
52+
func (c *ConfigItem) setChild(name string, value interface{}) {
53+
if v, ok := c.value.(map[interface{}]interface{}); ok {
54+
v[name] = value
55+
}
56+
}
57+
58+
func (c *ConfigItem) Get(name string) *ConfigItem {
59+
if v, ok := c.value.(map[interface{}]interface{}); ok {
60+
if child, ok := v[name]; ok {
61+
return &ConfigItem{value: child, parent: c, name: name, writer: c.writer}
62+
}
63+
}
64+
return &ConfigItem{value: nil, parent: c, name: name, writer: c.writer}
65+
}
66+
67+
func (c *ConfigItemIterator) Get(name string) *ConfigItemIterator {
68+
items := make([]*ConfigItem, len(c.items))
69+
for i, item := range c.items {
70+
items[i] = item.Get(name)
71+
}
72+
return &ConfigItemIterator{items: items}
73+
}
74+
75+
func (c *ConfigItem) Path() string {
76+
if c.parent == nil || c.parent.name == "" {
77+
return c.name
78+
}
79+
return c.parent.Path() + "." + c.name
80+
}
81+
82+
func (c *ConfigItem) Exists() bool {
83+
return c.value != nil
84+
}
85+
86+
func (c *ConfigItem) Length() int {
87+
if v, ok := c.value.([]interface{}); ok {
88+
return len(v)
89+
}
90+
return 0
91+
}
92+
93+
func (c *ConfigItem) Each() *ConfigItemIterator {
94+
list, ok := c.value.([]interface{})
95+
if !ok {
96+
return &ConfigItemIterator{items: make([]*ConfigItem, 0)}
97+
}
98+
items := make([]*ConfigItem, len(list))
99+
for i, val := range list {
100+
items[i] = &ConfigItem{
101+
value: val,
102+
parent: c.parent,
103+
name: c.name,
104+
writer: c.writer,
105+
}
106+
}
107+
return &ConfigItemIterator{items: items}
108+
}
109+
110+
func (c *ConfigItemIterator) Run(fn func(item *ConfigItem)) *ConfigItemIterator {
111+
for _, item := range c.items {
112+
fn(item)
113+
}
114+
return c
115+
}
116+
117+
func (c *ConfigItem) Create() *ConfigItem {
118+
if !c.Exists() {
119+
if c.parent != nil {
120+
c.parent.Create()
121+
}
122+
c.value = make(map[interface{}]interface{})
123+
c.parent.setChild(c.name, c.value)
124+
}
125+
return c
126+
}
127+
128+
func (c *ConfigItem) Set(value interface{}) *ConfigItem {
129+
fmt.Fprintf(c.writer, "Create: %s: %s\n", c.Path(), value)
130+
c.value = value
131+
c.parent.Create()
132+
c.parent.setChild(c.name, c.value)
133+
return c
134+
}
135+
136+
func (c *ConfigItemIterator) Set(value interface{}) *ConfigItemIterator {
137+
for _, item := range c.items {
138+
item.Set(value)
139+
}
140+
return c
141+
}
142+
143+
func (c *ConfigItem) SetIfEmpty(value interface{}) *ConfigItem {
144+
if !c.Exists() {
145+
c.Set(value)
146+
}
147+
return c
148+
}
149+
150+
func (c *ConfigItem) Delete() *ConfigItem {
151+
if c.Exists() {
152+
fmt.Fprintf(c.writer, "Delete: %s\n", c.Path())
153+
c.parent.deleteChild(c.name)
154+
}
155+
return c
156+
}
157+
158+
func (c *ConfigItemIterator) Delete() *ConfigItemIterator {
159+
for _, item := range c.items {
160+
item.Delete()
161+
}
162+
return c
163+
}
164+
165+
func (c *ConfigItem) RenameTo(name string) *ConfigItem {
166+
if c.Exists() {
167+
if c.parent.hasChild(name) {
168+
// Don't overwrite if the new key already exists
169+
c.Delete()
170+
} else {
171+
fmt.Fprintf(c.writer, "Rename: %s -> .%s\n", c.Path(), name)
172+
c.parent.deleteChild(c.name)
173+
c.parent.setChild(name, c.value)
174+
c.name = name
175+
}
176+
}
177+
return c
178+
}
179+
180+
func (c *ConfigItemIterator) RenameTo(name string) *ConfigItemIterator {
181+
for _, item := range c.items {
182+
item.RenameTo(name)
183+
}
184+
return c
185+
}
186+
187+
func (c *ConfigItem) ReplaceValue(old interface{}, new interface{}) *ConfigItem {
188+
if c.value == old {
189+
fmt.Fprintf(c.writer, "Change: %s: %s -> %s\n", c.Path(), old, new)
190+
c.value = new
191+
c.parent.setChild(c.name, new)
192+
}
193+
return c
194+
}
195+
196+
func (c *ConfigItemIterator) ReplaceValue(old interface{}, new interface{}) *ConfigItemIterator {
197+
for _, item := range c.items {
198+
item.ReplaceValue(old, new)
199+
}
200+
return c
201+
}

ffconfig/migrate/config_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright © 2022 Kaleido, Inc.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package migrate
18+
19+
import (
20+
"os"
21+
"testing"
22+
23+
"github.com/stretchr/testify/assert"
24+
)
25+
26+
func TestDeleteList(t *testing.T) {
27+
value := map[interface{}]interface{}{
28+
"values": []interface{}{"test1", "test2"},
29+
}
30+
config := &ConfigItem{value: value, writer: os.Stdout}
31+
config.Get("values").Each().Delete()
32+
assert.Equal(t, 0, len(value))
33+
}
34+
35+
func TestNoRename(t *testing.T) {
36+
value := map[interface{}]interface{}{
37+
"key1": "val1",
38+
"key2": "val2",
39+
}
40+
config := &ConfigItem{value: value, writer: os.Stdout}
41+
config.Get("key1").RenameTo("key2")
42+
assert.Equal(t, map[interface{}]interface{}{
43+
"key2": "val2",
44+
}, value)
45+
}

0 commit comments

Comments
 (0)