feat: backend native executor implement
This commit is contained in:
@@ -20,6 +20,12 @@ type Identity struct {
|
||||
SHA256 string
|
||||
}
|
||||
|
||||
// Validate checks the exact immutable file identity without reading a file.
|
||||
func (i Identity) Validate() error {
|
||||
_, err := validateIdentity(i)
|
||||
return err
|
||||
}
|
||||
|
||||
// File 是一次原子提交的结果。
|
||||
type File struct {
|
||||
Path string
|
||||
@@ -61,10 +67,10 @@ func (s *Store) Commit(relativePath string, source io.Reader, expected Identity)
|
||||
if err != nil {
|
||||
return File{}, err
|
||||
}
|
||||
if !filepath.IsLocal(relativePath) || relativePath == "." {
|
||||
return File{}, fmt.Errorf("file store path is not a local relative path: %q", relativePath)
|
||||
target, err := s.destination(relativePath)
|
||||
if err != nil {
|
||||
return File{}, err
|
||||
}
|
||||
target := filepath.Join(s.root, filepath.Clean(relativePath))
|
||||
parent := filepath.Dir(target)
|
||||
if err := os.MkdirAll(parent, 0o750); err != nil {
|
||||
return File{}, fmt.Errorf("create destination directory: %w", err)
|
||||
@@ -139,6 +145,36 @@ func (s *Store) Commit(relativePath string, source io.Reader, expected Identity)
|
||||
return File{Path: target, Identity: expected}, nil
|
||||
}
|
||||
|
||||
// Inspect verifies an immutable destination without changing it.
|
||||
// found=false means that the exact destination does not exist.
|
||||
func (s *Store) Inspect(relativePath string, expected Identity) (file File, found bool, err error) {
|
||||
expectedDigest, err := validateIdentity(expected)
|
||||
if err != nil {
|
||||
return File{}, false, err
|
||||
}
|
||||
target, err := s.destination(relativePath)
|
||||
if err != nil {
|
||||
return File{}, false, err
|
||||
}
|
||||
parent := filepath.Dir(target)
|
||||
if _, err := os.Stat(parent); errors.Is(err, os.ErrNotExist) {
|
||||
return File{}, false, nil
|
||||
} else if err != nil {
|
||||
return File{}, false, fmt.Errorf("inspect destination directory: %w", err)
|
||||
}
|
||||
if err := s.verifyParent(parent); err != nil {
|
||||
return File{}, false, err
|
||||
}
|
||||
return verifyExisting(target, expected, expectedDigest)
|
||||
}
|
||||
|
||||
func (s *Store) destination(relativePath string) (string, error) {
|
||||
if !filepath.IsLocal(relativePath) || relativePath == "." {
|
||||
return "", fmt.Errorf("file store path is not a local relative path: %q", relativePath)
|
||||
}
|
||||
return filepath.Join(s.root, filepath.Clean(relativePath)), nil
|
||||
}
|
||||
|
||||
func (s *Store) verifyParent(parent string) error {
|
||||
resolvedParent, err := filepath.EvalSymlinks(parent)
|
||||
if err != nil {
|
||||
|
||||
@@ -38,6 +38,35 @@ func TestStoreCommitsAndReusesImmutableFile(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreInspectsCommittedIdentityWithoutMutation(t *testing.T) {
|
||||
t.Parallel()
|
||||
store, err := New(t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatalf("create file store: %v", err)
|
||||
}
|
||||
content := []byte("immutable backend jar")
|
||||
identity := identityOf(content)
|
||||
if _, err := store.Commit("releases/backend.jar", bytes.NewReader(content), identity); err != nil {
|
||||
t.Fatalf("commit file: %v", err)
|
||||
}
|
||||
inspected, found, err := store.Inspect("releases/backend.jar", identity)
|
||||
if err != nil || !found || inspected.Path == "" || !inspected.Reused {
|
||||
t.Fatalf("inspect committed file: file=%+v found=%t err=%v", inspected, found, err)
|
||||
}
|
||||
_, found, err = store.Inspect("releases/missing.jar", identity)
|
||||
if err != nil || found {
|
||||
t.Fatalf("inspect missing file: found=%t err=%v", found, err)
|
||||
}
|
||||
_, found, err = store.Inspect("missing/directory/backend.jar", identity)
|
||||
if err != nil || found {
|
||||
t.Fatalf("inspect file below missing directory: found=%t err=%v", found, err)
|
||||
}
|
||||
_, _, err = store.Inspect("releases/backend.jar", identityOf([]byte("different")))
|
||||
if !errors.Is(err, ErrDestinationConflict) {
|
||||
t.Fatalf("expected immutable identity conflict, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStoreRejectsMismatchAndNeverPublishesInvalidFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
root := t.TempDir()
|
||||
|
||||
Reference in New Issue
Block a user