Passed
Push — master ( d9cb1f...3ce59a )
by Jonas
02:42
created

RunCommand::validateSteps()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 14
c 0
b 0
f 0
rs 9.6111
cc 5
nc 5
nop 1
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
        $template = Template::getInstance()->searchTemplateByFilenameInGivenPaths($templateFileName, $this->paths);
0 ignored issues
show
Bug introduced by
It seems like $templateFileName can also be of type null and string[]; however, parameter $fileName of Glamorous\Boiler\Helpers...yFilenameInGivenPaths() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

118
        $template = Template::getInstance()->searchTemplateByFilenameInGivenPaths(/** @scrutinizer ignore-type */ $templateFileName, $this->paths);
Loading history...
119
120
        $templateName = $input->getOption('name') ? $input->getOption('name') : $template['name'];
121
        $directoryName = $input->getOption('dir') ?: $templateFileName;
122
123
        if (file_exists($directoryName)) {
124
            throw new BoilerException('Folder already exists');
125
        }
126
127
        $output->writeln('<info>Installing ' . $templateName . '</info>');
128
        $this->variables['template_name'] = $templateName;
129
130
        mkdir($directoryName);
131
        chdir($directoryName);
132
133
        $this->prepareTemplateFolder($templateFileName);
0 ignored issues
show
Bug introduced by
It seems like $templateFileName can also be of type null and string[]; however, parameter $name of Glamorous\Boiler\RunComm...prepareTemplateFolder() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

133
        $this->prepareTemplateFolder(/** @scrutinizer ignore-type */ $templateFileName);
Loading history...
134
135
        $this->executeScripts($output, $template);
136
    }
137
138
    /**
139
     * Prepare the project directory by copying files from the template directory if available.
140
     *
141
     * @param string $name
142
     */
143
    protected function prepareTemplateFolder(string $name): void
144
    {
145
        $finder = new Finder();
146
        foreach ($this->paths as $directory) {
147
            $templateDir = $directory . '/' . $name;
148
            if (! is_dir($templateDir)) {
149
                continue;
150
            }
151
152
            $finder->in($templateDir)
153
                ->notName($name . '.yml')
154
                ->sortByType()
155
                ->ignoreDotFiles(false);
156
157
            foreach ($finder as $file) {
158
                if ($file->isDir()) {
159
                    mkdir($file->getFilename(), 0777, true);
160
                    continue;
161
                }
162
163
                if ($file->isFile()) {
164
                    copy($file->getPathname(), $file->getRelativePathname());
165
                    file_put_contents($file->getRelativePathname(), $this->replaceVariables($file->getContents()));
166
                    continue;
167
                }
168
            }
169
        }//end foreach
170
    }
171
}
172