104 lines
2.4 KiB
Go
104 lines
2.4 KiB
Go
package create
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
_ "embed"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/pkg/stdcopy"
|
|
"github.com/go-errors/errors"
|
|
"github.com/spf13/afero"
|
|
"github.com/supabase/cli/internal/utils"
|
|
"github.com/supabase/cli/internal/utils/flags"
|
|
)
|
|
|
|
var (
|
|
//go:embed templates/clone.sh
|
|
cloneScript string
|
|
)
|
|
|
|
func Run(branch string, fsys afero.Fs) error {
|
|
if err := flags.LoadConfig(fsys); err != nil {
|
|
return err
|
|
}
|
|
if err := utils.AssertSupabaseDbIsRunning(); err != nil {
|
|
return err
|
|
}
|
|
|
|
branchPath := filepath.Join(filepath.Dir(utils.CurrBranchPath), branch)
|
|
if err := assertNewBranchIsValid(branchPath, fsys); err != nil {
|
|
return nil
|
|
}
|
|
|
|
var ctx = context.Background()
|
|
if err := createBranch(ctx, branch); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := fsys.MkdirAll(branchPath, 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Println("Created branch " + utils.Aqua(branch) + ".")
|
|
return nil
|
|
}
|
|
|
|
func assertNewBranchIsValid(branchPath string, fsys afero.Fs) error {
|
|
branch := filepath.Base(branchPath)
|
|
|
|
if utils.IsBranchNameReserved(branch) {
|
|
return errors.New("Cannot create branch " + utils.Aqua(branch) + ": branch name is reserved.")
|
|
}
|
|
|
|
if !utils.BranchNamePattern.MatchString(branch) {
|
|
return errors.New("Branch name " + utils.Aqua(branch) + " is invalid. Must match [0-9A-Za-z_-]+.")
|
|
}
|
|
|
|
if _, err := afero.ReadDir(fsys, branchPath); errors.Is(err, os.ErrNotExist) {
|
|
// skip
|
|
} else if err != nil {
|
|
return err
|
|
} else {
|
|
return errors.New("Branch " + utils.Aqua(branch) + " already exists.")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func createBranch(ctx context.Context, branch string) error {
|
|
exec, err := utils.Docker.ContainerExecCreate(ctx, utils.DbId, container.ExecOptions{
|
|
Cmd: []string{"/bin/bash", "-c", cloneScript},
|
|
Env: []string{"DB_NAME=" + branch},
|
|
AttachStderr: true,
|
|
AttachStdout: true,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Read exec output
|
|
resp, err := utils.Docker.ContainerExecAttach(ctx, exec.ID, container.ExecStartOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Close()
|
|
// Capture error details
|
|
var errBuf bytes.Buffer
|
|
if _, err := stdcopy.StdCopy(io.Discard, &errBuf, resp.Reader); err != nil {
|
|
return err
|
|
}
|
|
// Get the exit code
|
|
iresp, err := utils.Docker.ContainerExecInspect(ctx, exec.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if iresp.ExitCode > 0 {
|
|
return errors.New("Error creating branch: " + errBuf.String())
|
|
}
|
|
return nil
|
|
}
|