diff --git a/datasets_test.go b/datasets_test.go index 44d72ab..74c6eb4 100644 --- a/datasets_test.go +++ b/datasets_test.go @@ -12,7 +12,7 @@ func TestDatasets(t *testing.T) { require.NoError(t, err) defer func() { - _ = g.DeleteWorkspace(context.Background(), DeleteWorkspaceOptions{WorkspaceID: workspaceID}) + _ = g.DeleteWorkspace(context.Background(), workspaceID) }() // Create a dataset diff --git a/workspace.go b/workspace.go index cc51e58..aa4f175 100644 --- a/workspace.go +++ b/workspace.go @@ -7,6 +7,7 @@ import ( "fmt" "os" "strings" + "time" ) type NotFoundInWorkspaceError struct { @@ -36,24 +37,13 @@ func (g *GPTScript) CreateWorkspace(ctx context.Context, providerType string, fr return strings.TrimSpace(out), nil } -type DeleteWorkspaceOptions struct { - WorkspaceID string -} - -func (g *GPTScript) DeleteWorkspace(ctx context.Context, opts ...DeleteWorkspaceOptions) error { - var opt DeleteWorkspaceOptions - for _, o := range opts { - if o.WorkspaceID != "" { - opt.WorkspaceID = o.WorkspaceID - } - } - - if opt.WorkspaceID == "" { - opt.WorkspaceID = os.Getenv("GPTSCRIPT_WORKSPACE_ID") +func (g *GPTScript) DeleteWorkspace(ctx context.Context, workspaceID string) error { + if workspaceID == "" { + return fmt.Errorf("workspace ID cannot be empty") } _, err := g.runBasicCommand(ctx, "workspaces/delete", map[string]any{ - "id": opt.WorkspaceID, + "id": workspaceID, "workspaceTool": g.globalOpts.WorkspaceTool, "env": g.globalOpts.Env, }) @@ -218,3 +208,48 @@ func (g *GPTScript) ReadFileInWorkspace(ctx context.Context, filePath string, op return base64.StdEncoding.DecodeString(out) } + +type StatFileInWorkspaceOptions struct { + WorkspaceID string +} + +func (g *GPTScript) StatFileInWorkspace(ctx context.Context, filePath string, opts ...StatFileInWorkspaceOptions) (FileInfo, error) { + var opt StatFileInWorkspaceOptions + for _, o := range opts { + if o.WorkspaceID != "" { + opt.WorkspaceID = o.WorkspaceID + } + } + + if opt.WorkspaceID == "" { + opt.WorkspaceID = os.Getenv("GPTSCRIPT_WORKSPACE_ID") + } + + out, err := g.runBasicCommand(ctx, "workspaces/stat-file", map[string]any{ + "id": opt.WorkspaceID, + "filePath": filePath, + "workspaceTool": g.globalOpts.WorkspaceTool, + "env": g.globalOpts.Env, + }) + if err != nil { + if strings.HasSuffix(err.Error(), fmt.Sprintf("not found: %s/%s", opt.WorkspaceID, filePath)) { + return FileInfo{}, newNotFoundInWorkspaceError(opt.WorkspaceID, filePath) + } + return FileInfo{}, err + } + + var info FileInfo + err = json.Unmarshal([]byte(out), &info) + if err != nil { + return FileInfo{}, err + } + + return info, nil +} + +type FileInfo struct { + WorkspaceID string + Name string + Size int64 + ModTime time.Time +} diff --git a/workspace_test.go b/workspace_test.go index 8881d00..df51a86 100644 --- a/workspace_test.go +++ b/workspace_test.go @@ -8,13 +8,19 @@ import ( "testing" ) +func TestWorkspaceIDRequiredForDelete(t *testing.T) { + if err := g.DeleteWorkspace(context.Background(), ""); err == nil { + t.Error("Expected error but got nil") + } +} + func TestCreateAndDeleteWorkspace(t *testing.T) { id, err := g.CreateWorkspace(context.Background(), "directory") if err != nil { t.Fatalf("Error creating workspace: %v", err) } - err = g.DeleteWorkspace(context.Background(), DeleteWorkspaceOptions{WorkspaceID: id}) + err = g.DeleteWorkspace(context.Background(), id) if err != nil { t.Errorf("Error deleting workspace: %v", err) } @@ -27,7 +33,7 @@ func TestWriteReadAndDeleteFileFromWorkspace(t *testing.T) { } t.Cleanup(func() { - err := g.DeleteWorkspace(context.Background(), DeleteWorkspaceOptions{WorkspaceID: id}) + err := g.DeleteWorkspace(context.Background(), id) if err != nil { t.Errorf("Error deleting workspace: %v", err) } @@ -47,6 +53,28 @@ func TestWriteReadAndDeleteFileFromWorkspace(t *testing.T) { t.Errorf("Unexpected content: %s", content) } + // Stat the file to ensure it exists + fileInfo, err := g.StatFileInWorkspace(context.Background(), "test.txt", StatFileInWorkspaceOptions{WorkspaceID: id}) + if err != nil { + t.Errorf("Error statting file: %v", err) + } + + if fileInfo.WorkspaceID != id { + t.Errorf("Unexpected file workspace ID: %v", fileInfo.WorkspaceID) + } + + if fileInfo.Name != "test.txt" { + t.Errorf("Unexpected file name: %s", fileInfo.Name) + } + + if fileInfo.Size != 4 { + t.Errorf("Unexpected file size: %d", fileInfo.Size) + } + + if fileInfo.ModTime.IsZero() { + t.Errorf("Unexpected file mod time: %v", fileInfo.ModTime) + } + // Ensure we get the error we expect when trying to read a non-existent file _, err = g.ReadFileInWorkspace(context.Background(), "test1.txt", ReadFileInWorkspaceOptions{WorkspaceID: id}) if nf := (*NotFoundInWorkspaceError)(nil); !errors.As(err, &nf) { @@ -66,7 +94,7 @@ func TestLsComplexWorkspace(t *testing.T) { } t.Cleanup(func() { - err := g.DeleteWorkspace(context.Background(), DeleteWorkspaceOptions{WorkspaceID: id}) + err := g.DeleteWorkspace(context.Background(), id) if err != nil { t.Errorf("Error deleting workspace: %v", err) } @@ -139,7 +167,7 @@ func TestCreateAndDeleteWorkspaceS3(t *testing.T) { t.Fatalf("Error creating workspace: %v", err) } - err = g.DeleteWorkspace(context.Background(), DeleteWorkspaceOptions{WorkspaceID: id}) + err = g.DeleteWorkspace(context.Background(), id) if err != nil { t.Errorf("Error deleting workspace: %v", err) } @@ -156,7 +184,7 @@ func TestWriteReadAndDeleteFileFromWorkspaceS3(t *testing.T) { } t.Cleanup(func() { - err := g.DeleteWorkspace(context.Background(), DeleteWorkspaceOptions{WorkspaceID: id}) + err := g.DeleteWorkspace(context.Background(), id) if err != nil { t.Errorf("Error deleting workspace: %v", err) } @@ -176,6 +204,28 @@ func TestWriteReadAndDeleteFileFromWorkspaceS3(t *testing.T) { t.Errorf("Unexpected content: %s", content) } + // Stat the file to ensure it exists + fileInfo, err := g.StatFileInWorkspace(context.Background(), "test.txt", StatFileInWorkspaceOptions{WorkspaceID: id}) + if err != nil { + t.Errorf("Error statting file: %v", err) + } + + if fileInfo.WorkspaceID != id { + t.Errorf("Unexpected file workspace ID: %v", fileInfo.WorkspaceID) + } + + if fileInfo.Name != "test.txt" { + t.Errorf("Unexpected file name: %s", fileInfo.Name) + } + + if fileInfo.Size != 4 { + t.Errorf("Unexpected file size: %d", fileInfo.Size) + } + + if fileInfo.ModTime.IsZero() { + t.Errorf("Unexpected file mod time: %v", fileInfo.ModTime) + } + // Ensure we get the error we expect when trying to read a non-existent file _, err = g.ReadFileInWorkspace(context.Background(), "test1.txt", ReadFileInWorkspaceOptions{WorkspaceID: id}) if nf := (*NotFoundInWorkspaceError)(nil); !errors.As(err, &nf) { @@ -199,7 +249,7 @@ func TestLsComplexWorkspaceS3(t *testing.T) { } t.Cleanup(func() { - err := g.DeleteWorkspace(context.Background(), DeleteWorkspaceOptions{WorkspaceID: id}) + err := g.DeleteWorkspace(context.Background(), id) if err != nil { t.Errorf("Error deleting workspace: %v", err) }