스킵 구현

This commit is contained in:
2023-12-20 19:45:25 +09:00
parent 6503fd167b
commit 8a987320e0
775 changed files with 162601 additions and 135 deletions

View File

@@ -0,0 +1,242 @@
<?php
// D++ changelog generator, saves 15 minutes for each release :-)
// Categories, in display order
$catgroup = [
'💣 Breaking Changes' => [],
'✨ New Features' => [],
'🐞 Bug Fixes' => [],
'🚀 Performance Improvements' => [],
'♻️ Refactoring' => [],
'🚨 Testing' => [],
'📚 Documentation' => [],
'💎 Style Changes' => [],
'🔧 Chore' => [],
'📜 Miscellaneous Changes' => []
];
// Pattern list
$categories = [
'break' => '💣 Breaking Changes',
'breaking' => '💣 Breaking Changes',
'feat' => '✨ New Features',
'feature' => '✨ New Features',
'add' => '✨ New Features',
'added' => '✨ New Features',
'fix' => '🐞 Bug Fixes',
'bug' => '🐞 Bug Fixes',
'bugfix' => '🐞 Bug Fixes',
'fixed' => '🐞 Bug Fixes',
'fixes' => '🐞 Bug Fixes',
'perf' => '🚀 Performance Improvements',
'performance' => '🚀 Performance Improvements',
'impro' => '♻️ Refactoring',
'improved' => '♻️ Refactoring',
'improvement' => '♻️ Refactoring',
'refactor' => '♻️ Refactoring',
'refactored' => '♻️ Refactoring',
'refactoring' => '♻️ Refactoring',
'deprecated' => '♻️ Refactoring',
'deprecate' => '♻️ Refactoring',
'remove' => '♻️ Refactoring',
'change' => '♻️ Refactoring',
'changed' => '♻️ Refactoring',
'test' => '🚨 Testing',
'tests' => '🚨 Testing',
'testing' => '🚨 Testing',
'ci' => '👷 Build/CI',
'build' => '👷 Build/CI',
'docs' => '📚 Documentation',
'documentation' => '📚 Documentation',
'style' => '💎 Style Changes',
'chore' => '🔧 Chore',
'misc' => '📜 Miscellaneous Changes',
'update' => '📜 Miscellaneous Changes',
'updated' => '📜 Miscellaneous Changes',
];
$changelog = [];
$githubstyle = true;
if (count($argv) > 2 && $argv[1] == '--discord') {
$githubstyle = false;
}
$errors = [];
// Magic sauce
exec("git log --oneline --format=\"%s\" $(git log --no-walk --tags | head -n1 | cut -d ' ' -f 2)..HEAD | grep -v '^Merge '", $changelog);
// Case insensitive removal of duplicates
$changelog = array_intersect_key($changelog, array_unique(array_map("strtolower", $changelog)));
// remove duplicates where two entries are the same but one ends with a GitHub pull request link
foreach ($changelog as $item) {
$entryWithoutPrLink = preg_replace('/( \(#\d+\))$/', '', $item);
if ($entryWithoutPrLink === $item) {
continue;
}
// if $item ends with (#123)
foreach ($changelog as $key => $change) {
if ($entryWithoutPrLink === $change) {
unset($changelog[$key]);
break;
}
}
}
function add_change(string $change, string $category, string $scope = null) {
global $catgroup;
if (isset($scope) && !empty($scope)) {
// Group by feature inside the section
if (!isset($catgroup[$category][$scope])) {
$catgroup[$category][$scope] = [];
}
$catgroup[$category][$scope][] = $change;
return;
}
$catgroup[$category][] = $change;
}
foreach ($changelog as $change) {
// Wrap anything that looks like a symbol name in backticks
$change = preg_replace('/([a-zA-Z][\w_\/\-]+\.\w+|\S+\(\)|\w+::\w+|dpp::\w+|utility::\w+|(\w+_\w+)+)/', '`$1`', $change);
$change = preg_replace("/vs(\d+)/", "Visual Studio $1", $change);
$change = preg_replace("/\bfaq\b/", "FAQ", $change);
$change = preg_replace("/\bdiscord\b/", "Discord", $change);
$change = preg_replace("/\bmicrosoft\b/", "Microsoft", $change);
$change = preg_replace("/\bwindows\b/", "Windows", $change);
$change = preg_replace("/\blinux\b/", "Linux", $change);
$change = preg_replace("/\sarm(\d+)\s/i", ' ARM$1 ', $change);
$change = preg_replace("/\b(was|is|wo)nt\b/i", '$1n\'t', $change);
$change = preg_replace("/\bfreebsd\b/", 'FreeBSD', $change);
$change = preg_replace("/``/", "`", $change);
$change = trim($change);
$matched = false;
$matches = [];
// Extract leading category section
if (preg_match("/^((?:(?:[\w_]+(?:\([\w_]+\))?+)(?:[\s]*[,\/][\s]*)?)+):/i", $change, $matches) || preg_match("/^\[((?:(?:[\w_]+(?:\([\w_]+\))?+)(?:[\s]*[,\/][\s]*)?)+)\](?:\s*:)?/i", $change, $matches)) {
$categorysection = $matches[0];
$changecategories = $matches[1];
$matchflags = PREG_SET_ORDER | PREG_UNMATCHED_AS_NULL;
// Extract each category and scope
if (preg_match_all("/(?:[\s]*)([\w_]+)(?:\(([\w_]+)\))?(?:[\s]*)(?:[,\/]+)?/i", $changecategories, $matches, $matchflags) !== false) {
/**
* Given a commit "foo, bar(foobar): add many foos and bars" :
* $matches is [
* 0 => [[0] => 'foo,', [1] => 'foo', [2] => null],
* 1 => [[0] => ' bar(foobar)', [1] => 'bar', [2] => 'foobar'],
* ]
* In other words, for a matched category N, matches[N][1] is the category, matches[N][2] is the scope
*/
$header = $matches[0][1];
$scope = $matches[0][2];
$change = trim(substr($change, strlen($categorysection)));
// List in breaking if present
foreach ($matches as $nb => $match) {
if ($nb == 0) // Skip the first category which will be added anyways
continue;
$category = $match[1];
if (isset($categories[$category]) && $categories[$category] === '💣 Breaking Changes')
add_change($change, $categories[$category], $scope);
}
if (!isset($categories[$header])) {
$errors[] = "could not find category \"" . $header . "\" for commit \"" . $change . "\", adding it to misc";
$header = $categories['misc'];
}
else {
$header = $categories[$header];
}
if (!isset($catgroup[$header])) {
$catgroup[$header] = [];
}
$matched = true;
// Ignore version bumps
if (!preg_match("/^(version )?bump/i", $change)) {
add_change($change, $header, $scope);
}
}
}
if (!$matched) { // Could not parse category section, try keywords
// Match keywords against categories
foreach ($categories as $cat => $header) {
// Purposefully ignored: comments that are one word, merge commits, and version bumps
if (strpos($change, ' ') === false || preg_match("/^Merge (branch|pull request|remote-tracking branch) /", $change) || preg_match("/^(version )?bump/i", $change)) {
$matched = true;
break;
}
if (preg_match("/^" . $cat . " /i", $change)) {
if (!isset($catgroup[$header])) {
$catgroup[$header] = [];
}
$matched = true;
$catgroup[$header][] = $change;
break;
}
}
}
if (!$matched) {
$errors[] = "could not guess category for commit \"" . $change . "\", adding it to misc";
$header = $categories['misc'];
if (!isset($catgroup[$header])) {
$catgroup[$header] = [];
}
$matched = true;
$catgroup[$header][] = $change;
}
}
// Leadin
if ($githubstyle) {
echo "The changelog is listed below:\n\nRelease Changelog\n===========\n";
} else {
echo "The changelog is listed below:\n\n## Release Changelog\n";
}
function print_change(string $change) {
global $githubstyle;
// Exclude bad commit messages like 'typo fix', 'test push' etc by pattern
if (!preg_match("/^(typo|test|fix)\s\w+$/", $change) && strpos($change, ' ') !== false) {
echo ($githubstyle ? '-' : '•') . ' ' . ucfirst(str_replace('@', '', $change)) . "\n";
}
}
// Output tidy formatting
foreach ($catgroup as $cat => $list) {
if (!empty($list)) {
echo "\n" . ($githubstyle ? '## ' : '### ') . $cat . "\n";
foreach ($list as $key => $item) {
if (is_array($item)) {
foreach ($item as $change) {
print_change("$key: $change");
}
}
else {
print_change($item);
}
}
}
}
// Leadout
echo "\n\n**Thank you for using D++!**\n\n";
if (!$githubstyle) {
$version = $argv[2];
echo 'The ' . $version . ' download can be found here: <https://dl.dpp.dev/' . $version . '>';
echo "\n";
}
/*
* Disabled as it generates pages and pages of stack traces, making it
* extremely difficult to copy and paste the error log when running this
* on the command line for sending discord announcement changelogs.
*
* foreach ($errors as $err) {
* trigger_error($err, E_USER_WARNING);
* }
*
*/

