eng/tools/deprecate/cmd/package.go (92 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. package cmd import ( "errors" "fmt" "go/ast" "go/parser" "go/printer" "go/token" "io/ioutil" "os" "path/filepath" "github.com/spf13/cobra" ) var packageCmd = &cobra.Command{ Use: "package <package dir> <message>", Short: "Adds a deprecation comment to all exported types and functions.", Long: `The package command adds a deprecation comment to all exported types and functions in the specified package. The comment is of the form "// Deprecated: <message>".`, RunE: func(cmd *cobra.Command, args []string) error { return thePackageCmd(args) }, } func init() { rootCmd.AddCommand(packageCmd) } func thePackageCmd(args []string) error { if len(args) < 2 { return errors.New("not enough arguments were supplied") } fileInfos, err := ioutil.ReadDir(args[0]) if err != nil { return fmt.Errorf("failed to read directory: %v", err) } for _, fileInfo := range fileInfos { if fileInfo.IsDir() { continue } err := addDeprecationToFile(filepath.Join(args[0], fileInfo.Name()), args[1]) if err != nil { return fmt.Errorf("failed to add deprecation comments: %v", err) } } return nil } func addDeprecationToFile(file, message string) error { vprintf("adding deprecation comments to %s\n", file) fset := token.NewFileSet() node, err := parser.ParseFile(fset, file, nil, parser.ParseComments) if err != nil { return err } // walk the AST, for each exported type and func add deprecated message ast.Inspect(node, func(n ast.Node) bool { switch x := n.(type) { case *ast.GenDecl: if isExportedSpec(x.Specs) { addDeprecationComment(x.Doc, message) } case *ast.FuncDecl: if x.Name.IsExported() { addDeprecationComment(x.Doc, message) } // return false as we don't care about the function body. return false } return true }) // write the updated content f, err := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC, 0) if err != nil { return err } defer f.Close() return printer.Fprint(f, fset, node) } func addDeprecationComment(cg *ast.CommentGroup, message string) { if cg == nil { return } // create a new comment and add it to the beginning of the comment group nd := []*ast.Comment{ { Text: fmt.Sprintf("// Deprecated: %s", message), Slash: cg.Pos() - 1, }, } cg.List = append(nd, cg.List...) } func isExportedSpec(list []ast.Spec) bool { for _, l := range list { if s, ok := l.(*ast.TypeSpec); ok { return s.Name.IsExported() } } // assume it's exported return true }