github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/scripts/generate_site_sidebar/generate_site_sidebar.go (about)

     1  // Copyright 2019 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"fmt"
    19  	"html/template"
    20  	"os"
    21  	"path"
    22  	"path/filepath"
    23  	"regexp"
    24  	"sort"
    25  	"strings"
    26  
    27  	"github.com/igorsobreira/titlecase"
    28  )
    29  
    30  const markdownExtension = ".md"
    31  const introPage = "00.md"
    32  const templatePath = "scripts/generate_site_sidebar/sidebar_template.md.tmpl"
    33  
    34  var pagePrefix = regexp.MustCompile(`^\d\d-?`)
    35  
    36  func main() {
    37  	fmt.Println("<!--This sidebar was automatically generated by 'generate_site_sidebar'-->")
    38  	t := template.Must(
    39  		template.New(path.Base(templatePath)).
    40  			Funcs(template.FuncMap{"bookLayout": getBookOutline}).
    41  			ParseFiles(templatePath))
    42  
    43  	err := t.Execute(os.Stdout, nil)
    44  	if err != nil {
    45  		fmt.Fprintf(os.Stderr, "%v\n", err)
    46  		os.Exit(1)
    47  	}
    48  }
    49  
    50  func getBookOutline() string {
    51  	sourcePath := "site/book"
    52  	chapters := collectChapters(sourcePath)
    53  
    54  	return getChapterBlock(chapters)
    55  }
    56  
    57  func collectChapters(source string) []chapter {
    58  	chapters := make([]chapter, 0)
    59  	chapterDirs, err := os.ReadDir(source)
    60  	if err != nil {
    61  		fmt.Fprintf(os.Stderr, "%v\n", err)
    62  		os.Exit(1)
    63  	}
    64  
    65  	for _, dir := range chapterDirs {
    66  		if dir.IsDir() {
    67  			chapters = append(chapters, getChapter(dir.Name(), filepath.Join(source, dir.Name())))
    68  		}
    69  	}
    70  
    71  	return chapters
    72  }
    73  
    74  func getChapter(chapterDirName string, chapterDirPath string) chapter {
    75  	chapterBuilder := chapter{}
    76  
    77  	// Split into chapter number and hyphenated name
    78  	splitDirName := strings.SplitN(chapterDirName, "-", 2)
    79  	chapterBuilder.Number = splitDirName[0]
    80  	chapterBuilder.Name = titlecase.Title(strings.ReplaceAll(splitDirName[1], "-", " "))
    81  
    82  	pageFiles, err := os.ReadDir(chapterDirPath)
    83  	if err != nil {
    84  		fmt.Fprintf(os.Stderr, "%v\n", err)
    85  		os.Exit(1)
    86  	}
    87  
    88  	for _, pageFile := range pageFiles {
    89  		if filepath.Ext(pageFile.Name()) == markdownExtension && pagePrefix.MatchString(pageFile.Name()) {
    90  			chapterBuilder.Pages = append(chapterBuilder.Pages,
    91  				getPage(pageFile.Name(), chapterBuilder.Name, chapterDirPath))
    92  		}
    93  	}
    94  
    95  	return chapterBuilder
    96  }
    97  
    98  func getPage(pageFileName string, defaultName string, parentPath string) page {
    99  	// Split into page number and hyphenated name.
   100  	splitPageName := strings.SplitN(pageFileName, "-", 2)
   101  
   102  	pageName := defaultName
   103  	if pageFileName != introPage {
   104  		// Strip page number and extension from file name.
   105  		pageTitle := pagePrefix.ReplaceAll([]byte(pageFileName), []byte(""))
   106  		pageName = titlecase.Title(strings.ReplaceAll(strings.ReplaceAll(string(pageTitle), ".md", ""), "-", " "))
   107  	}
   108  
   109  	return page{
   110  		Number: splitPageName[0],
   111  		Name:   pageName,
   112  		Path:   filepath.Join(parentPath, pageFileName),
   113  	}
   114  }
   115  
   116  func getChapterBlock(chapters []chapter) string {
   117  	// Sort chapters in ascending order by chapter number.
   118  	sort.Slice(chapters, func(i, j int) bool { return chapters[i].Number < chapters[j].Number })
   119  	var sb strings.Builder
   120  	for chapterIndex, chapterEntry := range chapters {
   121  		chapterNumber := chapterIndex + 1
   122  		for pageIndex, pageEntry := range chapterEntry.Pages {
   123  			// Make path relative to site directory.
   124  			path := strings.Replace(pageEntry.Path, "site/", "", 1)
   125  
   126  			// Print non-chapter intro pages as children of chapter intro page.
   127  			if pageIndex == 0 {
   128  				sb.WriteString(fmt.Sprintf("\t- [%d %s](%s)\n", chapterNumber, pageEntry.Name, path))
   129  			} else {
   130  				sb.WriteString(fmt.Sprintf("\t\t- [%d.%d %s](%s)\n", chapterNumber, pageIndex, pageEntry.Name, path))
   131  			}
   132  		}
   133  	}
   134  	return strings.TrimRight(sb.String(), "\n")
   135  }
   136  
   137  type chapter struct {
   138  	Name   string
   139  	Pages  []page
   140  	Number string
   141  }
   142  
   143  type page struct {
   144  	Name   string
   145  	Path   string
   146  	Number string
   147  }