Добавлена возможность зарегистрировать локальный снапшот
This commit is contained in:
106
api.go
106
api.go
@@ -12,6 +12,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitea.unprism.ru/KRBL/Agate/store"
|
||||
"gitea.unprism.ru/KRBL/Agate/stores"
|
||||
@@ -325,7 +326,9 @@ func (a *Agate) saveCurrentSnapshotID() error {
|
||||
if a.currentSnapshotID == "" {
|
||||
// If there's no current snapshot ID, remove the file if it exists
|
||||
if _, err := os.Stat(a.currentIDFile); err == nil {
|
||||
return os.Remove(a.currentIDFile)
|
||||
if err := os.Remove(a.currentIDFile); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -358,7 +361,11 @@ func (a *Agate) GetRemoteSnapshot(ctx context.Context, address string, snapshotI
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
defer func() {
|
||||
if err := client.Close(); err != nil {
|
||||
a.options.Logger.Printf("ERROR: failed to close client: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
remoteSnapshot, err := client.FetchSnapshotDetails(ctx, snapshotID)
|
||||
if err != nil {
|
||||
@@ -373,7 +380,11 @@ func (a *Agate) GetRemoteSnapshot(ctx context.Context, address string, snapshotI
|
||||
if err := os.MkdirAll(newSnapshotDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create new snapshot directory: %w", err)
|
||||
}
|
||||
defer os.RemoveAll(newSnapshotDir)
|
||||
defer func() {
|
||||
if err := os.RemoveAll(newSnapshotDir); err != nil {
|
||||
a.options.Logger.Printf("ERROR: failed to remove temp dir: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if localParentID != "" {
|
||||
if err := a.manager.ExtractSnapshot(ctx, localParentID, newSnapshotDir, false); err != nil {
|
||||
@@ -409,7 +420,11 @@ func (a *Agate) GetRemoteSnapshot(ctx context.Context, address string, snapshotI
|
||||
if err := os.Rename(diffPartPath, diffArchivePath); err != nil {
|
||||
return fmt.Errorf("failed to finalize downloaded diff: %w", err)
|
||||
}
|
||||
defer os.Remove(diffArchivePath)
|
||||
defer func() {
|
||||
if err := os.Remove(diffArchivePath); err != nil {
|
||||
a.options.Logger.Printf("ERROR: failed to remove temp file: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := extractArchive(diffArchivePath, newSnapshotDir); err != nil {
|
||||
return fmt.Errorf("failed to extract diff archive: %w", err)
|
||||
@@ -419,7 +434,11 @@ func (a *Agate) GetRemoteSnapshot(ctx context.Context, address string, snapshotI
|
||||
if err := archive.CreateArchive(newSnapshotDir, finalArchivePath); err != nil {
|
||||
return fmt.Errorf("failed to create final snapshot archive: %w", err)
|
||||
}
|
||||
defer os.Remove(finalArchivePath)
|
||||
defer func() {
|
||||
if err := os.Remove(finalArchivePath); err != nil {
|
||||
a.options.Logger.Printf("ERROR: failed to remove temp file: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
finalArchiveFile, err := os.Open(finalArchivePath)
|
||||
if err != nil {
|
||||
@@ -443,3 +462,80 @@ func (a *Agate) GetRemoteSnapshot(ctx context.Context, address string, snapshotI
|
||||
func (a *Agate) GetCurrentSnapshotID() string {
|
||||
return a.currentSnapshotID
|
||||
}
|
||||
|
||||
// RegisterLocalSnapshot регистрирует локальный файл как блоб снимка и создает
|
||||
// соответствующую запись в метаданных. Если снимок с таким ID уже существует,
|
||||
// метод ничего не делает и возвращает nil.
|
||||
//
|
||||
// - ctx: Контекст для выполнения операции.
|
||||
// - snapshotID: ID регистрируемого снимка.
|
||||
// - parentID: ID родительского снимка. Может быть пустым для полных снимков.
|
||||
// - name: Описательное имя для снимка.
|
||||
// - localPath: Абсолютный путь к локальному файлу снимка (полному или дифф-архиву).
|
||||
func (ag *Agate) RegisterLocalSnapshot(ctx context.Context, snapshotID, parentID, name, localPath string) error {
|
||||
// 1. Check if snapshot already exists
|
||||
_, err := ag.manager.GetSnapshotDetails(ctx, snapshotID)
|
||||
if err == nil {
|
||||
ag.options.Logger.Printf("snapshot %s already exists, skipping registration", snapshotID)
|
||||
return nil // Snapshot already exists
|
||||
}
|
||||
// We expect ErrNotFound, anything else is a real error.
|
||||
if !errors.Is(err, ErrNotFound) {
|
||||
return fmt.Errorf("failed to check for existing snapshot: %w", err)
|
||||
}
|
||||
|
||||
// 2. Add the file to the blob store
|
||||
localFile, err := os.Open(localPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open local snapshot file: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := localFile.Close(); err != nil {
|
||||
ag.options.Logger.Printf("ERROR: failed to close local file: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
_, err = ag.options.BlobStore.StoreBlob(ctx, snapshotID, localFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to store blob from local file: %w", err)
|
||||
}
|
||||
|
||||
// 3. Create and save snapshot metadata
|
||||
// We get the file list from the archive to create the metadata.
|
||||
// Note: This method does not calculate file hashes, so the metadata will be incomplete.
|
||||
// This is a limitation of the current implementation.
|
||||
var files []store.FileInfo
|
||||
archiveFiles, err := archive.ListArchiveContents(localPath)
|
||||
if err != nil {
|
||||
// If we can't list the contents, we can't create the metadata.
|
||||
// We should clean up the blob we just stored.
|
||||
_ = ag.options.BlobStore.DeleteBlob(ctx, snapshotID)
|
||||
return fmt.Errorf("failed to list archive contents for metadata creation: %w", err)
|
||||
}
|
||||
|
||||
for _, f := range archiveFiles {
|
||||
files = append(files, store.FileInfo{
|
||||
Path: f.Path,
|
||||
Size: int64(f.Size),
|
||||
IsDir: f.IsDir,
|
||||
// SHA256 is intentionally left empty as we don't have it.
|
||||
})
|
||||
}
|
||||
|
||||
snapshot := store.Snapshot{
|
||||
ID: snapshotID,
|
||||
Name: name,
|
||||
ParentID: parentID,
|
||||
CreationTime: time.Now(),
|
||||
Files: files,
|
||||
}
|
||||
|
||||
if err := ag.options.MetadataStore.SaveSnapshotMetadata(ctx, snapshot); err != nil {
|
||||
// Clean up the blob
|
||||
_ = ag.options.BlobStore.DeleteBlob(ctx, snapshotID)
|
||||
return fmt.Errorf("failed to save snapshot metadata: %w", err)
|
||||
}
|
||||
|
||||
ag.options.Logger.Printf("Successfully registered local snapshot %s", snapshotID)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user