mirror of
https://github.com/cheat/cheat.git
synced 2026-03-07 03:03:32 +01:00
chore: housekeeping and refactoring (bump to 4.7.1)
- Remove unused parameters, dead files, and inaccurate doc.go files - Extract shared helpers, eliminate duplication - Rename cheatpath.Cheatpath to cheatpath.Path - Optimize filesystem walks (WalkDir, skip .git) - Move sheet name validation to sheet.Validate - Move integration tests to test/integration/ - Consolidate internal/mock into mocks/ - Move fuzz.sh to test/ - Inline loadSheets helper into command callers - Extract config.New into its own file - Fix stale references in HACKING.md and CLAUDE.md - Restore plan9 build target - Remove redundant and low-value tests - Clean up project documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
// Package sheets manages collections of cheat sheets across multiple cheatpaths.
|
||||
//
|
||||
// The sheets package provides functionality to:
|
||||
// - Load sheets from multiple cheatpaths
|
||||
// - Consolidate duplicate sheets (with precedence rules)
|
||||
// - Filter sheets by tags
|
||||
// - Sort sheets alphabetically
|
||||
// - Extract unique tags across all sheets
|
||||
//
|
||||
// # Loading Sheets
|
||||
//
|
||||
// Sheets are loaded recursively from cheatpath directories, excluding:
|
||||
// - Hidden files (starting with .)
|
||||
// - Files in .git directories
|
||||
// - Files with extensions (sheets have no extension)
|
||||
//
|
||||
// # Consolidation
|
||||
//
|
||||
// When multiple cheatpaths contain sheets with the same name, consolidation
|
||||
// rules apply based on the order of cheatpaths. Sheets from earlier paths
|
||||
// override those from later paths, allowing personal sheets to override
|
||||
// community sheets.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// cheatpaths:
|
||||
// 1. personal: ~/cheat
|
||||
// 2. community: ~/cheat/community
|
||||
//
|
||||
// If both contain "git", the version from "personal" is used.
|
||||
//
|
||||
// # Filtering
|
||||
//
|
||||
// Sheets can be filtered by:
|
||||
// - Tags: Include only sheets with specific tags
|
||||
// - Cheatpath: Include only sheets from specific paths
|
||||
//
|
||||
// Key Functions
|
||||
//
|
||||
// - Load: Loads all sheets from the given cheatpaths
|
||||
// - Filter: Filters sheets by tag
|
||||
// - Consolidate: Merges sheets from multiple paths with precedence
|
||||
// - Sort: Sorts sheets alphabetically by title
|
||||
// - Tags: Extracts all unique tags from sheets
|
||||
//
|
||||
// Example Usage
|
||||
//
|
||||
// // Load sheets from all cheatpaths
|
||||
// allSheets, err := sheets.Load(cheatpaths)
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// // Consolidate to handle duplicates
|
||||
// consolidated := sheets.Consolidate(allSheets)
|
||||
//
|
||||
// // Filter by tag
|
||||
// filtered := sheets.Filter(consolidated, "networking")
|
||||
//
|
||||
// // Sort alphabetically
|
||||
// sheets.Sort(filtered)
|
||||
//
|
||||
// // Get all unique tags
|
||||
// tags := sheets.Tags(consolidated)
|
||||
package sheets
|
||||
@@ -18,28 +18,26 @@ func TestFilterSingleTag(t *testing.T) {
|
||||
|
||||
map[string]sheet.Sheet{
|
||||
"foo": sheet.Sheet{Title: "foo", Tags: []string{"alpha", "bravo"}},
|
||||
"bar": sheet.Sheet{Title: "bar", Tags: []string{"bravo", "charlie"}},
|
||||
"bar": sheet.Sheet{Title: "bar", Tags: []string{"charlie"}},
|
||||
},
|
||||
|
||||
map[string]sheet.Sheet{
|
||||
"baz": sheet.Sheet{Title: "baz", Tags: []string{"alpha", "bravo"}},
|
||||
"baz": sheet.Sheet{Title: "baz", Tags: []string{"alpha"}},
|
||||
"bat": sheet.Sheet{Title: "bat", Tags: []string{"bravo", "charlie"}},
|
||||
},
|
||||
}
|
||||
|
||||
// filter the cheatsheets
|
||||
filtered := Filter(cheatpaths, []string{"bravo"})
|
||||
filtered := Filter(cheatpaths, []string{"alpha"})
|
||||
|
||||
// assert that the expect results were returned
|
||||
want := []map[string]sheet.Sheet{
|
||||
map[string]sheet.Sheet{
|
||||
"foo": sheet.Sheet{Title: "foo", Tags: []string{"alpha", "bravo"}},
|
||||
"bar": sheet.Sheet{Title: "bar", Tags: []string{"bravo", "charlie"}},
|
||||
},
|
||||
|
||||
map[string]sheet.Sheet{
|
||||
"baz": sheet.Sheet{Title: "baz", Tags: []string{"alpha", "bravo"}},
|
||||
"bat": sheet.Sheet{Title: "bat", Tags: []string{"bravo", "charlie"}},
|
||||
"baz": sheet.Sheet{Title: "baz", Tags: []string{"alpha"}},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,11 @@ import (
|
||||
"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) {
|
||||
func Load(cheatpaths []cp.Path) ([]map[string]sheet.Sheet, error) {
|
||||
|
||||
// create a slice of maps of sheets. This structure will store all sheets
|
||||
// that are associated with each cheatpath.
|
||||
@@ -27,10 +26,10 @@ func Load(cheatpaths []cp.Cheatpath) ([]map[string]sheet.Sheet, error) {
|
||||
|
||||
// recursively iterate over the cheatpath, and load each cheatsheet
|
||||
// encountered along the way
|
||||
err := filepath.Walk(
|
||||
err := filepath.WalkDir(
|
||||
cheatpath.Path, func(
|
||||
path string,
|
||||
info os.FileInfo,
|
||||
d fs.DirEntry,
|
||||
err error) error {
|
||||
|
||||
// fail if an error occurred while walking the directory
|
||||
@@ -38,8 +37,12 @@ func Load(cheatpaths []cp.Cheatpath) ([]map[string]sheet.Sheet, error) {
|
||||
return fmt.Errorf("failed to walk path: %v", err)
|
||||
}
|
||||
|
||||
// don't register directories as cheatsheets
|
||||
if info.IsDir() {
|
||||
if d.IsDir() {
|
||||
// skip .git directories to avoid hundreds/thousands of
|
||||
// needless syscalls (see repo.GitDir for full history)
|
||||
if filepath.Base(path) == ".git" {
|
||||
return fs.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -63,17 +66,6 @@ func Load(cheatpaths []cp.Cheatpath) ([]map[string]sheet.Sheet, error) {
|
||||
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,
|
||||
|
||||
@@ -5,22 +5,22 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/cheat/cheat/internal/cheatpath"
|
||||
"github.com/cheat/cheat/internal/mock"
|
||||
"github.com/cheat/cheat/mocks"
|
||||
)
|
||||
|
||||
// TestLoad asserts that sheets on valid cheatpaths can be loaded successfully
|
||||
func TestLoad(t *testing.T) {
|
||||
|
||||
// mock cheatpaths
|
||||
cheatpaths := []cheatpath.Cheatpath{
|
||||
cheatpaths := []cheatpath.Path{
|
||||
{
|
||||
Name: "community",
|
||||
Path: path.Join(mock.Path("cheatsheets"), "community"),
|
||||
Path: path.Join(mocks.Path("cheatsheets"), "community"),
|
||||
ReadOnly: true,
|
||||
},
|
||||
{
|
||||
Name: "personal",
|
||||
Path: path.Join(mock.Path("cheatsheets"), "personal"),
|
||||
Path: path.Join(mocks.Path("cheatsheets"), "personal"),
|
||||
ReadOnly: false,
|
||||
},
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func TestLoad(t *testing.T) {
|
||||
func TestLoadBadPath(t *testing.T) {
|
||||
|
||||
// mock a bad cheatpath
|
||||
cheatpaths := []cheatpath.Cheatpath{
|
||||
cheatpaths := []cheatpath.Path{
|
||||
{
|
||||
Name: "badpath",
|
||||
Path: "/cheat/test/path/does/not/exist",
|
||||
|
||||
@@ -32,9 +32,7 @@ func Tags(cheatpaths []map[string]sheet.Sheet) []string {
|
||||
}
|
||||
|
||||
// sort the slice
|
||||
sort.Slice(sorted, func(i, j int) bool {
|
||||
return sorted[i] < sorted[j]
|
||||
})
|
||||
sort.Strings(sorted)
|
||||
|
||||
return sorted
|
||||
}
|
||||
|
||||
@@ -127,64 +127,3 @@ func FuzzTags(f *testing.F) {
|
||||
}()
|
||||
})
|
||||
}
|
||||
|
||||
// FuzzTagsStress tests Tags function with large numbers of tags
|
||||
func FuzzTagsStress(f *testing.F) {
|
||||
// Seed: number of unique tags, number of sheets, tags per sheet
|
||||
f.Add(10, 10, 5)
|
||||
f.Add(100, 50, 10)
|
||||
f.Add(1000, 100, 20)
|
||||
|
||||
f.Fuzz(func(t *testing.T, numUniqueTags int, numSheets int, tagsPerSheet int) {
|
||||
// Limit to reasonable values
|
||||
if numUniqueTags > 1000 || numUniqueTags < 0 ||
|
||||
numSheets > 1000 || numSheets < 0 ||
|
||||
tagsPerSheet > 100 || tagsPerSheet < 0 {
|
||||
t.Skip("Skipping unreasonable test case")
|
||||
}
|
||||
|
||||
// Generate unique tags
|
||||
uniqueTags := make([]string, numUniqueTags)
|
||||
for i := 0; i < numUniqueTags; i++ {
|
||||
uniqueTags[i] = "tag" + string(rune(i))
|
||||
}
|
||||
|
||||
// Create sheets with random tags
|
||||
cheatpaths := []map[string]sheet.Sheet{
|
||||
make(map[string]sheet.Sheet),
|
||||
}
|
||||
|
||||
for i := 0; i < numSheets; i++ {
|
||||
// Select random tags for this sheet
|
||||
sheetTags := make([]string, 0, tagsPerSheet)
|
||||
for j := 0; j < tagsPerSheet && j < numUniqueTags; j++ {
|
||||
// Distribute tags across sheets
|
||||
tagIndex := (i*tagsPerSheet + j) % numUniqueTags
|
||||
sheetTags = append(sheetTags, uniqueTags[tagIndex])
|
||||
}
|
||||
|
||||
cheatpaths[0]["sheet"+string(rune(i))] = sheet.Sheet{
|
||||
Title: "sheet" + string(rune(i)),
|
||||
Tags: sheetTags,
|
||||
}
|
||||
}
|
||||
|
||||
// Should handle large numbers efficiently
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Errorf("Tags panicked with %d unique tags, %d sheets, %d tags/sheet: %v",
|
||||
numUniqueTags, numSheets, tagsPerSheet, r)
|
||||
}
|
||||
}()
|
||||
|
||||
result := Tags(cheatpaths)
|
||||
|
||||
// Should have at most numUniqueTags in result
|
||||
if len(result) > numUniqueTags {
|
||||
t.Errorf("More tags in result (%d) than unique tags created (%d)",
|
||||
len(result), numUniqueTags)
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user