# HG changeset patch
# User Ricky Stewart <rstewart@mozilla.com>
# Date 1592514109 0
# Node ID d6b0857e2fa1e2a43fe491df9a552b480945c1fb
# Parent  1332c58aa8b73f9b06f6263720feb83ee3e010cc
Bug 1645779 - Make icu_sources_data.py Python 3-compliant r=jwalden,anba

This removes a dependency on `pymake`, which is Python 2-only, and thoroughly unnecessary since we just use it to find assignments of the form `OBJECTS = ...`. We can replicate this logic by just isolating lines that begin with that literal string, and everything else can stay the same. This is definitionally more brittle than actually using a parser, but it works fine for now, and the original implementation wasn't significantly better (it didn't handle any form of dynamism, anything more complicated than a single unconditional assignment with a space-separated list of literal strings representing outputs, etc.)

Differential Revision: https://phabricator.services.mozilla.com/D79896

diff --git a/intl/icu_sources_data.py b/intl/icu_sources_data.py
--- a/intl/icu_sources_data.py
+++ b/intl/icu_sources_data.py
@@ -11,30 +11,29 @@
 # copy of ICU has been updated.
 
 from __future__ import absolute_import
 from __future__ import print_function
 
 import glob
 import multiprocessing
 import os
-import sets
 import shutil
 import subprocess
 import sys
 import tempfile
 
 from mozpack import path as mozpath
 
 # The following files have been determined to be dead/unused by a
 # semi-automated analysis. You can just remove any of the files below
 # if you need them. However, files marked with a "Cluster" comment
 # can only be removed together, as they have (directional) dependencies.
 # If you want to rerun this analysis, contact :decoder.
-UNUSED_SOURCES = sets.Set([
+UNUSED_SOURCES = set([
     'intl/icu/source/common/bytestrieiterator.cpp',
     'intl/icu/source/common/cstr.cpp',
     'intl/icu/source/common/cwchar.cpp',
     'intl/icu/source/common/icudataver.cpp',
     'intl/icu/source/common/icuplug.cpp',
     'intl/icu/source/common/pluralmap.cpp',
     'intl/icu/source/common/ucat.cpp',
     'intl/icu/source/common/ucnv2022.cpp',
@@ -132,52 +131,50 @@ def find_source_file(dir, filename):
     for ext in ('.cpp', '.c'):
         f = mozpath.join(dir, base + ext)
         if os.path.isfile(f):
             return f
     raise Exception("Couldn't find source file for: %s" % filename)
 
 
 def get_sources_from_makefile(makefile):
-    import pymake.parser
-    from pymake.parserdata import SetVariable
     srcdir = os.path.dirname(makefile)
-    for statement in pymake.parser.parsefile(makefile):
-        if (isinstance(statement, SetVariable) and
-                statement.vnameexp.is_static_string and
-                statement.vnameexp.s == 'OBJECTS'):
+    with open(makefile) as f:
+        contents = f.read().replace('\\\n', '').split('\n')
+    for line in contents:
+        if line.startswith('OBJECTS ='):
             return sorted((find_source_file(srcdir, s)
-                           for s in statement.value.split()),
+                           for s in line[len('OBJECTS ='):].strip().split()),
                           key=lambda x: x.lower())
+    raise AssertionError('OBJECTS definition not found in file %s' % makefile)
 
 
 def list_headers(path):
     result = []
     for name in os.listdir(path):
         f = mozpath.join(path, name)
         if os.path.isfile(f):
             result.append(f)
     return sorted(result, key=lambda x: x.lower())
 
 
 def write_sources(mozbuild, sources, headers):
-    with open(mozbuild, 'wb') as f:
+    with open(mozbuild, 'w', newline='\n', encoding='utf-8') as f:
         f.write('# THIS FILE IS GENERATED BY /intl/icu_sources_data.py ' +
                 'DO NOT EDIT\n' +
                 'SOURCES += [\n')
         f.write(''.join("   '/%s',\n" % s for s in sources))
         f.write(']\n\n')
         f.write('EXPORTS.unicode += [\n')
         f.write(''.join("   '/%s',\n" % s for s in headers))
         f.write(']\n')
 
 
 def update_sources(topsrcdir):
     print('Updating ICU sources lists...')
-    sys.path.append(mozpath.join(topsrcdir, 'build/pymake'))
     for d in ['common', 'i18n']:
         base_path = mozpath.join(topsrcdir, 'intl/icu/source/%s' % d)
         makefile = mozpath.join(base_path, 'Makefile.in')
         mozbuild = mozpath.join(topsrcdir,
                                 'config/external/icu/%s/sources.mozbuild' % d)
         sources = [mozpath.relpath(s, topsrcdir)
                    for s in get_sources_from_makefile(makefile)]
         sources = filter(lambda x: x not in UNUSED_SOURCES, sources)
@@ -243,18 +240,17 @@ def update_data_file(topsrcdir):
              '--disable-strict'],
             cwd=objdir,
             env=env):
         return False
     print('Running ICU make...')
     if not try_run(
             'icu-make',
             ['make',
-             '--jobs=%d' % multiprocessing.cpu_count(),
-             '--output-sync'],
+             '--jobs=%d' % multiprocessing.cpu_count() ],
             cwd=objdir):
         return False
     print('Copying ICU data file...')
     tree_data_path = mozpath.join(topsrcdir,
                                   'config/external/icu/data/')
     old_data_file = get_data_file(tree_data_path)
     if not old_data_file:
         print('Error: no ICU data file in %s' % tree_data_path,
