mirror of
https://github.com/cheat/cheat.git
synced 2026-03-07 11:13:33 +01:00
Bug fixes: - Fix inverted pager detection logic (returned error instead of path) - Fix repo.Clone ignoring destination directory parameter - Fix sheet loading using append on pre-sized slices - Clean up partial files on copy failure - Trim whitespace from editor config Security: - Add path traversal protection for cheatsheet names Performance: - Move regex compilation outside search loop - Replace string concatenation with strings.Join in search Build: - Remove go:generate; embed config and usage as string literals - Parallelize release builds - Add fuzz testing infrastructure Testing: - Improve test coverage from 38.9% to 50.2% - Add fuzz tests for search, filter, tags, and validation Documentation: - Fix inaccurate code examples in HACKING.md - Add missing --conf and --all options to man page - Add ADRs for path traversal, env parsing, and search parallelization - Update CONTRIBUTING.md to reflect project policy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
63 lines
1.6 KiB
Go
63 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/cheat/cheat/internal/cheatpath"
|
|
"github.com/cheat/cheat/internal/config"
|
|
"github.com/cheat/cheat/internal/sheets"
|
|
)
|
|
|
|
// cmdRemove removes (deletes) a cheatsheet.
|
|
func cmdRemove(opts map[string]interface{}, conf config.Config) {
|
|
|
|
cheatsheet := opts["--rm"].(string)
|
|
|
|
// validate the cheatsheet name
|
|
if err := cheatpath.ValidateSheetName(cheatsheet); err != nil {
|
|
fmt.Fprintf(os.Stderr, "invalid cheatsheet name: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// load the cheatsheets
|
|
cheatsheets, err := sheets.Load(conf.Cheatpaths)
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "failed to list cheatsheets: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// filter cheatcheats by tag if --tag was provided
|
|
if opts["--tag"] != nil {
|
|
cheatsheets = sheets.Filter(
|
|
cheatsheets,
|
|
strings.Split(opts["--tag"].(string), ","),
|
|
)
|
|
}
|
|
|
|
// consolidate the cheatsheets found on all paths into a single map of
|
|
// `title` => `sheet` (ie, allow more local cheatsheets to override less
|
|
// local cheatsheets)
|
|
consolidated := sheets.Consolidate(cheatsheets)
|
|
|
|
// fail early if the requested cheatsheet does not exist
|
|
sheet, ok := consolidated[cheatsheet]
|
|
if !ok {
|
|
fmt.Fprintf(os.Stderr, "No cheatsheet found for '%s'.\n", cheatsheet)
|
|
os.Exit(2)
|
|
}
|
|
|
|
// fail early if the sheet is read-only
|
|
if sheet.ReadOnly {
|
|
fmt.Fprintf(os.Stderr, "cheatsheet '%s' is read-only.\n", cheatsheet)
|
|
os.Exit(1)
|
|
}
|
|
|
|
// otherwise, attempt to delete the sheet
|
|
if err := os.Remove(sheet.Path); err != nil {
|
|
fmt.Fprintf(os.Stderr, "failed to delete sheet: %s, %v\n", sheet.Title, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|