github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/cli/man/generate.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "path/filepath" 8 "strconv" 9 "time" 10 11 "github.com/docker/cli/cli/command" 12 "github.com/docker/cli/cli/command/commands" 13 "github.com/spf13/cobra" 14 "github.com/spf13/cobra/doc" 15 "github.com/spf13/pflag" 16 ) 17 18 const descriptionSourcePath = "man/src/" 19 20 func generateManPages(opts *options) error { 21 header := &doc.GenManHeader{ 22 Title: "DOCKER", 23 Section: "1", 24 Source: "Docker Community", 25 Manual: "Docker User Manuals", 26 } 27 28 // If SOURCE_DATE_EPOCH is set, in order to allow reproducible package 29 // builds, we explicitly set the build time to SOURCE_DATE_EPOCH. 30 if epoch := os.Getenv("SOURCE_DATE_EPOCH"); epoch != "" { 31 unixEpoch, err := strconv.ParseInt(epoch, 10, 64) 32 if err != nil { 33 return fmt.Errorf("invalid SOURCE_DATE_EPOCH: %v", err) 34 } 35 now := time.Unix(unixEpoch, 0) 36 header.Date = &now 37 } 38 39 dockerCli, err := command.NewDockerCli() 40 if err != nil { 41 return err 42 } 43 cmd := &cobra.Command{Use: "docker"} 44 commands.AddCommands(cmd, dockerCli) 45 source := filepath.Join(opts.source, descriptionSourcePath) 46 if err := loadLongDescription(cmd, source); err != nil { 47 return err 48 } 49 50 cmd.DisableAutoGenTag = true 51 cmd.DisableFlagsInUseLine = true 52 return doc.GenManTreeFromOpts(cmd, doc.GenManTreeOptions{ 53 Header: header, 54 Path: opts.target, 55 CommandSeparator: "-", 56 }) 57 } 58 59 func loadLongDescription(cmd *cobra.Command, path string) error { 60 for _, cmd := range cmd.Commands() { 61 cmd.DisableFlagsInUseLine = true 62 if cmd.Name() == "" { 63 continue 64 } 65 fullpath := filepath.Join(path, cmd.Name()+".md") 66 67 if cmd.HasSubCommands() { 68 loadLongDescription(cmd, filepath.Join(path, cmd.Name())) 69 } 70 71 if _, err := os.Stat(fullpath); err != nil { 72 log.Printf("WARN: %s does not exist, skipping\n", fullpath) 73 continue 74 } 75 76 content, err := os.ReadFile(fullpath) 77 if err != nil { 78 return err 79 } 80 cmd.Long = string(content) 81 82 fullpath = filepath.Join(path, cmd.Name()+"-example.md") 83 if _, err := os.Stat(fullpath); err != nil { 84 continue 85 } 86 87 content, err = os.ReadFile(fullpath) 88 if err != nil { 89 return err 90 } 91 cmd.Example = string(content) 92 93 } 94 return nil 95 } 96 97 type options struct { 98 source string 99 target string 100 } 101 102 func parseArgs() (*options, error) { 103 opts := &options{} 104 cwd, _ := os.Getwd() 105 flags := pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError) 106 flags.StringVar(&opts.source, "root", cwd, "Path to project root") 107 flags.StringVar(&opts.target, "target", "/tmp", "Target path for generated man pages") 108 err := flags.Parse(os.Args[1:]) 109 return opts, err 110 } 111 112 func main() { 113 opts, err := parseArgs() 114 if err != nil { 115 fmt.Fprintln(os.Stderr, err.Error()) 116 } 117 fmt.Printf("Project root: %s\n", opts.source) 118 fmt.Printf("Generating man pages into %s\n", opts.target) 119 if err := generateManPages(opts); err != nil { 120 fmt.Fprintf(os.Stderr, "Failed to generate man pages: %s\n", err.Error()) 121 } 122 }