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 }