|
2 | 2 |
|
3 | 3 | namespace Trakli\PluginEngine\Console\Commands; |
4 | 4 |
|
5 | | -use Illuminate\Support\Facades\Http; |
6 | 5 | use Illuminate\Support\Str; |
7 | | -use RuntimeException; |
8 | 6 | use Symfony\Component\Process\Process; |
9 | | -use ZipArchive; |
10 | 7 |
|
11 | 8 | class InstallCommand extends PluginCommand |
12 | 9 | { |
13 | 10 | protected $signature = 'plugin:install |
14 | 11 | {package : The package name (vendor/name) or URL of the plugin to install} |
15 | 12 | {--dev : Install development dependencies}' |
16 | | - . '{--no-dev : Do not install development dependencies}' |
17 | | - . '{--no-scripts : Skip running installation scripts}' |
18 | | - . '{--no-plugins : Skip installing plugins}' |
19 | | - . '{--no-scripts : Skip running scripts}' |
20 | | - . '{--prefer-source : Install packages from source when possible}' |
21 | | - . '{--prefer-dist : Install packages from dist when possible}' |
22 | | - . '{--optimize-autoloader : Optimize autoloader during autoloader dump}' |
23 | | - . '{--classmap-authoritative : Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`}' |
24 | | - . '{--apcu-autoloader : Use APCu to cache found/not-found classes}'; |
| 13 | + .'{--no-dev : Do not install development dependencies}' |
| 14 | + .'{--no-scripts : Skip running installation scripts}' |
| 15 | + .'{--no-plugins : Skip installing plugins}' |
| 16 | + .'{--no-scripts : Skip running scripts}' |
| 17 | + .'{--prefer-source : Install packages from source when possible}' |
| 18 | + .'{--prefer-dist : Install packages from dist when possible}' |
| 19 | + .'{--optimize-autoloader : Optimize autoloader during autoloader dump}' |
| 20 | + .'{--classmap-authoritative : Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`}' |
| 21 | + .'{--apcu-autoloader : Use APCu to cache found/not-found classes}'; |
25 | 22 |
|
26 | 23 | protected $description = 'Install a plugin'; |
27 | 24 |
|
28 | 25 | public function handle() |
29 | 26 | { |
30 | 27 | $package = $this->argument('package'); |
31 | | - |
| 28 | + |
32 | 29 | try { |
33 | 30 | $this->info("Installing plugin: {$package}"); |
34 | | - |
| 31 | + |
35 | 32 | // Check if it's a URL or a package name |
36 | 33 | if (filter_var($package, FILTER_VALIDATE_URL)) { |
37 | 34 | return $this->installFromUrl($package); |
38 | 35 | } |
39 | | - |
| 36 | + |
40 | 37 | // Otherwise, treat as a Composer package |
41 | 38 | return $this->installWithComposer($package); |
42 | | - |
| 39 | + |
43 | 40 | } catch (\Exception $e) { |
44 | | - $this->error("Failed to install plugin: " . $e->getMessage()); |
| 41 | + $this->error('Failed to install plugin: '.$e->getMessage()); |
45 | 42 | if ($this->getOutput()->isVerbose()) { |
46 | 43 | $this->error($e->getTraceAsString()); |
47 | 44 | } |
| 45 | + |
48 | 46 | return 1; |
49 | 47 | } |
50 | 48 | } |
51 | | - |
| 49 | + |
52 | 50 | protected function installFromUrl(string $url): int |
53 | 51 | { |
54 | 52 | $this->info("Downloading plugin from URL: {$url}"); |
55 | | - |
| 53 | + |
56 | 54 | // Extract the plugin name from the URL or generate a random one |
57 | 55 | $pluginName = basename(parse_url($url, PHP_URL_PATH), '.git'); |
58 | 56 | $pluginName = preg_replace('/[^a-z0-9\-_]/i', '', $pluginName); |
59 | | - |
| 57 | + |
60 | 58 | if (empty($pluginName)) { |
61 | | - $pluginName = 'plugin-' . Str::random(8); |
| 59 | + $pluginName = 'plugin-'.Str::random(8); |
62 | 60 | } |
63 | | - |
64 | | - $tempDir = sys_get_temp_dir() . '/trakli-plugin-' . Str::random(8); |
| 61 | + |
| 62 | + $tempDir = sys_get_temp_dir().'/trakli-plugin-'.Str::random(8); |
65 | 63 | mkdir($tempDir, 0755, true); |
66 | | - |
| 64 | + |
67 | 65 | try { |
68 | 66 | // Clone the repository |
69 | 67 | $process = new Process(['git', 'clone', '--depth', '1', $url, $tempDir]); |
70 | 68 | $process->setTimeout(300); |
71 | 69 | $process->run(); |
72 | | - |
73 | | - if (!$process->isSuccessful()) { |
| 70 | + |
| 71 | + if (! $process->isSuccessful()) { |
74 | 72 | throw new \RuntimeException($process->getErrorOutput()); |
75 | 73 | } |
76 | | - |
| 74 | + |
77 | 75 | // Install the plugin |
78 | 76 | return $this->installFromPath($tempDir, $pluginName); |
79 | | - |
| 77 | + |
80 | 78 | } finally { |
81 | 79 | // Clean up |
82 | 80 | $this->removeDirectory($tempDir); |
83 | 81 | } |
84 | 82 | } |
85 | | - |
| 83 | + |
86 | 84 | protected function installWithComposer(string $package): int |
87 | 85 | { |
88 | 86 | $this->info("Installing plugin using Composer: {$package}"); |
89 | | - |
| 87 | + |
90 | 88 | // Build the Composer command |
91 | 89 | $command = array_merge( |
92 | 90 | ['composer', 'require', $package], |
93 | 91 | $this->getComposerOptions() |
94 | 92 | ); |
95 | | - |
| 93 | + |
96 | 94 | $process = new Process($command, base_path(), null, null, null); |
97 | 95 | $process->setTty(Process::isTtySupported()); |
98 | | - |
| 96 | + |
99 | 97 | $process->run(function ($type, $buffer) { |
100 | 98 | $this->output->write($buffer); |
101 | 99 | }); |
102 | | - |
103 | | - if (!$process->isSuccessful()) { |
| 100 | + |
| 101 | + if (! $process->isSuccessful()) { |
104 | 102 | throw new \RuntimeException("Failed to install package: {$package}"); |
105 | 103 | } |
106 | | - |
| 104 | + |
107 | 105 | return 0; |
108 | 106 | } |
109 | | - |
| 107 | + |
110 | 108 | protected function installFromPath(string $path, string $pluginName): int |
111 | 109 | { |
112 | 110 | $pluginsPath = config('plugins.path', base_path('plugins')); |
113 | | - $targetPath = rtrim($pluginsPath, '/') . '/' . $pluginName; |
114 | | - |
| 111 | + $targetPath = rtrim($pluginsPath, '/').'/'.$pluginName; |
| 112 | + |
115 | 113 | // Create plugins directory if it doesn't exist |
116 | | - if (!is_dir($pluginsPath)) { |
| 114 | + if (! is_dir($pluginsPath)) { |
117 | 115 | mkdir($pluginsPath, 0755, true); |
118 | 116 | } |
119 | | - |
| 117 | + |
120 | 118 | // Check if plugin already exists |
121 | 119 | if (is_dir($targetPath)) { |
122 | 120 | throw new \RuntimeException("Plugin directory already exists: {$targetPath}"); |
123 | 121 | } |
124 | | - |
| 122 | + |
125 | 123 | // Move the plugin to the plugins directory |
126 | 124 | rename($path, $targetPath); |
127 | | - |
| 125 | + |
128 | 126 | $this->info("Plugin installed successfully to: {$targetPath}"); |
129 | | - |
| 127 | + |
130 | 128 | // Run plugin discovery |
131 | 129 | $this->call('plugin:discover'); |
132 | | - |
| 130 | + |
133 | 131 | return 0; |
134 | 132 | } |
135 | | - |
| 133 | + |
136 | 134 | protected function getComposerOptions(): array |
137 | 135 | { |
138 | 136 | $options = []; |
139 | | - |
| 137 | + |
140 | 138 | // Add boolean options |
141 | 139 | foreach (['dev', 'no-dev', 'no-scripts', 'no-plugins', 'prefer-source', 'prefer-dist', 'optimize-autoloader', 'classmap-authoritative', 'apcu-autoloader'] as $option) { |
142 | 140 | if ($this->option($option)) { |
143 | | - $options[] = '--' . $option; |
| 141 | + $options[] = '--'.$option; |
144 | 142 | } |
145 | 143 | } |
146 | | - |
| 144 | + |
147 | 145 | return $options; |
148 | 146 | } |
149 | | - |
| 147 | + |
150 | 148 | protected function removeDirectory(string $directory): bool |
151 | 149 | { |
152 | | - if (!is_dir($directory)) { |
| 150 | + if (! is_dir($directory)) { |
153 | 151 | return false; |
154 | 152 | } |
155 | | - |
| 153 | + |
156 | 154 | $files = array_diff(scandir($directory), ['.', '..']); |
157 | | - |
| 155 | + |
158 | 156 | foreach ($files as $file) { |
159 | | - $path = $directory . '/' . $file; |
| 157 | + $path = $directory.'/'.$file; |
160 | 158 | is_dir($path) ? $this->removeDirectory($path) : unlink($path); |
161 | 159 | } |
162 | | - |
| 160 | + |
163 | 161 | return rmdir($directory); |
164 | 162 | } |
165 | 163 | } |
0 commit comments