Completed
Pull Request — master (#1)
by ANTHONIUS
02:56
created

InitCommand::configure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the dotfiles project.
7
 *
8
 *     (c) Anthonius Munthi <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Dotfiles\Core\Command;
15
16
use Dotfiles\Core\Exceptions\InvalidOperationException;
17
use Dotfiles\Core\Util\CommandProcessor;
18
use Dotfiles\Core\Util\Filesystem;
19
use Dotfiles\Core\Util\Toolkit;
20
use Symfony\Component\Console\Input\InputArgument;
21
use Symfony\Component\Console\Input\InputInterface;
22
use Symfony\Component\Console\Input\InputOption;
23
use Symfony\Component\Console\Output\OutputInterface;
24
use Symfony\Component\Console\Question\Question;
25
use Symfony\Component\Finder\Finder;
26
27
class InitCommand extends Command
28
{
29
    /**
30
     * @var CommandProcessor
31
     */
32
    private $commandProcessor;
33
    /**
34
     * @var InputInterface
35
     */
36
    private $input;
37
38
    /**
39
     * @var OutputInterface
40
     */
41
    private $output;
42
43
    public function __construct(?string $name = null, CommandProcessor $processor)
44
    {
45
        parent::__construct($name);
46
        $this->commandProcessor = $processor;
47
    }
48
49
    protected function configure(): void
50
    {
51
        $this
52
            ->setName('init')
53
            ->setDescription('Initialize new Dotfiles project.')
54
            ->addArgument('repo-dir', InputArgument::OPTIONAL, 'Local repository directory')
55
            ->addOption('home-dir', 'hd', InputOption::VALUE_OPTIONAL, 'Home directory')
56
            ->addOption('machine', 'm', InputOption::VALUE_OPTIONAL, 'Machine name')
57
        ;
58
    }
59
60
    /**
61
     * @param InputInterface  $input
62
     * @param OutputInterface $output
63
     *
64
     * @return int|null|void
65
     *
66
     * @throws InvalidOperationException when git is not installed
67
     */
68
    protected function execute(InputInterface $input, OutputInterface $output)
69
    {
70
        $this->input = $input;
71
        $this->output = $output;
72
73
        if (null === ($repoDir = $input->getArgument('repo-dir'))) {
74
            $repoDir = $this->doAskRepoDir();
75
        }
76
77
        if (null === ($machine = $input->getOption('machine'))) {
78
            $machine = $this->doAskMachineName();
79
        }
80
81
        if (null === ($homeDir = $input->getOption('home-dir'))) {
82
            $homeDir = $this->doAskHomeDir();
83
        }
84
85
        $this->initDotfilesDir($homeDir, $repoDir, $machine);
86
        $this->initRepoDir($repoDir);
87
    }
88
89
    private function doAskHomeDir()
90
    {
91
        $input = $this->input;
92
        $output = $this->output;
93
        $helper = $this->getHelper('question');
94
        $question = new Question(sprintf('Please enter your home directory (default: <comment>%s</comment>):', getenv('HOME')), getenv('HOME'));
95
96
        return $helper->ask($input, $output, $question);
97
    }
98
99
    private function doAskMachineName()
100
    {
101
        $input = $this->input;
102
        $output = $this->output;
103
        $helper = $this->getHelper('question');
104
        $question = new Question(sprintf('Please enter your machine name (default: <comment>%s</comment>):', gethostname()), gethostname());
105
106
        return $helper->ask($input, $output, $question);
107
    }
108
109
    private function doAskRepoDir()
110
    {
111
        $input = $this->input;
112
        $output = $this->output;
113
        $helper = $this->getHelper('question');
114
        $question = new Question('Please enter local repository dir: ');
115
        $question->setValidator(function ($answer) {
116
            if (null === $answer) {
117
                throw new InvalidOperationException('You have to define local repository directory');
118
            }
119
            $parent = dirname($answer);
120
            if (!is_dir($parent) || !is_writable($parent)) {
121
                throw new InvalidOperationException(
122
                    "Can not find parent directory, please ensure that $parent is exists and writable"
123
                );
124
            }
125
126
            return $answer;
127
        });
128
129
        $question->setMaxAttempts(3);
130
131
        return $helper->ask($input, $output, $question);
132
    }
133
134
    private function initDotFilesDir(string $homeDir, $repoDir, $machine): void
135
    {
136
        $dotfilesDir = $homeDir.DIRECTORY_SEPARATOR.'.dotfiles';
137
        Toolkit::ensureDir($dotfilesDir);
138
        $templateDir = __DIR__.'/../Resources/templates/dotfiles';
139
        $finder = Finder::create()
140
            ->in($templateDir)
141
            ->ignoreDotFiles(false)
142
            ->files()
143
        ;
144
        $fs = new Filesystem();
145
        $fs->mirror($templateDir, $dotfilesDir,$finder);
146
147
        $envFile = $dotfilesDir.DIRECTORY_SEPARATOR.'.env';
148
        $contents = file_get_contents($envFile);
149
        $contents = strtr($contents, array(
150
            '{{machine_name}}' => $machine,
151
            '{{repo_dir}}' => $repoDir,
152
        ));
153
        file_put_contents($envFile, $contents, LOCK_EX);
154
    }
155
156
    private function initRepoDir($repoDir): void
157
    {
158
        Toolkit::ensureDir($repoDir);
159
        $fs = new Filesystem();
160
        $fs->mirror(__DIR__.'/../Resources/templates/repo', $repoDir);
161
    }
162
}
163