Completed
Push — master ( 11156a...aa9feb )
by Arne
03:40
created

Compiler::getStub()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
1
<?php
2
3
namespace Archivr;
4
5
use Symfony\Component\Filesystem\Filesystem;
6
use Symfony\Component\Finder\Finder;
7
8
/**
9
 * Based on the composer counterpart: https://github.com/composer/composer/blob/master/src/Composer/Compiler.php
10
 */
11
class Compiler
12
{
13
    /**
14
     * @var Filesystem
15
     */
16
    protected $filesystem;
17
18
    public function __construct()
19
    {
20
        $this->filesystem = new Filesystem();
21
    }
22
23
    public function compile(string $targetFileName): void
24
    {
25
        if (file_exists($targetFileName))
26
        {
27
            $this->filesystem->remove($targetFileName);
28
        }
29
30
31
        $phar = new \Phar($targetFileName, 0, 'archivr.phar');
32
        $phar->setSignatureAlgorithm(\Phar::SHA256);
33
34
        $phar->startBuffering();
35
36
        $this->addSourceFiles($phar);
37
        $this->addDependencyFiles($phar);
38
39
        $this->addFile($phar, new \SplFileInfo(__DIR__ . '/../bootstrap.php'));
40
        $this->addFile($phar, new \SplFileInfo(__DIR__ . '/../bin/archivr'));
41
42
        $phar->setStub($this->getStub());
43
        $phar->compressFiles(\Phar::GZ);
44
45
        $phar->stopBuffering();
46
    }
47
48
    protected function addSourceFiles(\Phar $phar): void
49
    {
50
        $finder = new Finder();
51
        $finder->files()
52
            ->ignoreVCS(true)
53
            ->name('*.php')
54
            ->in(__DIR__)
55
        ;
56
        foreach ($finder as $file)
57
        {
58
            $this->addFile($phar, $file);
59
        }
60
    }
61
62
    protected function addDependencyFiles(\Phar $phar): void
63
    {
64
        $finder = new Finder();
65
        $finder->files()
66
            ->ignoreVCS(true)
67
            ->name('*.php')
68
            ->name('LICENSE')
69
            ->exclude('docs')
70
            ->exclude('examples')
71
            ->exclude('Tests')
72
            ->exclude('tests')
73
            ->in(__DIR__ . '/../vendor/')
74
        ;
75
        foreach ($finder as $file)
76
        {
77
            $this->addFile($phar, $file);
78
        }
79
    }
80
81
    protected function addFile(\Phar $phar, \SplFileInfo $file): void
82
    {
83
        $relativePath = $this->getRelativeFilePath($file);
84
        $content = $this->stripWhitespace(file_get_contents($file->getPathname()));
85
86
        $phar->addFromString($relativePath, $content);
87
    }
88
89
    protected function getRelativeFilePath(\SplFileInfo $file): string
90
    {
91
        $realPath = $file->getRealPath();
92
        $pathPrefix = dirname(__DIR__) . DIRECTORY_SEPARATOR;
93
94
        $pos = strpos($realPath, $pathPrefix);
95
        $relativePath = ($pos !== false) ? substr_replace($realPath, '', $pos, strlen($pathPrefix)) : $realPath;
96
97
        return strtr($relativePath, '\\', '/');
98
    }
99
100
    protected function stripWhitespace(string $source): string
101
    {
102
        $output = '';
103
104
        foreach (token_get_all($source) as $token)
105
        {
106
            if (is_string($token))
107
            {
108
                $output .= $token;
109
            }
110
            elseif (in_array($token[0], [T_COMMENT, T_DOC_COMMENT]))
111
            {
112
                $output .= str_repeat("\n", substr_count($token[1], "\n"));
113
            }
114
            elseif (T_WHITESPACE === $token[0])
115
            {
116
                // reduce wide spaces
117
                $whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
118
119
                // normalize newlines to \n
120
                $whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
121
122
                // trim leading spaces
123
                $whitespace = preg_replace('{\n +}', "\n", $whitespace);
124
125
                $output .= $whitespace;
126
            }
127
            else
128
            {
129
                $output .= $token[1];
130
            }
131
        }
132
133
        return $output;
134
    }
135
136
    protected function getStub(): string
137
    {
138
        return <<<EOF
139
#!/usr/bin/env php
140
<?php
141
142
Phar::mapPhar('archivr.phar');
143
144
require 'phar://archivr.phar/bin/archivr';
145
146
__HALT_COMPILER();
147
EOF;
148
    }
149
}
150