feat: skip already-indexed revisions, add --force flag
When indexing a revision that already exists, the indexer now returns early with information about the existing revision instead of re-indexing. Use the --force flag to re-index an existing revision. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
4
TODO.md
4
TODO.md
@@ -1,9 +1,5 @@
|
||||
# TODO - Future Improvements
|
||||
|
||||
## Quick Wins
|
||||
|
||||
- [ ] Check if revision exists before indexing (skip or require `--force`)
|
||||
|
||||
## Usability
|
||||
|
||||
- [ ] Progress reporting during indexing ("Fetching nixpkgs... Parsing options... Indexing files...")
|
||||
|
||||
@@ -50,12 +50,17 @@ func main() {
|
||||
Name: "no-files",
|
||||
Usage: "Skip indexing file contents (faster, disables get_file tool)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "force",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "Force re-indexing even if revision already exists",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
if c.NArg() < 1 {
|
||||
return fmt.Errorf("revision argument required")
|
||||
}
|
||||
return runIndex(c, c.Args().First(), !c.Bool("no-files"))
|
||||
return runIndex(c, c.Args().First(), !c.Bool("no-files"), c.Bool("force"))
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -162,7 +167,7 @@ func runServe(c *cli.Context) error {
|
||||
return server.Run(ctx, os.Stdin, os.Stdout)
|
||||
}
|
||||
|
||||
func runIndex(c *cli.Context, revision string, indexFiles bool) error {
|
||||
func runIndex(c *cli.Context, revision string, indexFiles bool, force bool) error {
|
||||
ctx := context.Background()
|
||||
|
||||
store, err := openStore(c.String("database"))
|
||||
@@ -178,11 +183,22 @@ func runIndex(c *cli.Context, revision string, indexFiles bool) error {
|
||||
indexer := nixos.NewIndexer(store)
|
||||
|
||||
fmt.Printf("Indexing revision: %s\n", revision)
|
||||
result, err := indexer.IndexRevision(ctx, revision)
|
||||
|
||||
var result *nixos.IndexResult
|
||||
if force {
|
||||
result, err = indexer.ReindexRevision(ctx, revision)
|
||||
} else {
|
||||
result, err = indexer.IndexRevision(ctx, revision)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("indexing failed: %w", err)
|
||||
}
|
||||
|
||||
if result.AlreadyIndexed {
|
||||
fmt.Printf("Revision already indexed (%d options). Use --force to re-index.\n", result.OptionCount)
|
||||
return nil
|
||||
}
|
||||
|
||||
fmt.Printf("Indexed %d options in %s\n", result.OptionCount, result.Duration)
|
||||
fmt.Printf("Git hash: %s\n", result.Revision.GitHash)
|
||||
if result.Revision.ChannelName != "" {
|
||||
|
||||
@@ -217,6 +217,20 @@ func (s *Server) makeIndexHandler(indexer *nixos.Indexer) ToolHandler {
|
||||
return ErrorContent(fmt.Errorf("indexing failed: %w", err)), nil
|
||||
}
|
||||
|
||||
// If already indexed, return early with info
|
||||
if result.AlreadyIndexed {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(fmt.Sprintf("Revision already indexed: %s\n", result.Revision.GitHash))
|
||||
if result.Revision.ChannelName != "" {
|
||||
sb.WriteString(fmt.Sprintf("Channel: %s\n", result.Revision.ChannelName))
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("Options: %d\n", result.OptionCount))
|
||||
sb.WriteString(fmt.Sprintf("Indexed at: %s\n", result.Revision.IndexedAt.Format("2006-01-02 15:04")))
|
||||
return CallToolResult{
|
||||
Content: []Content{TextContent(sb.String())},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Index files by default
|
||||
fileCount, err := indexer.IndexFiles(ctx, result.Revision.ID, result.Revision.GitHash)
|
||||
if err != nil {
|
||||
|
||||
@@ -39,6 +39,7 @@ type IndexResult struct {
|
||||
OptionCount int
|
||||
FileCount int
|
||||
Duration time.Duration
|
||||
AlreadyIndexed bool // True if revision was already indexed (skipped)
|
||||
}
|
||||
|
||||
// IndexRevision indexes a nixpkgs revision by git hash or channel name.
|
||||
@@ -58,6 +59,7 @@ func (idx *Indexer) IndexRevision(ctx context.Context, revision string) (*IndexR
|
||||
Revision: existing,
|
||||
OptionCount: existing.OptionCount,
|
||||
Duration: time.Since(start),
|
||||
AlreadyIndexed: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -112,6 +114,25 @@ func (idx *Indexer) IndexRevision(ctx context.Context, revision string) (*IndexR
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ReindexRevision forces re-indexing of a revision, deleting existing data first.
|
||||
func (idx *Indexer) ReindexRevision(ctx context.Context, revision string) (*IndexResult, error) {
|
||||
ref := resolveRevision(revision)
|
||||
|
||||
// Delete existing revision if present
|
||||
existing, err := idx.store.GetRevision(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check existing revision: %w", err)
|
||||
}
|
||||
if existing != nil {
|
||||
if err := idx.store.DeleteRevision(ctx, existing.ID); err != nil {
|
||||
return nil, fmt.Errorf("failed to delete existing revision: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Now index fresh
|
||||
return idx.IndexRevision(ctx, revision)
|
||||
}
|
||||
|
||||
// buildOptions builds options.json for a nixpkgs revision.
|
||||
func (idx *Indexer) buildOptions(ctx context.Context, ref string) (string, func(), error) {
|
||||
// Create temp directory
|
||||
|
||||
Reference in New Issue
Block a user