add windows support

This commit is contained in:
crazywhalecc
2024-01-10 21:08:25 +08:00
committed by Jerry Ma
parent 5f8641f417
commit 104778d17a
39 changed files with 1166 additions and 230 deletions

View File

@@ -168,14 +168,15 @@ class Downloader
public static function downloadFile(string $name, string $url, string $filename, ?string $move_path = null): void
{
logger()->debug("Downloading {$url}");
pcntl_signal(SIGINT, function () use ($filename) {
if (file_exists(DOWNLOAD_PATH . '/' . $filename)) {
$cancel_func = function () use ($filename) {
if (file_exists(FileSystem::convertPath(DOWNLOAD_PATH . '/' . $filename))) {
logger()->warning('Deleting download file: ' . $filename);
unlink(DOWNLOAD_PATH . '/' . $filename);
unlink(FileSystem::convertPath(DOWNLOAD_PATH . '/' . $filename));
}
});
self::curlDown(url: $url, path: DOWNLOAD_PATH . "/{$filename}");
pcntl_signal(SIGINT, SIG_IGN);
};
self::registerCancelEvent($cancel_func);
self::curlDown(url: $url, path: FileSystem::convertPath(DOWNLOAD_PATH . "/{$filename}"));
self::unregisterCancelEvent();
logger()->debug("Locking {$filename}");
self::lockSource($name, ['source_type' => 'archive', 'filename' => $filename, 'move_path' => $move_path]);
}
@@ -187,7 +188,7 @@ class Downloader
*/
public static function lockSource(string $name, array $data): void
{
if (!file_exists(DOWNLOAD_PATH . '/.lock.json')) {
if (!file_exists(FileSystem::convertPath(DOWNLOAD_PATH . '/.lock.json'))) {
$lock = [];
} else {
$lock = json_decode(FileSystem::readFile(DOWNLOAD_PATH . '/.lock.json'), true) ?? [];
@@ -204,24 +205,25 @@ class Downloader
*/
public static function downloadGit(string $name, string $url, string $branch, ?string $move_path = null): void
{
$download_path = DOWNLOAD_PATH . "/{$name}";
$download_path = FileSystem::convertPath(DOWNLOAD_PATH . "/{$name}");
if (file_exists($download_path)) {
FileSystem::removeDir($download_path);
}
logger()->debug("cloning {$name} source");
$check = !defined('DEBUG_MODE') ? ' -q' : '';
pcntl_signal(SIGINT, function () use ($download_path) {
$cancel_func = function () use ($download_path) {
if (is_dir($download_path)) {
logger()->warning('Removing path ' . $download_path);
FileSystem::removeDir($download_path);
}
});
};
self::registerCancelEvent($cancel_func);
f_passthru(
'git clone' . $check .
SPC_GIT_EXEC . ' clone' . $check .
' --config core.autocrlf=false ' .
"--branch \"{$branch}\" " . (defined('GIT_SHALLOW_CLONE') ? '--depth 1 --single-branch' : '') . " --recursive \"{$url}\" \"{$download_path}\""
);
pcntl_signal(SIGINT, SIG_IGN);
self::unregisterCancelEvent();
// Lock
logger()->debug("Locking git source {$name}");
@@ -251,7 +253,6 @@ class Downloader
* @param null|array $source source meta info: [type, path, rev, url, filename, regex, license]
* @throws DownloaderException
* @throws FileSystemException
* @throws RuntimeException
*/
public static function downloadSource(string $name, ?array $source = null, bool $force = false): void
{
@@ -359,12 +360,12 @@ class Downloader
};
$headerArg = implode(' ', array_map(fn ($v) => '"-H' . $v . '"', $headers));
$cmd = "curl -sfSL {$methodArg} {$headerArg} \"{$url}\"";
$cmd = SPC_CURL_EXEC . " -sfSL {$methodArg} {$headerArg} \"{$url}\"";
if (getenv('CACHE_API_EXEC') === 'yes') {
if (!file_exists(DOWNLOAD_PATH . '/.curl_exec_cache')) {
if (!file_exists(FileSystem::convertPath(DOWNLOAD_PATH . '/.curl_exec_cache'))) {
$cache = [];
} else {
$cache = json_decode(file_get_contents(DOWNLOAD_PATH . '/.curl_exec_cache'), true);
$cache = json_decode(file_get_contents(FileSystem::convertPath(DOWNLOAD_PATH . '/.curl_exec_cache')), true);
}
if (isset($cache[$cmd]) && $cache[$cmd]['expire'] >= time()) {
return $cache[$cmd]['cache'];
@@ -375,7 +376,7 @@ class Downloader
}
$cache[$cmd]['cache'] = implode("\n", $output);
$cache[$cmd]['expire'] = time() + 3600;
file_put_contents(DOWNLOAD_PATH . '/.curl_exec_cache', json_encode($cache));
file_put_contents(FileSystem::convertPath(DOWNLOAD_PATH . '/.curl_exec_cache'), json_encode($cache));
return $cache[$cmd]['cache'];
}
f_exec($cmd, $output, $ret);
@@ -404,7 +405,35 @@ class Downloader
};
$headerArg = implode(' ', array_map(fn ($v) => '"-H' . $v . '"', $headers));
$check = !defined('DEBUG_MODE') ? 's' : '#';
$cmd = "curl -{$check}fSL -o \"{$path}\" {$methodArg} {$headerArg} \"{$url}\"";
$cmd = SPC_CURL_EXEC . " -{$check}fSL -o \"{$path}\" {$methodArg} {$headerArg} \"{$url}\"";
f_passthru($cmd);
}
/**
* Register CTRL+C event for different OS.
*
* @param callable $callback callback function
*/
private static function registerCancelEvent(callable $callback): void
{
if (PHP_OS_FAMILY === 'Windows') {
sapi_windows_set_ctrl_handler($callback);
} elseif (extension_loaded('pcntl')) {
pcntl_signal(SIGINT, $callback);
} else {
logger()->debug('You have not enabled `pcntl` extension, cannot prevent download file corruption when Ctrl+C');
}
}
/**
* Unegister CTRL+C event for different OS.
*/
private static function unregisterCancelEvent(): void
{
if (PHP_OS_FAMILY === 'Windows') {
sapi_windows_set_ctrl_handler(null);
} elseif (extension_loaded('pcntl')) {
pcntl_signal(SIGINT, SIG_IGN);
}
}
}

View File

@@ -160,78 +160,35 @@ class FileSystem
}
logger()->info("extracting {$name} source to " . ($move_path ?? SOURCE_PATH . "/{$name}") . ' ...');
try {
$target = $move_path ?? (SOURCE_PATH . "/{$name}");
$target = self::convertPath($move_path ?? (SOURCE_PATH . "/{$name}"));
// Git source, just move
if (is_dir($filename)) {
self::copyDir($filename, $target);
if (is_dir(self::convertPath($filename))) {
self::copyDir(self::convertPath($filename), $target);
self::emitSourceExtractHook($name);
return;
}
if (f_mkdir(directory: $target, recursive: true) !== true) {
throw new FileSystemException('create ' . $name . 'source dir failed');
}
if (in_array(PHP_OS_FAMILY, ['Darwin', 'Linux', 'BSD'])) {
if (f_mkdir(directory: $target, recursive: true) !== true) {
throw new FileSystemException('create ' . $name . 'source dir failed');
}
switch (self::extname($filename)) {
case 'xz':
case 'txz':
f_passthru("tar -xf {$filename} -C {$target} --strip-components 1");
// f_passthru("cat {$filename} | xz -d | tar -x -C " . SOURCE_PATH . "/{$name} --strip-components 1");
break;
case 'gz':
case 'tgz':
f_passthru("tar -xzf {$filename} -C {$target} --strip-components 1");
break;
case 'bz2':
f_passthru("tar -xjf {$filename} -C {$target} --strip-components 1");
break;
case 'zip':
f_passthru("unzip {$filename} -d {$target}");
break;
// case 'zstd':
// case 'zst':
// passthru('cat ' . $filename . ' | zstd -d | tar -x -C ".SOURCE_PATH . "/' . $name . ' --strip-components 1', $ret);
// break;
case 'tar':
f_passthru("tar -xf {$filename} -C {$target} --strip-components 1");
break;
default:
throw new FileSystemException('unknown archive format: ' . $filename);
}
match (self::extname($filename)) {
'tar', 'xz', 'txz' => f_passthru("tar -xf {$filename} -C {$target} --strip-components 1"),
'tgz', 'gz' => f_passthru("tar -xzf {$filename} -C {$target} --strip-components 1"),
'bz2' => f_passthru("tar -xjf {$filename} -C {$target} --strip-components 1"),
'zip' => f_passthru("unzip {$filename} -d {$target}"),
default => throw new FileSystemException('unknown archive format: ' . $filename),
};
} elseif (PHP_OS_FAMILY === 'Windows') {
// find 7z
$_7zExe = self::findCommandPath('7z', [
'C:\Program Files\7-Zip-Zstandard',
'C:\Program Files (x86)\7-Zip-Zstandard',
'C:\Program Files\7-Zip',
'C:\Program Files (x86)\7-Zip',
]);
if (!$_7zExe) {
throw new FileSystemException('windows needs 7z to unpack');
}
// use php-sdk-binary-tools/bin/7za.exe
$_7z = self::convertPath(PHP_SDK_PATH . '/bin/7za.exe');
f_mkdir(SOURCE_PATH . "/{$name}", recursive: true);
switch (self::extname($filename)) {
case 'zstd':
case 'zst':
if (!str_contains($_7zExe, 'Zstandard')) {
throw new FileSystemException("zstd is not supported: {$filename}");
}
// no break
case 'xz':
case 'txz':
case 'gz':
case 'tgz':
case 'bz2':
f_passthru("\"{$_7zExe}\" x -so {$filename} | tar -f - -x -C {$target} --strip-components 1");
break;
case 'tar':
f_passthru("tar -xf {$filename} -C {$target} --strip-components 1");
break;
case 'zip':
f_passthru("\"{$_7zExe}\" x {$filename} -o{$target}");
break;
default:
throw new FileSystemException("unknown archive format: {$filename}");
}
match (self::extname($filename)) {
'tar' => f_passthru("tar -xf {$filename} -C {$target} --strip-components 1"),
'xz', 'txz', 'gz', 'tgz', 'bz2' => f_passthru("\"{$_7z}\" x -so {$filename} | tar -f - -x -C {$target} --strip-components 1"),
'zip' => f_passthru("\"{$_7z}\" x {$filename} -o{$target} -y"),
default => throw new FileSystemException("unknown archive format: {$filename}"),
};
}
self::emitSourceExtractHook($name);
} catch (RuntimeException $e) {
@@ -398,7 +355,7 @@ class FileSystem
public static function createDir(string $path): void
{
if (!is_dir($path) && !f_mkdir($path, 0755, true) && !is_dir($path)) {
throw new FileSystemException(sprintf('无法建立目录:%s', $path));
throw new FileSystemException(sprintf('Unable to create dir: %s', $path));
}
}
@@ -408,7 +365,7 @@ class FileSystem
*/
public static function writeFile(string $path, mixed $content, ...$args): bool|int|string
{
$dir = pathinfo($path, PATHINFO_DIRNAME);
$dir = pathinfo(self::convertPath($path), PATHINFO_DIRNAME);
if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
throw new FileSystemException('Write file failed, cannot create parent directory: ' . $dir);
}

View File

@@ -6,6 +6,7 @@ namespace SPC\store;
use SPC\builder\BuilderBase;
use SPC\builder\linux\LinuxBuilder;
use SPC\builder\unix\UnixBuilderBase;
use SPC\exception\FileSystemException;
use SPC\exception\RuntimeException;
@@ -31,6 +32,20 @@ class SourcePatcher
logger()->info('Extension [' . $ext->getName() . '] patched before buildconf');
}
}
// patch windows php 8.1 bug
if (PHP_OS_FAMILY === 'Windows' && $builder->getPHPVersionID() >= 80100 && $builder->getPHPVersionID() < 80200) {
logger()->info('Patching PHP 8.1 windows Fiber bug');
FileSystem::replaceFileStr(
SOURCE_PATH . '\php-src\win32\build\config.w32',
"ADD_FLAG('LDFLAGS', '$(BUILD_DIR)\\\\Zend\\\\jump_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj');",
"ADD_FLAG('ASM_OBJS', '$(BUILD_DIR)\\\\Zend\\\\jump_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj $(BUILD_DIR)\\\\Zend\\\\make_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj');"
);
FileSystem::replaceFileStr(
SOURCE_PATH . '\php-src\win32\build\config.w32',
"ADD_FLAG('LDFLAGS', '$(BUILD_DIR)\\\\Zend\\\\make_' + FIBER_ASM_ARCH + '_ms_pe_masm.obj');",
''
);
}
}
/**
@@ -181,9 +196,10 @@ class SourcePatcher
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCPY 1$/m', '');
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_STRLCAT 1$/m', '');
}
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_OPENPTY 1$/m', '');
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'install-micro', '');
if ($builder instanceof UnixBuilderBase) {
FileSystem::replaceFileRegex(SOURCE_PATH . '/php-src/main/php_config.h', '/^#define HAVE_OPENPTY 1$/m', '');
FileSystem::replaceFileStr(SOURCE_PATH . '/php-src/Makefile', 'install-micro', '');
}
// call extension patch before make
foreach ($builder->getExts() as $ext) {
@@ -252,4 +268,32 @@ class SourcePatcher
@unlink($embed_c_bak);
return $result;
}
/**
* Patch cli SAPI Makefile for Windows.
*
* @throws FileSystemException
* @throws RuntimeException
*/
public static function patchWindowsCLITarget(): void
{
// search Makefile code line contains "$(BUILD_DIR)\php.exe:"
$content = FileSystem::readFile(SOURCE_PATH . '/php-src/Makefile');
$lines = explode("\r\n", $content);
$line_num = 0;
$found = false;
foreach ($lines as $v) {
if (strpos($v, '$(BUILD_DIR)\php.exe:') !== false) {
$found = $line_num;
break;
}
++$line_num;
}
if ($found === false) {
throw new RuntimeException('Cannot patch windows CLI Makefile!');
}
$lines[$line_num] = '$(BUILD_DIR)\php.exe: generated_files $(DEPS_CLI) $(PHP_GLOBAL_OBJS) $(CLI_GLOBAL_OBJS) $(STATIC_EXT_OBJS) $(ASM_OBJS) $(BUILD_DIR)\php.exe.res $(BUILD_DIR)\php.exe.manifest';
$lines[$line_num + 1] = "\t" . '"$(LINK)" /nologo $(PHP_GLOBAL_OBJS_RESP) $(CLI_GLOBAL_OBJS_RESP) $(STATIC_EXT_OBJS_RESP) $(STATIC_EXT_LIBS) $(ASM_OBJS) $(LIBS) $(LIBS_CLI) $(BUILD_DIR)\php.exe.res /out:$(BUILD_DIR)\php.exe $(LDFLAGS) $(LDFLAGS_CLI) /ltcg /nodefaultlib:msvcrt /nodefaultlib:msvcrtd /ignore:4286';
FileSystem::writeFile(SOURCE_PATH . '/php-src/Makefile', implode("\r\n", $lines));
}
}