@@ -6,13 +6,19 @@ import re
66import shlex
77import subprocess
88import sys
9+ import shutil
10+ import string
911
1012CC = os .environ .get ('CC' , 'cc' )
1113
1214root_dir = os .path .dirname (__file__ )
1315sys .path .insert (0 , os .path .join (root_dir , 'tools' , 'gyp' , 'pylib' ))
1416from gyp .common import GetFlavor
1517
18+ # imports in tools/configure.d
19+ sys .path .insert (0 , os .path .join (root_dir , 'tools' , 'configure.d' ))
20+ import nodedownload
21+
1622# parse our options
1723parser = optparse .OptionParser ()
1824
@@ -216,16 +222,31 @@ parser.add_option('--with-etw',
216222 dest = 'with_etw' ,
217223 help = 'build with ETW (default is true on Windows)' )
218224
225+ parser .add_option ('--download' ,
226+ action = 'store' ,
227+ dest = 'download_list' ,
228+ help = nodedownload .help ())
229+
219230parser .add_option ('--with-icu-path' ,
220231 action = 'store' ,
221232 dest = 'with_icu_path' ,
222233 help = 'Path to icu.gyp (ICU i18n, Chromium version only.)' )
223234
235+ parser .add_option ('--with-icu-locales' ,
236+ action = 'store' ,
237+ dest = 'with_icu_locales' ,
238+ help = 'Comma-separated list of locales for "small-icu". Default: "root,en". "root" is assumed.' )
239+
224240parser .add_option ('--with-intl' ,
225241 action = 'store' ,
226242 dest = 'with_intl' ,
227243 help = 'Intl mode: none, full-icu, small-icu (default is none)' )
228244
245+ parser .add_option ('--with-icu-source' ,
246+ action = 'store' ,
247+ dest = 'with_icu_source' ,
248+ help = 'Intl mode: optional local path to icu/ dir, or path/URL of icu source archive.' )
249+
229250parser .add_option ('--with-perfctr' ,
230251 action = 'store_true' ,
231252 dest = 'with_perfctr' ,
@@ -274,6 +295,8 @@ parser.add_option('--xcode',
274295
275296(options , args ) = parser .parse_args ()
276297
298+ # set up auto-download list
299+ auto_downloads = nodedownload .parse (options .download_list )
277300
278301def b (value ):
279302 """Returns the string 'true' if value is truthy, 'false' otherwise."""
@@ -632,6 +655,35 @@ def glob_to_var(dir_base, dir_sub):
632655 return list
633656
634657def configure_intl (o ):
658+ icus = [
659+ {
660+ 'url' : 'http://download.icu-project.org/files/icu4c/54.1/icu4c-54_1-src.zip' ,
661+ # from https://ssl.icu-project.org/files/icu4c/54.1/icu4c-src-54_1.md5:
662+ 'md5' : '6b89d60e2f0e140898ae4d7f72323bca' ,
663+ },
664+ ]
665+ def icu_download (path ):
666+ # download ICU, if needed
667+ for icu in icus :
668+ url = icu ['url' ]
669+ md5 = icu ['md5' ]
670+ local = url .split ('/' )[- 1 ]
671+ targetfile = os .path .join (root_dir , 'deps' , local )
672+ if not os .path .isfile (targetfile ):
673+ if nodedownload .candownload (auto_downloads , "icu" ):
674+ nodedownload .retrievefile (url , targetfile )
675+ else :
676+ print ' Re-using existing %s' % targetfile
677+ if os .path .isfile (targetfile ):
678+ sys .stdout .write (' Checking file integrity with MD5:\r ' )
679+ gotmd5 = nodedownload .md5sum (targetfile )
680+ print ' MD5: %s %s' % (gotmd5 , targetfile )
681+ if (md5 == gotmd5 ):
682+ return targetfile
683+ else :
684+ print ' Expected: %s *MISMATCH*' % md5
685+ print '\n ** Corrupted ZIP? Delete %s to retry download.\n ' % targetfile
686+ return None
635687 icu_config = {
636688 'variables' : {}
637689 }
@@ -643,11 +695,11 @@ def configure_intl(o):
643695 write (icu_config_name , do_not_edit +
644696 pprint .pformat (icu_config , indent = 2 ) + '\n ' )
645697
646- # small ICU is off by default.
647698 # always set icu_small, node.gyp depends on it being defined.
648699 o ['variables' ]['icu_small' ] = b (False )
649700
650701 with_intl = options .with_intl
702+ with_icu_source = options .with_icu_source
651703 have_icu_path = bool (options .with_icu_path )
652704 if have_icu_path and with_intl :
653705 print 'Error: Cannot specify both --with-icu-path and --with-intl'
@@ -659,13 +711,26 @@ def configure_intl(o):
659711 o ['variables' ]['icu_gyp_path' ] = options .with_icu_path
660712 return
661713 # --with-intl=<with_intl>
714+ # set the default
715+ if with_intl is None :
716+ with_intl = 'none' # The default mode of Intl
717+ # sanity check localelist
718+ if options .with_icu_locales and (with_intl != 'small-icu' ):
719+ print 'Error: --with-icu-locales only makes sense with --with-intl=small-icu'
720+ sys .exit (1 )
662721 if with_intl == 'none' or with_intl is None :
663722 o ['variables' ]['v8_enable_i18n_support' ] = 0
664723 return # no Intl
665724 elif with_intl == 'small-icu' :
666725 # small ICU (English only)
667726 o ['variables' ]['v8_enable_i18n_support' ] = 1
668727 o ['variables' ]['icu_small' ] = b (True )
728+ with_icu_locales = options .with_icu_locales
729+ if not with_icu_locales :
730+ with_icu_locales = 'root,en'
731+ locs = set (with_icu_locales .split (',' ))
732+ locs .add ('root' ) # must have root
733+ o ['variables' ]['icu_locales' ] = string .join (locs ,',' )
669734 elif with_intl == 'full-icu' :
670735 # full ICU
671736 o ['variables' ]['v8_enable_i18n_support' ] = 1
@@ -689,20 +754,78 @@ def configure_intl(o):
689754 # Note: non-ICU implementations could use other 'with_intl'
690755 # values.
691756
757+ # this is just the 'deps' dir. Used for unpacking.
758+ icu_parent_path = os .path .join (root_dir , 'deps' )
759+
760+ # The full path to the ICU source directory.
761+ icu_full_path = os .path .join (icu_parent_path , 'icu' )
762+
763+ # icu-tmp is used to download and unpack the ICU tarball.
764+ icu_tmp_path = os .path .join (icu_parent_path , 'icu-tmp' )
765+
766+ # --with-icu-source processing
767+ # first, check that they didn't pass --with-icu-source=deps/icu
768+ if with_icu_source and os .path .abspath (icu_full_path ) == os .path .abspath (with_icu_source ):
769+ print 'Ignoring redundant --with-icu-source=%s' % (with_icu_source )
770+ with_icu_source = None
771+ # if with_icu_source is still set, try to use it.
772+ if with_icu_source :
773+ if os .path .isdir (icu_full_path ):
774+ print 'Deleting old ICU source: %s' % (icu_full_path )
775+ shutil .rmtree (icu_full_path )
776+ # now, what path was given?
777+ if os .path .isdir (with_icu_source ):
778+ # it's a path. Copy it.
779+ print '%s -> %s' % (with_icu_source , icu_full_path )
780+ shutil .copytree (with_icu_source , icu_full_path )
781+ else :
782+ # could be file or URL.
783+ # Set up temporary area
784+ if os .path .isdir (icu_tmp_path ):
785+ shutil .rmtree (icu_tmp_path )
786+ os .mkdir (icu_tmp_path )
787+ icu_tarball = None
788+ if os .path .isfile (with_icu_source ):
789+ # it's a file. Try to unpack it.
790+ icu_tarball = with_icu_source
791+ else :
792+ # Can we download it?
793+ local = os .path .join (icu_tmp_path , with_icu_source .split ('/' )[- 1 ]) # local part
794+ icu_tarball = nodedownload .retrievefile (with_icu_source , local )
795+ # continue with "icu_tarball"
796+ nodedownload .unpack (icu_tarball , icu_tmp_path )
797+ # Did it unpack correctly? Should contain 'icu'
798+ tmp_icu = os .path .join (icu_tmp_path , 'icu' )
799+ if os .path .isdir (tmp_icu ):
800+ os .rename (tmp_icu , icu_full_path )
801+ shutil .rmtree (icu_tmp_path )
802+ else :
803+ print ' Error: --with-icu-source=%s did not result in an "icu" dir.' % with_icu_source
804+ shutil .rmtree (icu_tmp_path )
805+ sys .exit (1 )
806+
692807 # ICU mode. (icu-generic.gyp)
693808 byteorder = sys .byteorder
694809 o ['variables' ]['icu_gyp_path' ] = 'tools/icu/icu-generic.gyp'
695810 # ICU source dir relative to root
696- icu_full_path = os .path .join (root_dir , 'deps/icu' )
697811 o ['variables' ]['icu_path' ] = icu_full_path
698812 if not os .path .isdir (icu_full_path ):
699- print 'Error: ICU path is not a directory: %s' % (icu_full_path )
813+ print '* ECMA-402 (Intl) support didn\' t find ICU in %s..' % (icu_full_path )
814+ # can we download (or find) a zipfile?
815+ localzip = icu_download (icu_full_path )
816+ if localzip :
817+ nodedownload .unpack (localzip , icu_parent_path )
818+ if not os .path .isdir (icu_full_path ):
819+ print ' Cannot build Intl without ICU in %s.' % (icu_full_path )
820+ print ' (Fix, or disable with "--with-intl=none" )'
700821 sys .exit (1 )
822+ else :
823+ print '* Using ICU in %s' % (icu_full_path )
701824 # Now, what version of ICU is it? We just need the "major", such as 54.
702825 # uvernum.h contains it as a #define.
703826 uvernum_h = os .path .join (icu_full_path , 'source/common/unicode/uvernum.h' )
704827 if not os .path .isfile (uvernum_h ):
705- print 'Error: could not load %s - is ICU installed?' % uvernum_h
828+ print ' Error: could not load %s - is ICU installed?' % uvernum_h
706829 sys .exit (1 )
707830 icu_ver_major = None
708831 matchVerExp = r'^\s*#define\s+U_ICU_VERSION_SHORT\s+"([^"]*)".*'
@@ -712,7 +835,7 @@ def configure_intl(o):
712835 if m :
713836 icu_ver_major = m .group (1 )
714837 if not icu_ver_major :
715- print 'Could not read U_ICU_VERSION_SHORT version from %s' % uvernum_h
838+ print ' Could not read U_ICU_VERSION_SHORT version from %s' % uvernum_h
716839 sys .exit (1 )
717840 icu_endianness = sys .byteorder [0 ]; # TODO(srl295): EBCDIC should be 'e'
718841 o ['variables' ]['icu_ver_major' ] = icu_ver_major
@@ -739,8 +862,8 @@ def configure_intl(o):
739862 # this is the icudt*.dat file which node will be using (platform endianness)
740863 o ['variables' ]['icu_data_file' ] = icu_data_file
741864 if not os .path .isfile (icu_data_path ):
742- print 'Error: ICU prebuilt data file %s does not exist.' % icu_data_path
743- print 'See the README.md.'
865+ print ' Error: ICU prebuilt data file %s does not exist.' % icu_data_path
866+ print ' See the README.md.'
744867 # .. and we're not about to build it from .gyp!
745868 sys .exit (1 )
746869 # map from variable name to subdirs
0 commit comments