Skip to content

Commit c5821f2

Browse files
committed
Replace eval() with AST parser.
plugin:list-all does not extend AbstractSite, infer $target_dir from CWD Remove non-specific "type" property from site:list Verify runtime path is writeable falling back to system temp directory.
1 parent 5d3c5bd commit c5821f2

File tree

5 files changed

+140
-87
lines changed

5 files changed

+140
-87
lines changed

src/Joomlatools/Console/Command/Database/Install.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
146146
};
147147

148148
$executeQuery("REPLACE INTO j_schemas (extension_id, version_id) VALUES (700, '$schema');");
149-
$executeQuery("UPDATE j_extensions SET manifest_cache = '{\"version\": \"$version->release\"}' WHERE manifest_cache = '';");
149+
$executeQuery("UPDATE j_extensions SET manifest_cache = '{\"version\": \"{$version->release}\"}' WHERE manifest_cache = '';");
150150
}
151151
}
152152

@@ -179,7 +179,7 @@ public function check(InputInterface $input, OutputInterface $output)
179179

180180
if($version !== false && $version->release)
181181
{
182-
if (in_array($sample_data, array('testing', 'learn')) && version_compare($version->release, '3.0.0', '<')) {
182+
if (in_array($sample_data, array('testing', 'learn')) && $version->major < 3) {
183183
throw new \RuntimeException(sprintf('%s does not support sample data %s', $version->release, $sample_data));
184184
}
185185
}
@@ -208,7 +208,7 @@ protected function _getSQLFiles(InputInterface $input, OutputInterface $output)
208208
if ($version !== false)
209209
{
210210
$users = 'joomla3.users.sql';
211-
if(is_numeric(substr($version->release, 0, 1)) && version_compare($version->release, '3.0.0', '<')) {
211+
if($version->major < 3) {
212212
$users = 'joomla2.users.sql';
213213
}
214214
$path = Util::getTemplatePath();
@@ -261,4 +261,4 @@ protected function _getInstallFiles($sample_data = false)
261261

262262
return $files;
263263
}
264-
}
264+
}

src/Joomlatools/Console/Command/Plugin/ListAll.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ protected function configure()
2424

2525
protected function execute(InputInterface $input, OutputInterface $output)
2626
{
27-
if (Util::isJoomla4($this->target_dir)) {
27+
if (Util::isJoomla4(getcwd() ?: dirname(__FILE__))) {
2828
$output->write("<error>This command is not implemented for Joomla 4</error>\n");
2929

30-
return;
30+
return 1;
3131
}
3232

3333
$plugins = $this->getApplication()->getPlugins();

src/Joomlatools/Console/Command/Site/Listing.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
6464
$sites[] = (object) array(
6565
'name' => $fileinfo->getFilename(),
6666
'docroot' => $docroot . '/' . $fileinfo->getFilename() . '/',
67-
'type' => $version->type == 'joomla-cms-new' ? 'joomla-cms' : $version->type,
6867
'version' => $version->release
6968
);
7069
}
@@ -82,14 +81,14 @@ protected function execute(InputInterface $input, OutputInterface $output)
8281
$result->command = $input->getArgument('command');
8382
$result->data = $sites;
8483

85-
$options = (version_compare(phpversion(),'5.4.0') >= 0 ? JSON_PRETTY_PRINT : 0);
84+
$options = (version_compare(PHP_VERSION,'5.4.0') >= 0 ? JSON_PRETTY_PRINT : 0);
8685
$string = json_encode($result, $options);
8786
break;
8887
case 'txt':
8988
default:
9089
$lines = array();
9190
foreach ($sites as $i => $site) {
92-
$lines[] = sprintf("<info>%s. %s</info> (%s %s)", ($i+1), $site->name, $site->type, $site->version);
91+
$lines[] = sprintf("<info>%s. %s</info> (%s)", ($i+1), $site->name, $site->version);
9392
}
9493

9594
$string = implode("\n", $lines);
@@ -100,4 +99,4 @@ protected function execute(InputInterface $input, OutputInterface $output)
10099

101100
return 0;
102101
}
103-
}
102+
}

src/Joomlatools/Console/Joomla/Util.php

Lines changed: 28 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99

