Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / tools / swarming_client / isolate_format.py
index 7591880..6b139dc 100644 (file)
@@ -20,7 +20,6 @@ import posixpath
 import re
 import sys
 
-from utils import short_expression_finder
 
 # Files that should be 0-length when mapped.
 KEY_TOUCHED = 'isolate_dependency_touched'
@@ -68,7 +67,7 @@ def replace_variable(part, variables):
       raise IsolateError(
         'Variable "%s" was not found in %s.\nDid you forget to specify '
         '--path-variable?' % (m.group(1), variables))
-    return variables[m.group(1)]
+    return str(variables[m.group(1)])
   return part
 
 
@@ -82,18 +81,6 @@ def eval_variables(item, variables):
       for p in re.split(r'(<\(' + VALID_VARIABLE + '\))', item))
 
 
-def split_touched(files):
-  """Splits files that are touched vs files that are read."""
-  tracked = []
-  touched = []
-  for f in files:
-    if f.size:
-      tracked.append(f)
-    else:
-      touched.append(f)
-  return tracked, touched
-
-
 def pretty_print(variables, stdout):
   """Outputs a .isolate file from the decoded variables.
 
@@ -103,7 +90,7 @@ def pretty_print(variables, stdout):
   """
   # Order the dictionary keys by these keys in priority.
   ORDER = (
-      'variables', 'condition', 'command', 'read_only',
+      'variables', 'condition', 'command', 'files', 'read_only',
       KEY_TRACKED, KEY_UNTRACKED)
 
   def sorting_key(x):
@@ -255,6 +242,7 @@ def verify_variables(variables):
     KEY_TRACKED,
     KEY_UNTRACKED,
     'command',
+    'files',
     'read_only',
   ]
   assert isinstance(variables, dict), variables
@@ -331,34 +319,6 @@ def verify_root(value, variables_and_values):
   verify_variables(variables)
 
 
-def remove_weak_dependencies(values, key, item, item_configs):
-  """Removes any configs from this key if the item is already under a
-  strong key.
-  """
-  if key == KEY_TOUCHED:
-    item_configs = set(item_configs)
-    for stronger_key in (KEY_TRACKED, KEY_UNTRACKED):
-      try:
-        item_configs -= values[stronger_key][item]
-      except KeyError:
-        pass
-
-  return item_configs
-
-
-def remove_repeated_dependencies(folders, key, item, item_configs):
-  """Removes any configs from this key if the item is in a folder that is
-  already included."""
-
-  if key in (KEY_UNTRACKED, KEY_TRACKED, KEY_TOUCHED):
-    item_configs = set(item_configs)
-    for (folder, configs) in folders.iteritems():
-      if folder != item and item.startswith(folder):
-        item_configs -= configs
-
-  return item_configs
-
-
 def get_folders(values_dict):
   """Returns a dict of all the folders in the given value_dict."""
   return dict(
@@ -367,136 +327,15 @@ def get_folders(values_dict):
   )
 
 
