package core import ( "fmt" "os" "path/filepath" "time" gogit "github.com/go-git/go-git/v5" ) // OnyxRepository implements the Repository interface type OnyxRepository struct { gitRepo *gogit.Repository onyxPath string gitPath string metadata *OnyxMetadata } // Open opens an existing Onyx repository at the given path func Open(path string) (*OnyxRepository, error) { // Resolve to absolute path absPath, err := filepath.Abs(path) if err != nil { return nil, fmt.Errorf("failed to resolve path: %w", err) } // Check if .git directory exists gitPath := filepath.Join(absPath, ".git") if _, err := os.Stat(gitPath); os.IsNotExist(err) { return nil, fmt.Errorf("not a git repository (no .git directory found)") } // Check if .onx directory exists onyxPath := filepath.Join(absPath, ".onx") if _, err := os.Stat(onyxPath); os.IsNotExist(err) { return nil, fmt.Errorf("not an onyx repository (no .onx directory found)") } // Open the Git repository gitRepo, err := gogit.PlainOpen(absPath) if err != nil { return nil, fmt.Errorf("failed to open git repository: %w", err) } // Load Onyx metadata metadata := &OnyxMetadata{ Version: "1.0.0", Created: time.Now(), // TODO: Load from .onx/metadata file OnyxPath: onyxPath, } return &OnyxRepository{ gitRepo: gitRepo, onyxPath: onyxPath, gitPath: gitPath, metadata: metadata, }, nil } // Init initializes a new Onyx repository at the given path func (r *OnyxRepository) Init(path string) error { // Resolve to absolute path absPath, err := filepath.Abs(path) if err != nil { return fmt.Errorf("failed to resolve path: %w", err) } // Check if directory exists, create if it doesn't if _, err := os.Stat(absPath); os.IsNotExist(err) { if err := os.MkdirAll(absPath, 0755); err != nil { return fmt.Errorf("failed to create directory: %w", err) } } // Initialize Git repository if it doesn't exist gitPath := filepath.Join(absPath, ".git") if _, err := os.Stat(gitPath); os.IsNotExist(err) { _, err := gogit.PlainInit(absPath, false) if err != nil { return fmt.Errorf("failed to initialize git repository: %w", err) } } // Create .onx directory structure onyxPath := filepath.Join(absPath, ".onx") if err := os.MkdirAll(onyxPath, 0755); err != nil { return fmt.Errorf("failed to create .onx directory: %w", err) } // Create subdirectories subdirs := []string{"rerere_cache"} for _, subdir := range subdirs { subdirPath := filepath.Join(onyxPath, subdir) if err := os.MkdirAll(subdirPath, 0755); err != nil { return fmt.Errorf("failed to create %s directory: %w", subdir, err) } } // Initialize oplog file oplogPath := filepath.Join(onyxPath, "oplog") if _, err := os.Stat(oplogPath); os.IsNotExist(err) { if err := os.WriteFile(oplogPath, []byte{}, 0644); err != nil { return fmt.Errorf("failed to create oplog file: %w", err) } } // Initialize workstreams.json workstreamsPath := filepath.Join(onyxPath, "workstreams.json") if _, err := os.Stat(workstreamsPath); os.IsNotExist(err) { initialContent := []byte("{\"workstreams\":{}}\n") if err := os.WriteFile(workstreamsPath, initialContent, 0644); err != nil { return fmt.Errorf("failed to create workstreams.json: %w", err) } } // Open the repository gitRepo, err := gogit.PlainOpen(absPath) if err != nil { return fmt.Errorf("failed to open git repository: %w", err) } // Set up the repository instance r.gitRepo = gitRepo r.onyxPath = onyxPath r.gitPath = gitPath r.metadata = &OnyxMetadata{ Version: "1.0.0", Created: time.Now(), OnyxPath: onyxPath, } return nil } // GetGitRepo returns the underlying Git repository func (r *OnyxRepository) GetGitRepo() *gogit.Repository { return r.gitRepo } // GetOnyxMetadata returns Onyx-specific metadata func (r *OnyxRepository) GetOnyxMetadata() *OnyxMetadata { return r.metadata } // Close releases any resources held by the repository func (r *OnyxRepository) Close() error { // Currently, go-git doesn't require explicit closing // This method is here for future-proofing return nil } // IsOnyxRepo checks if the given path is an Onyx repository func IsOnyxRepo(path string) bool { absPath, err := filepath.Abs(path) if err != nil { return false } // Check for both .git and .onx directories gitPath := filepath.Join(absPath, ".git") onyxPath := filepath.Join(absPath, ".onx") _, gitErr := os.Stat(gitPath) _, onyxErr := os.Stat(onyxPath) return gitErr == nil && onyxErr == nil } // GetOnyxPath returns the path to the .onx directory func (r *OnyxRepository) GetOnyxPath() string { return r.onyxPath } // GetGitPath returns the path to the .git directory func (r *OnyxRepository) GetGitPath() string { return r.gitPath }