package main import ( "context" "database/sql" "embed" "flag" "fmt" "os" "path/filepath" "time" _ "github.com/mattn/go-sqlite3" "codexis/db" "codexis/indexer" ) const dbDir = ".codexis" const dbFileName = "index.db" func main() { force := flag.Bool("force", false, "Force full re-index (ignore file hashes)") output := flag.String("o", "", "Output database path (default: /.codexis/index.db)") flag.Parse() root := "." if flag.NArg() > 0 { root = flag.Arg(0) } absRoot, err := filepath.Abs(root) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } dbDirPath := filepath.Join(absRoot, dbDir) if err := os.MkdirAll(dbDirPath, 0755); err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } dbPath := filepath.Join(dbDirPath, dbFileName) if *output != "" { dbPath = *output } if err := run(absRoot, dbPath, *force); err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } } func run(root, dbPath string, force bool) error { ctx := context.Background() sqlDB, err := sql.Open("sqlite3", dbPath+"?_journal_mode=WAL&_foreign_keys=on") if err != nil { return fmt.Errorf("opening database: %w", err) } defer sqlDB.Close() // Create schema if err := createSchema(ctx, sqlDB); err != nil { return fmt.Errorf("creating schema: %w", err) } queries := db.New(sqlDB) idx := indexer.New(queries, root, force) start := time.Now() fmt.Fprintf(os.Stderr, "Indexing %s...\n", root) stats, err := idx.Index(ctx) if err != nil { return fmt.Errorf("indexing: %w", err) } elapsed := time.Since(start) fmt.Fprintf(os.Stderr, "Done in %s\n", elapsed.Round(time.Millisecond)) fmt.Fprintf(os.Stderr, " Files: %d total, %d indexed, %d unchanged\n", stats.FilesTotal, stats.FilesIndexed, stats.FilesSkipped) fmt.Fprintf(os.Stderr, " Symbols: %d\n", stats.SymbolsTotal) fmt.Fprintf(os.Stderr, " Output: %s\n", dbPath) return nil } //go:embed db/schema.sql var schemaSQL string func createSchema(ctx context.Context, sqlDB *sql.DB) error { _, err := sqlDB.ExecContext(ctx, schemaSQL) return err }