Merge branch '15167-unlogged-attrs-api-docs'
[arvados.git] / lib / config / cmd.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package config
6
7 import (
8         "bytes"
9         "fmt"
10         "io"
11         "io/ioutil"
12         "os"
13         "os/exec"
14
15         "git.curoverse.com/arvados.git/lib/cmd"
16         "git.curoverse.com/arvados.git/sdk/go/ctxlog"
17         "github.com/ghodss/yaml"
18 )
19
20 var DumpCommand cmd.Handler = dumpCommand{}
21
22 type dumpCommand struct{}
23
24 func (dumpCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
25         var err error
26         defer func() {
27                 if err != nil {
28                         fmt.Fprintf(stderr, "%s\n", err)
29                 }
30         }()
31         if len(args) != 0 {
32                 err = fmt.Errorf("usage: %s <config-src.yaml >config-min.yaml", prog)
33                 return 2
34         }
35         log := ctxlog.New(stderr, "text", "info")
36         cfg, err := Load(stdin, log)
37         if err != nil {
38                 return 1
39         }
40         out, err := yaml.Marshal(cfg)
41         if err != nil {
42                 return 1
43         }
44         _, err = stdout.Write(out)
45         if err != nil {
46                 return 1
47         }
48         return 0
49 }
50
51 var CheckCommand cmd.Handler = checkCommand{}
52
53 type checkCommand struct{}
54
55 func (checkCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
56         var err error
57         defer func() {
58                 if err != nil {
59                         fmt.Fprintf(stderr, "%s\n", err)
60                 }
61         }()
62         if len(args) != 0 {
63                 err = fmt.Errorf("usage: %s <config-src.yaml && echo 'no changes needed'", prog)
64                 return 2
65         }
66         log := &plainLogger{w: stderr}
67         buf, err := ioutil.ReadAll(stdin)
68         if err != nil {
69                 return 1
70         }
71         withoutDepr, err := load(bytes.NewBuffer(buf), log, false)
72         if err != nil {
73                 return 1
74         }
75         withDepr, err := load(bytes.NewBuffer(buf), nil, true)
76         if err != nil {
77                 return 1
78         }
79         cmd := exec.Command("diff", "-u", "--label", "without-deprecated-configs", "--label", "relying-on-deprecated-configs", "/dev/fd/3", "/dev/fd/4")
80         for _, obj := range []interface{}{withoutDepr, withDepr} {
81                 y, _ := yaml.Marshal(obj)
82                 pr, pw, err := os.Pipe()
83                 if err != nil {
84                         return 1
85                 }
86                 defer pr.Close()
87                 go func() {
88                         io.Copy(pw, bytes.NewBuffer(y))
89                         pw.Close()
90                 }()
91                 cmd.ExtraFiles = append(cmd.ExtraFiles, pr)
92         }
93         diff, err := cmd.CombinedOutput()
94         if bytes.HasPrefix(diff, []byte("--- ")) {
95                 fmt.Fprintln(stdout, "Your configuration is relying on deprecated entries. Suggest making the following changes.")
96                 stdout.Write(diff)
97                 return 1
98         } else if len(diff) > 0 {
99                 fmt.Fprintf(stderr, "Unexpected diff output:\n%s", diff)
100                 return 1
101         } else if err != nil {
102                 return 1
103         }
104         if log.used {
105                 return 1
106         }
107         return 0
108 }
109
110 type plainLogger struct {
111         w    io.Writer
112         used bool
113 }
114
115 func (pl *plainLogger) Warnf(format string, args ...interface{}) {
116         pl.used = true
117         fmt.Fprintf(pl.w, format+"\n", args...)
118 }