@@ -6,13 +6,21 @@ import re
66import shlex
77import subprocess
88import sys
9+ import urllib
10+ import zipfile
11+ import hashlib
12+ import shutil
913
1014CC = os .environ .get ('CC' , 'cc' )
1115
1216root_dir = os .path .dirname (__file__ )
1317sys .path .insert (0 , os .path .join (root_dir , 'tools' , 'gyp' , 'pylib' ))
1418from gyp .common import GetFlavor
1519
20+ # imports in tools/configure.d
21+ sys .path .insert (0 , os .path .join (root_dir , 'tools' , 'configure.d' ))
22+ import nodedownload
23+
1624# parse our options
1725parser = optparse .OptionParser ()
1826
@@ -244,7 +252,7 @@ parser.add_option('--with-icu-path',
244252parser .add_option ('--with-intl' ,
245253 action = 'store' ,
246254 dest = 'with_intl' ,
247- help = 'Intl mode: none, full-icu, small-icu (default is none )' )
255+ help = 'Intl mode: none, full-icu, small-icu (default is small-icu )' )
248256
249257parser .add_option ('--with-perfctr' ,
250258 action = 'store_true' ,
@@ -712,6 +720,58 @@ def glob_to_var(dir_base, dir_sub):
712720 return list
713721
714722def configure_intl (o ):
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+ class ConfigOpener (urllib .FancyURLopener ):
731+ # append to existing version (UA)
732+ version = '%s (node.js/configure)' % urllib .URLopener .version
733+ def icu_download (path ):
734+ # download ICU, if needed
735+ def fmtMb (amt ):
736+ return "{:.1f}" .format (amt / 1024000. )
737+ def reporthook (count , size , total ):
738+ sys .stdout .write (' ICU: %c %sMB total, %sMB downloaded \r ' %
739+ (nodedownload .spin (count ),
740+ nodedownload .formatSize (total ),
741+ nodedownload .formatSize (count * size )))
742+ for icu in icus :
743+ url = icu ['url' ]
744+ md5 = icu ['md5' ]
745+ local = url .split ('/' )[- 1 ]
746+ targetfile = os .path .join (root_dir , 'deps' , local )
747+ if not os .path .isfile (targetfile ):
748+ try :
749+ sys .stdout .write (' <%s>\n Connecting...\r ' % url )
750+ sys .stdout .flush ()
751+ msg = urllib .urlretrieve (url , targetfile , reporthook = reporthook )
752+ print '' # clear the line
753+ except :
754+ print ' ** Error occurred while downloading\n <%s>' % url
755+ raise
756+ else :
757+ print ' Re-using existing %s' % targetfile
758+ if os .path .isfile (targetfile ):
759+ digest = hashlib .md5 ()
760+ count = 0
761+ sys .stdout .write (' Checking file integrity with MD5:\r ' )
762+ with open (targetfile , 'rb' ) as f :
763+ chunk = f .read (1024 )
764+ while chunk != "" :
765+ digest .update (chunk )
766+ chunk = f .read (1024 )
767+ gotmd5 = digest .hexdigest ()
768+ print ' MD5: %s %s' % (gotmd5 , targetfile )
769+ if (md5 == gotmd5 ):
770+ return targetfile
771+ else :
772+ print ' Expected: %s *MISMATCH*' % md5
773+ print '\n ** Corrupted ZIP? Delete %s to retry download.\n ' % targetfile
774+ return None
715775 icu_config = {
716776 'variables' : {}
717777 }
@@ -723,7 +783,6 @@ def configure_intl(o):
723783 write (icu_config_name , do_not_edit +
724784 pprint .pformat (icu_config , indent = 2 ) + '\n ' )
725785
726- # small ICU is off by default.
727786 # always set icu_small, node.gyp depends on it being defined.
728787 o ['variables' ]['icu_small' ] = b (False )
729788
@@ -739,6 +798,8 @@ def configure_intl(o):
739798 o ['variables' ]['icu_gyp_path' ] = options .with_icu_path
740799 return
741800 # --with-intl=<with_intl>
801+ if with_intl is None :
802+ with_intl = 'small-icu' # The default mode of Intl
742803 if with_intl == 'none' or with_intl is None :
743804 o ['variables' ]['v8_enable_i18n_support' ] = 0
744805 return # no Intl
@@ -769,20 +830,47 @@ def configure_intl(o):
769830 # Note: non-ICU implementations could use other 'with_intl'
770831 # values.
771832
833+ icu_parent_path = os .path .join (root_dir , 'deps' )
834+ icu_full_path = os .path .join (icu_parent_path , 'icu' )
835+ icu_small_path = os .path .join (icu_parent_path , 'icu-small' )
836+ icu_small_tag = os .path .join (icu_full_path , 'is-small-icu.txt' )
837+
838+ ## Use (or not) an embedded small-icu.
839+ if with_intl == 'small-icu' :
840+ if not os .path .isdir (icu_full_path ) and os .path .isdir (icu_small_path ):
841+ # deps/small-icu -> deps/icu
842+ print 'Copying small ICU %s to %s' % (icu_small_path , icu_full_path )
843+ shutil .copytree (icu_small_path , icu_full_path )
844+ #else:
845+ # print 'Not copying %s to %s' % (icu_small_path, icu_full_path)
846+ elif os .path .isfile (icu_small_tag ):
847+ print 'deleting small-icu %s for --with-intl=%s' % (icu_full_path , with_intl )
848+ shutil .rmtree (icu_full_path )
849+
772850 # ICU mode. (icu-generic.gyp)
773851 byteorder = sys .byteorder
774852 o ['variables' ]['icu_gyp_path' ] = 'tools/icu/icu-generic.gyp'
775853 # ICU source dir relative to root
776- icu_full_path = os .path .join (root_dir , 'deps/icu' )
777854 o ['variables' ]['icu_path' ] = icu_full_path
778855 if not os .path .isdir (icu_full_path ):
779- print 'Error: ICU path is not a directory: %s' % (icu_full_path )
856+ print '* ECMA-402 (Intl) support didn\' t find ICU in %s..' % (icu_full_path )
857+ # can we download (or find) a zipfile?
858+ localzip = icu_download (icu_full_path )
859+ if localzip :
860+ with zipfile .ZipFile (localzip , 'r' ) as icuzip :
861+ print ' Extracting ICU source zip: %s' % localzip
862+ icuzip .extractall (icu_parent_path )
863+ if not os .path .isdir (icu_full_path ):
864+ print ' Cannot build Intl without ICU in %s.' % (icu_full_path )
865+ print ' (Fix, or disable with "--with-intl=none" )'
780866 sys .exit (1 )
867+ else :
868+ print '* Using ICU in %s' % (icu_full_path )
781869 # Now, what version of ICU is it? We just need the "major", such as 54.
782870 # uvernum.h contains it as a #define.
783871 uvernum_h = os .path .join (icu_full_path , 'source/common/unicode/uvernum.h' )
784872 if not os .path .isfile (uvernum_h ):
785- print 'Error: could not load %s - is ICU installed?' % uvernum_h
873+ print ' Error: could not load %s - is ICU installed?' % uvernum_h
786874 sys .exit (1 )
787875 icu_ver_major = None
788876 matchVerExp = r'^\s*#define\s+U_ICU_VERSION_SHORT\s+"([^"]*)".*'
@@ -792,7 +880,7 @@ def configure_intl(o):
792880 if m :
793881 icu_ver_major = m .group (1 )
794882 if not icu_ver_major :
795- print 'Could not read U_ICU_VERSION_SHORT version from %s' % uvernum_h
883+ print ' Could not read U_ICU_VERSION_SHORT version from %s' % uvernum_h
796884 sys .exit (1 )
797885 icu_endianness = sys .byteorder [0 ]; # TODO(srl295): EBCDIC should be 'e'
798886 o ['variables' ]['icu_ver_major' ] = icu_ver_major
@@ -819,8 +907,8 @@ def configure_intl(o):
819907 # this is the icudt*.dat file which node will be using (platform endianness)
820908 o ['variables' ]['icu_data_file' ] = icu_data_file
821909 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.'
910+ print ' Error: ICU prebuilt data file %s does not exist.' % icu_data_path
911+ print ' See the README.md.'
824912 # .. and we're not about to build it from .gyp!
825913 sys .exit (1 )
826914 # map from variable name to subdirs
0 commit comments