Replace Bash qvm scripts with Go CLI implementation
This commit is contained in:
parent
ffb456707f
commit
2a6a333721
27 changed files with 2551 additions and 1702 deletions
139
internal/workspace/registry.go
Normal file
139
internal/workspace/registry.go
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
package workspace
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/samber/mo"
|
||||
)
|
||||
|
||||
type Workspace struct {
|
||||
HostPath string `json:"host_path"`
|
||||
Hash string `json:"hash"`
|
||||
MountTag string `json:"mount_tag"`
|
||||
GuestPath string `json:"guest_path"`
|
||||
}
|
||||
|
||||
type Registry struct {
|
||||
filePath string
|
||||
workspaces map[string]Workspace
|
||||
}
|
||||
|
||||
// Hash generates an 8-character hash from a path, matching bash behavior:
|
||||
// echo -n "$path" | sha256sum | cut -c1-8
|
||||
func Hash(path string) string {
|
||||
h := sha256.Sum256([]byte(path))
|
||||
return fmt.Sprintf("%x", h)[:8]
|
||||
}
|
||||
|
||||
// NewRegistry creates a new empty registry
|
||||
func NewRegistry(filePath string) *Registry {
|
||||
return &Registry{
|
||||
filePath: filePath,
|
||||
workspaces: make(map[string]Workspace),
|
||||
}
|
||||
}
|
||||
|
||||
// Load reads the registry from a JSON file
|
||||
func Load(filePath string) mo.Result[*Registry] {
|
||||
registry := NewRegistry(filePath)
|
||||
|
||||
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
||||
return mo.Ok(registry)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return mo.Err[*Registry](fmt.Errorf("failed to read workspaces file: %w", err))
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
return mo.Ok(registry)
|
||||
}
|
||||
|
||||
var workspaceList []Workspace
|
||||
if err := json.Unmarshal(data, &workspaceList); err != nil {
|
||||
return mo.Err[*Registry](fmt.Errorf("failed to parse workspaces JSON: %w", err))
|
||||
}
|
||||
|
||||
for _, ws := range workspaceList {
|
||||
registry.workspaces[ws.HostPath] = ws
|
||||
}
|
||||
|
||||
return mo.Ok(registry)
|
||||
}
|
||||
|
||||
// Save writes the registry to the JSON file
|
||||
func (r *Registry) Save() mo.Result[struct{}] {
|
||||
dir := filepath.Dir(r.filePath)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return mo.Err[struct{}](fmt.Errorf("failed to create directory: %w", err))
|
||||
}
|
||||
|
||||
workspaceList := make([]Workspace, 0, len(r.workspaces))
|
||||
for _, ws := range r.workspaces {
|
||||
workspaceList = append(workspaceList, ws)
|
||||
}
|
||||
|
||||
data, err := json.MarshalIndent(workspaceList, "", " ")
|
||||
if err != nil {
|
||||
return mo.Err[struct{}](fmt.Errorf("failed to marshal JSON: %w", err))
|
||||
}
|
||||
|
||||
if err := os.WriteFile(r.filePath, data, 0644); err != nil {
|
||||
return mo.Err[struct{}](fmt.Errorf("failed to write workspaces file: %w", err))
|
||||
}
|
||||
|
||||
return mo.Ok(struct{}{})
|
||||
}
|
||||
|
||||
// Register adds a workspace to the registry if it doesn't already exist
|
||||
func (r *Registry) Register(hostPath string) mo.Result[*Workspace] {
|
||||
absPath, err := filepath.Abs(hostPath)
|
||||
if err != nil {
|
||||
return mo.Err[*Workspace](fmt.Errorf("failed to resolve absolute path: %w", err))
|
||||
}
|
||||
|
||||
if existing, exists := r.workspaces[absPath]; exists {
|
||||
return mo.Ok(&existing)
|
||||
}
|
||||
|
||||
hash := Hash(absPath)
|
||||
ws := Workspace{
|
||||
HostPath: absPath,
|
||||
Hash: hash,
|
||||
MountTag: fmt.Sprintf("ws_%s", hash),
|
||||
GuestPath: fmt.Sprintf("/workspace/%s", hash),
|
||||
}
|
||||
|
||||
r.workspaces[absPath] = ws
|
||||
return mo.Ok(&ws)
|
||||
}
|
||||
|
||||
// List returns all registered workspaces
|
||||
func (r *Registry) List() []Workspace {
|
||||
result := make([]Workspace, 0, len(r.workspaces))
|
||||
for _, ws := range r.workspaces {
|
||||
result = append(result, ws)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Find looks up a workspace by host path
|
||||
func (r *Registry) Find(hostPath string) mo.Option[Workspace] {
|
||||
absPath, err := filepath.Abs(hostPath)
|
||||
if err != nil {
|
||||
if ws, exists := r.workspaces[hostPath]; exists {
|
||||
return mo.Some(ws)
|
||||
}
|
||||
return mo.None[Workspace]()
|
||||
}
|
||||
|
||||
if ws, exists := r.workspaces[absPath]; exists {
|
||||
return mo.Some(ws)
|
||||
}
|
||||
return mo.None[Workspace]()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue