Completed
Push — dev ( d88b71...b931a4 )
by Antonio
02:32 queued 17s
created

GitHooksInstaller::update()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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