fe953d
From 0028cc74dac4dd24b8599ade85cb49fdafa9f559 Mon Sep 17 00:00:00 2001
cecb21
From: Stephen Gallagher <sgallagh@redhat.com>
cecb21
Date: Fri, 6 Dec 2019 16:40:25 -0500
fe953d
Subject: [PATCH] build: auto-load ICU data from --with-icu-default-data-dir
cecb21
cecb21
When compiled with `--with-intl=small` and
cecb21
`--with-icu-default-data-dir=PATH`, Node.js will use PATH as a
cecb21
fallback location for the ICU data.
cecb21
cecb21
We will first perform an access check using fopen(PATH, 'r') to
cecb21
ensure that the file is readable. If it is, we'll set the
cecb21
icu_data_directory and proceed. There's a slight overhead for the
cecb21
fopen() check, but it should be barely measurable.
cecb21
cecb21
This will be useful for Linux distribution packagers who want to
cecb21
be able to ship a minimal node binary in a container image but
cecb21
also be able to add on the full i18n support where needed. With
cecb21
this patch, it becomes possible to ship the interpreter as
cecb21
/usr/bin/node in one package for the distribution and to ship the
cecb21
data files in another package (without a strict dependency
cecb21
between the two). This means that users of the distribution will
cecb21
not need to explicitly direct Node.js to locate the ICU data. It
cecb21
also means that in environments where full internationalization is
cecb21
not required, they do not need to carry the extra content (with
cecb21
the associated storage costs).
cecb21
cecb21
Refs: https://github.com/nodejs/node/issues/3460
cecb21
cecb21
Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>
fe953d
Signed-off-by: rpm-build <rpm-build>
cecb21
---
cecb21
 configure.py |  9 +++++++++
cecb21
 node.gypi    |  7 +++++++
cecb21
 src/node.cc  | 20 ++++++++++++++++++++
cecb21
 3 files changed, 36 insertions(+)
cecb21
cecb21
diff --git a/configure.py b/configure.py
fe953d
index 89f7bf5..d611a88 100755
cecb21
--- a/configure.py
cecb21
+++ b/configure.py
cecb21
@@ -433,6 +433,14 @@ intl_optgroup.add_option('--with-icu-source',
cecb21
         'the icu4c source archive. '
cecb21
         'v%d.x or later recommended.' % icu_versions['minimum_icu'])
fe953d
 
cecb21
+intl_optgroup.add_option('--with-icu-default-data-dir',
cecb21
+    action='store',
cecb21
+    dest='with_icu_default_data_dir',
cecb21
+    help='Path to the icuXXdt{lb}.dat file. If unspecified, ICU data will '
cecb21
+         'only be read if the NODE_ICU_DATA environment variable or the '
cecb21
+         '--icu-data-dir runtime argument is used. This option has effect '
cecb21
+         'only when Node.js is built with --with-intl=small-icu.')
cecb21
+
cecb21
 parser.add_option('--with-ltcg',
cecb21
     action='store_true',
cecb21
     dest='with_ltcg',
fe953d
@@ -1359,6 +1367,7 @@ def configure_intl(o):
cecb21
     locs.add('root')  # must have root
cecb21
     o['variables']['icu_locales'] = string.join(locs,',')
cecb21
     # We will check a bit later if we can use the canned deps/icu-small
cecb21
+    o['variables']['icu_default_data'] = options.with_icu_default_data_dir or ''
cecb21
   elif with_intl == 'full-icu':
cecb21
     # full ICU
cecb21
     o['variables']['v8_enable_i18n_support'] = 1
cecb21
diff --git a/node.gypi b/node.gypi
fe953d
index 466a174..65b97d6 100644
cecb21
--- a/node.gypi
cecb21
+++ b/node.gypi
cecb21
@@ -113,6 +113,13 @@
cecb21
       'conditions': [
cecb21
         [ 'icu_small=="true"', {
cecb21
           'defines': [ 'NODE_HAVE_SMALL_ICU=1' ],
cecb21
+          'conditions': [
cecb21
+            [ 'icu_default_data!=""', {
cecb21
+              'defines': [
cecb21
+                'NODE_ICU_DEFAULT_DATA_DIR="<(icu_default_data)"',
cecb21
+              ],
cecb21
+            }],
cecb21
+          ],
cecb21
       }]],
cecb21
     }],
cecb21
     [ 'node_use_bundled_v8=="true" and \
cecb21
diff --git a/src/node.cc b/src/node.cc
fe953d
index 7c01187..c9840e3 100644
cecb21
--- a/src/node.cc
cecb21
+++ b/src/node.cc
cecb21
@@ -92,6 +92,7 @@
fe953d
 
cecb21
 #if defined(NODE_HAVE_I18N_SUPPORT)
cecb21
 #include <unicode/uvernum.h>
cecb21
+#include <unicode/utypes.h>
cecb21
 #endif
fe953d
 
cecb21
 #if defined(LEAK_SANITIZER)
cecb21
@@ -2643,6 +2644,25 @@ void Init(std::vector<std::string>* argv,
cecb21
   // If the parameter isn't given, use the env variable.
cecb21
   if (per_process_opts->icu_data_dir.empty())
cecb21
     SafeGetenv("NODE_ICU_DATA", &per_process_opts->icu_data_dir);
cecb21
+
cecb21
+#ifdef NODE_ICU_DEFAULT_DATA_DIR
cecb21
+  // If neither the CLI option nor the environment variable was specified,
cecb21
+  // fall back to the configured default
cecb21
+  if (per_process_opts->icu_data_dir.empty()) {
cecb21
+    // Check whether the NODE_ICU_DEFAULT_DATA_DIR contains the right data
cecb21
+    // file and can be read.
cecb21
+    static const char full_path[] =
cecb21
+        NODE_ICU_DEFAULT_DATA_DIR "/" U_ICUDATA_NAME ".dat";
cecb21
+
cecb21
+    FILE* f = fopen(full_path, "rb");
cecb21
+
cecb21
+    if (f != nullptr) {
cecb21
+      fclose(f);
cecb21
+      per_process_opts->icu_data_dir = NODE_ICU_DEFAULT_DATA_DIR;
cecb21
+    }
cecb21
+  }
cecb21
+#endif  // NODE_ICU_DEFAULT_DATA_DIR
cecb21
+
cecb21
   // Initialize ICU.
cecb21
   // If icu_data_dir is empty here, it will load the 'minimal' data.
cecb21
   if (!i18n::InitializeICUDirectory(per_process_opts->icu_data_dir)) {
fe953d
-- 
fe953d
2.26.2
cecb21