Skip to content

Commit efba190

Browse files
authored
Merge pull request #328 from tighten/feat/prompts-enable-list
Use Prompts
2 parents 49f599d + c98d2e4 commit efba190

26 files changed

+536
-969
lines changed

.github/workflows/run-tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
uses: shivammathur/setup-php@v2
2525
with:
2626
php-version: ${{ matrix.php }}
27-
extensions: posix, dom, curl, libxml, fileinfo, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick
27+
extensions: dom, curl, libxml, fileinfo, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, sockets
2828
coverage: none
2929

3030
- name: Install dependencies

README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,19 @@ The recommended way to install Takeout is the dockerized version via an alias (a
3232
On Linux or macOS, use:
3333

3434
```bash
35-
alias takeout="docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -it tighten/takeout:latest"
35+
alias takeout="docker run --rm -v /var/run/docker.sock:/var/run/docker.sock --add-host=host.docker.internal:host-gateway -it tighten/takeout:latest"
3636
```
3737

38-
On Windows 10, if you're using Bash, use:
38+
On Windows 10|11, if you're using Bash, use:
3939

4040
```bash
41-
alias takeout="docker run --rm -v //var/run/docker.sock:/var/run/docker.sock -it tighten/takeout:latest"
41+
alias takeout="docker run --rm -v //var/run/docker.sock:/var/run/docker.sock --add-host=host.docker.internal:host-gateway -it tighten/takeout:latest"
4242
```
4343

44-
On Windows 10, if you're using PowerShell, use:
44+
On Windows 10|11, if you're using PowerShell, use:
4545

4646
```bash
47-
function takeout { docker run --rm -v //var/run/docker.sock:/var/run/docker.sock -it tighten/takeout:latest $args }
47+
function takeout { docker run --rm -v //var/run/docker.sock:/var/run/docker.sock --add-host=host.docker.internal:host-gateway -it tighten/takeout:latest $args }
4848
```
4949
5050
That's it. You may now use Takeout on your terminal. The first time you use this alias, it will pull the Takeout image from Docker Hub.

app/Commands/DisableCommand.php

+36-65
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@
55
use App\InitializesCommands;
66
use App\Shell\Docker;
77
use App\Shell\Environment;
8+
use Illuminate\Support\Collection;
89
use LaravelZero\Framework\Commands\Command;
910
use Throwable;
11+
use Illuminate\Support\Str;
12+
13+
use function Laravel\Prompts\confirm;
14+
use function Laravel\Prompts\select;
1015

1116
class DisableCommand extends Command
1217
{
@@ -25,100 +30,75 @@ public function handle(Docker $docker, Environment $environment)
2530
$this->docker = $docker;
2631
$this->environment = $environment;
2732
$this->initializeCommand();
28-
$this->disableableServices = $this->disableableServices();
33+
34+
$disableableServices = $this->disableableServices();
2935

3036
if ($this->option('all')) {
31-
foreach ($this->disableableServices as $containerId => $name) {
37+
$disableableServices->keys()->each(function ($containerId) {
3238
$this->disableByContainerId($containerId);
33-
}
39+
});
3440

3541
return;
3642
}
3743

38-
if (empty($this->disableableServices)) {
44+
if ($disableableServices->isEmpty()) {
3945
$this->info("There are no containers to disable.\n");
4046

4147
return;
4248
}
4349

4450
if (filled($services = $this->argument('serviceNames'))) {
4551
foreach ($services as $service) {
46-
$this->disableByServiceName($service);
52+
$this->disableByServiceName($service, $disableableServices);
4753
}
4854

4955
return;
5056
}
5157

52-
$this->showDisableServiceMenu();
58+
$this->disableByContainerId(
59+
$this->selectOptions($disableableServices),
60+
);
5361
}
5462

55-
public function disableableServices(): array
63+
private function disableableServices(): Collection
5664
{
5765
return $this->docker->takeoutContainers()->mapWithKeys(function ($container) {
5866
return [$container['container_id'] => str_replace('TO--', '', $container['names'])];
59-
})->toArray();
67+
});
6068
}
6169

