Skip to content

Commit

Permalink
cmd/atlas: rename dsn to url
Browse files Browse the repository at this point in the history
  • Loading branch information
a8m committed Feb 28, 2022
1 parent c4a851f commit 7f96b98
Show file tree
Hide file tree
Showing 13 changed files with 128 additions and 115 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ Instructions for other platforms and databases: [Getting Started](https://atlasg

Inspect and save output to a schema file.
```shell
atlas schema inspect -d "mysql://root:pass@tcp(localhost:3306)/example" > atlas.hcl
atlas schema inspect -u "mysql://root:pass@tcp(localhost:3306)/example" > atlas.hcl
```

## Apply change to Schema

```shell
atlas schema apply -d "mysql://root:pass@tcp(localhost:3306)/example" -f atlas.hcl
atlas schema apply -u "mysql://root:pass@tcp(localhost:3306)/example" -f atlas.hcl
```

Full [CLI documentation](https://atlasgo.io/cli/reference).
Expand Down
46 changes: 33 additions & 13 deletions cmd/action/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package action

import (
"context"
"errors"
"io/ioutil"
"strings"

Expand All @@ -18,7 +19,7 @@ import (
var (
// ApplyFlags are the flags used in Apply command.
ApplyFlags struct {
DSN string
URL string
File string
Web bool
Addr string
Expand All @@ -36,12 +37,12 @@ plan and prompt the user for approval.
If run with the "--dry-run" flag, atlas will exit after printing out the planned migration.`,
Run: CmdApplyRun,
Example: `atlas schema apply -d "mysql://user:pass@tcp(localhost:3306)/dbname" -f atlas.hcl
atlas schema apply -d "mysql://user:pass@tcp(localhost:3306)/" -f atlas.hcl --schema prod --schema staging
atlas schema apply -d "mysql://user:pass@tcp(localhost:3306)/dbname" -f atlas.hcl --dry-run
atlas schema apply -d "mariadb://user:pass@tcp(localhost:3306)/dbname" -f atlas.hcl
atlas schema apply --dsn "postgres://user:pass@host:port/dbname?sslmode=disable" -f atlas.hcl
atlas schema apply -d "sqlite://file:ex1.db?_fk=1" -f atlas.hcl`,
Example: ` atlas schema apply -u "mysql://user:pass@tcp(localhost:3306)/dbname" -f atlas.hcl
atlas schema apply -u "mysql://user:pass@tcp(localhost:3306)/" -f atlas.hcl --schema prod --schema staging
atlas schema apply -u "mysql://user:pass@tcp(localhost:3306)/dbname" -f atlas.hcl --dry-run
atlas schema apply -u "mariadb://user:pass@tcp(localhost:3306)/dbname" -f atlas.hcl
atlas schema apply --url "postgres://user:pass@host:port/dbname?sslmode=disable" -f atlas.hcl
atlas schema apply -u "sqlite://file:ex1.db?_fk=1" -f atlas.hcl`,
}
)

Expand All @@ -52,15 +53,16 @@ const (

func init() {
schemaCmd.AddCommand(ApplyCmd)
ApplyCmd.Flags().StringVarP(&ApplyFlags.DSN, "dsn", "d", "", "[driver://username:password@protocol(address)/dbname?param=value] Select data source using the dsn format")
ApplyCmd.Flags().StringVarP(&ApplyFlags.URL, "url", "u", "", "[driver://username:password@protocol(address)/dbname?param=value] Select data source using the url format")
ApplyCmd.Flags().StringVarP(&ApplyFlags.File, "file", "f", "", "[/path/to/file] file containing schema")
ApplyCmd.Flags().BoolVarP(&ApplyFlags.Web, "web", "w", false, "Open in a local Atlas UI")
ApplyCmd.Flags().BoolVarP(&ApplyFlags.DryRun, "dry-run", "", false, "Dry-run. Print SQL plan without prompting for execution")
ApplyCmd.Flags().StringVarP(&ApplyFlags.Addr, "addr", "", "127.0.0.1:5800", "used with -w, local address to bind the server to")
ApplyCmd.Flags().StringSliceVarP(&ApplyFlags.Schema, "schema", "s", nil, "Set schema name")
ApplyCmd.Flags().BoolVarP(&ApplyFlags.AutoApprove, "auto-approve", "", false, "Auto approve. Apply the schema changes without prompting for approval")
cobra.CheckErr(ApplyCmd.MarkFlagRequired("dsn"))
cobra.CheckErr(ApplyCmd.MarkFlagRequired("url"))
cobra.CheckErr(ApplyCmd.MarkFlagRequired("file"))
dsn2url(ApplyCmd, &ApplyFlags.URL)
}

// CmdApplyRun is the command used when running CLI.
Expand All @@ -69,15 +71,15 @@ func CmdApplyRun(cmd *cobra.Command, args []string) {
schemaCmd.PrintErrln("The Atlas UI is not available in this release.")
return
}
d, err := defaultMux.OpenAtlas(ApplyFlags.DSN)
d, err := defaultMux.OpenAtlas(ApplyFlags.URL)
cobra.CheckErr(err)
applyRun(d, ApplyFlags.DSN, ApplyFlags.File, ApplyFlags.DryRun, ApplyFlags.AutoApprove)
applyRun(d, ApplyFlags.URL, ApplyFlags.File, ApplyFlags.DryRun, ApplyFlags.AutoApprove)
}

func applyRun(d *Driver, dsn string, file string, dryRun bool, autoApprove bool) {
func applyRun(d *Driver, url string, file string, dryRun bool, autoApprove bool) {
ctx := context.Background()
schemas := ApplyFlags.Schema
if n, err := SchemaNameFromDSN(dsn); n != "" {
if n, err := SchemaNameFromURL(url); n != "" {
cobra.CheckErr(err)
schemas = append(schemas, n)
}
Expand Down Expand Up @@ -135,3 +137,21 @@ func promptUser() bool {
cobra.CheckErr(err)
return result == answerApply
}

func dsn2url(cmd *cobra.Command, p *string) {
cmd.Flags().StringVarP(p, "dsn", "d", "", "")
cobra.CheckErr(cmd.Flags().MarkHidden("dsn"))
cmd.PreRunE = func(cmd *cobra.Command, args []string) error {
dsnF, urlF := cmd.Flag("dsn"), cmd.Flag("url")
switch {
case !dsnF.Changed && !urlF.Changed:
return errors.New(`required flag "url" was not set`)
case dsnF.Changed && urlF.Changed:
return errors.New(`both flags "url" and "dsn" were set`)
case dsnF.Changed && !urlF.Changed:
urlF.Changed = true
urlF.Value = dsnF.Value
}
return nil
}
}
16 changes: 8 additions & 8 deletions cmd/action/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import (
)

type diffCmdOpts struct {
fromDSN string
toDSN string
fromURL string
toURL string
}

// newDiffCmd returns a new *cobra.Command that runs cmdDiffRun with the given flags and mux.
Expand All @@ -29,8 +29,8 @@ SQL statements to migrate the "from" database to the schema of the "to" database
cmdDiffRun(cmd, &opts)
},
}
cmd.Flags().StringVarP(&opts.fromDSN, "from", "", "", "[driver://username:password@protocol(address)/dbname?param=value] Select data source using the dsn format")
cmd.Flags().StringVarP(&opts.toDSN, "to", "", "", "[driver://username:password@protocol(address)/dbname?param=value] Select data source using the dsn format")
cmd.Flags().StringVarP(&opts.fromURL, "from", "", "", "[driver://username:password@protocol(address)/dbname?param=value] Select data source using the url format")
cmd.Flags().StringVarP(&opts.toURL, "to", "", "", "[driver://username:password@protocol(address)/dbname?param=value] Select data source using the url format")
cobra.CheckErr(cmd.MarkFlagRequired("from"))
cobra.CheckErr(cmd.MarkFlagRequired("to"))
return cmd
Expand All @@ -44,13 +44,13 @@ func init() {
// cmdDiffRun connects to the given databases, and prints an SQL plan to get from
// the "from" schema to the "to" schema.
func cmdDiffRun(cmd *cobra.Command, flags *diffCmdOpts) {
fromDriver, err := defaultMux.OpenAtlas(flags.fromDSN)
fromDriver, err := defaultMux.OpenAtlas(flags.fromURL)
cobra.CheckErr(err)
toDriver, err := defaultMux.OpenAtlas(flags.toDSN)
toDriver, err := defaultMux.OpenAtlas(flags.toURL)
cobra.CheckErr(err)
fromName, err := SchemaNameFromDSN(flags.fromDSN)
fromName, err := SchemaNameFromURL(flags.fromURL)
cobra.CheckErr(err)
toName, err := SchemaNameFromDSN(flags.toDSN)
toName, err := SchemaNameFromURL(flags.toURL)
cobra.CheckErr(err)
ctx := context.Background()
fromSchema, err := fromDriver.InspectSchema(ctx, fromName, nil)
Expand Down
4 changes: 2 additions & 2 deletions cmd/action/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestDiffCmd_Synced(t *testing.T) {
require.EqualValues(t, "Schemas are synced, no changes to be made.\n", s)
}

// openSQLite creates a sqlite db, seeds it with the seed query and returns the dsn to it.
// openSQLite creates a sqlite db, seeds it with the seed query and returns the url to it.
func openSQLite(t *testing.T, seed string) string {
f, err := ioutil.TempFile("", "sqlite.db")
require.NoError(t, err)
Expand All @@ -58,7 +58,7 @@ func openSQLite(t *testing.T, seed string) string {
return fmt.Sprintf("sqlite://%s", dsn)
}

func runCmd(cmd *cobra.Command, args... string) (string, error) {
func runCmd(cmd *cobra.Command, args ...string) (string, error) {
var out bytes.Buffer
cmd.SetOut(&out)
cmd.SetArgs(args)
Expand Down
34 changes: 14 additions & 20 deletions cmd/action/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
var (
// InspectFlags are the flags used in Inspect command.
InspectFlags struct {
DSN string
URL string
Web bool
Addr string
Schema []string
Expand All @@ -27,37 +27,31 @@ var (
It then prints to the screen the schema of that database in Atlas DDL syntax. This output can be
saved to a file, commonly by redirecting the output to a file named with a ".hcl" suffix:
atlas schema inspect -d "mysql://user:pass@tcp(localhost:3306)/dbname" > atlas.hcl
atlas schema inspect -u "mysql://user:pass@tcp(localhost:3306)/dbname" > atlas.hcl
This file can then be edited and used with the` + " `atlas schema apply` " + `command to plan
and execute schema migrations against the given database. In cases where users wish to inspect
all multiple schemas in a given database (for instance a MySQL server may contain multiple named
databases), omit the relevant part from the dsn, e.g. "mysql://user:pass@tcp(localhost:3306)/".
databases), omit the relevant part from the url, e.g. "mysql://user:pass@tcp(localhost:3306)/".
To select specific schemas from the databases, users may use the "--schema" (or "-s" shorthand)
flag.
`,
Run: CmdInspectRun,
Example: `
atlas schema inspect -d "mysql://user:pass@tcp(localhost:3306)/dbname"
atlas schema inspect -d "mariadb://user:pass@tcp(localhost:3306)/" --schema=schemaA,schemaB -s schemaC
atlas schema inspect --dsn "postgres://user:pass@host:port/dbname?sslmode=disable"
atlas schema inspect -d "sqlite://file:ex1.db?_fk=1"`,
Example: ` atlas schema inspect -u "mysql://user:pass@tcp(localhost:3306)/dbname"
atlas schema inspect -u "mariadb://user:pass@tcp(localhost:3306)/" --schema=schemaA,schemaB -s schemaC
atlas schema inspect --url "postgres://user:pass@host:port/dbname?sslmode=disable"
atlas schema inspect -u "sqlite://file:ex1.db?_fk=1"`,
}
)

func init() {
schemaCmd.AddCommand(InspectCmd)
InspectCmd.Flags().StringVarP(
&InspectFlags.DSN,
"dsn",
"d",
"",
"[driver://username:password@protocol(address)/dbname?param=value] Select data source using the dsn format",
)
InspectCmd.Flags().StringVarP(&InspectFlags.URL, "url", "u", "", "[driver://username:password@protocol(address)/dbname?param=value] Select data source using the url format")
InspectCmd.Flags().BoolVarP(&InspectFlags.Web, "web", "w", false, "Open in a local Atlas UI")
InspectCmd.Flags().StringVarP(&InspectFlags.Addr, "addr", "", "127.0.0.1:5800", "Used with -w, local address to bind the server to")
InspectCmd.Flags().StringSliceVarP(&InspectFlags.Schema, "schema", "s", nil, "Set schema name")
cobra.CheckErr(InspectCmd.MarkFlagRequired("dsn"))
cobra.CheckErr(InspectCmd.MarkFlagRequired("url"))
dsn2url(InspectCmd, &InspectFlags.URL)
}

// CmdInspectRun is the command used when running CLI.
Expand All @@ -66,15 +60,15 @@ func CmdInspectRun(_ *cobra.Command, _ []string) {
schemaCmd.PrintErrln("The Atlas UI is not available in this release.")
return
}
d, err := defaultMux.OpenAtlas(InspectFlags.DSN)
d, err := defaultMux.OpenAtlas(InspectFlags.URL)
cobra.CheckErr(err)
inspectRun(d, InspectFlags.DSN)
inspectRun(d, InspectFlags.URL)
}

func inspectRun(d *Driver, dsn string) {
func inspectRun(d *Driver, url string) {
ctx := context.Background()
schemas := InspectFlags.Schema
if n, err := SchemaNameFromDSN(dsn); n != "" {
if n, err := SchemaNameFromURL(url); n != "" {
cobra.CheckErr(err)
schemas = append(schemas, n)
}
Expand Down
22 changes: 11 additions & 11 deletions cmd/action/mux.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
)

type (
// Mux is used for routing dsn to correct provider.
// Mux is used for routing URLs to their correct provider.
Mux struct {
providers map[string]func(string) (*Driver, error)
}
Expand Down Expand Up @@ -56,8 +56,8 @@ func (u *Mux) RegisterProvider(key string, p func(string) (*Driver, error)) {
}

// OpenAtlas is used for opening an atlas driver on a specific data source.
func (u *Mux) OpenAtlas(dsn string) (*Driver, error) {
key, dsn, err := parseDSN(dsn)
func (u *Mux) OpenAtlas(url string) (*Driver, error) {
key, dsn, err := urlParts(url)
if err != nil {
return nil, fmt.Errorf("failed to init atlas driver, %s", err)
}
Expand All @@ -73,17 +73,17 @@ func (u *Mux) OpenAtlas(dsn string) (*Driver, error) {
return p(dsn)
}

func parseDSN(url string) (string, string, error) {
func urlParts(url string) (string, string, error) {
a := strings.SplitN(url, "://", 2)
if len(a) != 2 {
return "", "", fmt.Errorf(`failed to parse dsn: "%s"`, url)
return "", "", fmt.Errorf(`failed to parse url: "%s"`, url)
}
return a[0], a[1], nil
}

// SchemaNameFromDSN parses the dsn the returns schema name
func SchemaNameFromDSN(url string) (string, error) {
key, dsn, err := parseDSN(url)
// SchemaNameFromURL parses the url the returns schema name
func SchemaNameFromURL(url string) (string, error) {
key, dsn, err := urlParts(url)
if err != nil {
return "", err
}
Expand All @@ -104,15 +104,15 @@ func SchemaNameFromDSN(url string) (string, error) {
}

func postgresSchema(dsn string) (string, error) {
url, err := url.Parse(dsn)
u, err := url.Parse(dsn)
if err != nil {
return "", err
}
// lib/pq supports setting default schemas via the `search_path` parameter
// in a dsn.
// in a url.
//
// See: https://github.com/lib/pq/blob/8446d16b8935fdf2b5c0fe333538ac395e3e1e4b/conn.go#L1155-L1165
if schema := url.Query().Get("search_path"); schema != "" {
if schema := u.Query().Get("search_path"); schema != "" {
return schema, nil
}
return "", nil
Expand Down
Loading

0 comments on commit 7f96b98

Please sign in to comment.