source.go

72 lines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
package commands

import (
	"flag"
	"fmt"
	"io/fs"
	"log"
	"os"
	"path/filepath"

	"congo.gg"
)

const sourceUsage = `Extract the complete Congo source code

Usage:
  congo source [directory]

Extracts the full Congo module (CLI, dev platform, framework, website)
into the specified directory. Default: congo-src
`

func Source() {
	f := flag.NewFlagSet("source", flag.ExitOnError)
	f.Usage = func() { fmt.Print(sourceUsage) }
	f.Parse(os.Args[2:])

	dir := "congo-src"
	if f.NArg() > 0 {
		dir = f.Arg(0)
	}

	if _, err := os.Stat(dir); err == nil {
		log.Fatalf("directory %q already exists", dir)
	}

	fmt.Printf("Extracting Congo source to %s...\n", dir)

	// Extract the complete module from the embedded SourceFS
	if err := extractFS(congo.SourceFS, ".", dir); err != nil {
		log.Fatalf("extract source: %v", err)
	}

	fmt.Printf("Done. Build with:\n")
	fmt.Printf("  cd %s && go build -o congo ./cmd                    # CLI\n", dir)
	fmt.Printf("  cd %s && CGO_ENABLED=1 go build -o congo-dev ./dev  # Dev platform\n", dir)
	fmt.Printf("  cd %s && go build -o website ./web                   # Website\n", dir)
}

// extractFS writes all files from an embed.FS into targetDir,
// preserving directory structure.
func extractFS(fsys fs.FS, root, targetDir string) error {
	return fs.WalkDir(fsys, root, func(path string, d fs.DirEntry, err error) error {
		if err != nil || path == "." {
			return err
		}

		outPath := filepath.Join(targetDir, path)

		if d.IsDir() {
			return os.MkdirAll(outPath, 0755)
		}

		content, err := fs.ReadFile(fsys, path)
		if err != nil {
			return err
		}

		os.MkdirAll(filepath.Dir(outPath), 0755)
		return os.WriteFile(outPath, content, 0644)
	})
}