Completed
Push — master ( 1f7d3f...49921e )
by ANTHONIUS
12s
created

AddCommand::ensureDirOrFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 2
eloc 1
nc 2
nop 1
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', 'default')
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
        $homeDir = $config->get('dotfiles.home_dir');
78
        $recursive = $input->getOption('recursive');
79
        $machine = $input->getOption('machine');
80
        $repoDir = $config->get('dotfiles.repo_dir')."/src/$machine/home";
81
        $sourcePath = str_replace($homeDir.DIRECTORY_SEPARATOR, '', $input->getArgument('path'));
82
83
        // detect source path
84
        $originPath = $this->detectPath($sourcePath);
85
        $targetPath = $repoDir.'/'.str_replace('.', '', $sourcePath);
86
87
        Toolkit::ensureDir($repoDir);
88
89
        $basename = basename($sourcePath);
90
        if (0 === strpos($basename, '.')) {
91
            $targetPath = str_replace('.'.$sourcePath, $basename, $targetPath);
92
        }
93
94
        if (is_dir($originPath)) {
95
            $this->doAddDir($originPath, $targetPath, $recursive);
96
        } else {
97
            $this->doAddFile($originPath, $targetPath);
98
        }
99
    }
100
101
    private function detectPath($path)
102
    {
103
        if ($this->ensureDirOrFile($path)) {
104
            return $path;
105
        }
106
107
        $homeDir = $this->config->get('dotfiles.home_dir');
108
        $test = $homeDir.DIRECTORY_SEPARATOR.$path;
109
        if ($this->ensureDirOrFile($test)) {
110
            return $test;
111
        }
112
113
        if ($this->ensureDirOrFile($test = $homeDir.DIRECTORY_SEPARATOR.'.'.$path)) {
114
            return $test;
115
        }
116
117
        throw new InvalidOperationException("Can not find directory or file to process. Please make sure that $path is exists");
118
    }
119
120
    /**
121
     * @param string $origin
122
     * @param string $target
123
     * @param bool   $recursive
124
     *
125
     * @throws InvalidOperationException
126
     */
127
    private function doAddDir(string $origin, string $target, $recursive): void
128
    {
129
        if (!$recursive) {
130
            throw new InvalidOperationException('Add dir without recursive');
131
        }
132
133
        $finder = Finder::create()
134
            ->in($origin)
135
            ->ignoreVCS(true)
136
            ->ignoreDotFiles(false)
137
        ;
138
        $fs = new Filesystem();
139
        $fs->mirror($origin, $target, $finder);
140
        $this->output->writeln(sprintf(
141
            'copy files from <comment>%s</comment> to <comment>%s</comment>',
142
            $origin,
143
            $target
144
        ));
145
    }
146
147
    /**
148
     * @param string $origin
149
     * @param string $target
150
     */
151
    private function doAddFile(string $origin, string $target): void
152
    {
153
        $fs = new Filesystem();
154
        $fs->copy($origin, $target);
155
        $this->output->writeln(
156
            sprintf(
157
                'copy from <comment>%s</comment> to <comment>%s</comment>',
158
                $origin,
159
                $target
160
            )
161
        );
162
    }
163
164
    private function ensureDirOrFile($path)
165
    {
166
        return is_file($path) || is_dir($path);
167
    }
168
}
169