InitCommand::doBackupRepoDir()   B
last analyzed

Complexity

Conditions 5
Paths 2

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.5125
c 0
b 0
f 0
cc 5
eloc 15
nc 2
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\Config\Config;
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 Config
37
     */
38
    private $config;
39
40
    /**
41
     * @var string
42
     */
43
    private $defaultBackupDir;
44
45
    /**
46
     * @var string
47
     */
48
    private $defaultHomeDir;
49
50
    /**
51
     * @var InputInterface
52
     */
53
    private $input;
54
55
    /**
56
     * @var OutputInterface
57
     */
58
    private $output;
59
60
    public function __construct(?string $name = null, CommandProcessor $processor, Config $config)
61
    {
62
        parent::__construct($name);
63
        $this->commandProcessor = $processor;
64
        $this->config = $config;
65
        $this->defaultHomeDir = $config->get('dotfiles.home_dir');
66
        $this->defaultBackupDir = $config->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
        ;
77
    }
78
79
    /**
80
     * @param InputInterface  $input
81
     * @param OutputInterface $output
82
     *
83
     * @return int|null|void
84
     */
85
    protected function execute(InputInterface $input, OutputInterface $output)
86
    {
87
        $this->input = $input;
88
        $this->output = $output;
89
90
        if (null === ($backupDir = $input->getArgument('backup-dir'))) {
91
            $backupDir = $this->doBackupRepoDir();
92
        }
93
94
        if (null === ($machine = $input->getOption('machine'))) {
95
            $machine = $this->doAskMachineName();
96
        }
97
98
        $this->initDotfilesDir($backupDir, $machine);
99
        $this->initBackupDir($backupDir);
100
    }
101
102
    private function doAskMachineName()
103
    {
104
        $input = $this->input;
105
        $output = $this->output;
106
        $helper = $this->getHelper('question');
107
        $default = gethostname();
108
        $question = new Question(sprintf('Please enter your machine name (<comment>%s</comment>):', $default), $default);
109
110
        return $helper->ask($input, $output, $question);
111
    }
112
113
    private function doBackupRepoDir()
114
    {
115
        $input = $this->input;
116
        $output = $this->output;
117
        $helper = $this->getHelper('question');
118
        $default = 'dev' === getenv('DOTFILES_ENV') ? sys_get_temp_dir().'/dotfiles/backup' : getcwd();
119
        $question = new Question("Please enter local backup dir (<comment>$default</comment>): ", $default);
120
        $question->setValidator(function ($answer) {
121
            if (null === $answer) {
122
                throw new InvalidOperationException('You have to define local backup directory');
123
            }
124
            $parent = dirname($answer);
125
            if (!is_dir($parent) || !is_writable($parent)) {
126
                throw new InvalidOperationException(
127
                    "Can not find parent directory, please ensure that $parent is exists and writable"
128
                );
129
            }
130
131
            return $answer;
132
        });
133
134
        $question->setMaxAttempts(3);
135
136
        return $helper->ask($input, $output, $question);
137
    }
138
139
    private function initBackupDir($backupDir): void
140
    {
141
        Toolkit::ensureDir($backupDir);
142
        $origin = __DIR__.'/../Resources/templates/backup';
143
144
        $finder = Finder::create()
145
            ->ignoreVCS(true)
146
            ->ignoreDotFiles(false)
147
            ->in($origin)
148
            ->files()
149
        ;
150
        $fs = new Filesystem();
151
        $fs->mirror($origin, $backupDir, $finder);
152
    }
153
154
    private function initDotFilesDir(string $backupDir, string $machine): void
155
    {
156
        $dotfilesDir = $this->defaultHomeDir.DIRECTORY_SEPARATOR.'.dotfiles';
157
        Toolkit::ensureDir($dotfilesDir);
158
        $envFile = $dotfilesDir.DIRECTORY_SEPARATOR.'.env';
159
        $contents = <<<EOF
160
161
DOTFILES_MACHINE_NAME=$machine
162
DOTFILES_BACKUP_DIR=$backupDir
163
164
EOF;
165
166
        file_put_contents($envFile, $contents, LOCK_EX);
167
    }
168
}
169