1#!/usr/bin/python2.4
2# Copyright 2009 The Native Client Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Publish tool for SCons."""
7
8
9# List of published resources.  This is a dict indexed by group name.  Each
10# item in this dict is a dict indexed by resource type.  Items in that dict
11# are lists of files for that resource.
12__published = {}
13
14#------------------------------------------------------------------------------
15
16
17class PublishItem(object):
18  """Item to be published."""
19
20  def __init__(self, source, subdir):
21    """Initialize object.
22
23    Args:
24      source: Source node.
25      subdir: If not None, subdirectory to copy node into in
26          ReplicatePublished().
27    """
28    object.__init__(self)
29    self.source = source
30    self.subdir = subdir
31
32#------------------------------------------------------------------------------
33
34
35def _InitializePublish(env):
36  """Re-initializes published resources.
37
38  Args:
39    env: Parent environment
40  """
41  env=env     # Silence gpylint
42
43  # Clear the dict of published resources
44  __published.clear()
45
46
47def ReplicatePublished(self, target, group_name, resource_type):
48  """Replicate published resources for the group to the target directory.
49
50  Args:
51    self: Environment in which this function was called.
52    target: Target directory for resources.
53    group_name: Name of resource group, or a list of names of resource groups.
54    resource_type: Type of resources (string), or a list of resource types.
55
56    Uses the subdir parameter passed to Publish() when replicating source nodes
57    to the target.
58
59  Returns:
60    The list of target nodes from the calls to Replicate().
61
62  Since this is based on Replicate(), it will also use the REPLICATE_REPLACE
63  variable, if it's set in the calling environment.
64  """
65  target_path = self.Dir(target).abspath
66  #GOOGLE_CHANGE(pss) - FROM THIS:
67  #GOOGLE_CHANGE(pss) - TO THIS:
68  source_list = self.GetPublishedWithSubdirs(group_name, resource_type)
69  #GOOGLE_CHANGE(pss) - END CHANGES
70  dest_nodes = []
71  #GOOGLE_CHANGE(pss) - FROM THIS:
72  # for group in self.SubstList2(group_name):
73  #   for resource in self.SubstList2(resource_type):
74  #     # Get items for publish group and resource type
75  #     items = __published.get(group, {}).get(resource, [])
76  #     for i in items:
77  #       if i.subdir:
78  #         dest_nodes += self.Replicate(target_path + '/' + i.subdir, i.source)
79  #       else:
80  #         dest_nodes += self.Replicate(target_path, i.source)
81  #GOOGLE_CHANGE(pss) - TO THIS:
82  for source in source_list:
83    # Add the subdir if there is one in the source tuple.
84    if source[1]:
85      dest_nodes += self.Replicate(target_path + '/' + source[1], source[0])
86    else:
87      dest_nodes += self.Replicate(target_path, source[0])
88  #GOOGLE_CHANGE(pss) - END CHANGES
89  return dest_nodes
90
91
92#GOOGLE_CHANGE(pss) - FROM THIS:
93# def GetPublished(self, group_name, resource_type):
94#   """Returns a list of the published resources of the specified type.
95#
96#   Args:
97#     self: Environment in which this function was called.
98#     group_name: Name of resource group, or a list of names of resource groups.
99#     resource_type: Type of resources (string), or a list of resource types.
100#
101#   Returns:
102#     A flattened list of the source nodes from calls to Publish() for the
103#         specified group and resource type.  Returns an empty list if there are
104#         no matching resources.
105#   """
106#GOOGLE_CHANGE(pss) - TO THIS:
107def GetPublishedWithSubdirs(self, group_name, resource_type):
108  """Returns a list of the published resources of the specified type.
109
110  Args:
111    self: Environment in which this function was called.
112    group_name: Name of resource group, or a list of names of resource groups.
113    resource_type: Type of resources (string), or a list of resource types.
114
115  Returns:
116    A flattened list of the source nodes from calls to Publish() for the
117        specified group and resource type.  Each source node is represented
118        by a pair consisting of (source_node, subdir). Returns an empty list
119        if there are no matching resources.
120  """
121#GOOGLE_CHANGE(pss) - END CHANGES
122  source_list = []
123  for group in self.SubstList2(group_name):
124    # Get items for publish group and resource type
125    for resource in self.SubstList2(resource_type):
126      items = __published.get(group, {}).get(resource, [])
127      for i in items:
128        #GOOGLE_CHANGE(pss) - FROM THIS:
129        # source_list.append(i.source)
130        #GOOGLE_CHANGE(pss) - TO THIS:
131        source_list.append((i.source, i.subdir))
132        #GOOGLE_CHANGE(pss) - END CHANGES
133
134  return source_list
135
136
137#GOOGLE_CHANGE(pss) - FROM THIS:
138#GOOGLE_CHANGE(pss) - TO THIS:
139def GetPublished(self, group_name, resource_type):
140  """Returns a list of the published resources of the specified type.
141
142  Args:
143    self: Environment in which this function was called.
144    group_name: Name of resource group, or a list of names of resource groups.
145    resource_type: Type of resources (string), or a list of resource types.
146
147  Returns:
148    A flattened list of the source nodes from calls to Publish() for the
149        specified group and resource type.  Returns an empty list if there are
150        no matching resources.
151  """
152  source_list = self.GetPublishedWithSubdirs(group_name, resource_type)
153  return [source[0] for source in source_list]
154
155
156#GOOGLE_CHANGE(pss) - END CHANGES
157def Publish(self, group_name, resource_type, source, subdir=None):
158  """Publishes resources for use by other scripts.
159
160  Args:
161    self: Environment in which this function was called.
162    group_name: Name of resource group.
163    resource_type: Type of resources (string).
164    source: Source file(s) to copy.  May be a string, Node, or a list of
165        mixed strings or Nodes.  Strings will be passed through env.Glob() to
166        evaluate wildcards.  If a source evaluates to a directory, the entire
167        directory will be recursively copied.
168    subdir: Subdirectory to which the resources should be copied, relative to
169        the primary directory for that resource type, if not None.
170  """
171  if subdir is None:
172    subdir = ''         # Make string so we can append to it
173
174  # Evaluate SCons variables in group name
175  # TODO: Should Publish() be able to take a list of group names and publish
176  # the resource to all of them?
177  group_name = self.subst(group_name)
178
179  # Get list of sources
180  items = []
181  for source_entry in self.Flatten(source):
182    if isinstance(source_entry, str):
183      # Search for matches for each source entry
184      # TODO: Should generate an error if there were no matches?  But need to
185      # skip this warning if this is a recursive call to self.Publish() from
186      # below.
187      source_nodes = self.Glob(source_entry)
188    else:
189      # Source entry is already a file or directory node; no need to glob it
190      source_nodes = [source_entry]
191    for s in source_nodes:
192      if str(s.__class__) == 'SCons.Node.FS.Dir':
193        # Recursively publish all files in subdirectory.  Since glob('*')
194        # doesn't match dot files, also glob('.*').
195        self.Publish(group_name, resource_type,
196                     [s.abspath + '/*', s.abspath + '/.*'],
197                     subdir=subdir + '/' + s.name)
198      else:
199        items.append(PublishItem(s, subdir))
200
201  # Publish items, if any
202  if items:
203    # Get publish group
204    if group_name not in __published:
205      __published[group_name] = {}
206    group = __published[group_name]
207    if resource_type not in group:
208      group[resource_type] = []
209
210    # Publish items into group
211    group[resource_type] += items
212
213
214def generate(env):
215  # NOTE: SCons requires the use of this name, which fails gpylint.
216  """SCons entry point for this tool."""
217
218  # Defer initializing publish, but do before building SConscripts
219  env.Defer(_InitializePublish)
220  env.Defer('BuildEnvironmentSConscripts', after=_InitializePublish)
221
222  #GOOGLE_CHANGE(pss) - FROM THIS:
223  #GOOGLE_CHANGE(pss) - TO THIS:
224  env.AddMethod(GetPublishedWithSubdirs)
225  #GOOGLE_CHANGE(pss) - END CHANGES
226  env.AddMethod(GetPublished)
227  env.AddMethod(Publish)
228  env.AddMethod(ReplicatePublished)
229