@@ -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
@@ -712,6 +720,56 @@ 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  reporthook (count , size , total ):
736+       sys .stdout .write (' ICU: %c %sMB total, %sMB downloaded   \r '  % 
737+                        (nodedownload .spin (count ),
738+                         nodedownload .formatSize (total ),
739+                         nodedownload .formatSize (count * size )))
740+     for  icu  in  icus :
741+       url  =  icu ['url' ]
742+       md5  =  icu ['md5' ]
743+       local  =  url .split ('/' )[- 1 ]
744+       targetfile  =  os .path .join (root_dir , 'deps' , local )
745+       if  not  os .path .isfile (targetfile ):
746+         try :
747+           sys .stdout .write (' <%s>\n Connecting...\r '  %  url )
748+           sys .stdout .flush ()
749+           msg  =  urllib .urlretrieve (url , targetfile , reporthook = reporthook )
750+           print  ''   # clear the line 
751+         except :
752+           print  ' ** Error occurred while downloading\n  <%s>'  %  url 
753+           raise 
754+       else :
755+         print  ' Re-using existing %s'  %  targetfile 
756+       if  os .path .isfile (targetfile ):
757+         digest  =  hashlib .md5 ()
758+         count  =  0 
759+         sys .stdout .write (' Checking file integrity with MD5:\r ' )
760+         with  open (targetfile , 'rb' ) as  f :
761+           chunk  =  f .read (1024 )
762+           while  chunk  !=   "" :
763+             digest .update (chunk )
764+             chunk  =  f .read (1024 )
765+         gotmd5  =  digest .hexdigest ()
766+         print  ' MD5:      %s  %s'  %  (gotmd5 , targetfile )
767+         if  (md5  ==  gotmd5 ):
768+           return  targetfile 
769+         else :
770+           print  ' Expected: %s      *MISMATCH*'  %  md5 
771+           print  '\n  ** Corrupted ZIP? Delete %s to retry download.\n '  %  targetfile 
772+     return  None 
715773  icu_config  =  {
716774    'variables' : {}
717775  }
@@ -723,7 +781,6 @@ def configure_intl(o):
723781  write (icu_config_name , do_not_edit  + 
724782        pprint .pformat (icu_config , indent = 2 ) +  '\n ' )
725783
726-   # small ICU is off by default. 
727784  # always set icu_small, node.gyp depends on it being defined. 
728785  o ['variables' ]['icu_small' ] =  b (False )
729786
@@ -739,6 +796,8 @@ def configure_intl(o):
739796    o ['variables' ]['icu_gyp_path' ] =  options .with_icu_path 
740797    return 
741798  # --with-intl=<with_intl> 
799+   if  with_intl  is  None :
800+     with_intl  =  'none'   # The default mode of Intl 
742801  if  with_intl  ==  'none'  or  with_intl  is  None :
743802    o ['variables' ]['v8_enable_i18n_support' ] =  0 
744803    return   # no Intl 
@@ -769,20 +828,47 @@ def configure_intl(o):
769828  # Note: non-ICU implementations could use other 'with_intl' 
770829  # values. 
771830
831+   icu_parent_path  =  os .path .join (root_dir , 'deps' )
832+   icu_full_path  =  os .path .join (icu_parent_path , 'icu' )
833+   icu_small_path  =  os .path .join (icu_parent_path , 'icu-small' )
834+   icu_small_tag  =  os .path .join (icu_full_path , 'is-small-icu.txt' )
835+ 
836+   ## Use (or not) an embedded small-icu. 
837+   if  with_intl  ==  'small-icu' :
838+     if  not  os .path .isdir (icu_full_path ) and  os .path .isdir (icu_small_path ):
839+       # deps/small-icu -> deps/icu 
840+       print  'Copying small ICU %s to %s'  %  (icu_small_path , icu_full_path )
841+       shutil .copytree (icu_small_path , icu_full_path )
842+     #else: 
843+     #  print 'Not copying %s to %s' % (icu_small_path, icu_full_path) 
844+   elif  os .path .isfile (icu_small_tag ):
845+     print  'deleting small-icu %s for --with-intl=%s'  %  (icu_full_path , with_intl )
846+     shutil .rmtree (icu_full_path )
847+ 
772848  # ICU mode. (icu-generic.gyp) 
773849  byteorder  =  sys .byteorder 
774850  o ['variables' ]['icu_gyp_path' ] =  'tools/icu/icu-generic.gyp' 
775851  # ICU source dir relative to root 
776-   icu_full_path  =  os .path .join (root_dir , 'deps/icu' )
777852  o ['variables' ]['icu_path' ] =  icu_full_path 
778853  if  not  os .path .isdir (icu_full_path ):
779-     print  'Error: ICU path is not a directory: %s'  %  (icu_full_path )
854+     print  '* ECMA-402 (Intl) support didn\' t find ICU in %s..'  %  (icu_full_path )
855+     # can we download (or find) a zipfile? 
856+     localzip  =  icu_download (icu_full_path )
857+     if  localzip :
858+       with  zipfile .ZipFile (localzip , 'r' ) as  icuzip :
859+         print  ' Extracting ICU source zip: %s'  %  localzip 
860+         icuzip .extractall (icu_parent_path )
861+   if  not  os .path .isdir (icu_full_path ):
862+     print  ' Cannot build Intl without ICU in %s.'  %  (icu_full_path )
863+     print  ' (Fix, or disable with "--with-intl=none" )' 
780864    sys .exit (1 )
865+   else :
866+     print  '* Using ICU in %s'  %  (icu_full_path )
781867  # Now, what version of ICU is it? We just need the "major", such as 54. 
782868  # uvernum.h contains it as a #define. 
783869  uvernum_h  =  os .path .join (icu_full_path , 'source/common/unicode/uvernum.h' )
784870  if  not  os .path .isfile (uvernum_h ):
785-     print  'Error: could not load %s - is ICU installed?'  %  uvernum_h 
871+     print  '  Error: could not load %s - is ICU installed?'  %  uvernum_h 
786872    sys .exit (1 )
787873  icu_ver_major  =  None 
788874  matchVerExp  =  r'^\s*#define\s+U_ICU_VERSION_SHORT\s+"([^"]*)".*' 
@@ -792,7 +878,7 @@ def configure_intl(o):
792878    if  m :
793879      icu_ver_major  =  m .group (1 )
794880  if  not  icu_ver_major :
795-     print  'Could not read U_ICU_VERSION_SHORT version from %s'  %  uvernum_h 
881+     print  '  Could not read U_ICU_VERSION_SHORT version from %s'  %  uvernum_h 
796882    sys .exit (1 )
797883  icu_endianness  =  sys .byteorder [0 ];  # TODO(srl295): EBCDIC should be 'e' 
798884  o ['variables' ]['icu_ver_major' ] =  icu_ver_major 
@@ -819,8 +905,8 @@ def configure_intl(o):
819905  # this is the icudt*.dat file which node will be using (platform endianness) 
820906  o ['variables' ]['icu_data_file' ] =  icu_data_file 
821907  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.' 
908+     print  '  Error: ICU prebuilt data file %s does not exist.'  %  icu_data_path 
909+     print  '  See the README.md.' 
824910    # .. and we're not about to build it from .gyp! 
825911    sys .exit (1 )
826912  # map from variable name to subdirs 
0 commit comments