Skip to content

Commit 964fcb8

Browse files
committed
Saving changes
1 parent 0a8ac1c commit 964fcb8

File tree

18 files changed

+231
-187
lines changed

18 files changed

+231
-187
lines changed

cmd/modern/root.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,12 @@ func (c *Root) SubCommands() []cmdparser.Command {
6868
cmdparser.New[*root.Start](dependencies),
6969
cmdparser.New[*root.Stop](dependencies),
7070
cmdparser.New[*root.Uninstall](dependencies),
71-
cmdparser.New[*root.Use](dependencies),
71+
}
72+
73+
// If the current context is a container, then add the "use" sub-command, so
74+
// databases can be added to the already existing container.
75+
if config.CurrentContextEndpointHasContainer() {
76+
subCommands = append(subCommands, cmdparser.New[*root.Use](dependencies))
7277
}
7378

7479
// BUG(stuartpa): - Add Linux support

cmd/modern/root/install/mssql-base.go

Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package install
55

66
import (
77
"fmt"
8+
"github.com/microsoft/go-sqlcmd/pkg/mssqlcontainer/ingest/mechanism"
89
"runtime"
910
"strings"
1011

@@ -100,11 +101,11 @@ func (c *MssqlBase) AddFlags(
100101
Usage: "Context name (a default context name will be created if not provided)",
101102
})
102103

103-
// BUG(stuartpa): Make this a hidden flag so we don't break existing usage
104104
addFlag(cmdparser.FlagOptions{
105105
String: &c.defaultDatabase,
106106
Name: "user-database",
107107
Shorthand: "u",
108+
Hidden: true,
108109
Usage: "[DEPRECATED use --database] Create a user database and set it as the default for login",
109110
})
110111

@@ -223,11 +224,11 @@ func (c *MssqlBase) AddFlags(
223224
Usage: "Port (next available port from 1433 upwards used by default)",
224225
})
225226

226-
// BUG(stuartpa): Make this a hidden flag so we don't break existing usage
227227
addFlag(cmdparser.FlagOptions{
228228
String: &c.useDatabaseUrl,
229229
DefaultString: "",
230230
Name: "using",
231+
Hidden: true,
231232
Usage: fmt.Sprintf("[DEPRECATED use --use] Download %q and use database", ingest.ValidFileExtensions()),
232233
})
233234

@@ -242,7 +243,7 @@ func (c *MssqlBase) AddFlags(
242243
String: &c.useMechanism,
243244
DefaultString: "",
244245
Name: "use-mechanism",
245-
Usage: "Mechanism to use to bring database online (attach, restore, dacfx)",
246+
Usage: fmt.Sprintf("Mechanism to use to bring database online (%s)", strings.Join(mechanism.Mechanisms(), ",")),
246247
})
247248