View File

@@ -0,0 +1,135 @@
<?php
namespace Dpp\Generator;
use Dpp\StructGeneratorInterface;
/**
* Generate header and .cpp file for coroutine calls (starting with 'co_')
*/
class CoroGenerator implements StructGeneratorInterface
{
/**
* @inheritDoc
*/
public function generateHeaderStart(): string
{
return <<<EOT
/************************************************************************************
*
* D++, A Lightweight C++ library for Discord
*
* Copyright 2022 Craig Edwards and D++ contributors
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
************************************************************************************/
/* Auto @generated by buildtools/make_coro_struct.php.
*
* DO NOT EDIT BY HAND!
*
* To re-generate this header file re-run the script!
*/
EOT;
}
/**
* @inheritDoc
*/
public function generateCppStart(): string
{
return $this->generateHeaderStart() . <<<EOT
#ifdef DPP_CORO
#include <dpp/export.h>
#include <dpp/snowflake.h>
#include <dpp/cluster.h>
#include <dpp/coro.h>
namespace dpp {
EOT;
}
/**
* @inheritDoc
*/
public function checkForChanges(): bool
{
/* Check if we need to re-generate by comparing modification times */
$us = file_exists('include/dpp/cluster_coro_calls.h') ? filemtime('include/dpp/cluster_coro_calls.h') : 0;
$them = filemtime('include/dpp/cluster.h');
if ($them <= $us) {
echo "-- No change required.\n";
return false;
}
echo "-- Autogenerating include/dpp/cluster_coro_calls.h\n";
echo "-- Autogenerating src/dpp/cluster_coro_calls.cpp\n";
return true;
}
/**
* @inheritDoc
*/
public function generateHeaderDef(string $returnType, string $currentFunction, string $parameters, string $noDefaults, string $parameterTypes, string $parameterNames): string
{
return "[[nodiscard]] async<confirmation_callback_t> co_{$currentFunction}($parameters);\n\n";
}
/**
* @inheritDoc
*/
public function generateCppDef(string $returnType, string $currentFunction, string $parameters, string $noDefaults, string $parameterTypes, string $parameterNames): string
{
/* if (substr($parameterNames, 0, 2) === ", ")
$parameterNames = substr($parameterNames, 2); */
return "async<confirmation_callback_t> cluster::co_${currentFunction}($noDefaults) {\n\treturn async{ this, static_cast<void (cluster::*)($parameterTypes". (!empty($parameterTypes) ? ", " : "") . "command_completion_event_t)>(&cluster::$currentFunction)$parameterNames };\n}\n\n";
}
/**
* @inheritDoc
*/
public function getCommentArray(): array
{
return [" * \memberof dpp::cluster"];
}
/**
* @inheritDoc
*/
public function saveHeader(string $content): void
{
$content .= "[[nodiscard]] async<http_request_completion_t> co_request(const std::string &url, http_method method, const std::string &postdata = \"\", const std::string &mimetype = \"text/plain\", const std::multimap<std::string, std::string> &headers = {});\n\n";
file_put_contents('include/dpp/cluster_coro_calls.h', $content);
}
/**
* @inheritDoc
*/
public function saveCpp(string $cppcontent): void
{
$cppcontent .= "dpp::async<dpp::http_request_completion_t> dpp::cluster::co_request(const std::string &url, http_method method, const std::string &postdata, const std::string &mimetype, const std::multimap<std::string, std::string> &headers) {\n\treturn async<http_request_completion_t>{ [&, this] <typename C> (C &&cc) { return this->request(url, method, std::forward<C>(cc), postdata, mimetype, headers); }};\n}
#endif
";
file_put_contents('src/dpp/cluster_coro_calls.cpp', $cppcontent);
}
}

View File

@@ -0,0 +1,130 @@
<?php
namespace Dpp\Generator;
use Dpp\StructGeneratorInterface;
/**
* Generate header and .cpp file for synchronous calls (ending in '_sync')
*/
class SyncGenerator implements StructGeneratorInterface
{
/**
* @inheritDoc
*/
public function generateHeaderStart(): string
{
return <<<EOT
/************************************************************************************
*
* D++, A Lightweight C++ library for Discord
*
* Copyright 2022 Craig Edwards and D++ contributors
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
************************************************************************************/
/* Auto @generated by buildtools/make_sync_struct.php.
*
* DO NOT EDIT BY HAND!
*
* To re-generate this header file re-run the script!
*/
EOT;
}
/**
* @inheritDoc
*/
public function generateCppStart(): string
{
return $this->generateHeaderStart() . <<<EOT
#include <dpp/export.h>
#include <dpp/snowflake.h>
#include <dpp/cluster.h>
namespace dpp {
EOT;
}
/**
* @inheritDoc
*/
public function checkForChanges(): bool
{
/* Check if we need to re-generate by comparing modification times */
$us = file_exists('include/dpp/cluster_sync_calls.h') ? filemtime('include/dpp/cluster_sync_calls.h') : 0;
$them = filemtime('include/dpp/cluster.h');
if ($them <= $us) {
echo "-- No change required.\n";
return false;
}
echo "-- Autogenerating include/dpp/cluster_sync_calls.h\n";
echo "-- Autogenerating src/dpp/cluster_sync_calls.cpp\n";
return true;
}
/**
* @inheritDoc
*/
public function generateHeaderDef(string $returnType, string $currentFunction, string $parameters, string $noDefaults, string $parameterTypes, string $parameterNames): string
{
return "$returnType {$currentFunction}_sync($parameters);\n\n";
}
/**
* @inheritDoc
*/
public function generateCppDef(string $returnType, string $currentFunction, string $parameters, string $noDefaults, string $parameterTypes, string $parameterNames): string
{
return "$returnType cluster::{$currentFunction}_sync($noDefaults) {\n\treturn dpp::sync<$returnType>(this, static_cast<void (cluster::*)($parameterTypes". (!empty($parameterTypes) ? ", " : "") . "command_completion_event_t)>(&cluster::$currentFunction)$parameterNames);\n}\n\n";
}
/**
* @inheritDoc
*/
public function getCommentArray(): array
{
return [
" * \memberof dpp::cluster",
" * @throw dpp::rest_exception upon failure to execute REST function",
" * @warning This function is a blocking (synchronous) call and should only be used from within a separate thread.",
" * Avoid direct use of this function inside an event handler.",
];
}
/**
* @inheritDoc
*/
public function saveHeader(string $content): void
{
file_put_contents('include/dpp/cluster_sync_calls.h', $content);
}
/**
* @inheritDoc
*/
public function saveCpp(string $cppcontent): void
{
file_put_contents('src/dpp/cluster_sync_calls.cpp', $cppcontent);
}
}

View File

@@ -0,0 +1,284 @@
<?php
namespace Dpp\Packager;
use \RuntimeException;
const GREEN = "\033[32m";
const RED = "\033[31m";
const WHITE = "\033[0m";
class Vcpkg
{
/**
* @var string Git Tag
*/
private string $latestTag;
/**
* @var string Semver version
*/
private string $version;
/**
* @var string Path to GIT
*/
private string $git;
/**
* @var string Path to SUDO
*/
private string $sudo;
/**
* @var bool True when we have done the first build to get the SHA512 sum
*/
private bool $firstBuildComplete = false;
/**
* Constructor
*
* Examines current diretory's git repository to get latest tag and version.
*/
public function __construct()
{
global $argv;
if (count($argv) < 2) {
throw new RuntimeException(RED . "Missing github repository owner and access token\n" . WHITE);
}
echo GREEN . "Starting vcpkg updater...\n" . WHITE;
/* Get the latest tag from the version of the repository checked out by default into the action */
$this->latestTag = preg_replace("/\n/", "", shell_exec("git describe --tags `git rev-list --tags --max-count=1`"));
$this->version = preg_replace('/^v/', '', $this->getTag());
echo GREEN . "Latest tag: " . $this->getTag() . " version: " . $this->getVersion() . "\n" . WHITE;
$this->git = trim(`which git`);
$this->sudo = trim(`which sudo`);
}
/**
* Get semver version
*
* @return string
*/
public function getVersion(): string
{
return $this->version;
}
/**
* Get the git tag we are building
*
* @return string
*/
public function getTag(): string
{
return $this->latestTag;
}
private function git(string $parameters, bool $sudo = false): void
{
system(($sudo ? $this->sudo . ' ' : '') . $this->git . ' ' . $parameters);
}
private function sudo(string $command): void
{
system($this->sudo . ' ' . $command);
}
/**
* Check out a repository by tag or branch name to ~/dpp,
* using the personal access token and username passed in as command line parameters.
*
* @param string $tag Tag to clone
* @return bool false if the repository could not be cloned
*/
function checkoutRepository(string $tag = ""): bool
{
global $argv;
if (empty($tag)) {
/* Empty tag means use the main branch */
$tag = `{$this->git} config --get init.defaultBranch || echo master`;
}
$repositoryUrl = 'https://' . urlencode($argv[1]) . ':' . urlencode($argv[2]) . '@github.com/brainboxdotcc/DPP';
echo GREEN . "Check out repository: $tag (user: ". $argv[1] . " branch: " . $tag . ")\n" . WHITE;
chdir(getenv('HOME'));
system('rm -rf ./dpp');
$this->git('config --global user.email "noreply@dpp.dev"');
$this->git('config --global user.name "DPP VCPKG Bot"');
$this->git('clone ' . escapeshellarg($repositoryUrl) . ' ./dpp --depth=1');
/* This is noisy, silence it */
$status = chdir(getenv("HOME") . '/dpp');
$this->git('fetch -at 2>/dev/null');
$this->git('checkout ' . escapeshellarg($tag) . ' 2>/dev/null');
return $status;
}
/**
* Create ./vcpkg/ports/dpp/vcpkg.json and return the portfile contents to
* build the branch that is cloned at ~/dpp
*
* @param string $sha512 The SHA512 sum of the tagged download, or initially
* zero, which means that the vcpkg install command should obtain it the
* second time around.
* @return string The portfile content
*/
function constructPortAndVersionFile(string $sha512 = "0"): string
{
echo GREEN . "Construct portfile for " . $this->getVersion() . ", sha512: $sha512\n" . WHITE;
chdir(getenv("HOME") . '/dpp');
$portFileContent = 'vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO brainboxdotcc/DPP
REF "v${VERSION}"
SHA512 ' . $sha512 . '
)
vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}"
DISABLE_PARALLEL_CONFIGURE
)
vcpkg_cmake_install()
vcpkg_cmake_config_fixup(NO_PREFIX_CORRECTION)
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share/dpp")
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
if(VCPKG_LIBRARY_LINKAGE STREQUAL "static")
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/bin" "${CURRENT_PACKAGES_DIR}/debug/bin")
endif()
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")
file(COPY "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
';
// ./vcpkg/ports/dpp/vcpkg.json
$versionFileContent = '{
"name": "dpp",
"version": ' . json_encode($this->getVersion()) . ',
"description": "D++ Extremely Lightweight C++ Discord Library.",
"homepage": "https://dpp.dev/",
"license": "Apache-2.0",
"supports": "((windows & !static & !uwp) | linux | osx)",
"dependencies": [
"libsodium",
"nlohmann-json",
"openssl",
"opus",
"zlib",
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
}
]
}';
echo GREEN . "Writing portfile...\n" . WHITE;
file_put_contents('./vcpkg/ports/dpp/vcpkg.json', $versionFileContent);
return $portFileContent;
}
/**
* Attempt the first build of the vcpkg port. This will always fail, as it is given
* an SHA512 sum of 0. When it fails the output contains the SHA512 sum, which is then
* extracted from the error output using a regular expression, and saved for a second
* attempt.
* @param string $portFileContent Portfile content from constructPortAndVersionFile()
* with an SHA512 sum of 0 passed in.
* @return string SHA512 sum of build output
*/
function firstBuild(string $portFileContent): string
{
echo GREEN . "Starting first build\n" . WHITE;
chdir(getenv("HOME") . '/dpp');
echo GREEN . "Create /usr/local/share/vcpkg/ports/dpp/\n" . WHITE;
$this->sudo('mkdir -p /usr/local/share/vcpkg/ports/dpp/');
echo GREEN . "Copy vcpkg.json to /usr/local/share/vcpkg/ports/dpp/vcpkg.json\n" . WHITE;
$this->sudo('cp -v -R ./vcpkg/ports/dpp/vcpkg.json /usr/local/share/vcpkg/ports/dpp/vcpkg.json');
file_put_contents('/tmp/portfile', $portFileContent);
$this->sudo('cp -v -R /tmp/portfile /usr/local/share/vcpkg/ports/dpp/portfile.cmake');
unlink('/tmp/portfile');
$buildResults = shell_exec($this->sudo . ' /usr/local/share/vcpkg/vcpkg install dpp:x64-linux');
$matches = [];
if (preg_match('/Actual hash:\s+([0-9a-fA-F]+)/', $buildResults, $matches)) {
echo GREEN . "Obtained SHA512 for first build: " . $matches[1] . "\n" . WHITE;
$this->firstBuildComplete = true;
return $matches[1];
}
echo RED . "No SHA512 found during first build :(\n" . WHITE;
return '';
}
/**
* Second build using a valid SHA512 sum. This attempt should succeed, allowing us to push
* the changed vcpkg portfiles into the master branch, where they can be used in a PR to
* microsoft/vcpkg repository later.
*
* @param string $portFileContent the contents of the portfile, containing a valid SHA512
* sum from the first build attempt.
* @return bool False if the build failed
*/
function secondBuild(string $portFileContent): bool
{
if (!$this->firstBuildComplete) {
throw new RuntimeException("No SHA512 sum is available, first build has not been run!");
}
echo GREEN . "Executing second build\n" . WHITE;
echo GREEN . "Copy local port files to /usr/local/share...\n" . WHITE;
chdir(getenv("HOME") . '/dpp');
file_put_contents('./vcpkg/ports/dpp/portfile.cmake', $portFileContent);
$this->sudo('cp -v -R ./vcpkg/ports/dpp/vcpkg.json /usr/local/share/vcpkg/ports/dpp/vcpkg.json');
$this->sudo('cp -v -R ./vcpkg/ports/dpp/portfile.cmake /usr/local/share/vcpkg/ports/dpp/portfile.cmake');
$this->sudo('cp -v -R ./vcpkg/ports/* /usr/local/share/vcpkg/ports/');
echo GREEN . "vcpkg x-add-version...\n" . WHITE;
chdir('/usr/local/share/vcpkg');
$this->sudo('./vcpkg format-manifest ./ports/dpp/vcpkg.json');
/* Note: We commit this in /usr/local, but we never push it (we can't) */
$this->git('add .', true);
$this->git('-c user.name="DPP VCPKG Bot" -c user.email=noreply@dpp.dev commit -m "[bot] VCPKG info update"', true);
$this->sudo('/usr/local/share/vcpkg/vcpkg x-add-version dpp');
echo GREEN . "Copy back port files from /usr/local/share...\n" . WHITE;
chdir(getenv('HOME') . '/dpp');
system('cp -v -R /usr/local/share/vcpkg/ports/dpp/vcpkg.json ./vcpkg/ports/dpp/vcpkg.json');
system('cp -v -R /usr/local/share/vcpkg/versions/baseline.json ./vcpkg/versions/baseline.json');
system('cp -v -R /usr/local/share/vcpkg/versions/d-/dpp.json ./vcpkg/versions/d-/dpp.json');
echo GREEN . "Commit and push changes to master branch\n" . WHITE;
$this->git('config --global user.email "noreply@dpp.dev"');
$this->git('config --global user.name "DPP VCPKG Bot"');
$this->git('add .');
$this->git('commit -m "[bot] VCPKG info update [skip ci]"');
$this->git('config pull.rebase false');
$this->git('pull');
$this->git('push origin master');
echo GREEN . "vcpkg install...\n" . WHITE;
$resultCode = 0;
$output = [];
exec($this->sudo . ' /usr/local/share/vcpkg/vcpkg install dpp:x64-linux', $output, $resultCode);
if ($resultCode != 0) {
echo RED . "There were build errors!\n\nBuild log:\n" . WHITE;
readfile("/usr/local/share/vcpkg/buildtrees/dpp/install-x64-linux-dbg-out.log");
}
return $resultCode == 0;
}
};

