Merge branch '15368-python-deps' closes #15368
[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         "flag"
10         "fmt"
11         "io"
12         "io/ioutil"
13         "os"
14         "os/exec"
15
16         "git.curoverse.com/arvados.git/lib/cmd"
17         "git.curoverse.com/arvados.git/sdk/go/arvados"
18         "git.curoverse.com/arvados.git/sdk/go/ctxlog"
19         "github.com/ghodss/yaml"
20 )
21
22 var DumpCommand cmd.Handler = dumpCommand{}
23
24 type dumpCommand struct{}
25
26 func (dumpCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
27         var err error
28         defer func() {
29                 if err != nil {
30                         fmt.Fprintf(stderr, "%s\n", err)
31                 }
32         }()
33
34         flags := flag.NewFlagSet("", flag.ContinueOnError)
35         flags.SetOutput(stderr)
36         configFile := flags.String("config", arvados.DefaultConfigFile, "Site configuration `file`")
37         err = flags.Parse(args)
38         if err == flag.ErrHelp {
39                 err = nil
40                 return 0
41         } else if err != nil {
42                 return 2
43         }
44
45         if len(flags.Args()) != 0 {
46                 flags.Usage()
47                 return 2
48         }
49         log := ctxlog.New(stderr, "text", "info")
50         cfg, err := loadFileOrStdin(*configFile, stdin, log)
51         if err != nil {
52                 return 1
53         }
54         out, err := yaml.Marshal(cfg)
55         if err != nil {
56                 return 1
57         }
58         _, err = stdout.Write(out)
59         if err != nil {
60                 return 1
61         }
62         return 0
63 }
64
65 var CheckCommand cmd.Handler = checkCommand{}
66
67 type checkCommand struct{}
68
69 func (checkCommand) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
70         var err error
71         defer func() {
72                 if err != nil {
73                         fmt.Fprintf(stderr, "%s\n", err)
74                 }
75         }()
76
77         flags := flag.NewFlagSet("", flag.ContinueOnError)
78         flags.SetOutput(stderr)
79         configFile := flags.String("config", arvados.DefaultConfigFile, "Site configuration `file`")
80         err = flags.Parse(args)
81         if err == flag.ErrHelp {
82                 err = nil
83                 return 0
84         } else if err != nil {
85                 return 2
86         }
87
88         if len(flags.Args()) != 0 {
89                 flags.Usage()
90                 return 2
91         }
92         log := &plainLogger{w: stderr}
93         var buf []byte
94         if *configFile == "-" {
95                 buf, err = ioutil.ReadAll(stdin)
96         } else {
97                 buf, err = ioutil.ReadFile(*configFile)
98         }
99         if err != nil {
100                 return 1
101         }
102         withoutDepr, err := load(bytes.NewBuffer(buf), log, false)
103         if err != nil {
104                 return 1
105         }
106         withDepr, err := load(bytes.NewBuffer(buf), nil, true)
107         if err != nil {
108                 return 1
109         }
110         cmd := exec.Command("diff", "-u", "--label", "without-deprecated-configs", "--label", "relying-on-deprecated-configs", "/dev/fd/3", "/dev/fd/4")
111         for _, obj := range []interface{}{withoutDepr, withDepr} {
112                 y, _ := yaml.Marshal(obj)
113                 pr, pw, err := os.Pipe()
114                 if err != nil {
115                         return 1
116                 }
117                 defer pr.Close()
118                 go func() {
119                         io.Copy(pw, bytes.NewBuffer(y))
120                         pw.Close()
121                 }()
122                 cmd.ExtraFiles = append(cmd.ExtraFiles, pr)
123         }
124         diff, err := cmd.CombinedOutput()
125         if bytes.HasPrefix(diff, []byte("--- ")) {
126                 fmt.Fprintln(stdout, "Your configuration is relying on deprecated entries. Suggest making the following changes.")
127                 stdout.Write(diff)
128                 return 1
129         } else if len(diff) > 0 {
130                 fmt.Fprintf(stderr, "Unexpected diff output:\n%s", diff)
131                 return 1
132         } else if err != nil {
133                 return 1
134         }
135         if log.used {
136                 return 1
137         }
138         return 0
139 }
140
141 type plainLogger struct {
142         w    io.Writer
143         used bool
144 }
145
146 func (pl *plainLogger) Warnf(format string, args ...interface{}) {
147         pl.used = true
148         fmt.Fprintf(pl.w, format+"\n", args...)
149 }