mirror of
https://github.com/php-win-ext/php-sdk-binary-tools.git
synced 2026-03-24 17:12:12 +01:00
Some are not as specific as they should be, and some may even be wrong, but since these are only type hints (not type declarations) they won't affect code execution, but rather provide some help to better understand the code – for developers as well as tooling.
457 lines
12 KiB
PHP
457 lines
12 KiB
PHP
<?php
|
|
|
|
namespace SDK;
|
|
|
|
use SDK\Build\Dependency\Fetcher;
|
|
|
|
class Config
|
|
{
|
|
/* Config variables. */
|
|
|
|
/** @var string */
|
|
protected static $depsHost = 'downloads.php.net';
|
|
|
|
/** @var int */
|
|
protected static $depsPort = 443;
|
|
|
|
/** @var string */
|
|
protected static $depsUriScheme = "https";
|
|
|
|
/** @var string */
|
|
protected static $depsBaseUri = "/~windows/php-sdk/deps";
|
|
|
|
/** @var string */
|
|
protected static $sdkNugetFeedUrl = "http://127.0.0.1/sdk/nuget"; // experimental?
|
|
|
|
/** @var array<mixed> */
|
|
protected static $knownBranches = array ();
|
|
|
|
/* Helper props and methods. */
|
|
|
|
/** @var ?string */
|
|
protected static $currentBranchName = NULL;
|
|
|
|
/** @var ?string */
|
|
protected static $currentArchName = NULL;
|
|
|
|
/** @var ?string */
|
|
protected static $currentCrtName = NULL;
|
|
|
|
/** @var ?string */
|
|
protected static $currentStabilityName = NULL;
|
|
|
|
/** @var ?string */
|
|
protected static $depsLocalPath = NULL;
|
|
|
|
public static function getDepsHost() : string
|
|
{/*{{{*/
|
|
return self::$depsHost;
|
|
}/*}}}*/
|
|
|
|
public static function getDepsPort() : int
|
|
{/*{{{*/
|
|
return self::$depsPort;
|
|
}/*}}}*/
|
|
|
|
public static function getDepsUriScheme() : string
|
|
{/*{{{*/
|
|
return self::$depsUriScheme;
|
|
}/*}}}*/
|
|
|
|
public static function getDepsBaseUri() : string
|
|
{/*{{{*/
|
|
return self::$depsBaseUri;
|
|
}/*}}}*/
|
|
|
|
public static function setCurrentArchName(string $arch) : void
|
|
{/*{{{*/
|
|
$arch = strtolower($arch);
|
|
|
|
if ("x64" != $arch && "x86" != $arch && "arm64" != $arch) {
|
|
throw new Exception("Unknown arch keyword, x86 or x64 or arm64 is accepted");
|
|
}
|
|
|
|
self::$currentArchName = $arch;
|
|
} /*}}}*/
|
|
|
|
public static function getCurrentArchName() : string
|
|
{/*{{{*/
|
|
if (NULL === self::$currentArchName) {
|
|
if (FALSE !== ($env = getenv('PHP_SDK_ARCH'))) {
|
|
self::setCurrentArchName($env);
|
|
} else {
|
|
/* XXX this might be not true for other compilers! */
|
|
passthru("where cl.exe >nul", $status);
|
|
if ($status) {
|
|
throw new Exception("Couldn't execute cl.exe.");
|
|
}
|
|
|
|
exec("cl.exe /? 2>&1", $out);
|
|
|
|
if (preg_match(",x64,", $out[0])) {
|
|
self::setCurrentArchName("x64");
|
|
} elseif (preg_match(",x86,", $out[0])) {
|
|
self::setCurrentArchName("x86");
|
|
} elseif (preg_match(",arm64,", $out[0])) {
|
|
self::setCurrentArchName("arm64");
|
|
} else {
|
|
throw new Exception("Couldn't determine Arch.");
|
|
}
|
|
}
|
|
}
|
|
|
|
return self::$currentArchName;
|
|
} /*}}}*/
|
|
|
|
public static function setCurrentCrtName(string $crt) : void
|
|
{/*{{{*/
|
|
self::$currentCrtName = $crt;
|
|
} /*}}}*/
|
|
|
|
public static function getCurrentCrtName() : ?string
|
|
{/*{{{*/
|
|
if (NULL === self::$currentCrtName) {
|
|
if (FALSE !== ($env = getenv('PHP_SDK_VS'))) {
|
|
self::setCurrentCrtName($env);
|
|
} else {
|
|
$all_branches = Config::getKnownBranches();
|
|
|
|
if (!isset($all_branches[Config::getCurrentBranchName()])) {
|
|
throw new Exception("Couldn't find any configuration for branch '" . Config::getCurrentBranchName() . "'");
|
|
}
|
|
|
|
$branch = $all_branches[Config::getCurrentBranchName()];
|
|
if (count($branch) > 1) {
|
|
throw new Exception("Multiple CRTs are available for this branch, please choose one from " . implode(",", array_keys($branch)));
|
|
}
|
|
|
|
self::setCurrentCrtName(array_keys($branch)[0]);
|
|
}
|
|
}
|
|
|
|
return self::$currentCrtName;
|
|
} /*}}}*/
|
|
|
|
public static function setCurrentStabilityName(string $stability) : void
|
|
{/*{{{*/
|
|
if ("stable" != $stability && "staging" != $stability) {
|
|
throw new Exception("Unknown stability keyword, either stable or staging is accepted");
|
|
}
|
|
|
|
self::$currentStabilityName = $stability;
|
|
} /*}}}*/
|
|
|
|
public static function getCurrentStabilityName() : ?string
|
|
{/*{{{*/
|
|
if (NULL === self::$currentStabilityName) {
|
|
if ("master" == Config::getCurrentBranchName()) {
|
|
Config::setCurrentStabilityName("staging");
|
|
} else {
|
|
Config::setCurrentStabilityName("stable");
|
|
}
|
|
}
|
|
|
|
return self::$currentStabilityName;
|
|
} /*}}}*/
|
|
|
|
/** @return array<mixed> */
|
|
public static function getKnownBranches() : array
|
|
{/*{{{*/
|
|
if (empty(self::$knownBranches)) {
|
|
$cache_file = "known_branches.txt";
|
|
$deps_path = self::getDepsLocalPath();
|
|
if (!$deps_path) {
|
|
throw new Exception("Couldn't determine dependencies path. Please either switch to the PHP source root or use -d option.");
|
|
}
|
|
$cache = new Cache($deps_path);
|
|
$fetcher = new Fetcher(self::$depsHost, self::$depsPort, self::$depsUriScheme);
|
|
|
|
$tmp = $fetcher->getByUri(self::$depsBaseUri . "/series/");
|
|
if ("" !== $tmp) {
|
|
$data = array();
|
|
if (preg_match_all(",packages-(.+)-(v[cs]\d+)-(x86|x64|arm64)-(stable|staging)\.txt,Us", $tmp, $m, PREG_SET_ORDER)) {
|
|
foreach ($m as $b) {
|
|
if (!isset($data[$b[1]])) {
|
|
$data[$b[1]] = array();
|
|
}
|
|
|
|
$data[$b[1]][$b[2]][] = array("arch" => $b[3], "stability" => $b[4]);
|
|
}
|
|
|
|
$cache->cachecontent($cache_file, json_encode($data, JSON_PRETTY_PRINT), true);
|
|
}
|
|
} else {
|
|
/* It might be ok to use cached branches list, if a fetch failed. */
|
|
$tmp = $cache->getCachedContent($cache_file, true);
|
|
if (NULL == $tmp) {
|
|
throw new Exception("No cached branches list found");
|
|
}
|
|
$data = json_decode($tmp, true);
|
|
}
|
|
|
|
if (!is_array($data) || empty($data)) {
|
|
throw new Exception("Failed to fetch supported branches");
|
|
}
|
|
self::$knownBranches = $data;
|
|
}
|
|
|
|
return self::$knownBranches;
|
|
}/*}}}*/
|
|
|
|
public static function setCurrentBranchName(string $name) : void
|
|
{/*{{{*/
|
|
if (!array_key_exists($name, self::getKnownBranches())) {
|
|
throw new Exception("Unsupported branch '$name'");
|
|
}
|
|
|
|
self::$currentBranchName = $name;
|
|
}/*}}}*/
|
|
|
|
public static function guessCurrentBranchName() : ?string
|
|
{/*{{{*/
|
|
$branch = NULL;
|
|
$found = false;
|
|
|
|
$rmtools_branch = getenv("PHP_RMTOOLS_PHP_BUILD_BRANCH");
|
|
if ("master" == $rmtools_branch) {
|
|
return "master";
|
|
}
|
|
|
|
/* Try to figure out the branch. The worky scenarios are
|
|
- CWD is in php-src
|
|
- phpize is on the path
|
|
FIXME for the dev package, there should be a php-config utility
|
|
*/
|
|
$fl = "main/php_version.h";
|
|
$found = file_exists($fl);
|
|
|
|
if (!$found) {
|
|
exec("where phpize", $out, $status);
|
|
if (!$status) {
|
|
$fl = dirname($out[0]) . DIRECTORY_SEPARATOR . "include" . DIRECTORY_SEPARATOR . $fl;
|
|
$found = file_exists($fl);
|
|
}
|
|
}
|
|
|
|
if ($found) {
|
|
$s = file_get_contents($fl);
|
|
$major = $minor = NULL;
|
|
|
|
if (preg_match(",PHP_MAJOR_VERSION (\d+),", $s, $m)) {
|
|
$major = $m[1];
|
|
}
|
|
if (preg_match(",PHP_MINOR_VERSION (\d+),", $s, $m)) {
|
|
$minor = $m[1];
|
|
}
|
|
|
|
if (is_numeric($major) && is_numeric($minor)) {
|
|
$branch = "$major.$minor";
|
|
}
|
|
|
|
/* Verify that we use an available branch name. Master has some
|
|
version, but no dedicated series. For master, it rather
|
|
makes sense to use master as branch name. */
|
|
$git = trim(shell_exec("where git.exe"));
|
|
if ($git && is_dir(".git")) {
|
|
$cmd = "\"$git\" branch";
|
|
|
|
$ret = trim(shell_exec($cmd));
|
|
if (preg_match_all(",\*\s+master,", $ret) > 0) {
|
|
$branch = "master";
|
|
}
|
|
}
|
|
}
|
|
|
|
return $branch;
|
|
}/*}}}*/
|
|
|
|
public static function getCurrentBranchName() : string
|
|
{/*{{{*/
|
|
if (NULL == self::$currentBranchName) {
|
|
$branch = self::guessCurrentBranchName();
|
|
self::setCurrentBranchName($branch);
|
|
}
|
|
|
|
return self::$currentBranchName;
|
|
}/*}}}*/
|
|
|
|
/** @return array<mixed> */
|
|
public static function getCurrentBranchData() : array
|
|
{/*{{{*/
|
|
$ret = array();
|
|
$branches = self::getKnownBranches();
|
|
|
|
$current_branch_name = self::getCurrentBranchName();
|
|
if (!array_key_exists($current_branch_name, $branches)) {
|
|
throw new Exception("Unknown branch '$current_branch_name'");
|
|
}
|
|
|
|
$crt = null;
|
|
$cur_crt = Config::getCurrentCrtName();
|
|
if (count($branches[$current_branch_name]) > 1) {
|
|
if (NULL === $cur_crt) {
|
|
throw new Exception("More than one CRT is available for branch '$current_branch_name', pass one explicitly.");
|
|
}
|
|
|
|
$cur_crt_usable = false;
|
|
foreach (array_keys($branches[$current_branch_name]) as $crt) {
|
|
if ($cur_crt == $crt) {
|
|
$cur_crt_usable = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!$cur_crt_usable) {
|
|
throw new Exception("The passed CRT '$cur_crt' doesn't match any available for branch '$current_branch_name'");
|
|
}
|
|
$data = $branches[$current_branch_name][$cur_crt];
|
|
} else {
|
|
/* Evaluate CRTs, to avoid ambiquity. */
|
|
$crt = key($branches[$current_branch_name]);
|
|
$data = $branches[$current_branch_name][$crt];
|
|
if ($crt != $cur_crt) {
|
|
throw new Exception("The passed CRT '$cur_crt' doesn't match any available for branch '$current_branch_name'");
|
|
}
|
|
}
|
|
|
|
$ret["name"] = $current_branch_name;
|
|
$ret["crt"] = $crt;
|
|
|
|
/* Last step, filter by arch and stability. */
|
|
foreach ($data as $d) {
|
|
if (self::getCurrentArchName() == $d["arch"]) {
|
|
if (self::getCurrentStabilityName() == $d["stability"]) {
|
|
$ret["arch"] = $d["arch"];
|
|
$ret["stability"] = $d["stability"];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!isset($ret["arch"]) || !$ret["arch"]) {
|
|
throw new Exception("Failed to find config with arch '" . self::getCurrentArchName() . "'");
|
|
}
|
|
if (!isset($ret["stability"]) || !$ret["stability"]) {
|
|
throw new Exception("Failed to find config with stability '" . self::getCurrentStabilityName() . "'");
|
|
}
|
|
if (!isset($ret["crt"]) || !$ret["crt"]) {
|
|
throw new Exception("Failed to find config with arch '" . self::getCurrentArchName() . "'");
|
|
}
|
|
|
|
return $ret;
|
|
}/*}}}*/
|
|
|
|
public static function getSdkNugetFeedUrl() : string
|
|
{/*{{{*/
|
|
return self::$sdkNugetFeedUrl;
|
|
}/*}}}*/
|
|
|
|
public static function getSdkPath() : string
|
|
{/*{{{*/
|
|
$path = getenv("PHP_SDK_ROOT_PATH");
|
|
|
|
if (!$path) {
|
|
throw new Exception("PHP_SDK_ROOT_PATH isn't set!");
|
|
}
|
|
|
|
$path = realpath($path);
|
|
if (!file_exists($path)) {
|
|
throw new Exception("The path '$path' is non existent.");
|
|
}
|
|
|
|
return $path;
|
|
}/*}}}*/
|
|
|
|
public static function getSdkVersion() : string
|
|
{/*{{{*/
|
|
$path = self::getSdkPath() . DIRECTORY_SEPARATOR . "VERSION";
|
|
|
|
if (!file_exists($path)) {
|
|
throw new Exception("Couldn't find the SDK version file.");
|
|
}
|
|
|
|
return file_get_contents($path);
|
|
}/*}}}*/
|
|
|
|
public static function getDepsLocalPath() : ?string
|
|
{/*{{{*/
|
|
if (NULL == self::$depsLocalPath) {
|
|
if (file_exists("Makefile")) {
|
|
$s = file_get_contents("Makefile");
|
|
|
|
if (preg_match(",PHP_BUILD=(.+),", $s, $m)) {
|
|
if (isset($m[1])) {
|
|
self::setDepsLocalPath(trim($m[1]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NULL == self::$depsLocalPath) {
|
|
$tmp = dirname(getcwd()) . DIRECTORY_SEPARATOR . "deps";
|
|
if (is_dir($tmp)) {
|
|
self::setDepsLocalPath($tmp);
|
|
}
|
|
}
|
|
|
|
if (NULL == self::$depsLocalPath) {
|
|
$tmp = realpath("../deps");
|
|
if (is_dir($tmp)) {
|
|
self::setDepsLocalPath($tmp);
|
|
}
|
|
}
|
|
|
|
if (NULL == self::$depsLocalPath) {
|
|
if (file_exists("main/php_version.h")) {
|
|
/* Deps dir might not exist. */
|
|
self::setDepsLocalPath(realpath("..") . DIRECTORY_SEPARATOR . "deps");
|
|
}
|
|
}
|
|
|
|
return self::$depsLocalPath;
|
|
}/*}}}*/
|
|
|
|
public static function setDepsLocalPath(string $path) : void
|
|
{/*{{{*/
|
|
self::$depsLocalPath = $path;
|
|
}/*}}}*/
|
|
|
|
public static function getCacheDir() : string
|
|
{/*{{{*/
|
|
$path = self::getSdkPath() . DIRECTORY_SEPARATOR . ".cache";
|
|
|
|
if (!file_exists($path)) {
|
|
if (!mkdir($path)) {
|
|
throw new Exception("Failed to create '$path'");
|
|
}
|
|
}
|
|
|
|
return $path;
|
|
}/*}}}*/
|
|
|
|
public static function getTmpDir() : string
|
|
{/*{{{*/
|
|
$path = self::getSdkPath() . DIRECTORY_SEPARATOR . ".tmp";
|
|
|
|
if (!file_exists($path)) {
|
|
if (!mkdir($path)) {
|
|
throw new Exception("Failed to create '$path'");
|
|
}
|
|
}
|
|
|
|
return $path;
|
|
}/*}}}*/
|
|
|
|
public static function getSdkUserAgentName() : string
|
|
{/*{{{*/
|
|
return "PHP-SDK-BINARY-TOOLS/" . self::getSdkVersion();
|
|
}/*}}}*/
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: sw=4 ts=4 fdm=marker
|
|
* vim<600: sw=4 ts=4
|
|
*/
|