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

InitCommand::initDotFilesDir()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 9
nc 1
nop 2
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\DI\Parameters;
17
use Dotfiles\Core\Exceptions\InvalidOperationException;
18
use Dotfiles\Core\Util\CommandProcessor;
19
use Dotfiles\Core\Util\Filesystem;
20
use Dotfiles\Core\Util\Toolkit;
21
use Symfony\Component\Console\Input\InputArgument;
22
use Symfony\Component\Console\Input\InputInterface;
23
use Symfony\Component\Console\Input\InputOption;
24
use Symfony\Component\Console\Output\OutputInterface;
25
use Symfony\Component\Console\Question\Question;
26
use Symfony\Component\Finder\Finder;
27
28
class InitCommand extends Command
29
{
30
    /**
31
     * @var CommandProcessor
32
     */
33
    private $commandProcessor;
34
35
    /**
36
     * @var string
37
     */
38
    private $defaultBackupDir;
39
40
    /**
41
     * @var string
42
     */
43
    private $defaultHomeDir;
44
45
    /**
46
     * @var InputInterface
47
     */
48
    private $input;
49
50
    /**
51
     * @var OutputInterface
52
     */
53
    private $output;
54
55
    /**
56
     * @var Parameters
57
     */
58
    private $parameters;
59
60
    public function __construct(?string $name = null, CommandProcessor $processor, Parameters $parameters)
61
    {
62
        parent::__construct($name);
63
        $this->commandProcessor = $processor;
64
        $this->parameters = $parameters;
65
        $this->defaultHomeDir = $parameters->get('dotfiles.home_dir');
66
        $this->defaultBackupDir = $parameters->get('dotfiles.backup_dir');
67
    }
68
69
    protected function configure(): void
70
    {
71
        $this
72
            ->setName('init')
73
            ->setDescription('Initialize new Dotfiles project.')
74
            ->addArgument('backup-dir', InputArgument::OPTIONAL, 'Local repository directory')
75
            ->addOption('machine', 'm', InputOption::VALUE_OPTIONAL, 'Machine name')
76
            ->addOption('install-dir', 'i', InputOption::VALUE_OPTIONAL, 'Dotfiles instalaltion directory installation')
77
        ;
78
    }
79
80
    /**
81
     * @param InputInterface  $input
82
     * @param OutputInterface $output
83
     *
84
     * @return int|null|void
85
     */
86
    protected function execute(InputInterface $input, OutputInterface $output)
87
    {
88
        $this->input = $input;
89
        $this->output = $output;
90
91
        if (null === ($backupDir = $input->getArgument('backup-dir'))) {
92
            $backupDir = $this->doBackupRepoDir();
93
        }
94
95
        if (null === ($machine = $input->getOption('machine'))) {
96
            $machine = $this->doAskMachineName();
97
        }
98
99
        if (null === ($installDir = $input->getOption('install-dir'))) {
100
            $installDir = $this->doAskInstallDir();
101
        }
102
103
        $this->initDotfilesProfile($backupDir, $machine, $installDir);
104
        $this->initBackupDir($backupDir);
105
        $this->initInstallDir($installDir);
106
    }
107
108
    private function doAskInstallDir()
109
    {
110
        $input = $this->input;
111
        $output = $this->output;
112
        $helper = $this->getHelper('question');
113
        $default = getenv('DOTFILES_HOME_DIR').'/.dotfiles';
114
        $question = new Question(sprintf('Your installation directory (<comment>%s</comment>):', $default), $default);
115
116
        return $helper->ask($input, $output, $question);
117
    }
118
119
    private function doAskMachineName()
120
    {
121
        $input = $this->input;
122
        $output = $this->output;
123
        $helper = $this->getHelper('question');
124
        $default = getenv('DOTFILES_MACHINE_NAME');
125
        $question = new Question(sprintf('Please enter your machine name (<comment>%s</comment>):', $default), $default);
126
127
        return $helper->ask($input, $output, $question);
128
    }
129
130
    private function doBackupRepoDir()
131
    {
132
        $input = $this->input;
133
        $output = $this->output;
134
        $helper = $this->getHelper('question');
135
        $default = getenv('DOTFILES_BACKUP_DIR');
136
        $question = new Question("Please enter local backup dir (<comment>$default</comment>): ", $default);
137
        $question->setValidator(function ($answer) {
138
            if (null === $answer) {
139
                throw new InvalidOperationException('You have to define local backup directory');
140
            }
141
            $parent = dirname($answer);
142
            if (!is_dir($parent) || !is_writable($parent)) {
143
                throw new InvalidOperationException(
144
                    "Can not find parent directory, please ensure that $parent is exists and writable"
145
                );
146
            }
147
148
            return $answer;
149
        });
150
151
        $question->setMaxAttempts(3);
152
153
        return $helper->ask($input, $output, $question);
154
    }
155
156
    private function initBackupDir($backupDir): void
157
    {
158
        Toolkit::ensureDir($backupDir);
159
        $origin = __DIR__.'/../Resources/templates/backup';
160
161
        $finder = Finder::create()
162
            ->ignoreVCS(true)
163
            ->ignoreDotFiles(false)
164
            ->in($origin)
165
            ->files()
166
        ;
167
        $fs = new Filesystem();
168
        $fs->mirror($origin, $backupDir, $finder);
169
    }
170
171
    private function initDotfilesProfile(string $backupDir, string $machine, $installDir): void
172
    {
173
        $time = (new \DateTime())->format('Y-m-d H:i:s');
174
        $envFile = getenv('DOTFILES_HOME_DIR').'/.dotfiles_profile';
175
        Toolkit::ensureFileDir($envFile);
176
        $contents = <<<EOF
177
# generated at $time
178
DOTFILES_MACHINE_NAME=$machine
179
DOTFILES_BACKUP_DIR=$backupDir
180
DOTFILES_INSTALL_DIR=$installDir
181
EOF;
182
183
        file_put_contents($envFile, $contents, LOCK_EX);
184
    }
185
186
    private function initInstallDir($installDir): void
187
    {
188
        Toolkit::ensureDir($installDir);
189
    }
190
}
191