github.com/omnigres/cli@v0.1.4/cmd/capture.go (about)

     1  package cmd
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"encoding/json"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	"github.com/charmbracelet/lipgloss"
    12  	cloudevents "github.com/cloudevents/sdk-go/v2"
    13  
    14  	"github.com/charmbracelet/log"
    15  	"github.com/omnigres/cli/orb"
    16  	"github.com/samber/lo"
    17  	"github.com/spf13/cobra"
    18  )
    19  
    20  var captureCmd = &cobra.Command{
    21  	Use:   "capture",
    22  	Short: "Capture a revision",
    23  	Long:  `By default, will capture all listed orbs`,
    24  	Run: func(cmd *cobra.Command, args []string) {
    25  		var cluster orb.OrbCluster
    26  		var err error
    27  		cluster, err = getOrbCluster()
    28  		if err != nil {
    29  			log.Fatal(err)
    30  		}
    31  
    32  		log.Debug("Workspace", "workspace", workspace)
    33  		cwd, err := os.Getwd()
    34  		if err != nil {
    35  			log.Fatal(err)
    36  		}
    37  
    38  		orbs, err := currentOrbs(cluster, cwd)
    39  		if err != nil {
    40  			log.Fatal(err)
    41  		}
    42  
    43  		ctx := context.Background()
    44  		log.Debug("Capturing orbs", "orbs", orbs)
    45  		captureOrbs(ctx, cluster, orbs)
    46  	},
    47  }
    48  
    49  func currentOrbs(cluster orb.OrbCluster, dir string) ([]string, error) {
    50  	if dir == workspace {
    51  		// return all orbs when running in workspace root
    52  		return lo.Map(
    53  			cluster.Config().Orbs,
    54  			func(cfg orb.OrbCfg, _ int) string { return cfg.Name },
    55  		), nil
    56  	}
    57  
    58  	parent := filepath.Dir(dir)
    59  	if parent == workspace {
    60  		// First level below workspace, this is the current orb
    61  		cwd, err := os.Getwd()
    62  		return []string{filepath.Base(cwd)}, err
    63  	}
    64  
    65  	if parent == dir {
    66  		// Reached the root, return as in workspace root
    67  		return currentOrbs(cluster, workspace)
    68  	}
    69  
    70  	return currentOrbs(cluster, parent)
    71  }
    72  
    73  func captureSchemaRevision(
    74  	ctx context.Context,
    75  	cluster orb.OrbCluster,
    76  	orbName string,
    77  ) (err error) {
    78  	var db *sql.DB
    79  	db, err = cluster.Connect(ctx, orbName)
    80  	if err != nil {
    81  		return
    82  	}
    83  
    84  	log.Infof("Capturing schema for orb %s", orbName)
    85  	_, err = db.ExecContext(ctx, "create extension if not exists omni_schema cascade")
    86  	if err != nil {
    87  		return err
    88  	}
    89  
    90  	conn, err := db.Conn(ctx)
    91  	if err != nil {
    92  		log.Fatal(err)
    93  	}
    94  	defer conn.Close()
    95  	err = setupCloudevents(ctx, conn)
    96  	if err != nil {
    97  		log.Error(err)
    98  		return err
    99  	}
   100  
   101  	var revision string
   102  	err = conn.QueryRowContext(
   103  		ctx,
   104  		`select omni_schema.capture_schema_revision(omni_vfs.local_fs($1), 'src', 'revisions')`,
   105  		fmt.Sprintf("/mnt/host/%s", orbName),
   106  	).Scan(&revision)
   107  	if err != nil {
   108  		log.Fatal(err)
   109  	}
   110  
   111  	_, err = db.ExecContext(ctx, fmt.Sprintf("drop database \"%s\"", revision))
   112  	if err != nil {
   113  		log.Errorf("Could not remove revision. You can try to manually remove using DROP DATABASE %s", revision)
   114  	}
   115  	log.Infof("📦 Revision %s created", revision)
   116  
   117  	return
   118  }
   119  
   120  func captureOrbs(
   121  	ctx context.Context,
   122  	cluster orb.OrbCluster,
   123  	orbs []string,
   124  ) (err error) {
   125  	var db *sql.DB
   126  	db, err = cluster.Connect(ctx, "omnigres")
   127  	if err != nil {
   128  		log.Error("Could not connect to orb. Ensure the docker container is running, perhaps 'omnigres start' will fix it.")
   129  		return
   130  	}
   131  	for _, orbName := range orbs {
   132  		log.Infof("Capturing orb %s", orbName)
   133  		var dbExists bool
   134  		err := db.QueryRowContext(
   135  			ctx,
   136  			`select exists(select from pg_database where datname = $1)`,
   137  			orbName,
   138  		).Scan(&dbExists)
   139  		if err != nil {
   140  			log.Fatal(err)
   141  		}
   142  
   143  		if !dbExists {
   144  			_, err = db.ExecContext(ctx, fmt.Sprintf(`create database %q`, orbName))
   145  			if err != nil {
   146  				log.Fatal(err)
   147  			}
   148  		}
   149  
   150  		captureSchemaRevision(ctx, cluster, orbName)
   151  	}
   152  	return
   153  }
   154  
   155  func init() {
   156  	handler := cloudeventHandler{
   157  		Callback: func(e *cloudevents.Event) {
   158  			switch e.Type() {
   159  			case "org.omnigres.omni_schema.progress_report.v1":
   160  				message := string(e.Data())
   161  				err := json.Unmarshal(e.Data(), &message)
   162  				if err != nil {
   163  					log.Errorf("Error parsing progress report %s", string(e.Data()))
   164  					return
   165  				}
   166  
   167  				style := lipgloss.NewStyle().
   168  					SetString("⏳ " + message).
   169  					PaddingLeft(2).
   170  					Width(120).
   171  					Foreground(lipgloss.Color("201"))
   172  				fmt.Print(style.Render() + "\r")
   173  			default:
   174  			}
   175  		},
   176  	}
   177  	cloudeventHandlers = append(cloudeventHandlers, handler)
   178  }