248249
addFlag(cmdparser.FlagOptions{
@@ -317,37 +318,7 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
317318
// Do an early exit if url doesn't exist
318319
var useDatabase ingest.Ingest
319320
if c.useDatabaseUrl != "" {
320-
useDatabase = ingest.NewIngest(c.useDatabaseUrl, controller, ingest.IngestOptions{
321-
Mechanism: c.useMechanism,
322-
})
323-
324-
if !useDatabase.IsValidFileExtension() {
325-
output.FatalfWithHints(
326-
[]string{
327-
fmt.Sprintf(
328-
"--using must be a path to a file with a %q extension",
329-
ingest.ValidFileExtensions(),
330-
),
331-
},
332-
"%q is not a valid file extension for --using flag", useDatabase.UserProvidedFileExt())
333-
}
334-
335-
if useDatabase.IsRemoteUrl() && !useDatabase.IsValidScheme() {
336-
output.FatalfWithHints(
337-
[]string{
338-
fmt.Sprintf(
339-
"--using URL must one of %q",
340-
strings.Join(useDatabase.ValidSchemes(), ", "),
341-
),
342-
},
343-
"%q is not a valid URL for --using flag", c.useDatabaseUrl)
344-
}
345-
346-
if !useDatabase.SourceFileExists() {
347-
output.FatalfWithHints(
348-
[]string{fmt.Sprintf("File does not exist at URL %q", c.useDatabaseUrl)},
349-
"Unable to download file")
350-
}
321+
useDatabase = c.verifyUseSourceFileExists(useDatabase, controller, output)
351322
}
352323

353324
if c.defaultDatabase != "" {
@@ -360,18 +331,18 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
360331
c.downloadImage(imageName, output, controller)
361332
}
362333

334+
runOptions := container.RunOptions{
335+
Env: env,
336+
Port: c.port,
337+
Name: c.name,
338+
Hostname: c.hostname,
339+
Architecture: c.architecture,
340+
Os: c.os,
341+
Command: []string{},
342+
}
343+
363344
output.Infof("Starting %v", imageName)
364-
containerId := controller.ContainerRun(
365-
imageName,
366-
env,
367-
c.port,
368-
c.name,
369-
c.hostname,
370-
c.architecture,
371-
c.os,
372-
[]string{},
373-
false,
374-
)
345+
containerId := controller.ContainerRun(imageName, runOptions)
375346
previousContextName := config.CurrentContextName()
376347

377348
userName := pal.UserName()
@@ -396,8 +367,7 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
396367

397368
controller.ContainerWaitForLogEntry(containerId, c.errorLogEntryToWaitFor)
398369

399-
output.Infof(
400-
"Disabled %q account (and rotated %q password). Creating user %q",
370+
output.Infof("Disabled %q account (and rotated %q password). Creating user %q",
401371
"sa",
402372
"sa",
403373
userName)
@@ -488,14 +458,10 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
488458
ads.PersistCredentialForAds(endpoint.EndpointDetails.Address, endpoint, user)
489459

490460
output := c.Output()
491-
args := []string{
492-
"-r",
493-
fmt.Sprintf(
494-
"--server=%s", fmt.Sprintf(
495-
"%s,%d",
496-
"127.0.0.1",
497-
c.port)),
498-
}
461+
args := []string{"-r", fmt.Sprintf("--server=%s", fmt.Sprintf(
462+
"%s,%d",
463+
"127.0.0.1",
464+
c.port))}
499465

500466
args = append(args, fmt.Sprintf("--user=%s",
501467
strings.Replace(userName, `"`, `\"`, -1)))
@@ -510,6 +476,41 @@ func (c *MssqlBase) createContainer(imageName string, contextName string) {
510476
}
511477
}
512478

479+
func (c *MssqlBase) verifyUseSourceFileExists(useDatabase ingest.Ingest, controller *container.Controller, output *output.Output) ingest.Ingest {
480+
useDatabase = ingest.NewIngest(c.useDatabaseUrl, controller, ingest.IngestOptions{
481+
Mechanism: c.useMechanism,
482+
})
483+
484+
if !useDatabase.IsValidFileExtension() {
485+
output.FatalfWithHints(
486+
[]string{
487+
fmt.Sprintf(
488+
"--using must be a path to a file with a %q extension",
489+
ingest.ValidFileExtensions(),
490+
),
491+
},
492+
"%q is not a valid file extension for --using flag", useDatabase.UserProvidedFileExt())
493+
}
494+
495+
if useDatabase.IsRemoteUrl() && !useDatabase.IsValidScheme() {
496+
output.FatalfWithHints(
497+
[]string{
498+
fmt.Sprintf(
499+
"--using URL must one of %q",
500+
strings.Join(useDatabase.ValidSchemes(), ", "),
501+
),
502+
},
503+
"%q is not a valid URL for --using flag", c.useDatabaseUrl)
504+
}
505+
506+
if !useDatabase.SourceFileExists() {
507+
output.FatalfWithHints(
508+
[]string{fmt.Sprintf("File does not exist at URL %q", c.useDatabaseUrl)},
509+
"Unable to download file")
510+
}
511+
return useDatabase
512+
}
513+
513514
// createNonSaUser creates a user (non-sa) and assigns the sysadmin role
514515
// to the user. It also creates a default database with the provided name
515516
// and assigns the default database to the user. Finally, it disables

cmd/modern/root/use.go

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -53,53 +53,43 @@ func (c *Use) DefineCommand(...cmdparser.CommandOptions) {
5353
func (c *Use) run() {
5454
output := c.Output()
5555

56-
if config.CurrentContextName() == "" {
56+
controller := container.NewController()
57+
id := config.ContainerId()
58+
59+
if !controller.ContainerRunning(id) {
5760
output.FatalfWithHintExamples([][]string{
58-
{"To view available contexts", "sqlcmd config get-contexts"},
59-
}, "No current context")
61+
{"Start container for current context", "sqlcmd start"},
62+
}, "Container for current context is not running")
6063
}
61-
if config.CurrentContextEndpointHasContainer() {
62-
controller := container.NewController()
63-
id := config.ContainerId()
64-
65-
if !controller.ContainerRunning(id) {
66-
output.FatalfWithHintExamples([][]string{
67-
{"Start container for current context", "sqlcmd start"},
68-
}, "Container for current context is not running")
69-
}
70-
71-
endpoint, user := config.CurrentContext()
72-
73-
c.sql = sql.New(sql.SqlOptions{UnitTesting: false})
74-
c.sql.Connect(endpoint, user, sql.ConnectOptions{Database: "master", Interactive: false})
75-
76-
useDatabase := ingest.NewIngest(c.url, controller, ingest.IngestOptions{
77-
Mechanism: c.useMechanism,
78-
})
79-
80-
if !useDatabase.SourceFileExists() {
81-
output.FatalfWithHints(
82-
[]string{fmt.Sprintf("File does not exist at URL %q", c.url)},
83-
"Unable to download file to container")
84-
}
85-
86-
useDatabase.CopyToContainer(id)
87-
88-
if useDatabase.IsExtractionNeeded() {
89-
output.Infof("Extracting files from %q", useDatabase.UrlFilename())
90-
useDatabase.Extract()
91-
}
92-
93-
useDatabase.BringOnline(
94-
c.sql.Query,
95-
user.BasicAuth.Username,
96-
secret.Decode(user.BasicAuth.Password, user.BasicAuth.PasswordEncryption),
97-
)
98-
} else {
99-
output.FatalfWithHintExamples([][]string{
100-
{"Create new context with a sql container ", "sqlcmd create mssql"},
101-
}, "Current context does not have a container")
64+
65+
endpoint, user := config.CurrentContext()
66+
67+
c.sql = sql.New(sql.SqlOptions{UnitTesting: false})
68+
c.sql.Connect(endpoint, user, sql.ConnectOptions{Database: "master", Interactive: false})
69+
70+
useDatabase := ingest.NewIngest(c.url, controller, ingest.IngestOptions{
71+
Mechanism: c.useMechanism,
72+
})
73+
74+
if !useDatabase.SourceFileExists() {
75+
output.FatalfWithHints(
76+
[]string{fmt.Sprintf("File does not exist at URL %q", c.url)},
77+
"Unable to download file to container")
10278
}
79+
80+
// Copy source file (e.g. .bak/.bacpac etc.) for database to be made available to container
81+
useDatabase.CopyToContainer(id)
82+
83+
if useDatabase.IsExtractionNeeded() {
84+
output.Infof("Extracting files from %q", useDatabase.UrlFilename())
85+
useDatabase.Extract()
86+
}
87+
88+
useDatabase.BringOnline(
89+
c.sql.Query,
90+
user.BasicAuth.Username,
91+
secret.Decode(user.BasicAuth.Password, user.BasicAuth.PasswordEncryption),
92+
)
10393
}
10494

10595
func (c *Use) query(commandText string) {

internal/cmdparser/cmd.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ func (c *Cmd) AddFlag(options FlagOptions) {
8585
options.Usage)
8686
}
8787
}
88+
89+
if options.Hidden {
90+
c.command.Flags().MarkHidden(options.Name)
91+
}
8892
}
8993

9094
// DefineCommand defines a command with the provided CommandOptions and adds

internal/cmdparser/options.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ type FlagOptions struct {
2828
Shorthand string
2929
Usage string
3030

31+
Hidden bool
32+
3133
String *string
3234
DefaultString string
3335

internal/container/controller.go

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -70,46 +70,39 @@ func (c Controller) EnsureImage(image string) (err error) {
7070
// the ID of the container.
7171
func (c Controller) ContainerRun(
7272
image string,
73-
env []string,
74-
port int,
75-
name string,
76-
hostname string,
77-
architecture string,
78-
os string,
79-
command []string,
80-
unitTestFailure bool,
73+
options RunOptions,
8174
) string {
8275
hostConfig := &container.HostConfig{
8376
PortBindings: nat.PortMap{
8477
nat.Port("1433/tcp"): []nat.PortBinding{
8578
{
8679
HostIP: "0.0.0.0",
87-
HostPort: strconv.Itoa(port),
80+
HostPort: strconv.Itoa(options.Port),
8881
},
8982
},
9083
},
9184
}
9285

9386
platform := specs.Platform{
94-
Architecture: architecture,
95-
OS: os,
87+
Architecture: options.Architecture,
88+
OS: options.Os,
9689
}
9790

9891
resp, err := c.cli.ContainerCreate(context.Background(), &container.Config{
9992
Tty: true,
10093
Image: image,
101-
Cmd: command,
102-
Env: env,
103-
Hostname: hostname,
104-
}, hostConfig, nil, &platform, name)
94+
Cmd: options.Command,
95+
Env: options.Env,
96+
Hostname: options.Hostname,
97+
}, hostConfig, nil, &platform, options.Name)
10598
checkErr(err)
10699

107100
err = c.cli.ContainerStart(
108101
context.Background(),
109102
resp.ID,
110103
types.ContainerStartOptions{},
111104
)
112-
if err != nil || unitTestFailure {
105+
if err != nil || options.UnitTestFailure {
113106
// Remove the container, because we haven't persisted to config yet, so
114107
// uninstall won't work yet
115108
if resp.ID != "" {

0 commit comments

Comments
 (0)