From e7db83bc9685538d0511087b298549fac26ede41 Mon Sep 17 00:00:00 2001 From: Snider Date: Mon, 3 Nov 2025 03:42:21 +0000 Subject: [PATCH] Add initialization comments for command registration in CLI --- cmd/all.go | 1 + cmd/collect.go | 1 + cmd/collect_github.go | 1 + cmd/collect_github_release_subcommand.go | 1 + cmd/collect_github_repo.go | 1 + cmd/collect_github_repos.go | 1 + cmd/collect_pwa.go | 1 + cmd/collect_website.go | 3 +- cmd/root.go | 1 + cmd/serve.go | 1 + main.go | 1 + pkg/datanode/datanode.go | 59 +++++++++++++++++++----- pkg/github/github.go | 5 ++ pkg/logger/logger.go | 2 + pkg/pwa/pwa.go | 2 + pkg/tarfs/tarfs.go | 30 +++++++++--- pkg/ui/non_interactive_prompter.go | 7 +++ pkg/ui/progress_writer.go | 5 +- pkg/ui/quote.go | 8 ++++ pkg/website/website.go | 7 +++ 20 files changed, 119 insertions(+), 19 deletions(-) diff --git a/cmd/all.go b/cmd/all.go index 7f7c782..c7075f0 100644 --- a/cmd/all.go +++ b/cmd/all.go @@ -60,6 +60,7 @@ var allCmd = &cobra.Command{ }, } +// init registers the 'all' command and its flags with the root command. func init() { RootCmd.AddCommand(allCmd) allCmd.PersistentFlags().String("output", ".", "Output directory for the DataNodes") diff --git a/cmd/collect.go b/cmd/collect.go index 8e3d817..eaec82f 100644 --- a/cmd/collect.go +++ b/cmd/collect.go @@ -11,6 +11,7 @@ var collectCmd = &cobra.Command{ Long: `Collect a resource from a git repository, a website, or other URI and store it in a DataNode.`, } +// init registers the collect command with the root. func init() { RootCmd.AddCommand(collectCmd) } diff --git a/cmd/collect_github.go b/cmd/collect_github.go index 58d6f8d..f44e386 100644 --- a/cmd/collect_github.go +++ b/cmd/collect_github.go @@ -11,6 +11,7 @@ var collectGithubCmd = &cobra.Command{ Long: `Collect a resource from a GitHub repository, such as a repository or a release.`, } +// init registers the GitHub collection parent command. func init() { collectCmd.AddCommand(collectGithubCmd) } diff --git a/cmd/collect_github_release_subcommand.go b/cmd/collect_github_release_subcommand.go index 83565c0..05f4ac5 100644 --- a/cmd/collect_github_release_subcommand.go +++ b/cmd/collect_github_release_subcommand.go @@ -126,6 +126,7 @@ var collectGithubReleaseCmd = &cobra.Command{ }, } +// init registers the 'collect github release' subcommand and its flags. func init() { collectGithubCmd.AddCommand(collectGithubReleaseCmd) collectGithubReleaseCmd.PersistentFlags().String("output", ".", "Output directory for the downloaded file") diff --git a/cmd/collect_github_repo.go b/cmd/collect_github_repo.go index f279129..97b0f1c 100644 --- a/cmd/collect_github_repo.go +++ b/cmd/collect_github_repo.go @@ -89,6 +89,7 @@ var collectGithubRepoCmd = &cobra.Command{ }, } +// init registers the 'collect github repo' subcommand and its flags. func init() { collectGithubCmd.AddCommand(collectGithubRepoCmd) collectGithubRepoCmd.PersistentFlags().String("output", "", "Output file for the DataNode") diff --git a/cmd/collect_github_repos.go b/cmd/collect_github_repos.go index dfcd315..e495a27 100644 --- a/cmd/collect_github_repos.go +++ b/cmd/collect_github_repos.go @@ -28,6 +28,7 @@ var collectGithubReposCmd = &cobra.Command{ }, } +// init registers the 'collect github repos' subcommand. func init() { collectGithubCmd.AddCommand(collectGithubReposCmd) } diff --git a/cmd/collect_pwa.go b/cmd/collect_pwa.go index 06e06f5..d1ce59d 100644 --- a/cmd/collect_pwa.go +++ b/cmd/collect_pwa.go @@ -94,6 +94,7 @@ Example: }, } +// init registers the 'collect pwa' subcommand and its flags. func init() { collectCmd.AddCommand(collectPWACmd) collectPWACmd.Flags().String("uri", "", "The URI of the PWA to collect") diff --git a/cmd/collect_website.go b/cmd/collect_website.go index 6b67a3b..97ed59e 100644 --- a/cmd/collect_website.go +++ b/cmd/collect_website.go @@ -4,11 +4,11 @@ import ( "fmt" "os" - "github.com/schollz/progressbar/v3" "github.com/Snider/Borg/pkg/compress" "github.com/Snider/Borg/pkg/matrix" "github.com/Snider/Borg/pkg/ui" "github.com/Snider/Borg/pkg/website" + "github.com/schollz/progressbar/v3" "github.com/spf13/cobra" ) @@ -83,6 +83,7 @@ var collectWebsiteCmd = &cobra.Command{ }, } +// init registers the 'collect website' subcommand and its flags. func init() { collectCmd.AddCommand(collectWebsiteCmd) collectWebsiteCmd.PersistentFlags().String("output", "", "Output file for the DataNode") diff --git a/cmd/root.go b/cmd/root.go index 9cadb27..651f2f7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" ) +// NewRootCmd constructs the root cobra.Command for the Borg CLI and wires common flags. func NewRootCmd() *cobra.Command { rootCmd := &cobra.Command{ Use: "borg", diff --git a/cmd/serve.go b/cmd/serve.go index 87e225f..15d333d 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -62,6 +62,7 @@ var serveCmd = &cobra.Command{ }, } +// init registers the 'serve' command and its flags with the root command. func init() { RootCmd.AddCommand(serveCmd) serveCmd.PersistentFlags().String("port", "8080", "Port to serve the PWA on") diff --git a/main.go b/main.go index 7c02e17..4064295 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,7 @@ import ( "github.com/Snider/Borg/pkg/logger" ) +// main is the entry point for the Borg CLI application. func main() { verbose, _ := cmd.RootCmd.PersistentFlags().GetBool("verbose") log := logger.New(verbose) diff --git a/pkg/datanode/datanode.go b/pkg/datanode/datanode.go index fe2f43b..881ac8c 100644 --- a/pkg/datanode/datanode.go +++ b/pkg/datanode/datanode.go @@ -260,19 +260,35 @@ type dataFile struct { modTime time.Time } +// Stat implements fs.File.Stat for a dataFile and returns its FileInfo. func (d *dataFile) Stat() (fs.FileInfo, error) { return &dataFileInfo{file: d}, nil } + +// Read implements fs.File.Read for a dataFile and reports EOF as files are in-memory. func (d *dataFile) Read(p []byte) (int, error) { return 0, io.EOF } -func (d *dataFile) Close() error { return nil } + +// Close implements fs.File.Close for a dataFile; it's a no-op. +func (d *dataFile) Close() error { return nil } // dataFileInfo implements fs.FileInfo for a dataFile. type dataFileInfo struct{ file *dataFile } -func (d *dataFileInfo) Name() string { return path.Base(d.file.name) } -func (d *dataFileInfo) Size() int64 { return int64(len(d.file.content)) } -func (d *dataFileInfo) Mode() fs.FileMode { return 0444 } +// Name returns the base name of the data file. +func (d *dataFileInfo) Name() string { return path.Base(d.file.name) } + +// Size returns the size of the data file in bytes. +func (d *dataFileInfo) Size() int64 { return int64(len(d.file.content)) } + +// Mode returns the file mode for data files (read-only). +func (d *dataFileInfo) Mode() fs.FileMode { return 0444 } + +// ModTime returns the modification time of the data file. func (d *dataFileInfo) ModTime() time.Time { return d.file.modTime } -func (d *dataFileInfo) IsDir() bool { return false } -func (d *dataFileInfo) Sys() interface{} { return nil } + +// IsDir reports whether the entry is a directory (false for data files). +func (d *dataFileInfo) IsDir() bool { return false } + +// Sys returns system-specific data, which is nil for data files. +func (d *dataFileInfo) Sys() interface{} { return nil } // dataFileReader implements fs.File for a dataFile. type dataFileReader struct { @@ -280,13 +296,18 @@ type dataFileReader struct { reader *bytes.Reader } +// Stat returns the FileInfo for the underlying data file. func (d *dataFileReader) Stat() (fs.FileInfo, error) { return d.file.Stat() } + +// Read reads from the underlying data file content. func (d *dataFileReader) Read(p []byte) (int, error) { if d.reader == nil { d.reader = bytes.NewReader(d.file.content) } return d.reader.Read(p) } + +// Close closes the data file reader (no-op). func (d *dataFileReader) Close() error { return nil } // dirInfo implements fs.FileInfo for an implicit directory. @@ -295,12 +316,23 @@ type dirInfo struct { modTime time.Time } -func (d *dirInfo) Name() string { return d.name } -func (d *dirInfo) Size() int64 { return 0 } -func (d *dirInfo) Mode() fs.FileMode { return fs.ModeDir | 0555 } +// Name returns the directory name. +func (d *dirInfo) Name() string { return d.name } + +// Size returns the size of the directory entry (always 0 for virtual dirs). +func (d *dirInfo) Size() int64 { return 0 } + +// Mode returns the file mode for directories. +func (d *dirInfo) Mode() fs.FileMode { return fs.ModeDir | 0555 } + +// ModTime returns the modification time of the directory. func (d *dirInfo) ModTime() time.Time { return d.modTime } -func (d *dirInfo) IsDir() bool { return true } -func (d *dirInfo) Sys() interface{} { return nil } + +// IsDir reports that the entry is a directory. +func (d *dirInfo) IsDir() bool { return true } + +// Sys returns system-specific data, which is nil for dirs. +func (d *dirInfo) Sys() interface{} { return nil } // dirFile implements fs.File for a directory. type dirFile struct { @@ -308,10 +340,15 @@ type dirFile struct { modTime time.Time } +// Stat returns the FileInfo for the directory. func (d *dirFile) Stat() (fs.FileInfo, error) { return &dirInfo{name: path.Base(d.path), modTime: d.modTime}, nil } + +// Read is invalid for directories and returns an error. func (d *dirFile) Read([]byte) (int, error) { return 0, &fs.PathError{Op: "read", Path: d.path, Err: fs.ErrInvalid} } + +// Close closes the directory file (no-op). func (d *dirFile) Close() error { return nil } diff --git a/pkg/github/github.go b/pkg/github/github.go index 022e255..1eed699 100644 --- a/pkg/github/github.go +++ b/pkg/github/github.go @@ -31,6 +31,8 @@ func (g *githubClient) GetPublicRepos(ctx context.Context, userOrOrg string) ([] return g.getPublicReposWithAPIURL(ctx, "https://api.github.com", userOrOrg) } +// newAuthenticatedClient returns an *http.Client that uses GITHUB_TOKEN if set. +// When no token is present, it falls back to http.DefaultClient. func (g *githubClient) newAuthenticatedClient(ctx context.Context) *http.Client { token := os.Getenv("GITHUB_TOKEN") if token == "" { @@ -42,6 +44,8 @@ func (g *githubClient) newAuthenticatedClient(ctx context.Context) *http.Client return oauth2.NewClient(ctx, ts) } +// getPublicReposWithAPIURL fetches public repository clone URLs for the given user/org +// using the provided GitHub API base URL, following pagination links as needed. func (g *githubClient) getPublicReposWithAPIURL(ctx context.Context, apiURL, userOrOrg string) ([]string, error) { client := g.newAuthenticatedClient(ctx) var allCloneURLs []string @@ -106,6 +110,7 @@ func (g *githubClient) getPublicReposWithAPIURL(ctx context.Context, apiURL, use return allCloneURLs, nil } +// findNextURL parses the HTTP Link header and returns the URL with rel="next", if any. func (g *githubClient) findNextURL(linkHeader string) string { links := strings.Split(linkHeader, ",") for _, link := range links { diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index 0dfc2d2..5984095 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -5,6 +5,8 @@ import ( "os" ) +// New constructs a slog.Logger configured for stderr with the given verbosity. +// When verbose is true, the logger emits debug-level messages; otherwise info-level. func New(verbose bool) *slog.Logger { level := slog.LevelInfo if verbose { diff --git a/pkg/pwa/pwa.go b/pkg/pwa/pwa.go index 0d72345..0885811 100644 --- a/pkg/pwa/pwa.go +++ b/pkg/pwa/pwa.go @@ -158,6 +158,7 @@ func (p *pwaClient) DownloadAndPackagePWA(baseURL string, manifestURL string, ba return dn, nil } +// resolveURL resolves ref against base and returns the absolute URL. func (p *pwaClient) resolveURL(base, ref string) (*url.URL, error) { baseURL, err := url.Parse(base) if err != nil { @@ -170,6 +171,7 @@ func (p *pwaClient) resolveURL(base, ref string) (*url.URL, error) { return baseURL.ResolveReference(refURL), nil } +// downloadAndAddFile downloads fileURL and adds it to dn at internalPath, updating the progress bar. func (p *pwaClient) downloadAndAddFile(dn *datanode.DataNode, fileURL *url.URL, internalPath string, bar *progressbar.ProgressBar) error { resp, err := p.client.Get(fileURL.String()) if err != nil { diff --git a/pkg/tarfs/tarfs.go b/pkg/tarfs/tarfs.go index 6abbee4..c60ef9c 100644 --- a/pkg/tarfs/tarfs.go +++ b/pkg/tarfs/tarfs.go @@ -67,16 +67,23 @@ type tarFile struct { modTime time.Time } -func (f *tarFile) Close() error { return nil } +// Close implements http.File Close with a no-op for tar-backed files. +func (f *tarFile) Close() error { return nil } + +// Read implements io.Reader by delegating to the underlying bytes.Reader. func (f *tarFile) Read(p []byte) (int, error) { return f.content.Read(p) } + +// Seek implements io.Seeker by delegating to the underlying bytes.Reader. func (f *tarFile) Seek(offset int64, whence int) (int64, error) { return f.content.Seek(offset, whence) } +// Readdir is unsupported for files in the tar filesystem and returns os.ErrInvalid. func (f *tarFile) Readdir(count int) ([]os.FileInfo, error) { return nil, os.ErrInvalid } +// Stat returns a FileInfo describing the tar-backed file. func (f *tarFile) Stat() (os.FileInfo, error) { return &tarFileInfo{ name: path.Base(f.header.Name), @@ -92,9 +99,20 @@ type tarFileInfo struct { modTime time.Time } -func (i *tarFileInfo) Name() string { return i.name } -func (i *tarFileInfo) Size() int64 { return i.size } -func (i *tarFileInfo) Mode() os.FileMode { return 0444 } +// Name returns the base name of the tar file. +func (i *tarFileInfo) Name() string { return i.name } + +// Size returns the size of the tar file in bytes. +func (i *tarFileInfo) Size() int64 { return i.size } + +// Mode returns a read-only file mode for tar entries. +func (i *tarFileInfo) Mode() os.FileMode { return 0444 } + +// ModTime returns the modification time recorded in the tar header. func (i *tarFileInfo) ModTime() time.Time { return i.modTime } -func (i *tarFileInfo) IsDir() bool { return false } -func (i *tarFileInfo) Sys() interface{} { return nil } + +// IsDir reports whether the entry is a directory (always false for files here). +func (i *tarFileInfo) IsDir() bool { return false } + +// Sys returns underlying data source (unused for tar entries). +func (i *tarFileInfo) Sys() interface{} { return nil } diff --git a/pkg/ui/non_interactive_prompter.go b/pkg/ui/non_interactive_prompter.go index 8144a72..35d99d5 100644 --- a/pkg/ui/non_interactive_prompter.go +++ b/pkg/ui/non_interactive_prompter.go @@ -10,6 +10,8 @@ import ( "github.com/mattn/go-isatty" ) +// NonInteractivePrompter periodically prints status quotes when the terminal is non-interactive. +// It is intended to give the user feedback during long-running operations. type NonInteractivePrompter struct { stopChan chan struct{} quoteFunc func() (string, error) @@ -18,6 +20,8 @@ type NonInteractivePrompter struct { stopOnce sync.Once } +// NewNonInteractivePrompter returns a new NonInteractivePrompter that will call +// the provided quoteFunc to retrieve text to display. func NewNonInteractivePrompter(quoteFunc func() (string, error)) *NonInteractivePrompter { return &NonInteractivePrompter{ stopChan: make(chan struct{}), @@ -25,6 +29,7 @@ func NewNonInteractivePrompter(quoteFunc func() (string, error)) *NonInteractive } } +// Start begins the periodic display of quotes until Stop is called. func (p *NonInteractivePrompter) Start() { p.mu.Lock() if p.started { @@ -59,6 +64,7 @@ func (p *NonInteractivePrompter) Start() { }() } +// Stop signals the prompter to stop printing further messages. func (p *NonInteractivePrompter) Stop() { if p.IsInteractive() { return @@ -68,6 +74,7 @@ func (p *NonInteractivePrompter) Stop() { }) } +// IsInteractive reports whether stdout is attached to an interactive terminal. func (p *NonInteractivePrompter) IsInteractive() bool { return isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()) } diff --git a/pkg/ui/progress_writer.go b/pkg/ui/progress_writer.go index b46b51b..510d169 100644 --- a/pkg/ui/progress_writer.go +++ b/pkg/ui/progress_writer.go @@ -1,16 +1,19 @@ - package ui import "github.com/schollz/progressbar/v3" +// progressWriter implements io.Writer to update a progress bar with textual status. type progressWriter struct { bar *progressbar.ProgressBar } +// NewProgressWriter returns a writer that updates the provided progress bar's description. func NewProgressWriter(bar *progressbar.ProgressBar) *progressWriter { return &progressWriter{bar: bar} } +// Write updates the progress bar description with the provided bytes as a string. +// It returns the length of p to satisfy io.Writer semantics. func (pw *progressWriter) Write(p []byte) (n int, err error) { if pw == nil || pw.bar == nil { return len(p), nil diff --git a/pkg/ui/quote.go b/pkg/ui/quote.go index 166cf91..9e72716 100644 --- a/pkg/ui/quote.go +++ b/pkg/ui/quote.go @@ -16,6 +16,7 @@ var ( quotesErr error ) +// init seeds the random number generator for quote selection. func init() { rand.Seed(time.Now().UnixNano()) } @@ -41,6 +42,7 @@ type Quotes struct { } `json:"image_related"` } +// loadQuotes reads and unmarshals the embedded quotes.json file into a Quotes struct. func loadQuotes() (*Quotes, error) { quotesFile, err := QuotesJSON.ReadFile("quotes.json") if err != nil { @@ -54,6 +56,7 @@ func loadQuotes() (*Quotes, error) { return "es, nil } +// getQuotes returns the cached Quotes, loading them once on first use. func getQuotes() (*Quotes, error) { quotesOnce.Do(func() { cachedQuotes, quotesErr = loadQuotes() @@ -61,6 +64,7 @@ func getQuotes() (*Quotes, error) { return cachedQuotes, quotesErr } +// GetRandomQuote returns a random quote string from the combined quote sets. func GetRandomQuote() (string, error) { quotes, err := getQuotes() if err != nil { @@ -82,6 +86,7 @@ func GetRandomQuote() (string, error) { return allQuotes[rand.Intn(len(allQuotes))], nil } +// PrintQuote prints a random quote to stdout in green for user feedback. func PrintQuote() { quote, err := GetRandomQuote() if err != nil { @@ -92,6 +97,7 @@ func PrintQuote() { c.Println(quote) } +// GetVCSQuote returns a random quote related to VCS processing. func GetVCSQuote() (string, error) { quotes, err := getQuotes() if err != nil { @@ -103,6 +109,7 @@ func GetVCSQuote() (string, error) { return quotes.VCSProcessing[rand.Intn(len(quotes.VCSProcessing))], nil } +// GetPWAQuote returns a random quote related to PWA processing. func GetPWAQuote() (string, error) { quotes, err := getQuotes() if err != nil { @@ -114,6 +121,7 @@ func GetPWAQuote() (string, error) { return quotes.PWAProcessing[rand.Intn(len(quotes.PWAProcessing))], nil } +// GetWebsiteQuote returns a random quote related to website processing. func GetWebsiteQuote() (string, error) { quotes, err := getQuotes() if err != nil { diff --git a/pkg/website/website.go b/pkg/website/website.go index 1780c0e..5a3d37c 100644 --- a/pkg/website/website.go +++ b/pkg/website/website.go @@ -53,6 +53,8 @@ func DownloadAndPackageWebsite(startURL string, maxDepth int, bar *progressbar.P return d.dn, nil } +// crawl traverses the website starting from pageURL up to maxDepth, +// storing pages and discovered local assets into the DataNode. func (d *Downloader) crawl(pageURL string, depth int) { if depth > d.maxDepth || d.visited[pageURL] { return @@ -110,6 +112,7 @@ func (d *Downloader) crawl(pageURL string, depth int) { f(doc) } +// downloadAsset fetches a single asset URL and stores it into the DataNode. func (d *Downloader) downloadAsset(assetURL string) { if d.visited[assetURL] { return @@ -136,6 +139,7 @@ func (d *Downloader) downloadAsset(assetURL string) { d.dn.AddData(relPath, body) } +// getRelativePath returns a path relative to the site's root for the given URL. func (d *Downloader) getRelativePath(pageURL string) string { u, err := url.Parse(pageURL) if err != nil { @@ -144,6 +148,7 @@ func (d *Downloader) getRelativePath(pageURL string) string { return strings.TrimPrefix(u.Path, "/") } +// resolveURL resolves ref against base and returns the absolute URL string. func (d *Downloader) resolveURL(base, ref string) (string, error) { baseURL, err := url.Parse(base) if err != nil { @@ -156,6 +161,7 @@ func (d *Downloader) resolveURL(base, ref string) (string, error) { return baseURL.ResolveReference(refURL).String(), nil } +// isLocal reports whether pageURL belongs to the same host as the base URL. func (d *Downloader) isLocal(pageURL string) bool { u, err := url.Parse(pageURL) if err != nil { @@ -164,6 +170,7 @@ func (d *Downloader) isLocal(pageURL string) bool { return u.Hostname() == d.baseURL.Hostname() } +// isAsset reports whether the URL likely points to a static asset we should download. func isAsset(pageURL string) bool { ext := []string{".css", ".js", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico"} for _, e := range ext {