Skip to content

Commit e515c14

Browse files
committed
Refactored start command
Start no longer outputs every attempt to start a service Dependencies will only be asked once instead of for every service with dependencies Added more docs about managing services Removed unused option from copy
1 parent fd4708b commit e515c14

File tree

4 files changed

+159
-42
lines changed

4 files changed

+159
-42
lines changed

readme.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,79 @@ for container names are:
321321
The import does not try to determine dependencies and will use the folder name as the project
322322
and dirname values.
323323

324+
### Working with services
325+
326+
#### Starting
327+
328+
`spm` provides several wrappers to help with starting / stopping and getting an overview of the
329+
current projects services. All services commands are prefixed with `services:`. Once you have
330+
added some services you can list them: `spm services:list` and then start one or more:
331+
`spm services:start service1 service2 service3` or start all of the services:
332+
`spm services:start all`. `services:start` is aliased to `start`
333+
334+
If you have defined dependencies and have not specified either `-d` to automatically start
335+
dependencies, or `-D` to not start dependencies; you will be prompted if you wish to start
336+
the dependencies first or not. If you opt to start services, then all dependencies will be
337+
resolved and started first. You will not be prompted again after being asked the first time.
338+
339+
#### Status Overview
340+
341+
To get an overview of the current project services: `spm services:status`. This will query
342+
Docker to get assorted data about all containers that match the preset compose name from the
343+
project config and display the information in a table. This information includes:
344+
345+
* running container name
346+
* current status (up/down etc)
347+
* the host if it has been set e.g. for traefik or the IP for the external DB connection
348+
* external port(s)
349+
* any volumes connected to the container
350+
351+
#### Stopping
352+
353+
To stop a service use: `spm services:stop service1 service2` or `spm services:stop all` to stop
354+
all running services. Services that have dependencies will automatically cause dependent services
355+
to be stopped as well. For example: if you have a main data service that provides databases and
356+
your apps depend on this and you stop it, then all the dependent services will be stopped first.
357+
`services:stop` is aliased to `stop`.
358+
359+
The docker logs can be viewed by running: `spm services:log service` or use the alias `log`. Add
360+
`-f` to follow the log and use Ctrl+C to stop.
361+
362+
#### Rebuilding / cleaning the docker containers
363+
364+
If you encounter major issues with your containers or just want to reset to a completely clean
365+
state, either use: `docker system prune --all --volumes` or `spm services:reset`. The `spm`
366+
command calls the same options under-the-hood.
367+
368+
For less drastic rebuilds, the `services:start` command allows for:
369+
370+
* `--rebuild / -b` - rebuild containers and then start
371+
* `--refresh / -r` - refresh and start
372+
373+
The difference between build and refresh is that refresh will force pull any new images as well
374+
as rebuild the container images. Use this if the upstream image has been updated and you need
375+
a new version instead of the cached version.
376+
377+
#### Copy files to/from containers
378+
379+
You can easily copy files to/from your running containers by using: `spm services:copy` that is
380+
aliased as `copy` and `cp`. Note: that one side of this command must be a service name specified
381+
as `service_name:/path/in/container`.
382+
383+
The format is: `spm services:copy source target`, for example to copy a file from your downloads
384+
into the users-app container, configured as `users`:
385+
386+
```shell script
387+
spm services:copy ~/Downloads/file.txt users:/app/tmp/file.txt
388+
```
389+
390+
Under-the-hood, `services:copy` uses `docker cp`.
391+
392+
__Note:__ the copy command uses the **service** name; _not_ the actual docker container name!
393+
394+
__Note:__ the copy command uses the current working directory and not the services path when it
395+
is running. Run `spm services:copy -h` for help and the current working folder.
396+
324397
### Setting Remote Repositories
325398

326399
By default when using `project:create`, `libraries:create` or `services:create` a git repository

src/Commands/Services/CopyToContainerCommand.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ protected function configure()
4141
->setDescription('Copy a file to/from the services configured application container')
4242
->addArgument('source', InputArgument::REQUIRED, 'The source, either local or the container (service:/path) or folder')
4343
->addArgument('target', InputArgument::REQUIRED, 'Where the source should be copied (service:/path) or folder')
44-
->addOption('follow', 'f', InputOption::VALUE_NONE, 'Read the logs continuously')
4544
->setHelp(<<<HLP
4645
4746
Copies a file(s) to/from the application container specified by the service.

src/Commands/Services/StartCommand.php

Lines changed: 59 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -73,52 +73,70 @@ private function startService(string $service): void
7373
return;
7474
}
7575

