func (ws *WorkspaceStore) Remove(obj xpresource.Object) error {
	ws.mu.Lock()
	defer ws.mu.Unlock()
	w, ok := ws.store[obj.GetUID()]
	if !ok {
		return nil
	}
	if err := ws.fs.RemoveAll(w.dir); err != nil {
		return errors.Wrap(err, "cannot remove workspace folder")
	}
	delete(ws.store, obj.GetUID())
	return nil
}
Remove deletes the workspace directory from the filesystem and erases its
record from the store.
package terraform
import (
	"context"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"github.com/crossplane/crossplane-runtime/pkg/logging"
	xpresource "github.com/crossplane/crossplane-runtime/pkg/resource"
	"github.com/pkg/errors"
	"github.com/spf13/afero"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"github.com/crossplane-contrib/terrajet/pkg/config"
	"github.com/crossplane-contrib/terrajet/pkg/resource"
)
type SetupFn func(ctx context.Context, client client.Client, mg xpresource.Managed) (Setup, error)
type ProviderRequirement struct {
	Source  string
	Version string
}
type ProviderConfiguration map[string]interface{}
type Setup struct {
	Version       string
	Requirement   ProviderRequirement
	Configuration ProviderConfiguration
	Env           []string
}
type WorkspaceStoreOption func(*WorkspaceStore)
func WithFs(fs afero.Fs) WorkspaceStoreOption {
	return func(ws *WorkspaceStore) {
		ws.fs = afero.Afero{Fs: fs}
	}
}
func NewWorkspaceStore(l logging.Logger, opts ...WorkspaceStoreOption) *WorkspaceStore {
	ws := &WorkspaceStore{
		store:  map[types.UID]*Workspace{},
		logger: l,
		mu:     sync.Mutex{},
		fs:     afero.Afero{Fs: afero.NewOsFs()},
	}
	for _, f := range opts {
		f(ws)
	}
	return ws
}
type WorkspaceStore struct {
	store  map[types.UID]*Workspace
	logger logging.Logger
	mu sync.Mutex
	fs afero.Afero
}
func (ws *WorkspaceStore) Workspace(ctx context.Context, c resource.SecretClient, tr resource.Terraformed, ts Setup, cfg config.Resource) (*Workspace, error) {
	dir := filepath.Join(ws.fs.GetTempDir(""), string(tr.GetUID()))
	if err := ws.fs.MkdirAll(dir, os.ModePerm); err != nil {
		return nil, errors.Wrap(err, "cannot create directory for workspace")
	}
	fp, err := NewFileProducer(ctx, c, dir, tr, ts, WithConfig(cfg))
	if err != nil {
		return nil, errors.Wrap(err, "cannot create a new file producer")
	}
	_, err = ws.fs.Stat(filepath.Join(fp.Dir, "terraform.tfstate"))
	if xpresource.Ignore(os.IsNotExist, err) != nil {
		return nil, errors.Wrap(err, "cannot stat terraform.tfstate file")
	}
	if os.IsNotExist(err) {
		if err := fp.WriteTFState(); err != nil {
			return nil, errors.Wrap(err, "cannot reproduce tfstate file")
		}
	}
	if err := fp.WriteMainTF(); err != nil {
		return nil, errors.Wrap(err, "cannot write main tf file")
	}
	l := ws.logger.WithValues("workspace", dir)
	ws.mu.Lock()
	w, ok := ws.store[tr.GetUID()]
	if !ok {
		ws.store[tr.GetUID()] = NewWorkspace(dir, WithLogger(l))
		w = ws.store[tr.GetUID()]
	}
	ws.mu.Unlock()
	_, err = ws.fs.Stat(filepath.Join(dir, ".terraform.lock.hcl"))
	if xpresource.Ignore(os.IsNotExist, err) != nil {
		return nil, errors.Wrap(err, "cannot stat init lock file")
	}
	w.env = ts.Env
	if !os.IsNotExist(err) {
		return w, nil
	}
	cmd := exec.CommandContext(ctx, "terraform", "init", "-input=false")
	cmd.Dir = w.dir
	out, err := cmd.CombinedOutput()
	l.Debug("init ended", "out", string(out))
	return w, errors.Wrapf(err, "cannot init workspace: %s", string(out))
}