Skip to content

Commit

Permalink
Merge pull request #328 from tighten/feat/prompts-enable-list
Browse files Browse the repository at this point in the history
Use Prompts
  • Loading branch information
tonysm authored Jan 3, 2025
2 parents 49f599d + c98d2e4 commit efba190
Show file tree
Hide file tree
Showing 26 changed files with 536 additions and 969 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: posix, dom, curl, libxml, fileinfo, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick
extensions: dom, curl, libxml, fileinfo, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, sockets
coverage: none

- name: Install dependencies
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@ The recommended way to install Takeout is the dockerized version via an alias (a
On Linux or macOS, use:

```bash
alias takeout="docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -it tighten/takeout:latest"
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"
```

On Windows 10, if you're using Bash, use:
On Windows 10|11, if you're using Bash, use:

```bash
alias takeout="docker run --rm -v //var/run/docker.sock:/var/run/docker.sock -it tighten/takeout:latest"
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"
```

On Windows 10, if you're using PowerShell, use:
On Windows 10|11, if you're using PowerShell, use:

```bash
function takeout { docker run --rm -v //var/run/docker.sock:/var/run/docker.sock -it tighten/takeout:latest $args }
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 }
```
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.
Expand Down
101 changes: 36 additions & 65 deletions app/Commands/DisableCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
use App\InitializesCommands;
use App\Shell\Docker;
use App\Shell\Environment;
use Illuminate\Support\Collection;
use LaravelZero\Framework\Commands\Command;
use Throwable;
use Illuminate\Support\Str;

use function Laravel\Prompts\confirm;
use function Laravel\Prompts\select;

class DisableCommand extends Command
{
Expand All @@ -25,100 +30,75 @@ public function handle(Docker $docker, Environment $environment)
$this->docker = $docker;
$this->environment = $environment;
$this->initializeCommand();
$this->disableableServices = $this->disableableServices();

$disableableServices = $this->disableableServices();

if ($this->option('all')) {
foreach ($this->disableableServices as $containerId => $name) {
$disableableServices->keys()->each(function ($containerId) {
$this->disableByContainerId($containerId);
}
});

return;
}

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

return;
}

if (filled($services = $this->argument('serviceNames'))) {
foreach ($services as $service) {
$this->disableByServiceName($service);
$this->disableByServiceName($service, $disableableServices);
}

return;
}

$this->showDisableServiceMenu();
$this->disableByContainerId(
$this->selectOptions($disableableServices),
);
}

public function disableableServices(): array
private function disableableServices(): Collection
{
return $this->docker->takeoutContainers()->mapWithKeys(function ($container) {
return [$container['container_id'] => str_replace('TO--', '', $container['names'])];
})->toArray();
});
}

public function disableByServiceName(string $service): void
private function disableByServiceName(string $service, Collection $disableableServices): void
{
$serviceMatches = collect($this->disableableServices)
->filter(function ($containerName) use ($service) {
return substr($containerName, 0, strlen($service)) === $service;
});

switch ($serviceMatches->count()) {
case 0:
$this->error("\nCannot find a Takeout-managed instance of {$service}.");
$serviceMatches = $disableableServices->filter(function ($containerName) use ($service) {
return Str::startsWith($containerName, $service);
});

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

if (! $serviceContainerId) {
return;
}
return;
}

$this->disableByContainerId($serviceContainerId);
}