-def invert_map(variables):
-  """Converts {config: {deptype: list(depvals)}} to
-  {deptype: {depval: set(configs)}}.
-  """
-  KEYS = (
-    KEY_TOUCHED,
-    KEY_TRACKED,
-    KEY_UNTRACKED,
-    'command',
-    'read_only',
-  )
-  out = dict((key, {}) for key in KEYS)
-  for config, values in variables.iteritems():
-    for key in KEYS:
-      if key == 'command':
-        items = [tuple(values[key])] if key in values else []
-      elif key == 'read_only':
-        items = [values[key]] if key in values else []
-      else:
-        assert key in (KEY_TOUCHED, KEY_TRACKED, KEY_UNTRACKED)
-        items = values.get(key, [])
-      for item in items:
-        out[key].setdefault(item, set()).add(config)
-  return out
-
-
-def reduce_inputs(values):
-  """Reduces the output of invert_map() to the strictest minimum list.
-
-  Looks at each individual file and directory, maps where they are used and
-  reconstructs the inverse dictionary.
-
-  Returns the minimized dictionary.
-  """
-  KEYS = (
-    KEY_TOUCHED,
-    KEY_TRACKED,
-    KEY_UNTRACKED,
-    'command',
-    'read_only',
-  )
-
-  # Folders can only live in KEY_UNTRACKED.
-  folders = get_folders(values.get(KEY_UNTRACKED, {}))
-
-  out = dict((key, {}) for key in KEYS)
-  for key in KEYS:
-    for item, item_configs in values.get(key, {}).iteritems():
-      item_configs = remove_weak_dependencies(values, key, item, item_configs)
-      item_configs = remove_repeated_dependencies(
-          folders, key, item, item_configs)
-      if item_configs:
-        out[key][item] = item_configs
-  return out
-
-
-def convert_map_to_isolate_dict(values, config_variables):
-  """Regenerates back a .isolate configuration dict from files and dirs
-  mappings generated from reduce_inputs().
-  """
-  # Gather a list of configurations for set inversion later.
-  all_mentioned_configs = set()
-  for configs_by_item in values.itervalues():
-    for configs in configs_by_item.itervalues():
-      all_mentioned_configs.update(configs)
-
-  # Invert the mapping to make it dict first.
-  conditions = {}
-  for key in values:
-    for item, configs in values[key].iteritems():
-      then = conditions.setdefault(frozenset(configs), {})
-      variables = then.setdefault('variables', {})
-
-      if key == 'read_only':
-        if not isinstance(item, int):
-          raise IsolateError(
-              'Unexpected entry type %r for key %s' % (item, key))
-        variables[key] = item
-      elif key == 'command':
-        if not isinstance(item, tuple):
-          raise IsolateError(
-              'Unexpected entry type %r for key %s' % (item, key))
-        if key in variables:
-          raise IsolateError('Unexpected duplicate key %s' % key)
-        if not item:
-          raise IsolateError('Expected non empty entry in %s' % key)
-        variables[key] = list(item)
-      elif key in (KEY_TOUCHED, KEY_TRACKED, KEY_UNTRACKED):
-        if not isinstance(item, basestring):
-          raise IsolateError('Unexpected entry type %r' % item)
-        if not item:
-          raise IsolateError('Expected non empty entry in %s' % key)
-        # The list of items (files or dirs). Append the new item and keep
-        # the list sorted.
-        l = variables.setdefault(key, [])
-        l.append(item)
-        l.sort()
-      else:
-        raise IsolateError('Unexpected key %s' % key)
-
-  if all_mentioned_configs:
-    # Change [(1, 2), (3, 4)] to [set(1, 3), set(2, 4)]
-    config_values = map(set, zip(*all_mentioned_configs))
-    for i in config_values:
-      i.discard(None)
-    sef = short_expression_finder.ShortExpressionFinder(
-        zip(config_variables, config_values))
-    conditions = sorted([sef.get_expr(c), v] for c, v in conditions.iteritems())
-  else:
-    conditions = []
-  out = {'conditions': conditions}
-  for c in conditions:
-    if c[0] == '':
-      # Extract the global.
-      out.update(c[1])
-      conditions.remove(c)
-      break
-  return out
-
-
 class ConfigSettings(object):
   """Represents the dependency variables for a single build configuration.
 
   The structure is immutable.
 
-  .touch, .tracked and .untracked are the list of dependencies. The items in
-      these lists use '/' as a path separator.
   .command and .isolate_dir describe how to run the command. .isolate_dir uses
       the OS' native path separator. It must be an absolute path, it's the path
       where to start the command from.
+  .files is the list of dependencies. The items use '/' as a path separator.
   .read_only describe how to map the files.
   """
   def __init__(self, values, isolate_dir):
@@ -507,9 +346,12 @@ class ConfigSettings(object):
     else:
       # Otherwise, the path must be absolute.
       assert os.path.isabs(isolate_dir), isolate_dir
-    self.touched = sorted(values.get(KEY_TOUCHED, []))
-    self.tracked = sorted(values.get(KEY_TRACKED, []))
-    self.untracked = sorted(values.get(KEY_UNTRACKED, []))
+
+    self.files = sorted(
+        values.get('files', []) +
+        values.get(KEY_TOUCHED, []) +
+        values.get(KEY_TRACKED, []) +
+        values.get(KEY_UNTRACKED, []))
     self.command = values.get('command', [])[:]
     self.isolate_dir = isolate_dir
     self.read_only = values.get('read_only')
