package sheets import ( "fmt" "io/fs" "os" "path/filepath" "strings" cp "github.com/cheat/cheat/internal/cheatpath" "github.com/cheat/cheat/internal/repo" "github.com/cheat/cheat/internal/sheet" ) // Load produces a map of cheatsheet titles to filesystem paths func Load(cheatpaths []cp.Cheatpath) ([]map[string]sheet.Sheet, error) { // create a slice of maps of sheets. This structure will store all sheets // that are associated with each cheatpath. sheets := make([]map[string]sheet.Sheet, len(cheatpaths)) // iterate over each cheatpath for _, cheatpath := range cheatpaths { // vivify the map of cheatsheets on this specific cheatpath pathsheets := make(map[string]sheet.Sheet) // recursively iterate over the cheatpath, and load each cheatsheet // encountered along the way err := filepath.Walk( cheatpath.Path, func( path string, info os.FileInfo, err error) error { // fail if an error occurred while walking the directory if err != nil { return fmt.Errorf("failed to walk path: %v", err) } // don't register directories as cheatsheets if info.IsDir() { return nil } // calculate the cheatsheet's "title" (the phrase with which it may be // accessed. Eg: `cheat tar` - `tar` is the title) title := strings.TrimPrefix( strings.TrimPrefix(path, cheatpath.Path), string(os.PathSeparator), ) // Don't walk the `.git` directory. Doing so creates // hundreds/thousands of needless syscalls and could // potentially harm performance on machines with slow disks. skip, err := repo.GitDir(path) if err != nil { return fmt.Errorf("failed to identify .git directory: %v", err) } if skip { return fs.SkipDir } // parse the cheatsheet file into a `sheet` struct s, err := sheet.New( title, cheatpath.Name, path, cheatpath.Tags, cheatpath.ReadOnly, ) if err != nil { return fmt.Errorf( "failed to load sheet: %s, path: %s, err: %v", title, path, err, ) } // register the cheatsheet on its cheatpath, keyed by its title pathsheets[title] = s return nil }) if err != nil { return sheets, fmt.Errorf("failed to load cheatsheets: %v", err) } // store the sheets on this cheatpath alongside the other cheatsheets on // other cheatpaths sheets = append(sheets, pathsheets) } // return the cheatsheets, grouped by cheatpath return sheets, nil }