Skip to content
This repository was archived by the owner on Apr 22, 2023. It is now read-only.

Commit 8a33708

Browse files
committed
build: i18n: Autodownload ICU, Intl small-icu by default!
* make `--with-intl=small-icu` the default * Download, verify (md5), unpack ICU's zip if not there * update docs This is to support joyent#7676, Intl by default. There's a "list" of URLs being used, but right now only the first is picked up. The logic works something like this: * if there is no directory `deps/icu`, * if no zip file (currently `icu4c-54_1-src.zip`), * download zip file (icu-project.org -> sf.net) * verify the MD5 sum of the zipfile * if bad, print error and exit * unpack the zipfile into `deps/icu` * if `deps/icu` now exists, use it, else fail with help text
1 parent ea4dc7d commit 8a33708

File tree

3 files changed

+103
-10
lines changed

3 files changed

+103
-10
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ ipch/
4646
email.md
4747
deps/v8-*
4848
deps/icu
49+
deps/icu*.zip
50+
deps/icu*.tgz
4951
./node_modules
5052
.svn/
5153

README.md

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,41 @@ make doc
8383
man doc/node.1
8484
```
8585

86-
### To build `Intl` (ECMA-402) support:
86+
### `Intl` (ECMA-402) support:
8787

88-
*Note:* more docs, including how to reduce disk footprint, are on
88+
The `small-icu` mode is enabled by default. It will build
89+
with English-only data. You can add full data at runtime.
90+
91+
*Note:* more docs are on
8992
[the wiki](https://github.com/joyent/node/wiki/Intl).
9093

94+
#### Build with full ICU support (all locales supported by ICU):
95+
96+
Unix/Macintosh:
97+
98+
```sh
99+
./configure --with-intl=full-icu
100+
```
101+
102+
Windows:
103+
104+
```sh
105+
vcbuild full-icu
106+
```
107+
108+
#### Build with no Intl support `:-(`
109+
110+
```sh
111+
./configure --with-intl=none
112+
```
113+
91114
#### Use existing installed ICU (Unix/Macintosh only):
92115

93116
```sh
94117
pkg-config --modversion icu-i18n && ./configure --with-intl=system-icu
95118
```
96119

97-
#### Build ICU from source:
120+
#### Build with a specific ICU:
98121

99122
First: Unpack latest ICU
100123
[icu4c-**##.#**-src.tgz](http://icu-project.org/download) (or `.zip`)

configure

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import re
66
import shlex
77
import subprocess
88
import sys
9+
import urllib
10+
import zipfile
11+
import hashlib
912

1013
CC = os.environ.get('CC', 'cc')
1114

@@ -244,7 +247,7 @@ parser.add_option('--with-icu-path',
244247
parser.add_option('--with-intl',
245248
action='store',
246249
dest='with_intl',
247-
help='Intl mode: none, full-icu, small-icu (default is none)')
250+
help='Intl mode: none, full-icu, small-icu (default is small-icu)')
248251

249252
parser.add_option('--with-perfctr',
250253
action='store_true',
@@ -712,6 +715,57 @@ def glob_to_var(dir_base, dir_sub):
712715
return list
713716

714717
def configure_intl(o):
718+
class ConfigOpener(urllib.FancyURLopener):
719+
# append to existing version (UA)
720+
version = '%s (node.js/configure)' % urllib.URLopener.version
721+
def icu_download(path):
722+
# download ICU, if needed
723+
icus = [
724+
{
725+
'url': 'http://download.icu-project.org/files/icu4c/54.1/icu4c-54_1-src.zip',
726+
# from https://ssl.icu-project.org/files/icu4c/54.1/icu4c-src-54_1.md5:
727+
'md5': '6b89d60e2f0e140898ae4d7f72323bca',
728+
},
729+
]
730+
def fmtMb(amt):
731+
return "{:.1f}".format(amt / 1024000.)
732+
spin = "\\|/-"
733+
def reporthook(count, size, total):
734+
sys.stdout.write(' ICU: %c %sMB total, %sMB downloaded \r' %
735+
(spin[count%4], fmtMb(total), fmtMb(count*size)))
736+
for icu in icus:
737+
url = icu['url']
738+
md5 = icu['md5']
739+
local = url.split('/')[-1]
740+
targetfile = os.path.join(root_dir, 'deps', local)
741+
if not os.path.isfile(targetfile):
742+
try:
743+
sys.stdout.write(' <%s>\nConnecting...\r' % url)
744+
sys.stdout.flush()
745+
msg = urllib.urlretrieve(url, targetfile, reporthook=reporthook)
746+
print '' # clear the line
747+
except:
748+
print ' ** Error occurred while downloading\n <%s>' % url
749+
raise
750+
else:
751+
print ' Re-using existing %s' % targetfile
752+
if os.path.isfile(targetfile):
753+
digest = hashlib.md5()
754+
count = 0
755+
sys.stdout.write(' Checking file integrity with MD5:\r')
756+
with open(targetfile, 'rb') as f:
757+
chunk = f.read(1024)
758+
while chunk != "":
759+
digest.update(chunk)
760+
chunk = f.read(1024)
761+
gotmd5 = digest.hexdigest()
762+
print ' MD5: %s %s' % (gotmd5, targetfile)
763+
if (md5 == gotmd5):
764+
return targetfile
765+
else:
766+
print ' Expected: %s *MISMATCH*' % md5
767+
print '\n ** Corrupted ZIP? Delete %s to retry download.\n' % targetfile
768+
return None
715769
icu_config = {
716770
'variables': {}
717771
}
@@ -739,6 +793,8 @@ def configure_intl(o):
739793
o['variables']['icu_gyp_path'] = options.with_icu_path
740794
return
741795
# --with-intl=<with_intl>
796+
if with_intl is None:
797+
with_intl = 'small-icu' # The default mode
742798
if with_intl == 'none' or with_intl is None:
743799
o['variables']['v8_enable_i18n_support'] = 0
744800
return # no Intl
@@ -773,16 +829,28 @@ def configure_intl(o):
773829
byteorder = sys.byteorder
774830
o['variables']['icu_gyp_path'] = 'tools/icu/icu-generic.gyp'
775831
# ICU source dir relative to root
776-
icu_full_path = os.path.join(root_dir, 'deps/icu')
832+
icu_parent_path = os.path.join(root_dir, 'deps')
833+
icu_full_path = os.path.join(icu_parent_path, 'icu')
777834
o['variables']['icu_path'] = icu_full_path
778835
if not os.path.isdir(icu_full_path):
779-
print 'Error: ICU path is not a directory: %s' % (icu_full_path)
836+
print '* ECMA-402 (Intl) support didn\'t find ICU in %s..' % (icu_full_path)
837+
# can we download (or find) a zipfile?
838+
localzip = icu_download(icu_full_path)
839+
if localzip:
840+
with zipfile.ZipFile(localzip, 'r') as icuzip:
841+
print ' Extracting ICU source zip: %s' % localzip
842+
icuzip.extractall(icu_parent_path)
843+
if not os.path.isdir(icu_full_path):
844+
print ' Cannot build Intl without ICU in %s.' % (icu_full_path)
845+
print ' (Fix, or disable with "--with-intl=none" )'
780846
sys.exit(1)
847+
else:
848+
print '* Using ICU in %s' % (icu_full_path)
781849
# Now, what version of ICU is it? We just need the "major", such as 54.
782850
# uvernum.h contains it as a #define.
783851
uvernum_h = os.path.join(icu_full_path, 'source/common/unicode/uvernum.h')
784852
if not os.path.isfile(uvernum_h):
785-
print 'Error: could not load %s - is ICU installed?' % uvernum_h
853+
print ' Error: could not load %s - is ICU installed?' % uvernum_h
786854
sys.exit(1)
787855
icu_ver_major = None
788856
matchVerExp = r'^\s*#define\s+U_ICU_VERSION_SHORT\s+"([^"]*)".*'
@@ -792,7 +860,7 @@ def configure_intl(o):
792860
if m:
793861
icu_ver_major = m.group(1)
794862
if not icu_ver_major:
795-
print 'Could not read U_ICU_VERSION_SHORT version from %s' % uvernum_h
863+
print ' Could not read U_ICU_VERSION_SHORT version from %s' % uvernum_h
796864
sys.exit(1)
797865
icu_endianness = sys.byteorder[0]; # TODO(srl295): EBCDIC should be 'e'
798866
o['variables']['icu_ver_major'] = icu_ver_major
@@ -819,8 +887,8 @@ def configure_intl(o):
819887
# this is the icudt*.dat file which node will be using (platform endianness)
820888
o['variables']['icu_data_file'] = icu_data_file
821889
if not os.path.isfile(icu_data_path):
822-
print 'Error: ICU prebuilt data file %s does not exist.' % icu_data_path
823-
print 'See the README.md.'
890+
print ' Error: ICU prebuilt data file %s does not exist.' % icu_data_path
891+
print ' See the README.md.'
824892
# .. and we're not about to build it from .gyp!
825893
sys.exit(1)
826894
# map from variable name to subdirs

0 commit comments

Comments
 (0)