mirror of
https://github.com/imjasonh/infinite-git
synced 2026-07-18 06:45:05 +00:00
Add cmd/infinite-go: serve Go package with PullTime via git
Refactor infinite-git to support pluggable content generation: - Extract ContentProvider interface (InitialFiles, GenerateFiles, CommitMessage) - Make repo.New accept initial files map instead of hardcoding content - Move infinite-git to cmd/infinite-git with gitContent provider - Add cmd/infinite-go that serves a Go module where each pull generates a new version with PullTime set to the pull timestamp - Include ?go-get=1 discovery middleware for Go module resolution https://claude.ai/code/session_01HpvELk7HnbJoXEUjqHP7SU
This commit is contained in:
parent
16db43a3af
commit
96dd2d9604
8 changed files with 325 additions and 106 deletions
|
|
@ -11,14 +11,16 @@ import (
|
|||
|
||||
// Generator creates new commits on demand.
|
||||
type Generator struct {
|
||||
repo *repo.Repository
|
||||
counter int64
|
||||
repo *repo.Repository
|
||||
counter int64
|
||||
provider ContentProvider
|
||||
}
|
||||
|
||||
// New creates a new commit generator.
|
||||
func New(r *repo.Repository) *Generator {
|
||||
func New(r *repo.Repository, provider ContentProvider) *Generator {
|
||||
return &Generator{
|
||||
repo: r,
|
||||
repo: r,
|
||||
provider: provider,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,29 +73,29 @@ func (g *Generator) GenerateCommit() (string, error) {
|
|||
// Parse existing tree entries
|
||||
existingEntries := parseTree(parentTreeData)
|
||||
|
||||
// Create updated hello.txt content with nanosecond precision
|
||||
filename := "hello.txt"
|
||||
content := fmt.Sprintf("Pull #%d\nTimestamp: %s\n", count, time.Now().Format("2006-01-02 15:04:05.999999999"))
|
||||
// Generate files from content provider
|
||||
now := time.Now()
|
||||
generatedFiles := g.provider.GenerateFiles(count, now)
|
||||
|
||||
// Create blob for updated file
|
||||
blob := object.NewBlob([]byte(content))
|
||||
blobHash, err := g.repo.WriteObject(blob)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("writing blob: %w", err)
|
||||
}
|
||||
|
||||
// Create new tree with all existing entries, replacing hello.txt
|
||||
// Create new tree with existing entries, replacing any generated files
|
||||
tree := object.NewTree()
|
||||
|
||||
// Add existing entries, but skip hello.txt as we'll add the updated one
|
||||
// Add existing entries, skipping any that will be replaced
|
||||
for _, entry := range existingEntries {
|
||||
if entry.Name != filename {
|
||||
if _, replaced := generatedFiles[entry.Name]; !replaced {
|
||||
tree.AddEntry(entry.Mode, entry.Name, entry.Hash)
|
||||
}
|
||||
}
|
||||
|
||||
// Add updated hello.txt
|
||||
tree.AddEntry("100644", filename, blobHash)
|
||||
// Add generated files
|
||||
for name, content := range generatedFiles {
|
||||
blob := object.NewBlob(content)
|
||||
blobHash, err := g.repo.WriteObject(blob)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("writing blob for %s: %w", name, err)
|
||||
}
|
||||
tree.AddEntry("100644", name, blobHash)
|
||||
}
|
||||
|
||||
treeHash, err := g.repo.WriteObject(tree)
|
||||
if err != nil {
|
||||
|
|
@ -101,7 +103,7 @@ func (g *Generator) GenerateCommit() (string, error) {
|
|||
}
|
||||
|
||||
// Create commit
|
||||
commitMsg := fmt.Sprintf("Pull #%d at %s", count, time.Now().Format("2006-01-02 15:04:05"))
|
||||
commitMsg := g.provider.CommitMessage(count, now)
|
||||
commit := object.NewCommit(
|
||||
treeHash,
|
||||
parentHash,
|
||||
|
|
|
|||
14
internal/generator/content.go
Normal file
14
internal/generator/content.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package generator
|
||||
|
||||
import "time"
|
||||
|
||||
// ContentProvider defines how to generate files for each pull.
|
||||
type ContentProvider interface {
|
||||
// InitialFiles returns the files for the initial commit.
|
||||
InitialFiles() map[string][]byte
|
||||
// GenerateFiles returns files to create/update on each pull.
|
||||
// Existing files not in this map are preserved.
|
||||
GenerateFiles(count int64, now time.Time) map[string][]byte
|
||||
// CommitMessage returns the commit message for a pull.
|
||||
CommitMessage(count int64, now time.Time) string
|
||||
}
|
||||
|
|
@ -20,7 +20,8 @@ type Repository struct {
|
|||
}
|
||||
|
||||
// New creates or opens a Git repository at the given path.
|
||||
func New(path string) (*Repository, error) {
|
||||
// initialFiles specifies the files to include in the initial commit.
|
||||
func New(path string, initialFiles map[string][]byte) (*Repository, error) {
|
||||
repo := &Repository{
|
||||
path: path,
|
||||
gitDir: filepath.Join(path, ".git"),
|
||||
|
|
@ -39,7 +40,7 @@ func New(path string) (*Repository, error) {
|
|||
}
|
||||
|
||||
// Create initial commit
|
||||
if err := repo.createInitialCommit(); err != nil {
|
||||
if err := repo.createInitialCommit(initialFiles); err != nil {
|
||||
return nil, fmt.Errorf("creating initial commit: %w", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -86,35 +87,29 @@ func (r *Repository) init() error {
|
|||
}
|
||||
|
||||
// createInitialCommit creates the first commit in the repository.
|
||||
func (r *Repository) createInitialCommit() error {
|
||||
// Create README content
|
||||
readmeContent := []byte("# Infinite Git Repository\n\nThis repository generates a new commit every time you pull.\n")
|
||||
|
||||
// Create blob for README
|
||||
readmeBlob := object.NewBlob(readmeContent)
|
||||
readmeBlobHash, err := object.Write(r.gitDir, readmeBlob)
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing README blob: %w", err)
|
||||
}
|
||||
|
||||
// Create initial hello.txt content
|
||||
helloContent := []byte("Pull #0\nTimestamp: Initial commit\n")
|
||||
helloBlob := object.NewBlob(helloContent)
|
||||
helloBlobHash, err := object.Write(r.gitDir, helloBlob)
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing hello.txt blob: %w", err)
|
||||
}
|
||||
|
||||
// Create tree with README and hello.txt
|
||||
func (r *Repository) createInitialCommit(files map[string][]byte) error {
|
||||
tree := object.NewTree()
|
||||
tree.AddEntry("100644", "README.md", readmeBlobHash)
|
||||
tree.AddEntry("100644", "hello.txt", helloBlobHash)
|
||||
|
||||
for name, content := range files {
|
||||
blob := object.NewBlob(content)
|
||||
blobHash, err := object.Write(r.gitDir, blob)
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing blob for %s: %w", name, err)
|
||||
}
|
||||
tree.AddEntry("100644", name, blobHash)
|
||||
|
||||
// Also write to working directory
|
||||
filePath := filepath.Join(r.path, name)
|
||||
if err := os.WriteFile(filePath, content, 0644); err != nil {
|
||||
return fmt.Errorf("writing %s to working directory: %w", name, err)
|
||||
}
|
||||
}
|
||||
|
||||
treeHash, err := object.Write(r.gitDir, tree)
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing tree: %w", err)
|
||||
}
|
||||
|
||||
// Create commit
|
||||
commit := object.NewCommit(
|
||||
treeHash,
|
||||
"", // No parent for initial commit
|
||||
|
|
@ -127,23 +122,11 @@ func (r *Repository) createInitialCommit() error {
|
|||
return fmt.Errorf("writing commit: %w", err)
|
||||
}
|
||||
|
||||
// Update refs/heads/main
|
||||
refPath := filepath.Join(r.gitDir, "refs", "heads", "main")
|
||||
if err := os.WriteFile(refPath, []byte(commitHash+"\n"), 0644); err != nil {
|
||||
return fmt.Errorf("updating ref: %w", err)
|
||||
}
|
||||
|
||||
// Also write README and hello.txt to working directory
|
||||
readmePath := filepath.Join(r.path, "README.md")
|
||||
if err := os.WriteFile(readmePath, readmeContent, 0644); err != nil {
|
||||
return fmt.Errorf("writing README to working directory: %w", err)
|
||||
}
|
||||
|
||||
helloPath := filepath.Join(r.path, "hello.txt")
|
||||
if err := os.WriteFile(helloPath, helloContent, 0644); err != nil {
|
||||
return fmt.Errorf("writing hello.txt to working directory: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ type Server struct {
|
|||
}
|
||||
|
||||
// New creates a new Git HTTP server.
|
||||
func New(r *repo.Repository) *Server {
|
||||
func New(r *repo.Repository, provider generator.ContentProvider) *Server {
|
||||
return &Server{
|
||||
repo: r,
|
||||
generator: generator.New(r),
|
||||
generator: generator.New(r, provider),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue