feat: add dry-run flag for config profile apply command
License: MIT Signed-off-by: chenminjian <727180553@qq.com>
chenminjian committed
Sep 13, 2018 at 16:39 UTC
2e3cbe3e27a2db90a1b99080af3c7847f0f0d930
3 files changed
+111
-11
core/commands/config.go
+63
-11
@@ -16,10 +16,17 @@ import (
16
repo "github.com/ipfs/go-ipfs/repo"
17
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
18
19
+ "gx/ipfs/QmP2i47tnU23ijdshrZtuvrSkQPtf9HhsMb9fwGVe8owj2/jsondiff"
20
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
21
"gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
22
)
23
24
+// ConfigUpdateOutput is config profile apply command's output
25
+type ConfigUpdateOutput struct {
26
+ Old config.Config
27
+ New config.Config
28
+}
29
+
30
type ConfigField struct {
31
Key string
32
Value interface{}
@@ -333,6 +340,9 @@ var configProfileApplyCmd = &cmds.Command{
340
Helptext: cmdkit.HelpText{
341
Tagline: "Apply profile to config.",
342
},
343
+ Options: []cmdkit.Option{
344
+ cmdkit.BoolOption("dry-run", "print difference between the current config and the config that would be generated"),
345
+ },
346
Arguments: []cmdkit.Argument{
347
cmdkit.StringArg("profile", true, false, "The profile to apply to the config."),
348
},
@@ -343,13 +353,40 @@ var configProfileApplyCmd = &cmds.Command{
353
return
354
}
355
346
- err := transformConfig(req.InvocContext().ConfigRoot, req.Arguments()[0], profile.Transform)
356
+ dryRun, _, _ := req.Option("dry-run").Bool()
357
+ oldCfg, newCfg, err := transformConfig(req.InvocContext().ConfigRoot, req.Arguments()[0], profile.Transform, dryRun)
358
if err != nil {
359
res.SetError(err, cmdkit.ErrNormal)
360
return
361
}
351
- res.SetOutput(nil)
362
+ res.SetOutput(&ConfigUpdateOutput{
363
+ Old: *oldCfg,
364
+ New: *newCfg,
365
+ })
366
+ },
367
+ Marshalers: cmds.MarshalerMap{
368
+ cmds.Text: func(res cmds.Response) (io.Reader, error) {
369
+ if res.Error() != nil {
370
+ return nil, res.Error()
371
+ }
372
+
373
+ v, err := unwrapOutput(res.Output())
374
+ if err != nil {
375
+ return nil, err
376
+ }
377
+
378
+ apply, ok := v.(*ConfigUpdateOutput)
379
+ if !ok {
380
+ return nil, e.TypeErr(apply, v)
381
+ }
382
+
383
+ diff := jsondiff.Compare(apply.Old, apply.New)
384
+ buf := jsondiff.Format(diff)
385
+
386
+ return strings.NewReader(string(buf)), nil
387
+ },
388
},
389
+ Type: ConfigUpdateOutput{},
390
}
391
392
func buildProfileHelp() string {
@@ -367,29 +404,44 @@ func buildProfileHelp() string {
404
return out
405
}
406
370
-func transformConfig(configRoot string, configName string, transformer config.Transformer) error {
407
+// transformConfig returns old config and new config instead of difference between they,
408
+// because apply command can provide stable API through this way.
409
+// If dryRun is true, repo's config should not be updated and persisted
410
+// to storage. Otherwise, repo's config should be updated and persisted
411
+// to storage.
412
+func transformConfig(configRoot string, configName string, transformer config.Transformer, dryRun bool) (*config.Config, *config.Config, error) {
413
r, err := fsrepo.Open(configRoot)
414
if err != nil {
373
- return err
415
+ return nil, nil, err
416
}
417
defer r.Close()
418
419
cfg, err := r.Config()
420
if err != nil {
379
- return err
421
+ return nil, nil, err
422
}
423
382
- err = transformer(cfg)
424
+ // make a copy to avoid updating repo's config unintentionally
425
+ oldCfg := *cfg
426
+ newCfg := oldCfg
427
+ err = transformer(&newCfg)
428
if err != nil {
384
- return err
429
+ return nil, nil, err
430
}
431
387
- _, err = r.BackupConfig("pre-" + configName + "-")
388
- if err != nil {
389
- return err
432
+ if !dryRun {
433
+ _, err = r.BackupConfig("pre-" + configName + "-")
434
+ if err != nil {
435
+ return nil, nil, err
436
+ }
437
+
438
+ err = r.SetConfig(&newCfg)
439
+ if err != nil {
440
+ return nil, nil, err
441
+ }
442
}
443
392
- return r.SetConfig(cfg)
444
+ return &oldCfg, &newCfg, nil
445
}
446
447
func getConfig(r repo.Repo, key string) (*ConfigField, error) {
package.json
+6
@@ -552,6 +552,12 @@
552
"name": "go-multiaddr-dns",
553
"version": "0.2.4"
554
},
555
+ {
556
+ "author": "elgris",
557
+ "hash": "QmP2i47tnU23ijdshrZtuvrSkQPtf9HhsMb9fwGVe8owj2",
558
+ "name": "jsondiff",
559
+ "version": "0.0.0"
560
+ },
561
{
562
"author": "marten-seemann",
563
"hash": "QmNtLLJMc7TDMSaNuJVFipxLji9NL56QyMnBBPk2X58Mno",
test/sharness/t0021-config.sh
+42
@@ -75,6 +75,17 @@ test_profile_apply_revert() {
75
'
76
}
77
78
+test_profile_apply_dry_run_not_alter() {
79
+ profile=$1
80
+
81
+ test_expect_success "'ipfs config profile apply ${profile} --dry-run' doesn't alter config" '
82
+ cat "$IPFS_PATH/config" >expected &&
83
+ ipfs config profile apply '${profile}' --dry-run &&
84
+ cat "$IPFS_PATH/config" >actual &&
85
+ test_cmp expected actual
86
+ '
87
+}
88
+
89
test_config_cmd() {
90
test_config_cmd_set "beep" "boop"
91
test_config_cmd_set "beep1" "boop2"
@@ -220,6 +231,37 @@ test_config_cmd() {
231
# need to do this in reverse as the test profile is already applied in sharness
232
test_profile_apply_revert default-networking test
233
234
+ test_profile_apply_dry_run_not_alter server
235
+
236
+ test_profile_apply_dry_run_not_alter local-discovery
237
+
238
+ test_profile_apply_dry_run_not_alter test
239
+
240
+ test_expect_success "'ipfs config profile apply local-discovery --dry-run' looks good with different profile info" '
241
+ ipfs config profile apply local-discovery --dry-run > diff_info &&
242
+ test `grep "DisableNatPortMap" diff_info | wc -l` = 2
243
+ '
244
+
245
+ test_expect_success "'ipfs config profile apply server --dry-run' looks good with same profile info" '
246
+ ipfs config profile apply server --dry-run > diff_info &&
247
+ test `grep "DisableNatPortMap" diff_info | wc -l` = 1
248
+ '
249
+
250
+ test_expect_success "'ipfs config profile apply server' looks good with same profile info" '
251
+ ipfs config profile apply server > diff_info &&
252
+ test `grep "DisableNatPortMap" diff_info | wc -l` = 1
253
+ '
254
+
255
+ test_expect_success "'ipfs config profile apply local-discovery' looks good with different profile info" '
256
+ ipfs config profile apply local-discovery > diff_info &&
257
+ test `grep "DisableNatPortMap" diff_info | wc -l` = 2
258
+ '
259
+
260
+ test_expect_success "'ipfs config profile apply test' looks good with different profile info" '
261
+ ipfs config profile apply test > diff_info &&
262
+ test `grep "DisableNatPortMap" diff_info | wc -l` = 2
263
+ '
264
+
265
# won't work as it changes datastore definition, which makes ipfs not launch
266
# without converting first
267
# test_profile_apply_revert badgerds