github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/hack/docgen/cli/main.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"log"
    23  	"os"
    24  	"path/filepath"
    25  	"strings"
    26  
    27  	"github.com/spf13/cobra"
    28  	"github.com/spf13/cobra/doc"
    29  
    30  	"github.com/1aal/kubeblocks/pkg/cli/cmd"
    31  )
    32  
    33  func genMarkdownTreeForOverview(cmd *cobra.Command, dir string) error {
    34  	filename := filepath.Join(dir, "cli.md")
    35  	f, err := os.Create(filename)
    36  	if err != nil {
    37  		return err
    38  	}
    39  	defer f.Close()
    40  
    41  	if _, err = io.WriteString(f, `---
    42  title: KubeBlocks CLI Overview
    43  description: KubeBlocks CLI overview
    44  sidebar_position: 1
    45  ---
    46  
    47  `); err != nil {
    48  		return err
    49  	}
    50  
    51  	for _, c := range cmd.Commands() {
    52  		if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
    53  			continue
    54  		}
    55  
    56  		// write parent command name
    57  		link := strings.ReplaceAll(cmd.Name()+" "+c.Name(), " ", "_")
    58  		_, err = io.WriteString(f, fmt.Sprintf("## [%s](%s.md)\n\n", c.Name(), link))
    59  		if err != nil {
    60  			return err
    61  		}
    62  
    63  		// write command description
    64  		switch {
    65  		case c.Long != "":
    66  			_, err = io.WriteString(f, fmt.Sprintf("%s\n\n", c.Long))
    67  		case c.Short != "":
    68  			_, err = io.WriteString(f, fmt.Sprintf("%s\n\n", c.Short))
    69  		}
    70  		if err != nil {
    71  			return err
    72  		}
    73  
    74  		// write subcommands
    75  		for _, sub := range c.Commands() {
    76  			if !sub.IsAvailableCommand() || sub.IsAdditionalHelpTopicCommand() {
    77  				continue
    78  			}
    79  			subName := cmd.Name() + " " + c.Name() + " " + sub.Name()
    80  			link = strings.ReplaceAll(subName, " ", "_")
    81  			_, err = io.WriteString(f, fmt.Sprintf("* [%s](%s.md)\t - %s\n", subName, link, sub.Short))
    82  			if err != nil {
    83  				return err
    84  			}
    85  		}
    86  		_, err = io.WriteString(f, "\n\n")
    87  		if err != nil {
    88  			return err
    89  		}
    90  	}
    91  	return nil
    92  }
    93  
    94  func main() {
    95  	rootPath := "./docs/user_docs/cli"
    96  	if len(os.Args) > 1 {
    97  		rootPath = os.Args[1]
    98  	}
    99  
   100  	fmt.Println("Scanning CLI docs rootPath: ", rootPath)
   101  	cli := cmd.NewCliCmd()
   102  	cli.Long = fmt.Sprintf("```\n%s\n```", cli.Long)
   103  
   104  	if cacheDirFlag := cli.Flag("cache-dir"); cacheDirFlag != nil {
   105  		cacheDirFlag.DefValue = "$HOME/.kube/cache"
   106  	}
   107  
   108  	// get infra command, replace the default value of output-kubeconfig flag
   109  	for _, c := range cli.Commands() {
   110  		if c.Name() != "infra" {
   111  			continue
   112  		}
   113  		for _, sub := range c.Commands() {
   114  			if sub.Name() != "create" {
   115  				continue
   116  			}
   117  			if outputKubeconfigFlag := sub.Flag("output-kubeconfig"); outputKubeconfigFlag != nil {
   118  				outputKubeconfigFlag.DefValue = "$HOME/.kube/config"
   119  			}
   120  			break
   121  		}
   122  	}
   123  
   124  	err := doc.GenMarkdownTree(cli, rootPath)
   125  	if err != nil {
   126  		log.Fatal(err)
   127  	}
   128  
   129  	err = genMarkdownTreeForOverview(cli, rootPath)
   130  	if err != nil {
   131  		log.Fatal("generate docs for cli overview failed", err)
   132  	}
   133  
   134  	err = filepath.Walk(rootPath, func(path string, info os.FileInfo, err error) error {
   135  		if err != nil {
   136  			return err
   137  		}
   138  		if info.IsDir() {
   139  			return nil
   140  		}
   141  		data, err := os.ReadFile(path)
   142  		if err != nil {
   143  			return err
   144  		}
   145  		lines := strings.Split(string(data), "\n")
   146  		if len(lines) == 0 {
   147  			return nil
   148  		}
   149  
   150  		firstLine := lines[0]
   151  		if !strings.HasPrefix(firstLine, "## kbcli") {
   152  			return nil
   153  		}
   154  
   155  		var lastIdx int
   156  		for idx := len(lines) - 1; idx >= 0; idx-- {
   157  			if strings.Contains(lines[idx], "Auto generated") {
   158  				lastIdx = idx
   159  				break
   160  			}
   161  		}
   162  		if lastIdx == 0 {
   163  			return nil
   164  		}
   165  		lines[lastIdx] = "#### Go Back to [CLI Overview](cli.md) Homepage.\n"
   166  
   167  		// update the title
   168  		lines[0] = "---"
   169  		title := strings.TrimPrefix(firstLine, "## ")
   170  		newLines := []string{"---", "title: " + title}
   171  		for idx, line := range lines {
   172  			if strings.Contains(line, "[kbcli](kbcli.md)") {
   173  				lines[idx] = ""
   174  				continue
   175  			}
   176  		}
   177  		newLines = append(newLines, lines...)
   178  		content := strings.Join(newLines, "\n")
   179  		return os.WriteFile(path, []byte(content), info.Mode())
   180  	})
   181  	if err != nil {
   182  		log.Fatal(err)
   183  	}
   184  }