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