archive | ||
examples | ||
grpc | ||
hash | ||
interfaces | ||
remote | ||
store | ||
stores | ||
.gitignore | ||
api_test.go | ||
api.go | ||
errors.go | ||
functional_test.go | ||
go.mod | ||
go.sum | ||
grpc_test.go | ||
Makefile | ||
manager_test.go | ||
manager.go | ||
performance_test.go | ||
README.md | ||
snapshot.go |
Agate
Agate is a Go library for creating, managing, and sharing snapshots of directories. It provides functionality for creating incremental snapshots, storing them efficiently, and sharing them over a network using gRPC.
Installation
go get gitea.unprism.ru/KRBL/Agate
Features
- Create snapshots of directories
- Incremental snapshots (only store changes)
- Restore snapshots
- List and manage snapshots
- Share snapshots over a network using gRPC
- Connect to remote snapshot repositories
Basic Usage
Creating a Snapshot Repository
To create a snapshot repository, you need to initialize the Agate library with the appropriate options:
package main
import (
"context"
"fmt"
"log"
"os"
"path/filepath"
"gitea.unprism.ru/KRBL/Agate"
"gitea.unprism.ru/KRBL/Agate/stores"
)
func main() {
// Create directories for your repository
workDir := "/path/to/your/repository"
if err := os.MkdirAll(workDir, 0755); err != nil {
log.Fatalf("Failed to create work directory: %v", err)
}
// Initialize the default stores
metadataStore, blobStore, err := stores.InitDefaultStores(workDir)
if err != nil {
log.Fatalf("Failed to initialize stores: %v", err)
}
defer metadataStore.Close()
// Initialize Agate
agateOptions := agate.AgateOptions{
WorkDir: workDir,
MetadataStore: metadataStore,
BlobStore: blobStore,
}
ag, err := agate.New(agateOptions)
if err != nil {
log.Fatalf("Failed to initialize Agate: %v", err)
}
defer ag.Close()
// Create a snapshot
ctx := context.Background()
snapshotID, err := ag.SaveSnapshot(ctx, "My First Snapshot", "")
if err != nil {
log.Fatalf("Failed to create snapshot: %v", err)
}
fmt.Printf("Created snapshot with ID: %s\n", snapshotID)
// List snapshots
snapshots, err := ag.ListSnapshots(ctx)
if err != nil {
log.Fatalf("Failed to list snapshots: %v", err)
}
fmt.Printf("Found %d snapshots:\n", len(snapshots))
for _, s := range snapshots {
fmt.Printf(" - %s: %s (created at %s)\n", s.ID, s.Name, s.CreationTime.Format("2006-01-02 15:04:05"))
}
}
Hosting a Snapshot Repository
To host a snapshot repository and make it available over the network, you can use the StartServer
method:
package main
import (
"context"
"log"
"os"
"os/signal"
"syscall"
"gitea.unprism.ru/KRBL/Agate"
"gitea.unprism.ru/KRBL/Agate/stores"
)
func main() {
// Create directories for your repository
workDir := "/path/to/your/repository"
if err := os.MkdirAll(workDir, 0755); err != nil {
log.Fatalf("Failed to create work directory: %v", err)
}
// Initialize the default stores
metadataStore, blobStore, err := stores.InitDefaultStores(workDir)
if err != nil {
log.Fatalf("Failed to initialize stores: %v", err)
}
defer metadataStore.Close()
// Initialize Agate
agateOptions := agate.AgateOptions{
WorkDir: workDir,
MetadataStore: metadataStore,
BlobStore: blobStore,
}
ag, err := agate.New(agateOptions)
if err != nil {
log.Fatalf("Failed to initialize Agate: %v", err)
}
defer ag.Close()
// Start the gRPC server
ctx := context.Background()
address := "0.0.0.0:50051" // Listen on all interfaces, port 50051
if err := ag.StartServer(ctx, address); err != nil {
log.Fatalf("Failed to start server: %v", err)
}
log.Printf("Server started on %s", address)
// Wait for termination signal
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
log.Println("Shutting down...")
}
Connecting to a Hosted Snapshot Repository
To connect to a hosted snapshot repository and retrieve snapshots:
package main
import (
"context"
"fmt"
"log"
"os"
"gitea.unprism.ru/KRBL/Agate"
"gitea.unprism.ru/KRBL/Agate/stores"
)
func main() {
// Create directories for your local repository
workDir := "/path/to/your/local/repository"
if err := os.MkdirAll(workDir, 0755); err != nil {
log.Fatalf("Failed to create work directory: %v", err)
}
// Initialize the default stores
metadataStore, blobStore, err := stores.InitDefaultStores(workDir)
if err != nil {
log.Fatalf("Failed to initialize stores: %v", err)
}
defer metadataStore.Close()
// Initialize Agate
agateOptions := agate.AgateOptions{
WorkDir: workDir,
MetadataStore: metadataStore,
BlobStore: blobStore,
}
ag, err := agate.New(agateOptions)
if err != nil {
log.Fatalf("Failed to initialize Agate: %v", err)
}
defer ag.Close()
// Connect to a remote server
ctx := context.Background()
remoteAddress := "remote-server:50051"
// List snapshots from the remote server
snapshots, err := ag.GetRemoteSnapshotList(ctx, remoteAddress)
if err != nil {
log.Fatalf("Failed to list remote snapshots: %v", err)
}
fmt.Printf("Found %d remote snapshots:\n", len(snapshots))
for _, s := range snapshots {
fmt.Printf(" - %s: %s (created at %s)\n", s.ID, s.Name, s.CreationTime.Format("2006-01-02 15:04:05"))
}
// Download a specific snapshot
if len(snapshots) > 0 {
snapshotID := snapshots[0].ID
fmt.Printf("Downloading snapshot %s...\n", snapshotID)
// Download the snapshot (pass empty string as localParentID if this is the first download)
if err := ag.GetRemoteSnapshot(ctx, remoteAddress, snapshotID, ""); err != nil {
log.Fatalf("Failed to download snapshot: %v", err)
}
fmt.Printf("Successfully downloaded snapshot %s\n", snapshotID)
}
}
Advanced Usage
Creating Incremental Snapshots
You can create incremental snapshots by specifying a parent snapshot ID:
// Create a first snapshot
snapshotID1, err := ag.SaveSnapshot(ctx, "First Snapshot", "")
if err != nil {
log.Fatalf("Failed to create first snapshot: %v", err)
}
// Make some changes to your files...
// Create a second snapshot with the first one as parent
snapshotID2, err := ag.SaveSnapshot(ctx, "Second Snapshot", snapshotID1)
if err != nil {
log.Fatalf("Failed to create second snapshot: %v", err)
}
Restoring a Snapshot
To restore a snapshot:
if err := ag.RestoreSnapshot(ctx, snapshotID); err != nil {
log.Fatalf("Failed to restore snapshot: %v", err)
}
Getting Snapshot Details
To get detailed information about a snapshot:
snapshot, err := ag.GetSnapshotDetails(ctx, snapshotID)
if err != nil {
log.Fatalf("Failed to get snapshot details: %v", err)
}
fmt.Printf("Snapshot: %s\n", snapshot.Name)
fmt.Printf("Created: %s\n", snapshot.CreationTime.Format("2006-01-02 15:04:05"))
fmt.Printf("Files: %d\n", len(snapshot.Files))
Deleting a Snapshot
To delete a snapshot:
if err := ag.DeleteSnapshot(ctx, snapshotID); err != nil {
log.Fatalf("Failed to delete snapshot: %v", err)
}
API Reference
Agate
The main entry point for the library.
New(options AgateOptions) (*Agate, error)
- Create a new Agate instanceSaveSnapshot(ctx context.Context, name string, parentID string) (string, error)
- Create a new snapshotRestoreSnapshot(ctx context.Context, snapshotID string) error
- Restore a snapshotListSnapshots(ctx context.Context) ([]store.SnapshotInfo, error)
- List all snapshotsGetSnapshotDetails(ctx context.Context, snapshotID string) (*store.Snapshot, error)
- Get details of a snapshotDeleteSnapshot(ctx context.Context, snapshotID string) error
- Delete a snapshotStartServer(ctx context.Context, address string) error
- Start a gRPC server to share snapshotsConnectRemote(address string) (*grpc.SnapshotClient, error)
- Connect to a remote serverGetRemoteSnapshotList(ctx context.Context, address string) ([]store.SnapshotInfo, error)
- List snapshots from a remote serverGetRemoteSnapshot(ctx context.Context, address string, snapshotID string, localParentID string) error
- Download a snapshot from a remote server
AgateOptions
Configuration options for the Agate library.
WorkDir string
- Directory where snapshots will be stored and managedOpenFunc func(dir string) error
- Called after a snapshot is restoredCloseFunc func() error
- Called before a snapshot is created or restoredMetadataStore store.MetadataStore
- Implementation of the metadata storeBlobStore store.BlobStore
- Implementation of the blob store
License
[Add your license information here]