Passed
Push — master ( dd4b11...72117a )
by Tom
04:20 queued 31s
created

Version::gitComposerVersion()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 8
nop 2
dl 0
loc 22
ccs 12
cts 12
cp 1
crap 5
rs 9.5222
c 0
b 0
f 0
1
<?php
2
3
/* this file is part of pipelines */
4
5
namespace Ktomk\Pipelines\Utility;
6
7
/**
8
 * Utility class to obtain version of a PHP based CLI utility including but not
9
 * limited to a Git project context
10
 *
11
 * @package Ktomk\Pipelines\Utility
12
 */
13
class Version
14
{
15
    /**
16
     * @var string
17
     */
18
    private $dir;
19
20
    /**
21
     * @var string
22
     */
23
    private $placeholder;
24
25
    /**
26
     * @var string
27
     */
28
    private $version;
29
30
    /**
31
     * resolve version in case it is still a placeholder @.@.@,
32
     * e.g. when a source installation (composer package or git
33
     * clone)
34
     *
35
     * @param string $version
36
     *
37
     * @return string resolved version
38
     */
39 1
    public static function resolve($version)
40
    {
41 1
        $subject = new self($version);
42
43 1
        return $subject->resolveSourceVersion();
44
    }
45
46
    /**
47
     * obtain version from git vcs
48
     *
49
     * the version is a composer accepted version (incl. additions from vcs format)
50
     *
51
     * @param string $dir
52
     * @param string $version [optional] provide version instead of obtaining from HEAD
53
     *
54
     * @return array($version, $error)
55
     */
56 4
    public static function gitComposerVersion($dir = '.', $version = null)
57
    {
58 4
        $status = 0;
59 4
        $version || $version = exec(
60 3
            sprintf(
61 3
                'git -C %s describe --tags --always --first-parent --dirty=+dirty --match \'[0-9].[0-9]*.[0-9]*\' 2>/dev/null',
62 3
                escapeshellarg($dir)
63
            ),
64
            $output,
65
            $status
66
        );
67 4
        unset($output);
68
69 4
        if (0 !== $status) {
70 2
            return array(null, sprintf('git-describe non-zero exit status: %d', $status));
71
        }
72
73 2
        if (!preg_match('~^(\d+\.\d+\.\d+)(?:[+-](.*))?$~D', $version, $matches)) {
74 2
            return array(null, sprintf('version format mismatch: %s', $version));
75
        }
76
77 1
        return array($matches[1] . (empty($matches[2]) ? '' : '+' . $matches[2]), null);
78
    }
79
80
    /**
81
     * Version constructor.
82
     *
83
     * @param string $version input
84
     * @param string $placeholder
85
     * @param string $dir [optional]
86
     */
87 11
    public function __construct($version, $placeholder = '@.@.@', $dir = null)
88
    {
89 11
        $this->version = $version;
90 11
        $this->placeholder = $placeholder;
91 11
        $this->dir = null === $dir ? __DIR__ : $dir;
92 11
    }
93
94
    /**
95
     * obtain utility version for the installation / source
96
     * in use.
97
     *
98
     * @return string
99
     */
100 5
    public function resolveSourceVersion()
101
    {
102
        // as build version
103 5
        if (null !== $buildVersion = $this->getBuildVersion()) {
104 1
            return $buildVersion;
105
        }
106
107
        // as composer package
108 4
        if (null !== $packageVersion = $this->getPackageVersion()) {
109 1
            return $packageVersion;
110
        }
111
112
        // as git repository
113 3
        if (null !== $gitVersion = $this->getGitVersion()) {
114 1
            return $gitVersion;
115
        }
116
117
        return $this->version; // @codeCoverageIgnore
118
    }
119
120
    /**
121
     * is version from build?
122
     *
123
     * @return bool
124
     */
125 3
    public function isBuildVersion()
126
    {
127 3
        return $this->placeholder !== $this->version;
128
    }
129
130
    /**
131
     * @return null|string version or null if there is no build version
132
     */
133 3
    public function getBuildVersion()
134
    {
135 3
        if ($this->isBuildVersion()) {
136 2
            return $this->version;
137
        }
138
139 1
        return null;
140
    }
141
142
    /**
143
     * get package version from composer/installed.json.
144
     *
145
     * this is possible if pipelines is required as a composer package.
146
     *
147
     * @return null|string version or null if not required as composer package
148
     */
149 3
    public function getPackageVersion()
150
    {
151 3
        foreach ($this->getInstalledPackages() as $package) {
152 2
            if (!isset($package->name) || 'ktomk/pipelines' !== $package->name) {
153 2
                continue;
154
            }
155 2
            if (!isset($package->version)) {
156 1
                break;
157
            }
158
159 1
            return $package->version . '-composer';
160
        }
161
162 2
        return null;
163
    }
164
165
    /**
166
     * obtain the list of installed packages
167
     *
168
     * from composer installed.json, file format change log:
169
     *
170
     *  1.0.0: no installed.json
171
     *  1.6.4: list of packages
172
     *  2.0.0: installed struct w/ packages (and dev flag, 2.0.5 dev-packages-names list)
173
     *
174
     * @return array of installed packages, empty array if none
175
     */
176 1
    public function getInstalledPackages()
177
    {
178 1
        $installedJsonFile = $this->dir . '/../../../../composer/installed.json';
179 1
        if (false === $buffer = @file_get_contents($installedJsonFile)) {
180 1
            $buffer = 'null';
181
        }
182
183 1
        $installed = json_decode($buffer, false);
184
185 1
        return (array)(isset($installed->packages) ? $installed->packages : $installed);
186
    }
187
188
    /**
189
     * get git version from git repository
190
     *
191
     * @return null|string
192
     */
193 3
    public function getGitVersion()
194
    {
195 3
        list($version) = self::gitComposerVersion($this->dir);
196
197 3
        return $version;
198
    }
199
}
200