GitHooksInstaller   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 179
Duplicated Lines 0 %

Test Coverage

Coverage 2.27%

Importance

Changes 0
Metric Value
wmc 25
dl 0
loc 179
ccs 2
cts 88
cp 0.0227
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A supports() 0 3 1
A getGitHooksInstallPath() 0 3 1
A uninstall() 0 23 3
A getGitRootPath() 0 6 2
B update() 0 27 3
A removeGitHooks() 0 14 4
C installGitHooks() 0 26 8
B install() 0 27 3
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 = $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->installGitHooks($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 = $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->installGitHooks($originPath, $targetPath, true);
85
    }
86
87
    /**
88
     * {@inheritDoc}
89
     */
90
    public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
91
    {
92
        $gitRootPath = $this->getGitRootPath();
93
        if (!is_dir($gitRootPath)) {
94
            $this->io->writeError(sprintf(
95
                '    <warning>Skipped update of %s: Not a git repository found on "git-root" path %s</warning>',
96
                $package->getName(),
97
                $gitRootPath
98
            ));
99
100
            return;
101
        }
102
103
        $originPath = $this->getInstallPath($package);
104
        $targetPath = $this->getGitHooksInstallPath();
105
106
        if ($this->io->isVerbose()) {
107
            $this->io->write(sprintf('    Uninstalling git hooks from %s into %s', $originPath, $targetPath));
108
        }
109
110
        $this->removeGitHooks($originPath, $targetPath);
111
112
        parent::uninstall($repo, $package);
113
    }
114
115
    /**
116
     * @param string $sourcePath
117
     * @param string $targetPath
118
     * @param bool   $isUpdate
119
     */
120
    private function installGitHooks($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 there is already a git hook with same name do nothing
133
            if (file_exists($newPath) && !$isUpdate) {
134
                $this->io->write(sprintf('    Found already existing %s git hook. Doing nothing.', $githook->getFilename()));
135
                continue;
136
            }
137
138
            // if hook already exist but anything changed update it
139
            if (file_exists($newPath) && $isUpdate && sha1_file($githook->getPathname()) === sha1_file($newPath)) {
140
                continue;
141
            }
142
143
            $this->io->write(sprintf('    Installing git hook %s', $githook->getFilename()));
144
            $this->filesystem->relativeSymlink($githook->getPathname(), $newPath);
145
            Silencer::call('chmod', $newPath, 0777 & ~umask());
146
        }
147
    }
148
149
    /**
150
     * @param string $sourcePath
151
     * @param string $targetPath
152
     */
153
    private function removeGitHooks($sourcePath, $targetPath)
154
    {
155
        $i = new \FilesystemIterator($sourcePath);
156
157
        foreach ($i as $githook) {
158
            // ignore all files not matching a git hook name
159
            if (!array_search($githook->getFilename(), GitHooks::$hookFilename)) {
160
                continue;
161
            }
162
163
            $newPath = $targetPath . '/' . $githook->getFilename();
164
            if (file_exists($newPath)) {
165
                $this->io->write(sprintf('   Removing git hook %s', $githook->getFilename()));
166
                unlink($newPath);
167
            }
168
        }
169
    }
170
171
    /**
172
     * Returns the installation path of the Git hooks
173
     *
174
     * @return string
175
     */
176
    private function getGitHooksInstallPath()
177
    {
178
        return $this->getGitRootPath() . '/hooks';
179
    }
180
181
    /**
182
     * Returns the git root path
183
     *
184
     * @return string
185
     */
186
    private function getGitRootPath()
187
    {
188
        $config = $this->composer->getPackage()->getExtra();
189
        $relPath = array_key_exists(Config::GIT_ROOT_DIR_KEY, $config) ? ('/' . $config[Config::GIT_ROOT_DIR_KEY]) : '';
190
191
        return $this->vendorDir . $relPath . '/../.git';
192
    }
193
}
194