Passed
Push — master ( deafd9...870f7c )
by Jonas
02:24
created

RunCommand::executeCommand()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 34
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 19
dl 0
loc 34
rs 8.8333
c 0
b 0
f 0
cc 7
nc 7
nop 2
1
<?php
2
3
namespace Glamorous\Boiler;
4
5
use Glamorous\Boiler\Helpers\Template;
6
use Symfony\Component\Console\Input\InputArgument;
7
use Symfony\Component\Console\Input\InputInterface;
8
use Symfony\Component\Console\Input\InputOption;
9
use Symfony\Component\Console\Output\OutputInterface;
10
use Symfony\Component\Finder\Finder;
11
12
class RunCommand extends ConfigurationCommand
13
{
14
    /**
15
     * Array with the paths.
16
     *
17
     * @var array
18
     */
19
    protected $paths;
20
21
    /**
22
     * Array with all possible variables.
23
     *
24
     * @var array
25
     */
26
    protected $variables = [];
27
28
    /**
29
     * Configure the command options.
30
     */
31
    protected function configure()
32
    {
33
        $this
34
            ->setName('create')
35
            ->setDescription('Create a project based on the given template')
36
            ->addArgument('template', InputArgument::REQUIRED)
37
            ->addOption(
38
                'dir',
39
                null,
40
                InputOption::VALUE_OPTIONAL,
41
                'Which name must the directory to create have?'
42
            )
43
            ->addOption(
44
                'name',
45
                null,
46
                InputOption::VALUE_OPTIONAL,
47
                'Which name must the project have?'
48
            );
49
    }
50
51
    /**
52
     * Execute the command and catch exceptions.
53
     *
54
     * @param InputInterface $input
55
     * @param OutputInterface $output
56
     *
57
     * @return void
58
     */
59
    protected function execute(InputInterface $input, OutputInterface $output): void
60
    {
61
        try {
62
            $this->executeCommand($input, $output);
63
        } catch (BoilerException $exception) {
64
            $output->write('<error>' . $exception->getMessage() . '</error>');
65
        }
66
    }
67
68
    /**
69
     * Replace variables in given string.
70
     *
71
     * @param string $contents
72
     *
73
     * @return string
74
     */
75
    private function replaceVariables(string $contents): string
76
    {
77
        $variables = [
78
            '{#PROJECT_NAME#}' => $this->variables['template_name'],
79
        ];
80
81
        return str_replace(array_keys($variables), array_values($variables), $contents);
82
    }
83
84
    /**
85
     * Execute the scripts from the template.
86
     *
87
     * @param OutputInterface $output
88
     * @param array $template
89
     */
90
    protected function executeScripts(OutputInterface $output, array $template): void
91
    {
92
        foreach ($template['steps'] as $step) {
93
            $output->writeln('<info>Executing ' . $template[$step]['name'] . '</info>');
94
            $scripts = is_array($template[$step]['script']) ? $template[$step]['script'] : [$template[$step]['script']];
95
            foreach ($scripts as $script) {
96
                exec($this->replaceVariables($script));
97
            }
98
        }
99
    }
100
101
    /**
102
     * Internal method to execute the command.
103
     *
104
     * @param InputInterface $input
105
     * @param OutputInterface $output
106
     *
107
     * @throws BoilerException
108
     */
109
    private function executeCommand(InputInterface $input, OutputInterface $output): void
110
    {
111
        $this->paths = $this->configuration->getPaths();
112
113
        if (empty($this->paths)) {
114
            throw new BoilerException('No paths configured');
115
        }
116
117
        $templateFileName = $input->getArgument('template');
118
119
        if (empty($templateFileName)) {
120
            throw new BoilerException('No template given.');
121
        } elseif (is_array($templateFileName)) {
122
            throw new BoilerException('Only one template is allowed.');
123
        }
124
125
        $template = Template::getInstance()->searchTemplateByFilenameInGivenPaths($templateFileName, $this->paths);
126
127
        $templateName = $input->getOption('name') ? $input->getOption('name') : $template['name'];
128
        $directoryName = $input->getOption('dir') ?: $templateFileName;
129
130
        if (file_exists($directoryName)) {
131
            throw new BoilerException('Folder already exists');
132
        }
133
134
        $output->writeln('<info>Installing ' . $templateName . '</info>');
135
        $this->variables['template_name'] = $templateName;
136
137
        mkdir($directoryName);
138
        chdir($directoryName);
139
140
        $this->prepareTemplateFolder($templateFileName);
141
142
        $this->executeScripts($output, $template);
143
    }
144
145
    /**
146
     * Prepare the project directory by copying files from the template directory if available.
147
     *
148
     * @param string $name
149
     */
150
    protected function prepareTemplateFolder(string $name): void
151
    {
152
        $finder = new Finder();
153
        foreach ($this->paths as $directory) {
154
            $templateDir = $directory . '/' . $name;
155
            if (! is_dir($templateDir)) {
156
                continue;
157
            }
158
159
            $finder->in($templateDir)
160
                ->notName($name . '.yml')
161
                ->sortByType()
162
                ->ignoreDotFiles(false);
163
164
            foreach ($finder as $file) {
165
                if ($file->isDir()) {
166
                    mkdir($file->getFilename(), 0777, true);
167
                    continue;
168
                }
169
170
                if ($file->isFile()) {
171
                    copy($file->getPathname(), $file->getRelativePathname());
172
                    file_put_contents($file->getRelativePathname(), $this->replaceVariables($file->getContents()));
173
                    continue;
174
                }
175
            }
176
        }//end foreach
177
    }
178
}
179