public function showDisableServiceMenu($disableableServices = null): void
{
if ($serviceContainerId = $this->selectMenu($disableableServices ?? $this->disableableServices)) {
$this->disableByContainerId($serviceContainerId);
}
}
if ($serviceMatches->count() === 1) {
$this->disableByContainerId($serviceMatches->flip()->first());

private function selectMenu($disableableServices): ?string
{
if ($this->environment->isWindowsOs()) {
return $this->windowsMenu($disableableServices);
return;
}

return $this->defaultMenu($disableableServices);
$this->disableByContainerId(
$this->selectOptions($disableableServices),
);
}

private function defaultMenu($disableableServices): ?string
private function selectOptions(Collection $disableableServices)
{
return $this->menu(self::MENU_TITLE, $disableableServices)
->addLineBreak('', 1)
->setPadding(2, 5)
->open();
return select(
label: self::MENU_TITLE,
options: $disableableServices
);
}

private function windowsMenu($disableableServices): ?string
{
array_push($disableableServices, '<info>Exit</>');

$choice = $this->choice(self::MENU_TITLE, array_values($disableableServices));

return array_search($choice, $disableableServices);
}

public function disableByContainerId(string $containerId): void
private function disableByContainerId(string $containerId): void
{
try {
$volumeName = $this->docker->attachedVolumeName($containerId);
Expand All @@ -134,16 +114,7 @@ public function disableByContainerId(string $containerId): void
if (count($this->docker->allContainers()) === 0) {
$question = 'No containers are running. Turn off Docker?';

if ($this->environment->isWindowsOs()) {
$option = $this->confirm($question);
} else {
$option = $this->menu($question, [
'Yes',
'No',
])->disableDefaultItems()->open();
}

if ($option === 0 || $option === true) {
if (confirm($question)) {
$this->task('Stopping Docker service ', $this->docker->stopDockerService());
}
}
Expand Down
115 changes: 28 additions & 87 deletions app/Commands/EnableCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
use App\InitializesCommands;
use App\Services;
use App\Shell\Environment;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Str;
use LaravelZero\Framework\Commands\Command;

use function Laravel\Prompts\search;

class EnableCommand extends Command
{
use InitializesCommands;
Expand Down Expand Up @@ -46,21 +47,17 @@ public function handle(Environment $environment, Services $services): void
return;
}

$option = $this->selectService();
$service = $this->selectService($this->availableServices());

if (! $option) {
return;
}

$this->enable($option, $useDefaults, $passthroughOptions);
$this->enable($service, $useDefaults, $passthroughOptions);
}

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

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

private function selectService(): ?string
private function availableServices(): Collection
{
if ($this->environment->isWindowsOs()) {
return $this->windowsMenu();
}

return $this->defaultMenu();
return $this->enableableServicesByCategory()->flatMap(function ($services, $category) {
return $this->menuItemsForServices($services)->mapWithKeys(function ($row, $key) use ($category) {
return [$key => "{$category}: {$row}"];
})->toArray();
});
}

private function defaultMenu(): ?string
private function selectService(Collection $servicesList): ?string
{
$option = $this->menu(self::MENU_TITLE)->setTitleSeparator('=');

foreach ($this->enableableServicesByCategory() as $category => $services) {
$separator = str_repeat('-', 1 + Str::length($category));

$option->addStaticItem("{$category}:")
->addStaticItem($separator)
->addOptions($this->menuItemsForServices($services))
->addLineBreak('', 1);
}

return $option->open();
return search(
label: self::MENU_TITLE,
options: fn(string $value) => strlen($value) > 0
? $servicesList->filter(function ($row) use ($value) {
return str($row)->lower()->contains(str($value)->lower());
})->toArray()
: $servicesList->toArray(),
scroll: 10
);
}

private function windowsMenu($category = null): ?string
{
$choices = [];
$groupedServices = $this->enableableServicesByCategory();

if ($category) {
$groupedServices = Arr::where($groupedServices, function ($value, $key) use ($category) {
return Str::contains($category, strtoupper($key));
});
}

foreach ($groupedServices as $serviceCategory => $services) {
$serviceCategoryMenuItem = '<fg=white;bg=blue;options=bold> ' . (Str::upper($serviceCategory)) . ' </>';
array_push($choices, $serviceCategoryMenuItem);

foreach ($this->menuItemsForServices($services) as $menuItemKey => $menuItemName) {
array_push($choices, $menuItemName);
}
}

if ($category) {
array_push($choices, '<info>Back</>');
}

array_push($choices, '<info>Exit</>');

$choice = $this->choice(self::MENU_TITLE, $choices);

if (Str::contains($choice, 'Back')) {
return $this->windowsMenu();
}

if (Str::contains($choice, 'Exit')) {
return null;
}

foreach ($this->enableableServices() as $shortName => $fqcn) {
if ($choice === $fqcn) {
return $shortName;
}
}

return $this->windowsMenu($choice);
}

private function menuItemsForServices($services): array
private function menuItemsForServices($services): Collection
{
return collect($services)->mapWithKeys(function ($service) {
return [$service['shortName'] => $service['name']];
})->toArray();
});
}

public function enableableServices(): array
{
return collect($this->services->all())->mapWithKeys(function ($fqcn, $shortName) {
return [$shortName => $fqcn::name()];
})->toArray();
}

public function enableableServicesByCategory(): array
private function enableableServicesByCategory(): Collection
{
return collect($this->services->all())
->mapToGroups(function ($fqcn, $shortName) {
Expand All @@ -214,11 +156,10 @@ public function enableableServicesByCategory(): array
],
];
})
->sortKeys()
->toArray();
->sortKeys();
}

public function enable(
private function enable(
string $service,
bool $useDefaults = false,
array $passthroughOptions = [],
Expand Down
8 changes: 5 additions & 3 deletions app/Commands/ListCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
use App\Shell\Docker;
use LaravelZero\Framework\Commands\Command;

use function Laravel\Prompts\info;
use function Laravel\Prompts\table;

class ListCommand extends Command
{
use InitializesCommands;
Expand All @@ -31,15 +34,14 @@ public function handle(Docker $docker): void
}

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

return;
}

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

$this->line("\n");
$this->table($columns, $containers);
table($columns, $containers);
}
}
Loading

0 comments on commit efba190

Please sign in to comment.