1010
class Util
1111
{
12+
const VERSION_LOCATIONS = [
13+
'/libraries/cms/version/version.php',
14+
'/libraries/src/Version.php', // 3.8+
15+
'/libraries/joomla/version.php'
16+
];
17+
1218
protected static $_versions = array();
1319

1420
public static function executeCommand(string $command): string
@@ -33,12 +39,12 @@ public static function executeCommand(string $command): string
3339

3440
public static function isJoomla4($base): bool
3541
{
36-
return (bool) \version_compare(static::getJoomlaVersion($base)->release, '4.0.0', '>=');
42+
return static::getJoomlaVersion($base)->major >= 4;
3743
}
3844

3945
public static function executeJ4CliCommand($base, $command): string
4046
{
41-
return static::executeCommand("php $base/cli/joomla.php $command");
47+
return static::executeCommand(PHP_BINARY . " " . escapeshellarg($base . "/cli/joomla.php") . $command);
4248
}
4349

4450
/**
@@ -56,82 +62,26 @@ public static function getJoomlaVersion($base)
5662

5763
if (!isset(self::$_versions[$key]))
5864
{
59-
$canonical = function($version) {
60-
if (isset($version->RELEASE)) {
61-
return 'v' . $version->RELEASE . '.' . $version->DEV_LEVEL;
62-
}
63-
64-
// Joomla 3.5 and up uses constants instead of properties in JVersion
65-
$className = get_class($version);
66-
if (defined("$className::RELEASE")) {
67-
return $version::RELEASE . '.' . $version::DEV_LEVEL;
68-
}
69-
70-
//start to provide support for Joomla 4 onwards
71-
if (defined( "$className::MAJOR_VERSION") && in_array($version::MAJOR_VERSION, ['4', '5'])){
72-
return $version::MAJOR_VERSION . "." . $version::MINOR_VERSION . "." . $version::PATCH_VERSION . ($version::EXTRA_VERSION ? "." . $version::EXTRA_VERSION : '');
73-
}
74-
75-
return 'unknown';
76-
};
77-
78-
$files = array(
79-
'joomla-cms' => '/libraries/cms/version/version.php',
80-
'joomla-cms-new' => '/libraries/src/Version.php', // 3.8+
81-
'joomla-1.5' => '/libraries/joomla/version.php'
82-
);
83-
84-
$code = false;
85-
$application = false;
86-
foreach ($files as $type => $file)
65+
self::$_versions[$key] = false;
66+
foreach (self::VERSION_LOCATIONS as $file)
8767
{
8868
$path = $base . $file;
8969

9070
if (file_exists($path))
9171
{
92-
$code = $path;
93-
$application = $type;
72+
self::$_versions[$key] = VersionSniffer::fromFile($path);
9473

9574
break;
9675
}
9776
}
9877

99-
if ($code !== false)
100-
{
101-
if (!defined('JPATH_PLATFORM')) {
102-
define('JPATH_PLATFORM', self::buildTargetPath('/libraries', $base));
103-
}
104-
105-
if (!defined('_JEXEC')) {
106-
define('_JEXEC', 1);
107-
}
108-
109-
$identifier = uniqid();
110-
111-
$source = file_get_contents($code);
112-
$source = preg_replace('/<\?php/', '', $source, 1);
113-
114-
$pattern = $application == 'joomla-cms-new' ? '/class Version/i' : '/class JVersion/i';
115-
$replacement = $application == 'joomla-cms-new' ? 'class Version' . $identifier : 'class JVersion' . $identifier;
116-
117-
$source = preg_replace($pattern, $replacement, $source);
118-
119-
eval($source);
120-
121-
$class = $application == 'joomla-cms-new' ? '\\Joomla\\CMS\\Version'.$identifier : 'JVersion'.$identifier;
122-
$version = new $class();
123-
124-
self::$_versions[$key] = (object) array('release' => $canonical($version), 'type' => $application);
125-
}
126-
else self::$_versions[$key] = false;
78+
return self::$_versions[$key];
12779
}
128-
129-
return self::$_versions[$key];
13080
}
13181

13282
/**
13383
* Builds the full path for a given path inside a Joomla project.
134-
*
84+
*
13585
* @param string $path The original relative path to the file/directory
13686
* @param string $base The root directory of the Joomla installation
13787
* @return string Target path
@@ -151,20 +101,21 @@ public static function buildTargetPath($path, $base = '')
151101
return $base.$path;
152102
}
153103

154-
/**
155-
* Return a writable path
156-
*
157-
* @return string
158-
*/
104+
/**
105+
* Return a writable path
106+
*
107+
* @return string
108+
*/
159109
public static function getWritablePath()
160110
{
161111
$path = \Phar::running();
162112

163-
if (!empty($path)) {
164-
return sys_get_temp_dir() . '/.joomla';
165-
}
113+
$templatePath = self::getTemplatePath();
114+
if (!empty($path) || !is_writable($templatePath)) {
115+
return sys_get_temp_dir() . '/.joomla';
116+
}
166117

167-
return self::getTemplatePath();
118+
return $templatePath;
168119
}
169120

170121
/**
@@ -176,12 +127,12 @@ public static function getTemplatePath()
176127
{
177128
$path = \Phar::running();
178129

179-
if (!empty($path)) {
180-
return $path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . '.files';
181-
}
130+
if (!empty($path)) {
131+
return $path . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . '.files';
132+
}
182133

183-
$root = dirname(dirname(dirname(dirname(__DIR__))));
134+
$root = dirname(dirname(dirname(dirname(__DIR__))));
184135

185-
return realpath($root .DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . '.files');
136+
return realpath($root .DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . '.files');
186137
}
187138
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
/**
3+
* @copyright Copyright (C) 2007 - 2015 Johan Janssens and Timble CVBA. (http://www.timble.net)
4+
* @license Mozilla Public License, version 2.0
5+
* @link http://github.com/joomlatools/joomlatools-console for the canonical source repository
6+
*/
7+
8+
namespace Joomlatools\Console\Joomla;
9+
10+
use PhpParser\Node;
11+
use PhpParser\Node\Stmt\Const_;
12+
use PhpParser\Node\Stmt\Expression;
13+
use PhpParser\NodeFinder;
14+
use PhpParser\NodeVisitorAbstract;
15+
16+
class VersionSniffer
17+
{
18+
public $release = 'unknown';
19+
20+
public $major;
21+
public $minor;
22+
public $patch;
23+
public $extra;
24+
25+
private function __construct(string $code)
26+
{
27+
$parser = (new \PhpParser\ParserFactory)->create(\PhpParser\ParserFactory::PREFER_PHP7);
28+
29+
$ast = $parser->parse($code);
30+
31+
$nodeFinder = new NodeFinder;
32+
$nodes = $nodeFinder->find($ast, function (Node $node) {
33+
return $node instanceof Node\Const_ || $node instanceof Node\Stmt\PropertyProperty;
34+
});
35+
foreach ($nodes as $node) {
36+
$value = $node instanceof Node\Stmt\PropertyProperty ? $node->default : $node->value;
37+
switch ((string)$node->name) {
38+
case 'RELEASE':
39+
// v3.5 <= version < 4.0
40+
[$major, $minor] = explode('.', $value->value);
41+
$this->major = (int)$major;
42+
$this->minor = (int)$minor;
43+
break;
44+
case 'MAJOR_VERSION':
45+
$this->major = (int)$value->value;
46+
break;
47+
case 'MINOR_VERSION':
48+
$this->minor = (int)$value->value;
49+
break;
50+
case 'PATCH_VERSION':
51+
case 'DEV_LEVEL':
52+
$this->patch = (int)$value->value;
53+
break;
54+
case 'EXTRA_VERSION':
55+
case 'BUILD':
56+
$this->extra = $value->value;
57+
break;
58+
}
59+
}
60+
$this->release = $this->version();
61+
}
62+
63+
public static function fromFile(string $file): self
64+
{
65+
if (!is_file($file)) {
66+
throw new \RuntimeException("File {$file} not found");
67+
}
68+
69+
return new static(file_get_contents($file));
70+
}
71+
72+
public function version(): string
73+
{
74+
if (empty($this->major)) {
75+
return 'unknown';
76+
}
77+
78+
return rtrim(
79+
implode('.', [$this->major, $this->minor, $this->patch]) . '-' . $this->extra,
80+
'-'
81+
);
82+
}
83+
84+
public function major(): ?int
85+
{
86+
return $this->major;
87+
}
88+
89+
public function minor(): ?int
90+
{
91+
return $this->minor;
92+
}
93+
94+
public function patch(): ?int
95+
{
96+
return $this->patch;
97+
}
98+
99+
public function extra(): ?string
100+
{
101+
return $this->extra;
102+
}
103+
}

0 commit comments

Comments
 (0)