@@ -542,7 +384,7 @@ class ConfigSettings(object):
       use_rhs = bool(not self.command and rhs.command)
     else:
       # If self doesn't define any file, use rhs.
-      use_rhs = not bool(self.touched or self.tracked or self.untracked)
+      use_rhs = not bool(self.files)
     if use_rhs:
       # Rebase files in rhs.
       l_rel_cwd, r_rel_cwd = r_rel_cwd, l_rel_cwd
@@ -561,10 +403,8 @@ class ConfigSettings(object):
       return sorted(l + map(rebase_item, r))
 
     var = {
-      KEY_TOUCHED: map_both(self.touched, rhs.touched),
-      KEY_TRACKED: map_both(self.tracked, rhs.tracked),
-      KEY_UNTRACKED: map_both(self.untracked, rhs.untracked),
       'command': self.command or rhs.command,
+      'files': map_both(self.files, rhs.files),
       'read_only': rhs.read_only if self.read_only is None else self.read_only,
     }
     return ConfigSettings(var, l_rel_cwd)
@@ -574,12 +414,8 @@ class ConfigSettings(object):
     out = {}
     if self.command:
       out['command'] = self.command
-    if self.touched:
-      out[KEY_TOUCHED] = self.touched
-    if self.tracked:
-      out[KEY_TRACKED] = self.tracked
-    if self.untracked:
-      out[KEY_UNTRACKED] = self.untracked
+    if self.files:
+      out['files'] = self.files
     if self.read_only is not None:
       out['read_only'] = self.read_only
     # TODO(maruel): Probably better to not output it if command is None?
@@ -589,8 +425,7 @@ class ConfigSettings(object):
 
   def __str__(self):
     """Returns a short representation useful for debugging."""
-    files = ''.join(
-        '\n    ' + f for f in (self.touched + self.tracked + self.untracked))
+    files = ''.join('\n    ' + f for f in self.files)
     return 'ConfigSettings(%s, %s, %s, %s)' % (
         self.command,
         self.isolate_dir,
@@ -713,14 +548,6 @@ class Configs(object):
     """
     return dict((k, v.flatten()) for k, v in self._by_config.iteritems())
 
-  def make_isolate_file(self):
-    """Returns a dictionary suitable for writing to a .isolate file.
-    """
-    dependencies_by_config = self.flatten()
-    configs_by_dependency = reduce_inputs(invert_map(dependencies_by_config))
-    return convert_map_to_isolate_dict(configs_by_dependency,
-                                       self.config_variables)
-
   def __str__(self):
     return 'Configs(%s,%s)' % (
       self._config_variables,
@@ -748,10 +575,7 @@ def load_isolate_as_config(isolate_dir, value, file_comment):
           'command': [
             ...
           ],
-          'isolate_dependency_tracked': [
-            ...
-          ],
-          'isolate_dependency_untracked': [
+          'files': [
             ...
           ],
           'read_only': 0,
@@ -818,7 +642,7 @@ def load_isolate_for_config(isolate_dir, content, config_variables):
   filtered for the specific OS.
 
   Returns:
-    tuple of command, dependencies, touched, read_only flag, isolate_dir.
+    tuple of command, dependencies, read_only flag, isolate_dir.
     The dependencies are fixed to use os.path.sep.
   """
   # Load the .isolate file, process its conditions, retrieve the command and
@@ -836,12 +660,5 @@ def load_isolate_for_config(isolate_dir, content, config_variables):
   # A configuration is to be created with all the combinations of free
   # variables.
   config = isolate.get_config(config_name)
-  # Merge tracked and untracked variables, isolate.py doesn't care about the
-  # trackability of the variables, only the build tool does.
-  dependencies = sorted(
-    f.replace('/', os.path.sep) for f in config.tracked + config.untracked
-  )
-  touched = sorted(f.replace('/', os.path.sep) for f in config.touched)
-  return (
-      config.command, dependencies, touched, config.read_only,
-      config.isolate_dir)
+  dependencies = [f.replace('/', os.path.sep) for f in config.files]
+  return config.command, dependencies, config.read_only, config.isolate_dir