View File

@@ -0,0 +1,75 @@
<?php
namespace Dpp;
/**
* Represents a header/cpp generator used to auto-generate cpp/.h files.
*/
interface StructGeneratorInterface
{
/**
* Generate the start of the header file
*
* @return string header content
*/
public function generateHeaderStart(): string;
/**
* Generate the start of the cpp file
*
* @return string cpp content
*/
public function generateCppStart(): string;
/**
* Check if the script should run and re-generate content or not
*
* @return string true if the script should run, false to exit
*/
public function checkForchanges(): bool;
/**
* Generate header definition for a function
*
* @param string $returnType Return type of function
* @param string $currentFunction Current function name
* @param string $parameters Current function parameters with default values
* @param string $noDefaults Current function parameters without default values
* @param string $parameterNames Parameter names only
* @return string header content to append
*/
public function generateHeaderDef(string $returnType, string $currentFunction, string $parameters, string $noDefaults, string $parameterTypes, string $parameterNames): string;
/**
* Generate cpp definition for a function
*
* @param string $returnType Return type of function
* @param string $currentFunction Current function name
* @param string $parameters Current function parameters with default values
* @param string $noDefaults Current function parameters without default values
* @param string $parameterNames Parameter names only
* @return string cpp content to append
*/
public function generateCppDef(string $returnType, string $currentFunction, string $parameters, string $noDefaults, string $parameterTypes, string $parameterNames): string;
/**
* Return comment lines to add to each header definition
*
* @return array Comment lines to add
*/
public function getCommentArray(): array;
/**
* Save the .h file
*
* @param string $content Content to save
*/
public function saveHeader(string $content): void;
/**
* Save the .cpp file
*
* @param string $cppcontent Content to save
*/
public function saveCpp(string $cppcontent): void;
};

