Completed
Push — dev ( 6ec814...1460f1 )
by Antonio
03:37
created

GitHooksInstaller::supports()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Ams\Composer\GitHooks\Installer;
4
5
use Ams\Composer\GitHooks\Config;
6
use Ams\Composer\GitHooks\GitHooks;
7
use Ams\Composer\GitHooks\Plugin;
8
use Composer\Installer\LibraryInstaller;
9
use Composer\Package\PackageInterface;
10
use Composer\Repository\InstalledRepositoryInterface;
11
use Composer\Util\Silencer;
12
13
class GitHooksInstaller extends LibraryInstaller
14
{
15
    /**
16
     * @inheritdoc
17
     */
18 2
    public function supports($packageType)
19
    {
20 2
        return $packageType === Plugin::PACKAGE_TYPE;
21
    }
22
23
    /**
24
     * {@inheritDoc}
25
     */
26
    public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
27
    {
28
        parent::install($repo, $package);
29
30
        $gitRootPath = realpath($this->getGitRootPath());
31
        if (!is_dir($gitRootPath)) {
32
            $this->io->writeError(sprintf(
33
                '    <warning>Skipped installation of %s: Not a git repository found on "git-root" path %s</warning>',
34
                $package->getName(),
35
                $gitRootPath
36
            ));
37
38
            return;
39
        }
40
41
        $originPath = $this->getInstallPath($package);
42
        $targetPath = $this->getGitHooksInstallPath();
43
44
        if ($this->io->isVerbose()) {
45
            $this->io->write(sprintf('    Installing git hooks from %s into %s', $originPath, $targetPath));
46
        }
47
48
        // throws exception if one of both paths doesn't exists or couldn't be created
49
        $this->filesystem->ensureDirectoryExists($originPath);
50
        $this->filesystem->ensureDirectoryExists($targetPath);
51
52
        $this->copyGitHooks($originPath, $targetPath);
53
    }
54
55
    /**
56
     * {@inheritDoc}
57
     */
58
    public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
59
    {
60
        parent::update($repo, $initial, $target);
61
62
        $gitRootPath = realpath($this->getGitRootPath());
63
        if (!is_dir($gitRootPath)) {
64
            $this->io->writeError(sprintf(
65
                '    <warning>Skipped update of %s: Not a git repository found on "git-root" path %s</warning>',
66
                $target->getName(),
67
                $gitRootPath
68
            ));
69
70
            return;
71
        }
72
73
        $originPath = $this->getInstallPath($initial);
74
        $targetPath = $this->getGitHooksInstallPath();
75
76
        if ($this->io->isVerbose()) {
77
            $this->io->write(sprintf('    Updating git hooks from %s into %s', $originPath, $targetPath));
78
        }
79
80
        // throws exception if one of both paths doesn't exists or couldn't be created
81
        $this->filesystem->ensureDirectoryExists($originPath);
82
        $this->filesystem->ensureDirectoryExists($targetPath);
83
84
        $this->copyGitHooks($originPath, $targetPath, true);
85
    }
86
87
    /**
88
     * {@inheritDoc}
89
     */
90
    public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
91
    {
92
        parent::uninstall($repo, $package);
93
94
        $gitRootPath = realpath($this->getGitRootPath());
95
        if (!is_dir($gitRootPath)) {
96
            $this->io->writeError(sprintf(
97
                '    <warning>Skipped update of %s: Not a git repository found on "git-root" path %s</warning>',
98
                $package->getName(),
99
                $gitRootPath
100
            ));
101
102
            return;
103
        }
104
105
        $originPath = $this->getInstallPath($package);
106
        $targetPath = $this->getGitHooksInstallPath();
107
108
        if ($this->io->isVerbose()) {
109
            $this->io->write(sprintf('    Uninstalling git hooks from %s into %s', $originPath, $targetPath));
110
        }
111
112
        $this->removeGitHooks($originPath, $targetPath);
113
    }
114
115
    /**
116
     * @param string $sourcePath
117
     * @param string $targetPath
118
     * @param bool   $isUpdate
119
     */
120
    private function copyGitHooks($sourcePath, $targetPath, $isUpdate = false)
121
    {
122
        $i = new \FilesystemIterator($sourcePath);
123
124
        foreach ($i as $githook) {
125
            // ignore all files not matching a git hook name
126
            if (!array_search($githook->getFilename(), GitHooks::$hookFilename)) {
127
                continue;
128
            }
129
130
            $newPath = $targetPath . '/' . $githook->getFilename();
131
132
            // check if .sample version exists in that case rename it
133
            if (file_exists($newPath . GitHooks::SAMPLE)) {
134
                rename($newPath . GitHooks::SAMPLE, $newPath . GitHooks::SAMPLE . '.bk');
135
            }
136
137
            // check if there is already a git hook with same name do nothing
138
            if (file_exists($newPath) && !$isUpdate) {
139
                $this->io->write(sprintf('    Found already existing %s git hook. Doing nothing.', $githook->getFilename()));
140
                continue;
141
            }
142
143
            // if hook already exist but anything changed update it
144
            if (file_exists($newPath) && $isUpdate && sha1_file($githook->getPathname()) === sha1_file($newPath)) {
145
                continue;
146
            }
147
148
            $this->io->write(sprintf('    Installing git hook %s', $githook->getFilename()));
149
            $this->filesystem->relativeSymlink($githook->getPathname(), $newPath);
150
            Silencer::call('chmod', $newPath, 0777 & ~umask());
151
        }
152
    }
153
154
    /**
155
     * @param string $sourcePath
156
     * @param string $targetPath
157
     */
158
    private function removeGitHooks($sourcePath, $targetPath)
159
    {
160
        $i = new \FilesystemIterator($sourcePath);
161
162
        foreach ($i as $githook) {
163
            // ignore all files not matching a git hook name
164
            if (!array_search($githook->getFilename(), GitHooks::$hookFilename)) {
165
                continue;
166
            }
167
168
            $newPath = $targetPath . '/' . $githook->getFilename();
169
            if (file_exists($newPath)) {
170
                $this->io->write(sprintf('   Removing git hook %s', $githook->getFilename()));
171
                unlink($newPath);
172
            }
173
        }
174
    }
175
176
    /**
177
     * Returns the installation path of the Git hooks
178
     *
179
     * @return string
180
     */
181
    private function getGitHooksInstallPath()
182
    {
183
        return $this->getGitRootPath() . '/hooks';
184
    }
185
186
    /**
187
     * Returns the git root path
188
     *
189
     * @return string
190
     */
191
    private function getGitRootPath()
192
    {
193
        $config = $this->composer->getPackage()->getExtra();
194
        $relPath = array_key_exists(Config::GIT_ROOT_DIR_KEY, $config) ? ('/' . $config[Config::GIT_ROOT_DIR_KEY]) : '';
195
196
        return $this->vendorDir . $relPath . '/../.git';
197
    }
198
}
199