62-
public function disableByServiceName(string $service): void
70+
private function disableByServiceName(string $service, Collection $disableableServices): void
6371
{
64-
$serviceMatches = collect($this->disableableServices)
65-
->filter(function ($containerName) use ($service) {
66-
return substr($containerName, 0, strlen($service)) === $service;
67-
});
68-
69-
switch ($serviceMatches->count()) {
70-
case 0:
71-
$this->error("\nCannot find a Takeout-managed instance of {$service}.");
72+
$serviceMatches = $disableableServices->filter(function ($containerName) use ($service) {
73+
return Str::startsWith($containerName, $service);
74+
});
7275

73-
return;
74-
case 1:
75-
$serviceContainerId = $serviceMatches->flip()->first();
76-
break;
77-
default: // > 1
78-
$serviceContainerId = $this->selectMenu($this->disableableServices);
76+
if ($serviceMatches->isEmpty()) {
77+
$this->error("\nCannot find a Takeout-managed instance of {$service}.");
7978

80-
if (! $serviceContainerId) {
81-
return;
82-
}
79+
return;
8380
}
8481

85-
$this->disableByContainerId($serviceContainerId);
86-
}
87-
88-
public function showDisableServiceMenu($disableableServices = null): void
89-
{
90-
if ($serviceContainerId = $this->selectMenu($disableableServices ?? $this->disableableServices)) {
91-
$this->disableByContainerId($serviceContainerId);
92-
}
93-
}
82+
if ($serviceMatches->count() === 1) {
83+
$this->disableByContainerId($serviceMatches->flip()->first());
9484

95-
private function selectMenu($disableableServices): ?string
96-
{
97-
if ($this->environment->isWindowsOs()) {
98-
return $this->windowsMenu($disableableServices);
85+
return;
9986
}
10087

101-
return $this->defaultMenu($disableableServices);
88+
$this->disableByContainerId(
89+
$this->selectOptions($disableableServices),
90+
);
10291
}
10392

104-
private function defaultMenu($disableableServices): ?string
93+
private function selectOptions(Collection $disableableServices)
10594
{
106-
return $this->menu(self::MENU_TITLE, $disableableServices)
107-
->addLineBreak('', 1)
108-
->setPadding(2, 5)
109-
->open();
95+
return select(
96+
label: self::MENU_TITLE,
97+
options: $disableableServices
98+
);
11099
}
111100

112-
private function windowsMenu($disableableServices): ?string
113-
{
114-
array_push($disableableServices, '<info>Exit</>');
115-
116-
$choice = $this->choice(self::MENU_TITLE, array_values($disableableServices));
117-
118-
return array_search($choice, $disableableServices);
119-
}
120-
121-
public function disableByContainerId(string $containerId): void
101+
private function disableByContainerId(string $containerId): void
122102
{
123103
try {
124104
$volumeName = $this->docker->attachedVolumeName($containerId);
@@ -134,16 +114,7 @@ public function disableByContainerId(string $containerId): void
134114
if (count($this->docker->allContainers()) === 0) {
135115
$question = 'No containers are running. Turn off Docker?';
136116

137-
if ($this->environment->isWindowsOs()) {
138-
$option = $this->confirm($question);
139-
} else {
140-
$option = $this->menu($question, [
141-
'Yes',
142-
'No',
143-
])->disableDefaultItems()->open();
144-
}
145-
146-
if ($option === 0 || $option === true) {
117+
if (confirm($question)) {
147118
$this->task('Stopping Docker service ', $this->docker->stopDockerService());
148119
}
149120
}

app/Commands/EnableCommand.php

+28-87
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
use App\InitializesCommands;
66
use App\Services;
77
use App\Shell\Environment;
8-
use Illuminate\Support\Arr;
8+
use Illuminate\Support\Collection;
99
use Illuminate\Support\Facades\App;
10-
use Illuminate\Support\Str;
1110
use LaravelZero\Framework\Commands\Command;
1211

12+
use function Laravel\Prompts\search;
13+
1314
class EnableCommand extends Command
1415
{
1516
use InitializesCommands;
@@ -46,21 +47,17 @@ public function handle(Environment $environment, Services $services): void
4647
return;
4748
}
4849

49-
$option = $this->selectService();
50+
$service = $this->selectService($this->availableServices());
5051

51-
if (! $option) {
52-
return;
53-
}
54-
55-
$this->enable($option, $useDefaults, $passthroughOptions);
52+
$this->enable($service, $useDefaults, $passthroughOptions);
5653
}
5754

5855
/**
5956
* Since we're pulling the *full* list of server arguments, not just relying on
6057
* $this->argument, we have to do our own manual overriding for testing scenarios,
6158
* because pulling $_SERVER['argv'] won't give the right results in testing.
6259
*/
63-
public function serverArguments(): array
60+
private function serverArguments(): array
6461
{
6562
if (App::environment() === 'testing') {
6663
$string = array_merge(['takeout', 'enable'], $this->argument('serviceNames'));
@@ -104,7 +101,7 @@ public function extractPassthroughOptions(array $arguments): array
104101
public function removeOptions(array $arguments): array
105102
{
106103
$arguments = collect($arguments)
107-
->reject(fn ($argument) => str_starts_with($argument, '--') && strlen($argument) > 2)
104+
->reject(fn($argument) => str_starts_with($argument, '--') && strlen($argument) > 2)
108105
->values()
109106
->toArray();
110107

@@ -119,91 +116,36 @@ public function removeOptions(array $arguments): array
119116
return array_slice($arguments, $start);
120117
}
121118

122-
private function selectService(): ?string
119+
private function availableServices(): Collection
123120
{
124-
if ($this->environment->isWindowsOs()) {
125-
return $this->windowsMenu();
126-
}
127-
128-
return $this->defaultMenu();
121+
return $this->enableableServicesByCategory()->flatMap(function ($services, $category) {
122+
return $this->menuItemsForServices($services)->mapWithKeys(function ($row, $key) use ($category) {
123+
return [$key => "{$category}: {$row}"];
124+
})->toArray();
125+
});
129126
}
130127

131-
private function defaultMenu(): ?string
128+
private function selectService(Collection $servicesList): ?string
132129
{
133-
$option = $this->menu(self::MENU_TITLE)->setTitleSeparator('=');
134-
135-
foreach ($this->enableableServicesByCategory() as $category => $services) {
136-
$separator = str_repeat('-', 1 + Str::length($category));
137-
138-
$option->addStaticItem("{$category}:")
139-
->addStaticItem($separator)
140-
->addOptions($this->menuItemsForServices($services))
141-
->addLineBreak('', 1);
142-
}
143-
144-
return $option->open();
130+
return search(
131+
label: self::MENU_TITLE,
132+
options: fn(string $value) => strlen($value) > 0
133+
? $servicesList->filter(function ($row) use ($value) {
134+
return str($row)->lower()->contains(str($value)->lower());
135+
})->toArray()
136+
: $servicesList->toArray(),
137+
scroll: 10
138+
);
145139
}
146140

147-
private function windowsMenu($category = null): ?string
148-
{
149-
$choices = [];
150-
$groupedServices = $this->enableableServicesByCategory();
151-
152-
if ($category) {
153-
$groupedServices = Arr::where($groupedServices, function ($value, $key) use ($category) {
154-
return Str::contains($category, strtoupper($key));
155-
});
156-
}
157-
158-
foreach ($groupedServices as $serviceCategory => $services) {
159-
$serviceCategoryMenuItem = '<fg=white;bg=blue;options=bold> ' . (Str::upper($serviceCategory)) . ' </>';
160-
array_push($choices, $serviceCategoryMenuItem);
161-
162-
foreach ($this->menuItemsForServices($services) as $menuItemKey => $menuItemName) {
163-
array_push($choices, $menuItemName);
164-
}
165-
}
166-
167-
if ($category) {
168-
array_push($choices, '<info>Back</>');
169-
}
170-
171-
array_push($choices, '<info>Exit</>');
172-
173-
$choice = $this->choice(self::MENU_TITLE, $choices);
174-
175-
if (Str::contains($choice, 'Back')) {
176-
return $this->windowsMenu();
177-
}
178-
179-
if (Str::contains($choice, 'Exit')) {
180-
return null;
181-
}
182-
183-
foreach ($this->enableableServices() as $shortName => $fqcn) {
184-
if ($choice === $fqcn) {
185-
return $shortName;
186-
}
187-
}
188-
189-
return $this->windowsMenu($choice);
190-
}
191-
192-
private function menuItemsForServices($services): array
141+
private function menuItemsForServices($services): Collection
193142
{
194143
return collect($services)->mapWithKeys(function ($service) {
195144
return [$service['shortName'] => $service['name']];
196-
})->toArray();
145+
});
197146
}
198147

199-
public function enableableServices(): array
200-
{
201-
return collect($this->services->all())->mapWithKeys(function ($fqcn, $shortName) {
202-
return [$shortName => $fqcn::name()];
203-
})->toArray();
204-
}
205-
206-
public function enableableServicesByCategory(): array
148+
private function enableableServicesByCategory(): Collection
207149
{
208150
return collect($this->services->all())
209151
->mapToGroups(function ($fqcn, $shortName) {
@@ -214,11 +156,10 @@ public function enableableServicesByCategory(): array
214156
],
215157
];
216158
})
217-
->sortKeys()
218-
->toArray();
159+
->sortKeys();
219160
}
220161

221-
public function enable(
162+
private function enable(
222163
string $service,
223164
bool $useDefaults = false,
224165
array $passthroughOptions = [],

app/Commands/ListCommand.php

+5-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
use App\Shell\Docker;
88
use LaravelZero\Framework\Commands\Command;
99

10+
use function Laravel\Prompts\info;
11+
use function Laravel\Prompts\table;
12+
1013
class ListCommand extends Command
1114
{
1215
use InitializesCommands;
@@ -31,15 +34,14 @@ public function handle(Docker $docker): void
3134
}
3235

3336
if ($containersCollection->isEmpty()) {
34-
$this->info("No Takeout containers are enabled.\n");
37+
info('No Takeout containers are enabled.');
3538

3639
return;
3740
}
3841

3942
$containers = $containersCollection->toArray();
4043
$columns = array_map('App\title_from_slug', array_keys(reset($containers)));
4144

42-
$this->line("\n");
43-
$this->table($columns, $containers);
45+
table($columns, $containers);
4446
}
4547
}

0 commit comments

Comments
 (0)