@@ -24,15 +24,16 @@ var genCmd = &cobra.Command{
2424 Use : "gen" ,
2525 Short : "Generate Hugo markdown content from database" ,
2626 Long : `Generate Hugo/Hextra-compatible markdown files for PostgreSQL extensions` ,
27- Example : ` pgext gen ext # Generate extension detail pages
27+ Example : ` pgext gen page # Generate extension detail pages
28+ pgext gen ext # Generate extension list pages with stats
29+ pgext gen pkg # Generate package list pages with stats
2830 pgext gen index # Generate extension index pages
2931 pgext gen cate # Generate category list pages
3032 pgext gen lang # Generate language list pages
3133 pgext gen license # Generate license list pages
3234 pgext gen catalog # Generate catalog pages
33- pgext gen ext # Generate extension list pages with stats
34- pgext gen pkg # Generate package list pages with stats
35- pgext gen os # Generate OS-specific availability page` ,
35+ pgext gen os # Generate OS-specific availability page
36+ pgext gen conf # Generate Pigsty configuration files` ,
3637}
3738
3839// genIndexCmd generates extension index pages
@@ -535,6 +536,98 @@ If no argument is provided, generates pages for all active OS distributions.`,
535536 },
536537}
537538
539+ // genPageCmd generates individual extension detail pages
540+ var genPageCmd = & cobra.Command {
541+ Use : "page [extension-names...]" ,
542+ Short : "Generate individual extension detail pages" ,
543+ Long : `Generate Hugo markdown detail pages for PostgreSQL extensions.
544+ If no extension names are provided, generates pages for all extensions.` ,
545+ Example : ` pgext gen page # Generate pages for all extensions
546+ pgext gen page pgvector # Generate page for pgvector extension
547+ pgext gen page pgvector postgis pg_stat_statements # Generate pages for specific extensions` ,
548+ RunE : func (cmd * cobra.Command , args []string ) error {
549+ ctx := context .Background ()
550+
551+ // Initialize database connection
552+ if err := cli .InitDB (dbURL ); err != nil {
553+ return fmt .Errorf ("failed to initialize database: %w" , err )
554+ }
555+ defer cli .CloseDB ()
556+
557+ // Load extension cache
558+ logrus .Info ("Loading extension data..." )
559+ cache , err := cli .LoadExtensionCache (ctx )
560+ if err != nil {
561+ return fmt .Errorf ("failed to load extension cache: %w" , err )
562+ }
563+
564+ // Prepare output directory
565+ extDir := filepath .Join (outputDir , "e" )
566+ if err := os .MkdirAll (extDir , 0755 ); err != nil {
567+ return fmt .Errorf ("failed to create output directory: %w" , err )
568+ }
569+
570+ // Initialize generator
571+ generator := cli .NewExtensionGenerator (cache , extDir )
572+
573+ // Determine which extensions to generate
574+ var extensionsToGenerate []* cli.Extension
575+ if len (args ) == 0 {
576+ // No arguments provided, generate all extensions (except not-ready)
577+ for _ , ext := range cache .Extensions {
578+ if ! ext .State .Valid || ext .State .String != "not-ready" {
579+ extensionsToGenerate = append (extensionsToGenerate , ext )
580+ }
581+ }
582+ logrus .Infof ("Generating pages for all %d extensions..." , len (extensionsToGenerate ))
583+ } else {
584+ // Specific extensions requested
585+ for _ , name := range args {
586+ ext , exists := cache .ExtMap [name ]
587+ if ! exists {
588+ logrus .Warnf ("Extension '%s' not found in cache, skipping" , name )
589+ continue
590+ }
591+ extensionsToGenerate = append (extensionsToGenerate , ext )
592+ }
593+ if len (extensionsToGenerate ) == 0 {
594+ return fmt .Errorf ("no valid extensions found from provided names" )
595+ }
596+ logrus .Infof ("Generating pages for %d specified extensions..." , len (extensionsToGenerate ))
597+ }
598+
599+ // Generate pages with progress tracking
600+ successCount := 0
601+ var failedExtensions []string
602+
603+ for i , ext := range extensionsToGenerate {
604+ // Progress logging for batch generation
605+ if len (extensionsToGenerate ) > 10 && (i + 1 )% 100 == 0 {
606+ logrus .Infof ("Progress: %d/%d extensions processed" , i + 1 , len (extensionsToGenerate ))
607+ }
608+
609+ if err := generator .GenerateExtensionPage (ctx , ext ); err != nil {
610+ logrus .Errorf ("Failed to generate page for %s: %v" , ext .Name , err )
611+ failedExtensions = append (failedExtensions , ext .Name )
612+ } else {
613+ successCount ++
614+ if len (args ) > 0 {
615+ // Only log individual successes when specific extensions are requested
616+ logrus .Infof ("Generated: %s/%s.md" , extDir , ext .Name )
617+ }
618+ }
619+ }
620+
621+ // Final summary
622+ logrus .Infof ("Successfully generated %d/%d extension pages" , successCount , len (extensionsToGenerate ))
623+ if len (failedExtensions ) > 0 {
624+ logrus .Warnf ("Failed to generate pages for: %v" , failedExtensions )
625+ }
626+
627+ return nil
628+ },
629+ }
630+
538631// genConfCmd generates Pigsty configuration files
539632var genConfCmd = & cobra.Command {
540633 Use : "conf [os...]" ,
@@ -616,7 +709,7 @@ based on the availability data in the pgext database.`,
616709func init () {
617710 rootCmd .AddCommand (genCmd )
618711
619- genCmd .AddCommand (genExtCmd , genPkgCmd , genIndexCmd , genCateCmd , genLangCmd , genLicenseCmd , genCatalogCmd , genOSCmd , genConfCmd )
712+ genCmd .AddCommand (genExtCmd , genPkgCmd , genPageCmd , genIndexCmd , genCateCmd , genLangCmd , genLicenseCmd , genCatalogCmd , genOSCmd , genConfCmd )
620713
621714 genCmd .PersistentFlags ().StringVarP (& outputDir , "output" , "o" , "content" ,
622715 "Output directory for generated files" )
0 commit comments