View File

@@ -0,0 +1,17 @@
{
"name": "brainboxdotcc/dpp",
"description": "DPP Build Tools",
"type": "project",
"license": "Apache 2.0",
"autoload": {
"psr-4": {
"Dpp\\": "classes/"
}
},
"authors": [
{
"name": "brain"
}
],
"require": {}
}

View File

@@ -0,0 +1,46 @@
<?php
ini_set("default_charset", "UTF-8");
echo "-- Autogenrating include/dpp/unicode_emoji.h\n";
$url = "https://raw.githubusercontent.com/ArkinSolomon/discord-emoji-converter/master/emojis.json";
$header = <<<END
#pragma once
namespace dpp {
/**
* @brief Emoji unicodes.
*
* @note The unicode emojis in this namespace are auto-generated from https://raw.githubusercontent.com/ArkinSolomon/discord-emoji-converter/master/emojis.json
*
* @warning If you want to use this, you have to pull the header in separately. For example:
* ```cpp
* #include <dpp/dpp.h>
* #include <dpp/unicode_emoji.h>
* ```
*/
namespace unicode_emoji {
END;
/* This JSON is generated originally via the NPM package maintained by Discord themselves at https://www.npmjs.com/package/discord-emoji */
$emojis = json_decode(file_get_contents($url));
if ($emojis) {
foreach ($emojis as $name=>$code) {
if (preg_match("/^\d+/", $name)) {
$name = "_" . $name;
}
$name = str_replace("-", "minus", $name);
$name = str_replace("+", "plus", $name);
$name = str_replace("ñ", "n", $name);
if ($name == "new") {
$name = "_new";
}
$header .= " inline constexpr const char " .$name . "[] = \"$code\";\n";
}
$header .= "}\n};\n";
file_put_contents("include/dpp/unicode_emoji.h", $header);
}

View File

@@ -0,0 +1,199 @@
<?php
chdir('buildtools');
require __DIR__ . '/vendor/autoload.php';
use Dpp\StructGeneratorInterface;
if (count($argv) < 2) {
die("You must specify a generator type\n");
} else {
$generatorName = $argv[1];
$generator = new $generatorName();
}
chdir('..');
/* Get the content of all cluster source files into an array */
exec("cat src/dpp/cluster/*.cpp", $clustercpp);
/* These methods have signatures incompatible with this script */
$blacklist = [
];
/* The script cannot determine the correct return type of these methods,
* so we specify it by hand here.
*/
$forcedReturn = [
'direct_message_create' => 'message',
'guild_get_members' => 'guild_member_map',
'guild_search_members' => 'guild_member_map',
'message_create' => 'message',
'message_edit' => 'message',
'message_add_reaction' => 'confirmation',
'message_delete_reaction' => 'confirmation',
'message_delete_reaction_emoji' => 'confirmation',
'message_delete_all_reactions' => 'confirmation',
'message_delete_own_reaction' => 'confirmation',
'channel_edit_permissions' => 'confirmation',
'channel_typing' => 'confirmation',
'message_get_reactions' => 'emoji_map',
'thread_create_in_forum' => 'thread',
'threads_get_active' => 'active_threads',
'user_get_cached' => 'user_identified',
'application_role_connection_get' => 'application_role_connection',
'application_role_connection_update' => 'application_role_connection'
];
/* Get the contents of cluster.h into an array */
$header = explode("\n", file_get_contents('include/dpp/cluster.h'));
/* Finite state machine state constants */
const STATE_SEARCH_FOR_FUNCTION = 0;
const STATE_IN_FUNCTION = 1;
const STATE_END_OF_FUNCTION = 2;
$state = STATE_SEARCH_FOR_FUNCTION;
$currentFunction = $parameters = $returnType = '';
$content = $generator->generateHeaderStart();
$cppcontent = $generator->generatecppStart();
if (!$generator->checkForChanges()) {
exit(0);
}
$lastFunc = '<none>';
$l = 0;
/* Scan every line of the C++ source */
foreach ($clustercpp as $cpp) {
$l++;
/* Look for declaration of function body */
if ($state == STATE_SEARCH_FOR_FUNCTION &&
preg_match('/^\s*void\s+cluster::([^(]+)\s*\((.*)command_completion_event_t\s*callback\s*\)/', $cpp, $matches)) {
$currentFunction = $matches[1];
$parameters = preg_replace('/,\s*$/', '', $matches[2]);
if (!in_array($currentFunction, $blacklist)) {
$state = STATE_IN_FUNCTION;
}
/* Scan function body */
} elseif ($state == STATE_IN_FUNCTION) {
/* End of function */
if (preg_match('/^\}\s*$/', $cpp)) {
$state = STATE_END_OF_FUNCTION;
/* look for the return type of the method */
} elseif (preg_match('/rest_request<([^>]+)>/', $cpp, $matches)) {
/* rest_request<T> */
$returnType = $matches[1];
} elseif (preg_match('/rest_request_list<([^>]+)>/', $cpp, $matches)) {
/* rest_request_list<T> */
$returnType = $matches[1] . '_map';
} elseif (preg_match('/callback\(confirmation_callback_t\(\w+, ([^(]+)\(.*, \w+\)\)/', $cpp, $matches)) {
/* confirmation_callback_t */
$returnType = $matches[1];
} elseif (!empty($forcedReturn[$currentFunction])) {
/* Forced return type */
$returnType = $forcedReturn[$currentFunction];
}
}
/* Completed parsing of function body */
if ($state == STATE_END_OF_FUNCTION && !empty($currentFunction) && !empty($returnType)) {
if (!in_array($currentFunction, $blacklist)) {
$parameterList = explode(',', $parameters);
$parameterNames = [];
$parameterTypes = [];
foreach ($parameterList as $parameter) {
$parts = explode(' ', trim($parameter));
$name = trim(preg_replace('/[\s\*\&]+/', '', $parts[count($parts) - 1]));
$parameterNames[] = $name;
$parameterTypes[] = trim(substr($parameter, 0, strlen($parameter) - strlen($name)));
}
$content .= getComments($generator, $currentFunction, $returnType, $parameterNames) . "\n";
$fullParameters = getFullParameters($currentFunction, $parameterNames);
$parameterNames = trim(join(', ', $parameterNames));
$parameterTypes = trim(join(', ', $parameterTypes));
if (!empty($parameterNames)) {
$parameterNames = ', ' . $parameterNames;
}
$noDefaults = $parameters;
$parameters = !empty($fullParameters) ? $fullParameters : $parameters;
$content .= $generator->generateHeaderDef($returnType, $currentFunction, $parameters, $noDefaults, $parameterTypes, $parameterNames);
$cppcontent .= $generator->generateCppDef($returnType, $currentFunction, $parameters, $noDefaults, $parameterTypes, $parameterNames);
}
$lastFunc = $currentFunction;
$currentFunction = $parameters = $returnType = '';
$state = STATE_SEARCH_FOR_FUNCTION;
}
}
if ($state != STATE_SEARCH_FOR_FUNCTION) {
die("\n\n\nBuilding headers is broken ($l) - state machine finished in the middle of function $currentFunction (previous $lastFunc) with parameters $parameters rv $returnType state=$state\n\n\n");
}
$content .= <<<EOT
/* End of auto-generated definitions */
EOT;
$cppcontent .= <<<EOT
};
/* End of auto-generated definitions */
EOT;
/**
* @brief Get parameters of a function with defaults
* @param string $currentFunction Current function name
* @param array $parameters Parameter names
* @return string Parameter list
*/
function getFullParameters(string $currentFunction, array $parameters): string
{
global $header;
foreach ($header as $line) {
if (preg_match('/^\s*void\s+' . $currentFunction . '\s*\((.*' . join('.*', $parameters) . '.*)command_completion_event_t\s*callback\s*/', $line, $matches)) {
return preg_replace('/,\s*$/', '', $matches[1]);
}
}
return '';
}
/**
* @brief Get the comment block of a function.
* Adds see/return doxygen tags
* @param string $currentFunction function name
* @param string $returnType Return type of function
* @param array $parameters Parameter names
* @return string Comment block
*/
function getComments(StructGeneratorInterface $generator, string $currentFunction, string $returnType, array $parameters): string
{
global $header;
/* First find the function */
foreach ($header as $i => $line) {
if (preg_match('/^\s*void\s+' . $currentFunction . '\s*\(.*' . join('.*', $parameters) . '.*command_completion_event_t\s*callback\s*/', $line)) {
/* Backpeddle */
$lineIndex = 1;
for ($n = $i; $n != 0; --$n, $lineIndex++) {
$header[$n] = preg_replace('/^\t+/', '', $header[$n]);
$header[$n] = preg_replace('/@see (.+?)$/', '@see dpp::cluster::' . $currentFunction . "\n * @see \\1", $header[$n]);
$header[$n] = preg_replace('/@param callback .*$/', '@return ' . $returnType . ' returned object on completion', $header[$n]);
if (preg_match('/\s*\* On success /i', $header[$n])) {
$header[$n] = "";
}
if (preg_match('/\s*\/\*\*\s*$/', $header[$n])) {
$part = array_slice($header, $n, $lineIndex - 1);
array_splice($part, count($part) - 1, 0, $generator->getCommentArray());
return str_replace("\n\n", "\n", join("\n", $part));
}
}
return '';
}
}
return '';
}
/* Finished parsing, output autogenerated files */
$generator->saveHeader($content);
$generator->savecpp($cppcontent);

View File

@@ -0,0 +1,62 @@
<?php
/**
* Automatic CI process for generating new vcpkg releases.
* Based loosely on RealTimeChris's shell script version.
*
* This updates the content of ./vcpkg directory within the DPP
* repository on the master branch, which can then be diffed into
* the microsoft/vcpkg master branch to build a PR for the new
* release.
*
* The procedure for this is:
*
* 1) Generate various configuration files and put them into the
* systemwide vcpkg installation inside the CI container
* 2) Attempt to build the package from the release tag,
* this will fail due to invalid SHA512 sum and return the
* correct SHA512 sum in the error output. Inability to get the
* SHA512 sum here will return nonzero from the script, failing
* the CI action.
* 3) Capture the SHA512 from the error output, switch to master
* 4) Copy the correct configuration into both the systemwide
* vcpkg install in the container, and into the vcpkg directory
* of master branch.
* 5) Rerun the `vcpkg install` process again to verify it is working.
* A build failure here will return a nonzero return code from
* the script, failing the CI action.
*/
require __DIR__ . '/vendor/autoload.php';
use Dpp\Packager\Vcpkg;
$vcpkg = new Vcpkg();
/* Check out source for latest tag */
if (!$vcpkg->checkoutRepository($vcpkg->getTag())) {
exit(1);
}
/* First run with SHA512 of 0 to gather actual value and save it */
$sha512 = $vcpkg->firstBuild(
$vcpkg->constructPortAndVersionFile()
);
if (!empty($sha512)) {
/* Now check out master */
if (!$vcpkg->checkoutRepository()) {
exit(1);
}
/* Attempt second build with the valid SHA512 sum. Program exit
* status is the exit status of `vcpkg install`
*/
exit(
$vcpkg->secondBuild(
$vcpkg->constructPortAndVersionFile($sha512)
)
);
}
/* Error if no SHA sum could be generated */
exit(1);

View File

@@ -0,0 +1,12 @@
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
exit(1);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit0e8415491642f27914717986db49b1db::getLoader();

View File

@@ -0,0 +1,572 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var ?string */
private $vendorDir;
// PSR-4
/**
* @var array[]
* @psalm-var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, array<int, string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* @var array[]
* @psalm-var array<string, array<string, string[]>>
*/
private $prefixesPsr0 = array();
/**
* @var array[]
* @psalm-var array<string, string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var string[]
* @psalm-var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var bool[]
* @psalm-var array<string, bool>
*/
private $missingClasses = array();
/** @var ?string */
private $apcuPrefix;
/**
* @var self[]
*/
private static $registeredLoaders = array();
/**
* @param ?string $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
}
/**
* @return string[]
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
/**
* @return array[]
* @psalm-return array<string, array<int, string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return array[]
* @psalm-return array<string, string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return string[] Array of classname => path
* @psalm-return array<string, string>
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param string[] $classMap Class to filename map
* @psalm-param array<string, string> $classMap
*
* @return void
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
return null;
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
/**
* Returns the currently registered loaders indexed by their corresponding vendor directories.
*
* @return self[]
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
* @private
*/
function includeFile($file)
{
include $file;
}

View File

@@ -0,0 +1,21 @@
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,10 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);

View File

@@ -0,0 +1,9 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
);

View File

@@ -0,0 +1,10 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Dpp\\' => array($baseDir . '/classes'),
);

View File

@@ -0,0 +1,36 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit0e8415491642f27914717986db49b1db
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit0e8415491642f27914717986db49b1db', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit0e8415491642f27914717986db49b1db', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit0e8415491642f27914717986db49b1db::getInitializer($loader));
$loader->register(true);
return $loader;
}
}

View File

@@ -0,0 +1,36 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit0e8415491642f27914717986db49b1db
{
public static $prefixLengthsPsr4 = array (
'D' =>
array (
'Dpp\\' => 4,
),
);
public static $prefixDirsPsr4 = array (
'Dpp\\' =>
array (
0 => __DIR__ . '/../..' . '/classes',
),
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit0e8415491642f27914717986db49b1db::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit0e8415491642f27914717986db49b1db::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit0e8415491642f27914717986db49b1db::$classMap;
}, null, ClassLoader::class);
}
}