AddCommand::doAddFile()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 7
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\Config\Config;
17
use Dotfiles\Core\Exceptions\InvalidOperationException;
18
use Dotfiles\Core\Util\Filesystem;
19
use Dotfiles\Core\Util\Toolkit;
20
use Psr\Log\LoggerInterface;
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\Finder\Finder;
26
27
class AddCommand extends Command implements CommandInterface
28
{
29
    /**
30
     * @var Config
31
     */
32
    private $config;
33
34
    /**
35
     * @var LoggerInterface
36
     */
37
    private $logger;
38
39
    /**
40
     * @var OutputInterface
41
     */
42
    private $output;
43
44
    public function __construct(
45
        ?string $name = null,
46
        Config $config,
47
        LoggerInterface $logger
48
    ) {
49
        parent::__construct($name);
50
        $this->config = $config;
51
        $this->logger = $logger;
52
    }
53
54
    protected function configure(): void
55
    {
56
        $this
57
            ->setName('add')
58
            ->setDescription('Add new file into dotfiles manager')
59
            ->addArgument('path', InputArgument::REQUIRED, 'A file or directory name to add. This file must be exists in $HOME directory')
60
            ->addOption('machine', '-m', InputOption::VALUE_OPTIONAL, 'Add this file/directory into machine registry', 'defaults')
61
            ->addOption('recursive', '-r', InputOption::VALUE_NONE, 'Import all directory contents recursively')
62
        ;
63
    }
64
65
    /**
66
     * @param InputInterface  $input
67
     * @param OutputInterface $output
68
     *
69
     * @return int|null|void
70
     *
71
     * @throws InvalidOperationException when path not exists
72
     */
73
    protected function execute(InputInterface $input, OutputInterface $output)
74
    {
75
        $this->output = $output;
76
        $config = $this->config;
77
        $recursive = $input->getOption('recursive');
78
        $machine = $input->getOption('machine');
79
        $backupDir = $config->get('dotfiles.backup_dir')."/src/$machine/home";
80
        $sourcePath = $input->getArgument('path');
81
        $homeDir = $config->get('dotfiles.home_dir');
82
83
        // detect source path
84
        $originPath = $this->detectPath($sourcePath);
85
        $targetPath = $backupDir.'/'.str_replace('.', '', $sourcePath);
86
        $targetPath = str_replace($homeDir.DIRECTORY_SEPARATOR, '', $targetPath);
87
88
        Toolkit::ensureDir($backupDir);
89
90
        $basename = basename($sourcePath);
91
        if (0 === strpos($basename, '.')) {
92
            $targetPath = str_replace('.'.$sourcePath, $basename, $targetPath);
93
        }
94
95
        if (is_dir($originPath)) {
96
            $this->doAddDir($originPath, $targetPath, $recursive);
97
        } else {
98
            $this->doAddFile($originPath, $targetPath);
99
        }
100
    }
101
102
    private function detectPath(string $path)
103
    {
104
        if ($this->ensureDirOrFile($path)) {
105
            return $path;
106
        }
107
108
        $homeDir = $this->config->get('dotfiles.home_dir');
109
        $test = $homeDir.DIRECTORY_SEPARATOR.$path;
110
        if ($this->ensureDirOrFile($test)) {
111
            return $test;
112
        }
113
114
        if ($this->ensureDirOrFile($test = $homeDir.DIRECTORY_SEPARATOR.'.'.$path)) {
115
            return $test;
116
        }
117
118
        throw new InvalidOperationException("Can not find directory or file to process. Please make sure that $path is exists");
119
    }
120
121
    /**
122
     * @param string $origin
123
     * @param string $target
124
     * @param bool   $recursive
125
     *
126
     * @throws InvalidOperationException
127
     */
128
    private function doAddDir(string $origin, string $target, $recursive): void
129
    {
130
        if (!$recursive) {
131
            throw new InvalidOperationException('Add dir without recursive');
132
        }
133
134
        $finder = Finder::create()
135
            ->in($origin)
136
            ->ignoreVCS(true)
137
            ->ignoreDotFiles(false)
138
        ;
139
        $fs = new Filesystem();
140
        $fs->mirror($origin, $target, $finder);
141
        $this->output->writeln(sprintf(
142
            'copy files from <comment>%s</comment> to <comment>%s</comment>',
143
            $origin,
144
            $target
145
        ));
146
    }
147
148
    /**
149
     * @param string $origin
150
     * @param string $target
151
     */
152
    private function doAddFile(string $origin, string $target): void
153
    {
154
        $fs = new Filesystem();
155
        $fs->copy($origin, $target);
156
        $this->output->writeln(
157
            sprintf(
158
                'copy from <comment>%s</comment> to <comment>%s</comment>',
159
                $origin,
160
                $target
161
            )
162
        );
163
    }
164
165
    private function ensureDirOrFile($path)
166
    {
167
        return is_file($path) || is_dir($path);
168
    }
169
}
170