33namespace Bugo \Sass ;
44
55use Composer \Composer ;
6- use Composer \EventDispatcher \EventSubscriberInterface ;
76use Composer \IO \IOInterface ;
7+ use Composer \Plugin \PluginInterface ;
8+ use Composer \EventDispatcher \EventSubscriberInterface ;
89use Composer \Installer \PackageEvent ;
10+ use Composer \Script \Event ;
11+ use Composer \Script \ScriptEvents ;
912use Composer \Installer \PackageEvents ;
10- use Composer \ Plugin \ PluginInterface ;
13+ use RuntimeException ;
1114use Symfony \Component \Process \Process ;
1215
1316use function copy ;
@@ -23,57 +26,69 @@ class Plugin implements PluginInterface, EventSubscriberInterface
2326{
2427 private const PACKAGE_NAME = 'sass-embedded-php ' ;
2528
26- private string $ packagePath ;
29+ private string $ packagePath = '' ;
2730
28- private string $ binDir ;
31+ private string $ binDir = '' ;
2932
3033 public function activate (Composer $ composer , IOInterface $ io ): void
3134 {
3235 $ config = $ composer ->getConfig ();
3336
34- $ this ->packagePath = realpath (__DIR__ . '/../ ' );
37+ $ this ->packagePath = ( string ) realpath (__DIR__ . '/../ ' );
3538 $ this ->binDir = (string ) $ config ->get ('bin-dir ' );
3639 }
3740
38- public function deactivate (Composer $ composer , IOInterface $ io ): void
39- {
40- }
41+ public function deactivate (Composer $ composer , IOInterface $ io ): void {}
4142
42- public function uninstall (Composer $ composer , IOInterface $ io ): void
43- {
44- }
43+ public function uninstall (Composer $ composer , IOInterface $ io ): void {}
4544
46- /* @uses onPostPackageUpdate */
45+ /* @uses onPackageEvent */
46+ /* @uses onScriptEvent */
4747 public static function getSubscribedEvents (): array
4848 {
4949 return [
50- PackageEvents::POST_PACKAGE_INSTALL => 'onPostPackageUpdate ' ,
51- PackageEvents::POST_PACKAGE_UPDATE => 'onPostPackageUpdate ' ,
50+ PackageEvents::POST_PACKAGE_INSTALL => 'onPackageEvent ' ,
51+ PackageEvents::POST_PACKAGE_UPDATE => 'onPackageEvent ' ,
52+ ScriptEvents::POST_AUTOLOAD_DUMP => 'onScriptEvent ' ,
5253 ];
5354 }
5455
55- public function onPostPackageUpdate (PackageEvent $ event ): void
56+ public function onPackageEvent (PackageEvent $ event ): void
5657 {
57- static $ alreadyRun = false ;
58+ $ this ->ensureInitializedFromComposer ($ event ->getComposer ());
59+ $ this ->runInstall ($ event ->getIO ());
60+ }
5861
59- if ($ alreadyRun ) {
60- return ;
62+ public function onScriptEvent (Event $ event ): void
63+ {
64+ $ this ->ensureInitializedFromComposer ($ event ->getComposer ());
65+ $ this ->runInstall ($ event ->getIO ());
66+ }
67+
68+ private function ensureInitializedFromComposer (?Composer $ composer ): void
69+ {
70+ if ($ this ->packagePath === '' ) {
71+ $ this ->packagePath = (string ) realpath (__DIR__ . '/../ ' );
6172 }
6273
63- $ alreadyRun = true ;
74+ if ($ composer !== null && $ this ->binDir === '' ) {
75+ $ this ->binDir = (string ) $ composer ->getConfig ()->get ('bin-dir ' );
76+ }
77+ }
6478
65- $ this ->installNpm ($ event ->getIO ());
66- $ this ->copyBinary ($ event ->getIO ());
79+ private function runInstall (IOInterface $ io ): void
80+ {
81+ $ this ->installNpm ($ io );
82+ $ this ->copyBinary ($ io );
6783 }
6884
6985 private function installNpm (IOInterface $ io ): void
7086 {
71- if ($ this ->packagePath === '' ) {
87+ if ($ this ->packagePath === '' || ! is_dir ( $ this -> packagePath ) ) {
7288 $ io ->write (sprintf (
7389 '<warning>[%s]</warning> package directory not found, skipping npm install. ' ,
7490 self ::PACKAGE_NAME
7591 ));
76-
7792 return ;
7893 }
7994
@@ -84,20 +99,31 @@ private function installNpm(IOInterface $io): void
8499 self ::PACKAGE_NAME ,
85100 $ this ->packagePath
86101 ));
87-
88102 return ;
89103 }
90104
91105 $ npmBin = (strtoupper (substr (PHP_OS , 0 , 3 )) === 'WIN ' ) ? 'npm.cmd ' : 'npm ' ;
92106
93- $ checkNpm = new Process ([$ npmBin , '--version ' ]);
94- $ checkNpm ->run ();
95- if (! $ checkNpm ->isSuccessful ()) {
107+ $ check = new Process ([$ npmBin , '--version ' ]);
108+ $ check ->setTimeout (10 );
109+
110+ try {
111+ $ check ->run ();
112+ } catch (RuntimeException $ e ) {
96113 $ io ->write (sprintf (
97- '<warning>[%s]</warning> npm not found in PATH, skipping npm install. ' ,
98- self ::PACKAGE_NAME
114+ '<warning>[%s]</warning> failed to execute "%s --version": %s ' ,
115+ self ::PACKAGE_NAME ,
116+ $ npmBin ,
117+ $ e ->getMessage ()
99118 ));
119+ return ;
120+ }
100121
122+ if (! $ check ->isSuccessful ()) {
123+ $ io ->write (sprintf (
124+ '<warning>[%s]</warning> npm not found in PATH or not executable, skipping npm install. ' ,
125+ self ::PACKAGE_NAME
126+ ));
101127 return ;
102128 }
103129
@@ -107,33 +133,49 @@ private function installNpm(IOInterface $io): void
107133 '<info>[%s]</info> node_modules/sass-embedded already exists, skipping npm install. ' ,
108134 self ::PACKAGE_NAME
109135 ));
110-
111136 return ;
112137 }
113138
114139 $ process = new Process ([$ npmBin , 'install ' ], $ this ->packagePath );
115- $ process ->setTimeout (null );
116- $ process ->run (function ($ type , $ buffer ): void { echo $ buffer ; });
140+ $ process ->setTimeout (300 );
141+
142+ $ io ->write (sprintf (
143+ '<info>[%s]</info> running "npm install" in %s ' ,
144+ self ::PACKAGE_NAME , $ this ->packagePath
145+ ));
146+
147+ $ process ->run (function (string $ type , string $ buffer ) use ($ io ): void {
148+ $ io ->write ($ buffer );
149+ });
117150
118151 if ($ process ->isSuccessful ()) {
119152 $ io ->write (sprintf (
120153 '<info>[%s]</info> npm install completed successfully. ' ,
121154 self ::PACKAGE_NAME
122155 ));
123-
124156 return ;
125157 }
126158
127- $ io ->write (sprintf ('<error>[%s]</error> npm install failed: ' , self ::PACKAGE_NAME ));
159+ $ io ->write (sprintf (
160+ '<error>[%s]</error> npm install failed: ' ,
161+ self ::PACKAGE_NAME
162+ ));
163+
128164 $ io ->write ($ process ->getErrorOutput ());
129165 }
130166
131167 private function copyBinary (IOInterface $ io ): void
132168 {
133169 $ source = $ this ->packagePath . '/bin/bridge.js ' ;
134- $ target = $ this ->binDir . '/bridge.js ' ;
170+ $ targetDir = rtrim ($ this ->binDir , '/ \\' );
171+ $ target = $ targetDir . DIRECTORY_SEPARATOR . 'bridge.js ' ;
135172
136173 if (! is_file ($ source )) {
174+ $ io ->write (sprintf (
175+ '<warning>[%s]</warning> binary not found in package (%s), skipping copy. ' ,
176+ self ::PACKAGE_NAME ,
177+ $ source
178+ ));
137179 return ;
138180 }
139181
@@ -142,9 +184,17 @@ private function copyBinary(IOInterface $io): void
142184 }
143185
144186 if (@copy ($ source , $ target )) {
145- $ io ->write (sprintf ('<info>[%s]</info> Binary overwritten: %s ' , self ::PACKAGE_NAME , $ target ));
187+ $ io ->write (sprintf (
188+ '<info>[%s]</info> Binary copied: %s ' ,
189+ self ::PACKAGE_NAME ,
190+ $ target
191+ ));
146192 } else {
147- $ io ->writeError (sprintf ('<error>[%s]</error> Failed to copy binary ' , self ::PACKAGE_NAME ));
193+ $ io ->write (sprintf (
194+ '<error>[%s]</error> Failed to copy binary to %s ' ,
195+ self ::PACKAGE_NAME ,
196+ $ target
197+ ));
148198 }
149199 }
150200}
0 commit comments