Completed
Pull Request — master (#1)
by ANTHONIUS
06:27
created

InitCommand::doAskRepoDir()   B

Complexity

Conditions 4
Paths 1

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 8.7972
c 0
b 0
f 0
cc 4
eloc 14
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
26
class InitCommand extends Command
27
{
28
    /**
29
     * @var CommandProcessor
30
     */
31
    private $commandProcessor;
32
    /**
33
     * @var InputInterface
34
     */
35
    private $input;
36
37
    /**
38
     * @var OutputInterface
39
     */
40
    private $output;
41
42
    public function __construct(?string $name = null, CommandProcessor $processor)
43
    {
44
        parent::__construct($name);
45
        $this->commandProcessor = $processor;
46
    }
47
48
    protected function configure(): void
49
    {
50
        $this
51
            ->setName('init')
52
            ->setDescription('Initialize new Dotfiles project.')
53
            ->addArgument('repo-dir', InputArgument::OPTIONAL, 'Local repository directory')
54
            ->addOption('home-dir', 'hd', InputOption::VALUE_OPTIONAL, 'Home directory')
55
            ->addOption('machine', 'm', InputOption::VALUE_OPTIONAL, 'Machine name')
56
        ;
57
    }
58
59
    /**
60
     * @param InputInterface  $input
61
     * @param OutputInterface $output
62
     *
63
     * @return int|null|void
64
     *
65
     * @throws InvalidOperationException when git is not installed
66
     */
67
    protected function execute(InputInterface $input, OutputInterface $output)
68
    {
69
        $this->input = $input;
70
        $this->output = $output;
71
72
        if (null === ($repoDir = $input->getArgument('repo-dir'))) {
73
            $repoDir = $this->doAskRepoDir();
74
        }
75
76
        if (null === ($machine = $input->getOption('machine'))) {
77
            $machine = $this->doAskMachineName();
78
        }
79
80
        if (null === ($homeDir = $input->getOption('home-dir'))) {
81
            $homeDir = $this->doAskHomeDir();
82
        }
83
84
        $this->initDotfilesDir($homeDir, $repoDir, $machine);
85
        $this->initRepoDir($repoDir);
86
    }
87
88
    private function doAskHomeDir()
89
    {
90
        $input = $this->input;
91
        $output = $this->output;
92
        $helper = $this->getHelper('question');
93
        $question = new Question(sprintf('Please enter your home directory (default: <comment>%s</comment>):', getenv('HOME')), getenv('HOME'));
94
95
        return $helper->ask($input, $output, $question);
96
    }
97
98
    private function doAskMachineName()
99
    {
100
        $input = $this->input;
101
        $output = $this->output;
102
        $helper = $this->getHelper('question');
103
        $question = new Question(sprintf('Please enter your machine name (default: <comment>%s</comment>):', gethostname()), gethostname());
104
105
        return $helper->ask($input, $output, $question);
106
    }
107
108
    private function doAskRepoDir()
109
    {
110
        $input = $this->input;
111
        $output = $this->output;
112
        $helper = $this->getHelper('question');
113
        $question = new Question('Please enter local repository dir: ');
114
        $question->setValidator(function ($answer) {
115
            if (null === $answer) {
116
                throw new InvalidOperationException('You have to define local repository directory');
117
            }
118
            $parent = dirname($answer);
119
            if (!is_dir($parent) || !is_writable($parent)) {
120
                throw new InvalidOperationException(
121
                    "Can not find parent directory, please ensure that $parent is exists and writable"
122
                );
123
            }
124
125
            return $answer;
126
        });
127
128
        $question->setMaxAttempts(3);
129
130
        return $helper->ask($input, $output, $question);
131
    }
132
133
    private function initDotFilesDir(string $homeDir, $repoDir, $machine): void
134
    {
135
        $dotfilesDir = $homeDir.DIRECTORY_SEPARATOR.'.dotfiles';
136
        Toolkit::ensureDir($dotfilesDir);
137
138
        $fs = new Filesystem();
139
        $fs->mirror(__DIR__.'/../Resources/templates/.dotfiles', $dotfilesDir);
140
141
        $envFile = $dotfilesDir.DIRECTORY_SEPARATOR.'.env';
142
        $contents = file_get_contents($envFile);
143
        $contents = strtr($contents, array(
144
            '{{machine_name}}' => $machine,
145
            '{{repo_dir}}' => $repoDir,
146
        ));
147
        file_put_contents($envFile, $contents, LOCK_EX);
148
    }
149
150
    private function initRepoDir($repoDir): void
151
    {
152
        Toolkit::ensureDir($repoDir);
153
        $fs = new Filesystem();
154
        $fs->mirror(__DIR__.'/../Resources/templates/repo', $repoDir);
155
    }
156
}
157