Skip to content

Commit 490cf3e

Browse files
authored
Merge pull request #382 from tighten/tm/mssql-express
Change the Microsoft SQL Server base image
2 parents b34f57f + b333550 commit 490cf3e

7 files changed

Lines changed: 100 additions & 88 deletions

File tree

app/Providers/AppServiceProvider.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Providers;
44

5+
use App\Shell\Platform;
56
use Illuminate\Support\ServiceProvider;
67

78
class AppServiceProvider extends ServiceProvider
@@ -23,6 +24,6 @@ public function boot()
2324
*/
2425
public function register()
2526
{
26-
//
27+
$this->app->scoped(Platform::class);
2728
}
2829
}

app/Services/BaseService.php

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,12 @@ public static function name(): string
6868
return static::$displayName ?? Str::afterLast(static::class, '\\');
6969
}
7070

71-
public function enable(bool $useDefaults = false, array $passthroughOptions = [], string $runOptions = null): void
71+
public static function category(): string
72+
{
73+
return static::$category ?? 'Other';
74+
}
75+
76+
public function enable(bool $useDefaults = false, array $passthroughOptions = [], ?string $runOptions = null): void
7277
{
7378
$this->useDefaults = $useDefaults;
7479

@@ -80,9 +85,9 @@ public function enable(bool $useDefaults = false, array $passthroughOptions = []
8085

8186
try {
8287
$this->docker->bootContainer(
83-
join(' ', array_filter([
88+
implode(' ', array_filter([
8489
$runOptions,
85-
$this->sanitizeDockerRunTemplate($this->dockerRunTemplate),
90+
$this->sanitizeDockerRunTemplate($this->dockerRunTemplate()),
8691
$this->buildPassthroughOptionsString($passthroughOptions),
8792
])),
8893
$this->buildParameters(),
@@ -111,11 +116,6 @@ public function forwardShell(): void
111116
$this->docker->forwardShell($service['container_id'], $this->shellCommand());
112117
}
113118

114-
protected function shellCommand(): string
115-
{
116-
return 'bash';
117-
}
118-
119119
public function organization(): string
120120
{
121121
return $this->organization;
@@ -126,11 +126,6 @@ public function imageName(): string
126126
return $this->imageName;
127127
}
128128

129-
public static function category(): string
130-
{
131-
return static::$category ?? 'Other';
132-
}
133-
134129
public function shortName(): string
135130
{
136131
return strtolower(class_basename(static::class));
@@ -146,6 +141,29 @@ public function defaultPort(): int
146141
return $this->defaultPort;
147142
}
148143

144+
public function sanitizeDockerRunTemplate($dockerRunTemplate): string
145+
{
146+
if ($this->environment->isWindowsOs()) {
147+
return stripslashes($dockerRunTemplate);
148+
}
149+
150+
return $dockerRunTemplate;
151+
}
152+
153+
public function buildPassthroughOptionsString(array $passthroughOptions): string
154+
{
155+
if (empty($passthroughOptions)) {
156+
return '';
157+
}
158+
159+
return implode(' ', $passthroughOptions);
160+
}
161+
162+
protected function shellCommand(): string
163+
{
164+
return 'bash';
165+
}
166+
149167
protected function ensureImageIsDownloaded(): void
150168
{
151169
if ($this->docker->imageIsDownloaded($this->organization, $this->imageName, $this->tag)) {
@@ -244,22 +262,4 @@ protected function containerName(): string
244262

245263
return 'TO--' . $this->shortName() . '--' . $this->tag . $portTag;
246264
}
247-
248-
public function sanitizeDockerRunTemplate($dockerRunTemplate): string
249-
{
250-
if ($this->environment->isWindowsOs()) {
251-
return stripslashes($dockerRunTemplate);
252-
}
253-
254-
return $dockerRunTemplate;
255-
}
256-
257-
public function buildPassthroughOptionsString(array $passthroughOptions): string
258-
{
259-
if (empty($passthroughOptions)) {
260-
return '';
261-
}
262-
263-
return join(' ', $passthroughOptions);
264-
}
265265
}

app/Services/MsSql.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
namespace App\Services;
44

55
use App\Shell\MicrosoftDockerTags;
6+
use App\Shell\Platform;
67

78
class MsSql extends BaseService
89
{
910
protected static $category = Category::DATABASE;
1011

12+
protected static $displayName = 'MS SQL Server';
13+
1114
protected $organization = 'mcr.microsoft.com';
12-
protected $imageName = 'azure-sql-edge';
15+
protected $imageName = 'mssql/server';
1316
protected $dockerTagsClass = MicrosoftDockerTags::class;
1417
protected $defaultPort = 1433;
1518
protected $prompts = [
@@ -27,9 +30,20 @@ class MsSql extends BaseService
2730

2831
protected $dockerRunTemplate = '-p "${:port}":1433 \
2932
-e ACCEPT_EULA=Y \
33+
-e MSSQL_PID=Express \
3034
-e SA_PASSWORD="${:sa_password}" \
3135
-v "${:volume}":/var/opt/mssql \
3236
"${:organization}"/"${:image_name}":"${:tag}"';
3337

34-
protected static $displayName = 'MS SQL Server';
38+
public function dockerRunTemplate(): string
39+
{
40+
// The Microsoft image doesn't provide a proper ARM64 build,
41+
// so we need to rely on Rosetta for Mac users. We can do
42+
// that by specifying a platform such as `linux/amd64`.
43+
44+
return match (Platform::isArm()) {
45+
true => '--platform linux/amd64 \\' . PHP_EOL . $this->dockerRunTemplate,
46+
default => $this->dockerRunTemplate,
47+
};
48+
}
3549
}

app/Shell/DockerTags.php

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,9 @@ public function getTags(): Collection
4545
{
4646
$response = json_decode($this->getTagsResponse()->getContents(), true);
4747

48-
$platform = $this->platform();
49-
5048
return collect($response['results'])
51-
->when(in_array($platform, $this->armArchitectures, true), $this->onlyArmImagesFilter())
52-
->when(! in_array($platform, $this->armArchitectures, true), $this->onlyNonArmImagesFilter())
49+
->when(Platform::isArm(), $this->onlyArmImagesFilter())
50+
->when(! Platform::isArm(), $this->onlyNonArmImagesFilter())
5351
->pluck('name')
5452
->sort(new VersionComparator)
5553
->values();
@@ -61,7 +59,7 @@ protected function onlyArmImagesFilter()
6159
return $tags->filter(function ($tag) {
6260
$supportedArchs = collect($tag['images'])->pluck('architecture');
6361

64-
foreach ($this->armArchitectures as $arch) {
62+
foreach (Platform::$armArchitectures as $arch) {
6563
if ($supportedArchs->contains($arch)) {
6664
return true;
6765
}
@@ -85,16 +83,11 @@ protected function onlyNonArmImagesFilter()
8583
// still be other options in the supported architectures
8684
// so we can consider that the tag is not arm-only.
8785

88-
return $supportedArchitectures->diff($this->armArchitectures)->count() > 0;
86+
return $supportedArchitectures->diff(Platform::$armArchitectures)->count() > 0;
8987
});
9088
};
9189
}
9290

93-
protected function platform(): string
94-
{
95-
return php_uname('m');
96-
}
97-
9891
protected function getTagsResponse(): StreamInterface
9992
{
10093
return $this->guzzle

app/Shell/Platform.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace App\Shell;
4+
5+
class Platform
6+
{
7+
public static array $armArchitectures = ['arm64', 'aarch64'];
8+
9+
public function __construct(
10+
private ?string $platform = null,
11+
) {
12+
}
13+
14+
public static function make(): static
15+
{
16+
return resolve(Platform::class);
17+
}
18+
19+
public static function fake(string $platform): Platform
20+
{
21+
return app()->instance(Platform::class, new Platform($platform));
22+
}
23+
24+
public static function isArm(): bool
25+
{
26+
return in_array(static::make()->platform(), static::$armArchitectures, true);
27+
}
28+
29+
protected function platform(): string
30+
{
31+
return $this->platform ??= php_uname('m');
32+
}
33+
}

tests/Feature/DockerTagsTest.php

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,18 @@
55
use App\Services\MySql;
66
use App\Services\PostgreSql;
77
use App\Shell\DockerTags;
8+
use App\Shell\Platform;
89
use GuzzleHttp\Client;
910
use GuzzleHttp\Handler\MockHandler;
1011
use GuzzleHttp\HandlerStack;
1112
use GuzzleHttp\Psr7\Response;
1213
use Mockery as M;
13-
use Tests\Support\FakePlatformDockerTags;
1414
use Tests\TestCase;
1515

1616
class DockerTagsTest extends TestCase
1717
{
18-
public static function armPlatforms(): array
19-
{
20-
return [
21-
[FakePlatformDockerTags::M1_ARM_PLATFORM],
22-
[FakePlatformDockerTags::LINUX_ARM_PLATFORM],
23-
];
24-
}
25-
2618
/** @test */
27-
function it_gets_the_latest_tag_not_named_latest()
19+
public function it_gets_the_latest_tag_not_named_latest()
2820
{
2921
$dockerTags = M::mock(DockerTags::class, [app(Client::class), app(MySql::class)])->makePartial();
3022
$dockerTags->shouldReceive('getTags')->andReturn(collect(['latest', 'some named tag', '1.0.0']));
@@ -33,7 +25,7 @@ function it_gets_the_latest_tag_not_named_latest()
3325
}
3426

3527
/** @test */
36-
function if_latest_is_the_only_tag_it_returns_latest()
28+
public function if_latest_is_the_only_tag_it_returns_latest()
3729
{
3830
$dockerTags = M::mock(DockerTags::class, [app(Client::class), app(MySql::class)])->makePartial();
3931
$dockerTags->shouldReceive('getTags')->andReturn(collect(['latest']));
@@ -42,7 +34,7 @@ function if_latest_is_the_only_tag_it_returns_latest()
4234
}
4335

4436
/** @test */
45-
function it_sorts_the_versions_naturally()
37+
public function it_sorts_the_versions_naturally()
4638
{
4739
$postgres = app(PostgreSql::class);
4840
$dockerTags = app(DockerTags::class, ['service' => $postgres]);
@@ -55,25 +47,30 @@ function it_sorts_the_versions_naturally()
5547
/**
5648
* @test
5749
*
58-
* @dataProvider armPlatforms
50+
* @testWith ["arm64"]
51+
* ["aarch64"]
5952
*/
60-
function it_detects_arm_based_images_when_running_on_arm64_based_host($platform)
53+
public function it_detects_arm_based_images_when_running_on_arm64_based_host($platform)
6154
{
6255
$handlerStack = HandlerStack::create($this->mockImagesResponseHandler());
6356
$client = new Client(['handler' => $handlerStack]);
6457

65-
$dockerTags = (new FakePlatformDockerTags($client, app(MySql::class)))->withFakePlatform($platform);
58+
Platform::fake($platform);
59+
60+
$dockerTags = new DockerTags($client, app(MySql::class));
6661

6762
$this->assertEquals('1.0.0-arm64', $dockerTags->getLatestTag());
6863
}
6964

7065
/** @test */
71-
function it_gets_latest_tag_on_intel_platform()
66+
public function it_gets_latest_tag_on_intel_platform()
7267
{
7368
$handlerStack = HandlerStack::create($this->mockImagesResponseHandler());
7469
$client = new Client(['handler' => $handlerStack]);
7570

76-
$dockerTags = (new FakePlatformDockerTags($client, app(MySql::class)))->withFakePlatform(FakePlatformDockerTags::INTEL_ARM_PLATFORM);
71+
Platform::fake('x86_64');
72+
73+
$dockerTags = new DockerTags($client, app(MySql::class));
7774

7875
$this->assertEquals('1.0.0', $dockerTags->getLatestTag());
7976
}

tests/Support/FakePlatformDockerTags.php

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)