temp for tree extraction
This commit is contained in:
231
internal/commands/init.go
Normal file
231
internal/commands/init.go
Normal file
@ -0,0 +1,231 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.dws.rip/DWS/onyx/internal/core"
|
||||
"git.dws.rip/DWS/onyx/internal/storage"
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// NewInitCmd creates the init command
|
||||
func NewInitCmd() *cobra.Command {
|
||||
var remoteURL string
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "init [path]",
|
||||
Short: "Initialize a new Onyx repository",
|
||||
Long: `Initialize a new Onyx repository in the specified directory.
|
||||
If no path is provided, initializes in the current directory.
|
||||
|
||||
This command will:
|
||||
- Create a Git repository (if one doesn't exist)
|
||||
- Create the .onx directory structure
|
||||
- Initialize the oplog file
|
||||
- Create default workstreams.json
|
||||
- Add .onx to .gitignore
|
||||
- Optionally configure a remote repository
|
||||
|
||||
Example:
|
||||
onx init
|
||||
onx init --remote https://git.dws.rip/DWS/onyx.git`,
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runInit(cmd, args, remoteURL)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&remoteURL, "remote", "r", "", "Remote repository URL to configure as 'origin'")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runInit(cmd *cobra.Command, args []string, remoteURL string) error {
|
||||
// Determine the path
|
||||
path := "."
|
||||
if len(args) > 0 {
|
||||
path = args[0]
|
||||
}
|
||||
|
||||
// Resolve to absolute path
|
||||
absPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to resolve path: %w", err)
|
||||
}
|
||||
|
||||
// Check if already an Onyx repository
|
||||
if core.IsOnyxRepo(absPath) {
|
||||
return fmt.Errorf("already an onyx repository: %s", absPath)
|
||||
}
|
||||
|
||||
// Create and initialize repository
|
||||
repo := &core.OnyxRepository{}
|
||||
err = repo.Init(absPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize repository: %w", err)
|
||||
}
|
||||
|
||||
// Add remote if specified
|
||||
if remoteURL != "" {
|
||||
gitRepo := repo.GetGitRepo()
|
||||
_, err = gitRepo.CreateRemote(&config.RemoteConfig{
|
||||
Name: "origin",
|
||||
URLs: []string{remoteURL},
|
||||
})
|
||||
if err != nil {
|
||||
// Don't fail the init, but warn the user
|
||||
fmt.Fprintf(os.Stderr, "Warning: failed to add remote: %v\n", err)
|
||||
} else {
|
||||
fmt.Printf("Added remote 'origin': %s\n", remoteURL)
|
||||
}
|
||||
}
|
||||
|
||||
// Create default workstream matching the current Git branch
|
||||
wsManager := core.NewWorkstreamManager(repo)
|
||||
if err := wsManager.CreateDefaultWorkstream(); err != nil {
|
||||
// Don't fail init if workstream creation fails, just warn
|
||||
fmt.Fprintf(os.Stderr, "Warning: failed to create default workstream: %v\n", err)
|
||||
}
|
||||
|
||||
// Add .onx to .gitignore
|
||||
gitignorePath := filepath.Join(absPath, ".gitignore")
|
||||
err = addToGitignore(gitignorePath, ".onx/")
|
||||
if err != nil {
|
||||
// Don't fail if we can't update .gitignore, just warn
|
||||
fmt.Fprintf(os.Stderr, "Warning: failed to update .gitignore: %v\n", err)
|
||||
}
|
||||
|
||||
// Log the init operation to oplog
|
||||
txn, err := core.NewTransaction(repo)
|
||||
if err != nil {
|
||||
// Don't fail if we can't create transaction, repo is already initialized
|
||||
fmt.Fprintf(os.Stderr, "Warning: failed to log init to oplog: %v\n", err)
|
||||
} else {
|
||||
defer txn.Close()
|
||||
|
||||
// Execute a no-op function just to log the init
|
||||
err = txn.ExecuteWithTransaction("init", "Initialized Onyx repository", func() error {
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Warning: failed to log init: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Get the workstream name to display to the user
|
||||
currentWs, _ := wsManager.GetCurrentWorkstreamName()
|
||||
if currentWs == "" {
|
||||
currentWs = "master" // fallback
|
||||
}
|
||||
|
||||
fmt.Printf("Initialized empty Onyx repository in %s\n", filepath.Join(absPath, ".onx"))
|
||||
fmt.Printf("\n✓ Created workstream '%s' tracking branch '%s'\n", currentWs, currentWs)
|
||||
|
||||
if remoteURL != "" {
|
||||
fmt.Printf("\nYou can now:\n")
|
||||
fmt.Printf(" onx save -m \"message\" # Save your work\n")
|
||||
fmt.Printf(" onx push # Push to remote\n")
|
||||
} else {
|
||||
fmt.Printf("\nYou can now:\n")
|
||||
fmt.Printf(" onx save -m \"message\" # Save your work\n")
|
||||
fmt.Printf(" onx new <name> # Create a new workstream\n")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// addToGitignore adds an entry to .gitignore if it doesn't already exist
|
||||
func addToGitignore(gitignorePath, entry string) error {
|
||||
// Read existing .gitignore if it exists
|
||||
var content []byte
|
||||
if _, err := os.Stat(gitignorePath); err == nil {
|
||||
content, err = os.ReadFile(gitignorePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read .gitignore: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if entry already exists
|
||||
contentStr := string(content)
|
||||
if len(contentStr) > 0 && contentStr[len(contentStr)-1] != '\n' {
|
||||
contentStr += "\n"
|
||||
}
|
||||
|
||||
// Add entry if it doesn't exist
|
||||
needle := entry
|
||||
if len(needle) > 0 && needle[len(needle)-1] != '\n' {
|
||||
needle += "\n"
|
||||
}
|
||||
|
||||
// Simple check - not perfect but good enough
|
||||
if !containsLine(contentStr, entry) {
|
||||
contentStr += needle
|
||||
}
|
||||
|
||||
// Write back to .gitignore
|
||||
err := os.WriteFile(gitignorePath, []byte(contentStr), 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write .gitignore: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// containsLine checks if a multi-line string contains a specific line
|
||||
func containsLine(content, line string) bool {
|
||||
// Simple implementation - just check if the line exists as a substring
|
||||
// In the future, we might want to do line-by-line checking
|
||||
target := line
|
||||
if len(target) > 0 && target[len(target)-1] == '\n' {
|
||||
target = target[:len(target)-1]
|
||||
}
|
||||
|
||||
lines := splitLines(content)
|
||||
for _, l := range lines {
|
||||
if l == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// splitLines splits a string into lines
|
||||
func splitLines(s string) []string {
|
||||
if s == "" {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
var lines []string
|
||||
start := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == '\n' {
|
||||
lines = append(lines, s[start:i])
|
||||
start = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
// Add the last line if it doesn't end with newline
|
||||
if start < len(s) {
|
||||
lines = append(lines, s[start:])
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
|
||||
// GetOplogWriter creates an oplog writer for the repository at the given path
|
||||
func GetOplogWriter(path string) (*storage.OplogWriter, error) {
|
||||
absPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to resolve path: %w", err)
|
||||
}
|
||||
|
||||
if !core.IsOnyxRepo(absPath) {
|
||||
return nil, fmt.Errorf("not an onyx repository: %s", absPath)
|
||||
}
|
||||
|
||||
oplogPath := filepath.Join(absPath, ".onx", "oplog")
|
||||
return storage.OpenOplog(oplogPath)
|
||||
}
|
Reference in New Issue
Block a user