xref: /aosp_15_r20/external/bazelbuild-rules_go/go/tools/releaser/releaser.go (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1*9bb1b549SSpandan Das// Copyright 2021 The Bazel Authors. All rights reserved.
2*9bb1b549SSpandan Das//
3*9bb1b549SSpandan Das// Licensed under the Apache License, Version 2.0 (the "License");
4*9bb1b549SSpandan Das// you may not use this file except in compliance with the License.
5*9bb1b549SSpandan Das// You may obtain a copy of the License at
6*9bb1b549SSpandan Das//
7*9bb1b549SSpandan Das//    http://www.apache.org/licenses/LICENSE-2.0
8*9bb1b549SSpandan Das//
9*9bb1b549SSpandan Das// Unless required by applicable law or agreed to in writing, software
10*9bb1b549SSpandan Das// distributed under the License is distributed on an "AS IS" BASIS,
11*9bb1b549SSpandan Das// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9bb1b549SSpandan Das// See the License for the specific language governing permissions and
13*9bb1b549SSpandan Das// limitations under the License.
14*9bb1b549SSpandan Das
15*9bb1b549SSpandan Das// releaser is a tool for maintaining rules_go and Gazelle. It automates
16*9bb1b549SSpandan Das// multiple tasks related to preparing releases, like upgrading dependencies,
17*9bb1b549SSpandan Das// and uploading release artifacts.
18*9bb1b549SSpandan Daspackage main
19*9bb1b549SSpandan Das
20*9bb1b549SSpandan Dasimport (
21*9bb1b549SSpandan Das	"context"
22*9bb1b549SSpandan Das	"errors"
23*9bb1b549SSpandan Das	"fmt"
24*9bb1b549SSpandan Das	"io"
25*9bb1b549SSpandan Das	"os"
26*9bb1b549SSpandan Das	"os/signal"
27*9bb1b549SSpandan Das)
28*9bb1b549SSpandan Das
29*9bb1b549SSpandan Dasfunc main() {
30*9bb1b549SSpandan Das	ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
31*9bb1b549SSpandan Das	defer cancel()
32*9bb1b549SSpandan Das	if err := run(ctx, os.Stderr, os.Args[1:]); err != nil {
33*9bb1b549SSpandan Das		fmt.Fprintln(os.Stderr, err)
34*9bb1b549SSpandan Das		os.Exit(1)
35*9bb1b549SSpandan Das	}
36*9bb1b549SSpandan Das}
37*9bb1b549SSpandan Das
38*9bb1b549SSpandan Dastype command struct {
39*9bb1b549SSpandan Das	name, description, help string
40*9bb1b549SSpandan Das	run                     func(context.Context, io.Writer, []string) error
41*9bb1b549SSpandan Das}
42*9bb1b549SSpandan Das
43*9bb1b549SSpandan Dasvar commands = []*command{
44*9bb1b549SSpandan Das	&helpCmd,
45*9bb1b549SSpandan Das	&prepareCmd,
46*9bb1b549SSpandan Das	&upgradeDepCmd,
47*9bb1b549SSpandan Das}
48*9bb1b549SSpandan Das
49*9bb1b549SSpandan Dasfunc run(ctx context.Context, stderr io.Writer, args []string) error {
50*9bb1b549SSpandan Das	if len(args) == 0 {
51*9bb1b549SSpandan Das		return errors.New("no command specified. For a list of commands, run:\n\treleaser help")
52*9bb1b549SSpandan Das	}
53*9bb1b549SSpandan Das	name, args := args[0], args[1:]
54*9bb1b549SSpandan Das	for _, arg := range args {
55*9bb1b549SSpandan Das		if arg == "-h" || name == "-help" || name == "--help" {
56*9bb1b549SSpandan Das			return helpCmd.run(ctx, stderr, args)
57*9bb1b549SSpandan Das		}
58*9bb1b549SSpandan Das	}
59*9bb1b549SSpandan Das	for _, cmd := range commands {
60*9bb1b549SSpandan Das		if cmd.name == name {
61*9bb1b549SSpandan Das			return cmd.run(ctx, stderr, args)
62*9bb1b549SSpandan Das		}
63*9bb1b549SSpandan Das	}
64*9bb1b549SSpandan Das	return fmt.Errorf("unknown command %q. For a list of commands, run:\n\treleaser help", name)
65*9bb1b549SSpandan Das}
66*9bb1b549SSpandan Das
67*9bb1b549SSpandan Dasvar helpCmd = command{
68*9bb1b549SSpandan Das	name:        "help",
69*9bb1b549SSpandan Das	description: "prints information on how to use any subcommand",
70*9bb1b549SSpandan Das	help: `releaser help [subcommand]
71*9bb1b549SSpandan Das
72*9bb1b549SSpandan DasThe help sub-command prints information on how to use any subcommand. Run help
73*9bb1b549SSpandan Daswithout arguments for a list of all subcommands.
74*9bb1b549SSpandan Das`,
75*9bb1b549SSpandan Das}
76*9bb1b549SSpandan Das
77*9bb1b549SSpandan Dasfunc init() {
78*9bb1b549SSpandan Das	// break init cycle
79*9bb1b549SSpandan Das	helpCmd.run = runHelp
80*9bb1b549SSpandan Das}
81*9bb1b549SSpandan Das
82*9bb1b549SSpandan Dasfunc runHelp(ctx context.Context, stderr io.Writer, args []string) error {
83*9bb1b549SSpandan Das	if len(args) > 1 {
84*9bb1b549SSpandan Das		return usageErrorf(&helpCmd, "help accepts at most one argument.")
85*9bb1b549SSpandan Das	}
86*9bb1b549SSpandan Das
87*9bb1b549SSpandan Das	if len(args) == 1 {
88*9bb1b549SSpandan Das		name := args[0]
89*9bb1b549SSpandan Das		for _, cmd := range commands {
90*9bb1b549SSpandan Das			if cmd.name == name {
91*9bb1b549SSpandan Das				fmt.Fprintf(stderr, "%s\n\n%s\n", cmd.description, cmd.help)
92*9bb1b549SSpandan Das				return nil
93*9bb1b549SSpandan Das			}
94*9bb1b549SSpandan Das		}
95*9bb1b549SSpandan Das		return fmt.Errorf("Unknown command %s. For a list of supported subcommands, run:\n\treleaser help", name)
96*9bb1b549SSpandan Das	}
97*9bb1b549SSpandan Das
98*9bb1b549SSpandan Das	fmt.Fprint(stderr, "releaser supports the following subcommands:\n\n")
99*9bb1b549SSpandan Das	maxNameLen := 0
100*9bb1b549SSpandan Das	for _, cmd := range commands {
101*9bb1b549SSpandan Das		if len(cmd.name) > maxNameLen {
102*9bb1b549SSpandan Das			maxNameLen = len(cmd.name)
103*9bb1b549SSpandan Das		}
104*9bb1b549SSpandan Das	}
105*9bb1b549SSpandan Das	for _, cmd := range commands {
106*9bb1b549SSpandan Das		fmt.Fprintf(stderr, "\t%-*s    %s\n", maxNameLen, cmd.name, cmd.description)
107*9bb1b549SSpandan Das	}
108*9bb1b549SSpandan Das	fmt.Fprintf(stderr, "\nRun 'releaser help <subcommand>' for more information on any command.\n")
109*9bb1b549SSpandan Das	return nil
110*9bb1b549SSpandan Das}
111*9bb1b549SSpandan Das
112*9bb1b549SSpandan Dastype usageError struct {
113*9bb1b549SSpandan Das	cmd *command
114*9bb1b549SSpandan Das	err error
115*9bb1b549SSpandan Das}
116*9bb1b549SSpandan Das
117*9bb1b549SSpandan Dasfunc (e *usageError) Error() string {
118*9bb1b549SSpandan Das	return fmt.Sprintf("%v. For usage info, run:\n\treleaser help %s", e.err, e.cmd.name)
119*9bb1b549SSpandan Das}
120*9bb1b549SSpandan Das
121*9bb1b549SSpandan Dasfunc (e *usageError) Unwrap() error {
122*9bb1b549SSpandan Das	return e.err
123*9bb1b549SSpandan Das}
124*9bb1b549SSpandan Das
125*9bb1b549SSpandan Dasfunc usageErrorf(cmd *command, format string, args ...interface{}) error {
126*9bb1b549SSpandan Das	return &usageError{cmd: cmd, err: fmt.Errorf(format, args...)}
127*9bb1b549SSpandan Das}
128