Completed
Pull Request — master (#25)
by Damian
03:36
created

VendorPlugin   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 57
dl 0
loc 200
rs 10
c 0
b 0
f 0
wmc 22

11 Methods

Rating   Name   Duplication   Size   Complexity  
A getSubscribedEvents() 0 8 1
A uninstallPackage() 0 23 5
A installPackage() 0 10 2
A installRootPackage() 0 8 1
A getLibrary() 0 14 2
A getCapabilities() 0 4 1
A installLibrary() 0 13 3
A __construct() 0 3 1
A getOperationPackage() 0 13 4
A getProjectPath() 0 3 1
A activate() 0 2 1
1
<?php
2
3
namespace SilverStripe\VendorPlugin;
4
5
use Composer\Composer;
6
use Composer\DependencyResolver\Operation\InstallOperation;
7
use Composer\DependencyResolver\Operation\UninstallOperation;
8
use Composer\DependencyResolver\Operation\UpdateOperation;
9
use Composer\EventDispatcher\EventSubscriberInterface;
10
use Composer\Factory;
11
use Composer\Installer\PackageEvent;
12
use Composer\IO\IOInterface;
13
use Composer\Package\PackageInterface;
14
use Composer\Plugin\Capability\CommandProvider;
15
use Composer\Plugin\Capable;
16
use Composer\Plugin\PluginInterface;
17
use Composer\Script\Event;
18
use Composer\Util\Filesystem;
19
use SilverStripe\VendorPlugin\Console\VendorCommandProvider;
20
21
/**
22
 * Provides public webroot rewrite functionality for vendor modules
23
 */
24
class VendorPlugin implements PluginInterface, EventSubscriberInterface, Capable
25
{
26
    /**
27
     * Method env var to query
28
     */
29
    const METHOD_ENV = 'SS_VENDOR_METHOD';
30
31
    /**
32
     * Method name for "none" option
33
     */
34
    const METHOD_NONE = 'none';
35
36
    /**
37
     * Method name to auto-attempt best method
38
     */
39
    const METHOD_AUTO = 'auto';
40
41
    /**
42
     * File name to use for linking method storage
43
     */
44
    const METHOD_FILE = '.method';
45
46
    /**
47
     * Define default as 'auto'
48
     */
49
    const METHOD_DEFAULT = self::METHOD_AUTO;
50
51
    /**
52
     * @var Filesystem
53
     */
54
    protected $filesystem = null;
55
56
    public function __construct()
57
    {
58
        $this->filesystem = new Filesystem();
59
    }
60
61
    /**
62
     * Apply vendor plugin
63
     *
64
     * @param Composer $composer
65
     * @param IOInterface $io
66
     */
67
    public function activate(Composer $composer, IOInterface $io)
68
    {
69
    }
70
71
    public static function getSubscribedEvents()
72
    {
73
        return [
74
            'post-package-update' => 'installPackage',
75
            'post-package-install' => 'installPackage',
76
            'pre-package-uninstall' => 'uninstallPackage',
77
            'post-install-cmd' => 'installRootPackage',
78
            'post-update-cmd' => 'installRootPackage',
79
        ];
80
    }
81
82
    /**
83
     * Gets library being installed
84
     *
85
     * @param PackageEvent $event
86
     * @return Library|null
87
     */
88
    public function getLibrary(PackageEvent $event)
89
    {
90
        // Ensure package is the valid type
91
        $package = $this->getOperationPackage($event);
92
        if (!$package) {
0 ignored issues
show
introduced by
$package is of type Composer\Package\PackageInterface, thus it always evaluated to true.
Loading history...
93
            return null;
94
        }
95
96
        // Get appropriate installer and query install path
97
        $installer = $event->getComposer()->getInstallationManager()->getInstaller($package->getType());
98
        $path = $installer->getInstallPath($package);
99
100
        // Build module
101
        return new Library($this->getProjectPath(), $path);
102
    }
103
104
    /**
105
     * Install resources from an installed or updated package
106
     *
107
     * @param PackageEvent $event
108
     */
109
    public function installPackage(PackageEvent $event)
110
    {
111
        // Ensure module exists and requires exposure
112
        $library = $this->getLibrary($event);
113
        if (!$library) {
0 ignored issues
show
introduced by
$library is of type SilverStripe\VendorPlugin\Library, thus it always evaluated to true.
Loading history...
114
            return;
115
        }
116
117
        // Install found library
118
        $this->installLibrary($event->getIO(), $library);
119
    }
120
121
    /**
122
     * Install resources from the root package
123
     *
124
     * @param Event $event
125
     */
126
    public function installRootPackage(Event $event)
127
    {
128
        // Build library in base path
129
        $basePath = $this->getProjectPath();
130
        $library = new Library($basePath, $basePath);
131
132
        // Pass to library installer
133
        $this->installLibrary($event->getIO(), $library);
134
    }
135
136
    /**
137
     * Get base path to project
138
     *
139
     * @return string
140
     */
141
    protected function getProjectPath()
142
    {
143
        return dirname(realpath(Factory::getComposerFile()));
144
    }
145
146
    /**
147
     * Remove package
148
     *
149
     * @param PackageEvent $event
150
     */
151
    public function uninstallPackage(PackageEvent $event)
152
    {
153
        // Check if library exists and exposes any directories
154
        $library = $this->getLibrary($event);
155
        if (!$library || !$library->requiresExpose()) {
0 ignored issues
show
introduced by
$library is of type SilverStripe\VendorPlugin\Library, thus it always evaluated to true.
Loading history...
156
            return;
157
        }
158
159
        // Check path to remove
160
        $target = $library->getPublicPath();
161
        if (!is_dir($target)) {
162
            return;
163
        }
164
165
        // Remove directory
166
        $name = $library->getName();
167
        $event->getIO()->write("Removing web directories for module <info>{$name}</info>:");
168
        $this->filesystem->removeDirectory($target);
169
170
        // Cleanup empty vendor dir if this is the last module
171
        $targetParent = dirname($target);
172
        if ($this->filesystem->isDirEmpty($targetParent)) {
173
            $this->filesystem->removeDirectory($targetParent);
174
        }
175
    }
176
177
    /**
178
     * Get target package from operation
179
     *
180
     * @param PackageEvent $event
181
     * @return PackageInterface
182
     */
183
    protected function getOperationPackage(PackageEvent $event)
184
    {
185
        $operation = $event->getOperation();
186
        if ($operation instanceof UpdateOperation) {
187
            return $operation->getTargetPackage();
188
        }
189
        if ($operation instanceof InstallOperation) {
190
            return $operation->getPackage();
191
        }
192
        if ($operation instanceof UninstallOperation) {
193
            return $operation->getPackage();
194
        }
195
        return null;
196
    }
197
198
    public function getCapabilities()
199
    {
200
        return [
201
            CommandProvider::class => VendorCommandProvider::class
202
        ];
203
    }
204
205
    /**
206
     * Expose the given Library object
207
     *
208
     * @param IOInterface $IO
209
     * @param Library $library
210
     */
211
    protected function installLibrary(IOInterface $IO, Library $library)
212
    {
213
        if (!$library || !$library->requiresExpose()) {
0 ignored issues
show
introduced by
$library is of type SilverStripe\VendorPlugin\Library, thus it always evaluated to true.
Loading history...
214
            return;
215
        }
216
217
        // Create exposure task
218
        $task = new VendorExposeTask(
219
            $this->getProjectPath(),
220
            $this->filesystem,
221
            $library->getBasePublicPath()
222
        );
223
        $task->process($IO, [$library]);
224
    }
225
}
226