76+
if (!$service->runningContainerId()) {
77+
$this->docker->resolve($service);
78+
}
79+
80+
if ($service->isRunning()) {
81+
return;
82+
}
83+
7684
if ($service->hasDependencies()) {
77-
$deps = null;
78-
79-
if ($this->tools()->input()->getOption('with-deps')) {
80-
$deps = 'y';
81-
}
82-
if ($this->tools()->input()->getOption('without-deps')) {
83-
$deps = 'n';
84-
}
85-
if (!$deps) {
86-
$deps = $this->tools()->ask('Service %s has dependencies, do you want these to be started? (y/n) ', false, $service->name());
87-
}
88-
89-
if (strtolower(trim($deps)) === 'y') {
90-
$service->dependencies()->each(function ($name) {
91-
$this->startService($name);
92-
});
93-
}
85+
$this->handleServiceDependencies($service);
9486
}
9587

9688
$command = $this->tools()->input()->getOption('refresh') ? 'refresh' : ($this->tools()->input()->getOption('rebuild') ? 'build' : 'start');
9789

98-
switch ($command):
99-
case 'refresh':
100-
$this->tools()->info('attempting to <info>refresh</info> service <info>%s</info> ', $service->name());
101-
$this->docker->refresh($service);
102-
$this->docker->start($service);
103-
break;
104-
105-
case 'build':
106-
$this->tools()->info('attempting to <info>build</info> service <info>%s</info> ', $service->name());
107-
$this->docker->build($service);
108-
$this->docker->start($service);
109-
break;
110-
111-
case 'start' && !$service->isRunning():
112-
$this->tools()->info('attempting to <info>start</info> service <info>%s</info> ', $service->name());
113-
$this->docker->start($service);
114-
endswitch;
115-
116-
$service->isRunning()
117-
?
118-
$this->tools()->success('service started <info>successfully</info>')
119-
:
120-
$this->tools()->error('service did not start, re-run with <info>-vvv</info> or use <info>docker-compose</info>')
121-
;
90+
$this->{$command}($service);
91+
92+
$this->tools()->when(
93+
$service->isRunning(),
94+
'service started <info>successfully</info>',
95+
'service did not start, re-run with <info>-vvv</info> or use <info>docker-compose</info>'
96+
);
12297
$this->tools()->newline();
12398
}
99+
100+
private function handleServiceDependencies(Service $service): void
101+
{
102+
$deps = null;
103+
104+
if ($this->tools()->input()->getOption('with-deps')) {
105+
$deps = 'y';
106+
}
107+
if ($this->tools()->input()->getOption('without-deps')) {
108+
$deps = 'n';
109+
}
110+
if (!$deps) {
111+
$deps = $this->tools()->ask('Service %s has dependencies, do you want these to be started? (y/n) ', false, $service->name());
112+
113+
$this->tools()->input()->setOption('with-deps', $deps);
114+
}
115+
116+
if (strtolower(trim($deps)) === 'y') {
117+
$service->dependencies()->each(function ($name) {
118+
$this->startService($name);
119+
});
120+
}
121+
}
122+
123+
private function refresh(Service $service): void
124+
{
125+
$this->tools()->info('attempting to <info>refresh</info> service <info>%s</info> ', $service->name());
126+
$this->docker->refresh($service);
127+
$this->docker->start($service);
128+
}
129+
130+
private function build(Service $service): void
131+
{
132+
$this->tools()->info('attempting to <info>build</info> service <info>%s</info> ', $service->name());
133+
$this->docker->build($service);
134+
$this->docker->start($service);
135+
}
136+
137+
private function start(Service $service): void
138+
{
139+
$this->tools()->info('attempting to <info>start</info> service <info>%s</info> ', $service->name());
140+
$this->docker->start($service);
141+
}
124142
}

src/Services/Console/ConsoleHelper.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Symfony\Component\Console\Question\ChoiceQuestion;
1414
use Symfony\Component\Console\Question\Question;
1515
use Symfony\Component\Process\Process;
16+
use function is_callable;
1617
use function sprintf;
1718

1819
/**
@@ -162,4 +163,30 @@ public function newline(): void
162163
{
163164
$this->noOutput ?: $this->output->writeln('');
164165
}
166+
167+
/**
168+
* When the condition is true, display success, else display error
169+
*
170+
* Additional args can be passed after the failure message as values to be inserted into the
171+
* message string. Success and failure are rendered using the success() / error() methods.
172+
*
173+
* Note: both success and failure messages should have the same number of parameters.
174+
*
175+
* @param bool|callable $condition
176+
* @param string $success
177+
* @param string $failure
178+
* @param mixed ...$args
179+
*/
180+
public function when($condition, string $success, string $failure, ...$args): void
181+
{
182+
if (is_callable($condition)) {
183+
$condition = $condition();
184+
}
185+
186+
if ($condition) {
187+
$this->success($success, ...$args);
188+
} else {
189+
$this->error($failure, ...$args);
190+
}
191+
}
165192
}

0 commit comments

Comments
 (0)