Passed
Push — feature/open-with ( a1b551...a1d555 )
by Arnaud
10:49 queued 05:26
created

AbstractCommand::hasEditor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
/**
3
 * This file is part of the Cecil/Cecil package.
4
 *
5
 * Copyright (c) Arnaud Ligny <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Cecil\Command;
12
13
use Cecil\Builder;
14
use Cecil\Exception\RuntimeException;
15
use Cecil\Logger\ConsoleLogger;
16
use Cecil\Util;
17
use Symfony\Component\Console\Command\Command;
18
use Symfony\Component\Console\Input\InputInterface;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Symfony\Component\Console\Style\SymfonyStyle;
21
use Symfony\Component\Filesystem\Filesystem;
22
use Symfony\Component\Process\Process;
23
use Symfony\Component\Yaml\Exception\ParseException;
24
use Symfony\Component\Yaml\Yaml;
25
26
class AbstractCommand extends Command
27
{
28
    const CONFIG_FILE = 'config.yml';
29
    const TMP_DIR = '.cecil';
30
31
    /** @var InputInterface */
32
    protected $input;
33
34
    /** @var OutputInterface */
35
    protected $output;
36
37
    /** @var SymfonyStyle */
38
    protected $io;
39
40
    /** @var Filesystem */
41
    protected $fs;
42
43
    /** @var string */
44
    protected $path;
45
46
    /** @var array */
47
    protected $configFiles;
48
49
    /** @var Builder */
50
    protected $builder;
51
52
    /**
53
     * {@inheritdoc}
54
     */
55
    protected function initialize(InputInterface $input, OutputInterface $output)
56
    {
57
        $this->input = $input;
58
        $this->output = $output;
59
        $this->io = new SymfonyStyle($input, $output);
60
        $this->fs = new Filesystem();
61
62
        if (!in_array($this->getName(), ['self-update'])) {
63
            // working directory
64
            $this->path = getcwd();
65
            if ($input->getArgument('path') !== null) {
66
                $this->path = (string) $input->getArgument('path');
67
            }
68
            if (realpath($this->getPath()) === false) {
69
                $this->fs->mkdir($this->getPath());
70
            }
71
            $this->path = realpath($this->getPath());
72
            // config file(s)
73
            if (!in_array($this->getName(), ['new:site'])) {
74
                // default
75
                $this->configFiles[self::CONFIG_FILE] = realpath(Util::joinFile($this->getPath(), self::CONFIG_FILE));
76
                // from --config=<file>
77
                if ($input->hasOption('config') && $input->getOption('config') !== null) {
78
                    foreach (explode(',', (string) $input->getOption('config')) as $configFile) {
79
                        $this->configFiles[$configFile] = realpath($configFile);
80
                        if (!Util\File::getFS()->isAbsolutePath($configFile)) {
81
                            $this->configFiles[$configFile] = realpath(Util::joinFile($this->getPath(), $configFile));
82
                        }
83
                    }
84
                }
85
                // checks file(s)
86
                foreach ($this->configFiles as $fileName => $filePath) {
87
                    if (!file_exists($filePath)) {
88
                        $this->getBuilder()->getLogger()->error(\sprintf('Could not find configuration file "%s": uses default/others.', $fileName));
89
                        unset($this->configFiles[$fileName]);
90
                    }
91
                }
92
            }
93
        }
94
95
        parent::initialize($input, $output);
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101
    public function run(InputInterface $input, OutputInterface $output)
102
    {
103
        if ($output->isDebug()) {
104
            putenv('CECIL_DEBUG=true');
105
106
            return parent::run($input, $output);
107
        }
108
        // simplified error message
109
        try {
110
            return parent::run($input, $output);
111
        } catch (\Exception $e) {
112
            if ($this->io === null) {
113
                $this->io = new SymfonyStyle($input, $output);
114
            }
115
            $this->io->error($e->getMessage());
116
117
            exit(1);
118
        }
119
    }
120
121
    /**
122
     * Returns the working directory.
123
     */
124
    protected function getPath(): ?string
125
    {
126
        return $this->path;
127
    }
128
129
    /**
130
     * Returns config file(s) path.
131
     */
132
    protected function getConfigFiles(): array
133
    {
134
        return array_unique($this->configFiles);
135
    }
136
137
    /**
138
     * Creates or returns a Builder instance.
139
     *
140
     * @throws RuntimeException
141
     */
142
    protected function getBuilder(array $config = []): Builder
143
    {
144
        try {
145
            $siteConfig = [];
146
            foreach ($this->getConfigFiles() as $fileName => $filePath) {
147
                if (false === $configContent = Util\File::fileGetContents($filePath)) {
148
                    throw new RuntimeException(\sprintf('Can\'t read configuration file "%s".', $fileName));
149
                }
150
                $siteConfig = array_replace_recursive($siteConfig, Yaml::parse($configContent));
151
            }
152
            $config = array_replace_recursive($siteConfig, $config);
153
154
            $this->builder = (new Builder($config, new ConsoleLogger($this->output)))
155
                ->setSourceDir($this->getPath())
156
                ->setDestinationDir($this->getPath());
157
        } catch (ParseException $e) {
158
            throw new RuntimeException(\sprintf('Configuration parsing error: %s', $e->getMessage()));
159
        } catch (\Exception $e) {
160
            throw new RuntimeException($e->getMessage());
161
        }
162
163
        return $this->builder;
164
    }
165
166
    /**
167
     * Editor is configured?
168
     */
169
    protected function hasEditor(): bool
170
    {
171
        return $this->getBuilder()->getConfig()->has('editor');
172
    }
173
174
    /**
175
     * Opens with editor (if configured).
176
     *
177
     * @throws RuntimeException
178
     */
179
    protected function openEditor(string $filePath): void
180
    {
181
        if ($editor = (string) $this->getBuilder()->getConfig()->get('editor')) {
182
            switch (Util\Plateform::getOS()) {
183
                case Util\Plateform::OS_WIN:
184
                    $command = sprintf('start /B "" %s "%s"', $editor, $filePath);
185
                    break;
186
187
                default:
188
                    $command = sprintf('%s "%s"', $editor, $filePath);
189
                    break;
190
            }
191
            // Typora on macOS
192
            if ($editor == 'typora' && Util\Plateform::getOS() == Util\Plateform::OS_OSX) {
193
                $command = sprintf('open -a typora "%s"', $filePath);
194
            }
195
            $process = Process::fromShellCommandline($command);
196
            $process->run();
197
            if (!$process->isSuccessful()) {
198
                throw new RuntimeException(\sprintf('Can\'t run "%s".', $command));
199
            }
200
        }
201
    }
202
}
203