src: initialize ICU version in per_process::metadata.versions
Instead of - Initialize the ICU versions in JS land after consulting internalBinding('config').hasIntl - Joining the version keys in C++ - Splitting the keys in JS and call into C++ again to get the value for each of the keys Do: - Guard the initialization code behind `NODE_HAVE_I18N_SUPPORT` - Do the initialization in C++ right after ICU data is loaded - Initialize each version directly using ICU functions/constants, and put them in per_process::metadata.versions. These will be copied into `process.versions` naturally later. This way, the initialization of the versions won't be called in worker threads again. PR-URL: https://github.com/nodejs/node/pull/25115 Reviewed-By: Steven R Loomis <srloomis@us.ibm.com> Reviewed-By: Richard Lau <riclau@uk.ibm.com> Reviewed-By: Minwoo Jung <minwoo@nodesource.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
a29c93a147
commit
263d13766f
@ -38,8 +38,6 @@ function startup() {
|
|||||||
// Do this good and early, since it handles errors.
|
// Do this good and early, since it handles errors.
|
||||||
setupProcessFatal();
|
setupProcessFatal();
|
||||||
|
|
||||||
setupProcessICUVersions();
|
|
||||||
|
|
||||||
setupGlobalVariables();
|
setupGlobalVariables();
|
||||||
|
|
||||||
// Bootstrappers for all threads, including worker threads and main thread
|
// Bootstrappers for all threads, including worker threads and main thread
|
||||||
@ -638,25 +636,6 @@ function setupProcessFatal() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupProcessICUVersions() {
|
|
||||||
const icu = internalBinding('config').hasIntl ?
|
|
||||||
internalBinding('icu') : undefined;
|
|
||||||
if (!icu) return; // no Intl/ICU: nothing to add here.
|
|
||||||
// With no argument, getVersion() returns a comma separated list
|
|
||||||
// of possible types.
|
|
||||||
const versionTypes = icu.getVersion().split(',');
|
|
||||||
|
|
||||||
for (var n = 0; n < versionTypes.length; n++) {
|
|
||||||
const name = versionTypes[n];
|
|
||||||
const version = icu.getVersion(name);
|
|
||||||
Object.defineProperty(process.versions, name, {
|
|
||||||
writable: false,
|
|
||||||
enumerable: true,
|
|
||||||
value: version
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function wrapForBreakOnFirstLine(source) {
|
function wrapForBreakOnFirstLine(source) {
|
||||||
if (!process._breakFirstLine)
|
if (!process._breakFirstLine)
|
||||||
return source;
|
return source;
|
||||||
|
@ -877,7 +877,10 @@ void SetupProcessObject(Environment* env,
|
|||||||
READONLY_PROPERTY(process, "versions", versions);
|
READONLY_PROPERTY(process, "versions", versions);
|
||||||
|
|
||||||
#define V(key) \
|
#define V(key) \
|
||||||
READONLY_STRING_PROPERTY(versions, #key, per_process::metadata.versions.key);
|
if (!per_process::metadata.versions.key.empty()) { \
|
||||||
|
READONLY_STRING_PROPERTY( \
|
||||||
|
versions, #key, per_process::metadata.versions.key); \
|
||||||
|
}
|
||||||
NODE_VERSIONS_KEYS(V)
|
NODE_VERSIONS_KEYS(V)
|
||||||
#undef V
|
#undef V
|
||||||
|
|
||||||
@ -1664,6 +1667,7 @@ void Init(std::vector<std::string>* argv,
|
|||||||
argv->at(0).c_str());
|
argv->at(0).c_str());
|
||||||
exit(9);
|
exit(9);
|
||||||
}
|
}
|
||||||
|
per_process::metadata.versions.InitializeIntlVersions();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We should set node_is_initialized here instead of in node::Start,
|
// We should set node_is_initialized here instead of in node::Start,
|
||||||
|
@ -510,67 +510,6 @@ void ICUErrorName(const FunctionCallbackInfo<Value>& args) {
|
|||||||
NewStringType::kNormal).ToLocalChecked());
|
NewStringType::kNormal).ToLocalChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TYPE_ICU "icu"
|
|
||||||
#define TYPE_UNICODE "unicode"
|
|
||||||
#define TYPE_CLDR "cldr"
|
|
||||||
#define TYPE_TZ "tz"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the workhorse function that deals with the actual version info.
|
|
||||||
* Get an ICU version.
|
|
||||||
* @param type the type of version to get. One of VERSION_TYPES
|
|
||||||
* @param buf optional buffer for result
|
|
||||||
* @param status ICU error status. If failure, assume result is undefined.
|
|
||||||
* @return version number, or NULL. May or may not be buf.
|
|
||||||
*/
|
|
||||||
const char* GetVersion(const char* type,
|
|
||||||
char buf[U_MAX_VERSION_STRING_LENGTH],
|
|
||||||
UErrorCode* status) {
|
|
||||||
if (!strcmp(type, TYPE_ICU)) {
|
|
||||||
return U_ICU_VERSION;
|
|
||||||
} else if (!strcmp(type, TYPE_UNICODE)) {
|
|
||||||
return U_UNICODE_VERSION;
|
|
||||||
} else if (!strcmp(type, TYPE_TZ)) {
|
|
||||||
return icu::TimeZone::getTZDataVersion(*status);
|
|
||||||
} else if (!strcmp(type, TYPE_CLDR)) {
|
|
||||||
UVersionInfo versionArray;
|
|
||||||
ulocdata_getCLDRVersion(versionArray, status);
|
|
||||||
if (U_SUCCESS(*status)) {
|
|
||||||
u_versionToString(versionArray, buf);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Fall through - unknown type or error case
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetVersion(const FunctionCallbackInfo<Value>& args) {
|
|
||||||
Environment* env = Environment::GetCurrent(args);
|
|
||||||
if ( args.Length() == 0 ) {
|
|
||||||
// With no args - return a comma-separated list of allowed values
|
|
||||||
args.GetReturnValue().Set(
|
|
||||||
String::NewFromUtf8(env->isolate(),
|
|
||||||
TYPE_ICU ","
|
|
||||||
TYPE_UNICODE ","
|
|
||||||
TYPE_CLDR ","
|
|
||||||
TYPE_TZ, NewStringType::kNormal).ToLocalChecked());
|
|
||||||
} else {
|
|
||||||
CHECK_GE(args.Length(), 1);
|
|
||||||
CHECK(args[0]->IsString());
|
|
||||||
Utf8Value val(env->isolate(), args[0]);
|
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
|
||||||
char buf[U_MAX_VERSION_STRING_LENGTH] = ""; // Possible output buffer.
|
|
||||||
const char* versionString = GetVersion(*val, buf, &status);
|
|
||||||
|
|
||||||
if (U_SUCCESS(status) && versionString) {
|
|
||||||
// Success.
|
|
||||||
args.GetReturnValue().Set(
|
|
||||||
String::NewFromUtf8(env->isolate(),
|
|
||||||
versionString, NewStringType::kNormal).ToLocalChecked());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
bool InitializeICUDirectory(const std::string& path) {
|
bool InitializeICUDirectory(const std::string& path) {
|
||||||
@ -868,7 +807,6 @@ void Initialize(Local<Object> target,
|
|||||||
env->SetMethod(target, "toUnicode", ToUnicode);
|
env->SetMethod(target, "toUnicode", ToUnicode);
|
||||||
env->SetMethod(target, "toASCII", ToASCII);
|
env->SetMethod(target, "toASCII", ToASCII);
|
||||||
env->SetMethod(target, "getStringWidth", GetStringWidth);
|
env->SetMethod(target, "getStringWidth", GetStringWidth);
|
||||||
env->SetMethod(target, "getVersion", GetVersion);
|
|
||||||
|
|
||||||
// One-shot converters
|
// One-shot converters
|
||||||
env->SetMethod(target, "icuErrName", ICUErrorName);
|
env->SetMethod(target, "icuErrName", ICUErrorName);
|
||||||
|
@ -11,6 +11,13 @@
|
|||||||
#include <openssl/opensslv.h>
|
#include <openssl/opensslv.h>
|
||||||
#endif // HAVE_OPENSSL
|
#endif // HAVE_OPENSSL
|
||||||
|
|
||||||
|
#ifdef NODE_HAVE_I18N_SUPPORT
|
||||||
|
#include <unicode/timezone.h>
|
||||||
|
#include <unicode/ulocdata.h>
|
||||||
|
#include <unicode/uvernum.h>
|
||||||
|
#include <unicode/uversion.h>
|
||||||
|
#endif // NODE_HAVE_I18N_SUPPORT
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
namespace per_process {
|
namespace per_process {
|
||||||
@ -34,6 +41,25 @@ std::string GetOpenSSLVersion() {
|
|||||||
}
|
}
|
||||||
#endif // HAVE_OPENSSL
|
#endif // HAVE_OPENSSL
|
||||||
|
|
||||||
|
#ifdef NODE_HAVE_I18N_SUPPORT
|
||||||
|
void Metadata::Versions::InitializeIntlVersions() {
|
||||||
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
|
|
||||||
|
const char* tz_version = icu::TimeZone::getTZDataVersion(status);
|
||||||
|
if (U_SUCCESS(status)) {
|
||||||
|
tz = tz_version;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[U_MAX_VERSION_STRING_LENGTH];
|
||||||
|
UVersionInfo versionArray;
|
||||||
|
ulocdata_getCLDRVersion(versionArray, &status);
|
||||||
|
if (U_SUCCESS(status)) {
|
||||||
|
u_versionToString(versionArray, buf);
|
||||||
|
cldr = buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // NODE_HAVE_I18N_SUPPORT
|
||||||
|
|
||||||
Metadata::Versions::Versions() {
|
Metadata::Versions::Versions() {
|
||||||
node = NODE_VERSION_STRING;
|
node = NODE_VERSION_STRING;
|
||||||
v8 = v8::V8::GetVersion();
|
v8 = v8::V8::GetVersion();
|
||||||
@ -49,6 +75,11 @@ Metadata::Versions::Versions() {
|
|||||||
#if HAVE_OPENSSL
|
#if HAVE_OPENSSL
|
||||||
openssl = GetOpenSSLVersion();
|
openssl = GetOpenSSLVersion();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NODE_HAVE_I18N_SUPPORT
|
||||||
|
icu = U_ICU_VERSION;
|
||||||
|
unicode = U_UNICODE_VERSION;
|
||||||
|
#endif // NODE_HAVE_I18N_SUPPORT
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
@ -25,14 +25,38 @@ namespace node {
|
|||||||
#define NODE_VERSIONS_KEY_CRYPTO(V)
|
#define NODE_VERSIONS_KEY_CRYPTO(V)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NODE_HAVE_I18N_SUPPORT
|
||||||
|
#define NODE_VERSIONS_KEY_INTL(V) \
|
||||||
|
V(cldr) \
|
||||||
|
V(icu) \
|
||||||
|
V(tz) \
|
||||||
|
V(unicode)
|
||||||
|
#else
|
||||||
|
#define NODE_VERSIONS_KEY_INTL(V)
|
||||||
|
#endif // NODE_HAVE_I18N_SUPPORT
|
||||||
|
|
||||||
#define NODE_VERSIONS_KEYS(V) \
|
#define NODE_VERSIONS_KEYS(V) \
|
||||||
NODE_VERSIONS_KEYS_BASE(V) \
|
NODE_VERSIONS_KEYS_BASE(V) \
|
||||||
NODE_VERSIONS_KEY_CRYPTO(V)
|
NODE_VERSIONS_KEY_CRYPTO(V) \
|
||||||
|
NODE_VERSIONS_KEY_INTL(V)
|
||||||
|
|
||||||
class Metadata {
|
class Metadata {
|
||||||
public:
|
public:
|
||||||
|
Metadata() = default;
|
||||||
|
Metadata(Metadata&) = delete;
|
||||||
|
Metadata(Metadata&&) = delete;
|
||||||
|
Metadata operator=(Metadata&) = delete;
|
||||||
|
Metadata operator=(Metadata&&) = delete;
|
||||||
|
|
||||||
struct Versions {
|
struct Versions {
|
||||||
Versions();
|
Versions();
|
||||||
|
|
||||||
|
#ifdef NODE_HAVE_I18N_SUPPORT
|
||||||
|
// Must be called on the main thread after
|
||||||
|
// i18n::InitializeICUDirectory()
|
||||||
|
void InitializeIntlVersions();
|
||||||
|
#endif // NODE_HAVE_I18N_SUPPORT
|
||||||
|
|
||||||
#define V(key) std::string key;
|
#define V(key) std::string key;
|
||||||
NODE_VERSIONS_KEYS(V)
|
NODE_VERSIONS_KEYS(V)
|
||||||
#undef V
|
#undef V
|
||||||
|
Loading…
x
Reference in New Issue
Block a user