A helper function that ensures that self._index is
    up-to-date.  If the index is older than self.INDEX_TIMEOUT,
    then download it again.

def _update_index(self, url=None):
    """A helper function that ensures that self._index is
    up-to-date.  If the index is older than self.INDEX_TIMEOUT,
    then download it again."""
    # Check if the index is aleady up-to-date.  If so, do nothing.
    if not (self._index is None or url is not None or
        time.time()-self._index_timestamp > self.INDEX_TIMEOUT):
      return

    # If a URL was specified, then update our URL.
    self._url = url or self._url

    source = self._source
    assert source == 'google' or source == 'mirror'

    # Download the index file.
    if source == 'google':
        host = "www.googleapis.com"
        conn = HTTPSConnection(host)
        conn.request("GET", "/storage/v1/b/{}/o".format(self._url))
        r1 = conn.getresponse()
        data = r1.read()
    elif source == 'mirror':
        index_url = path.join(self._url, 'index.json')
        data = urlopen(index_url).read()

    if six.PY3:
      data = data.decode('utf-8')
    data = loads(data)
    objs = data["items"]

    self._index_timestamp = time.time()

    # Build a dictionary of packages.
    packages = []
    for p in objs:
      P = Package.fromcsobj(p)
      packages.append(P)
    self._packages = dict((p.id, p) for p in packages)

    # Build language collections.
    langs = defaultdict(lambda: [])
    for k in self._packages:
      package = self._packages[k]
      langs[package.language].append(package)

    tasks = defaultdict(lambda: [])
    for k in self._packages:
      package = self._packages[k]
      tasks[package.task].append(package)

    collections = []

    for lang in langs:
      children = langs[lang]

      name1 = Locale(lang).getDisplayLanguage()

      try:
        name2 = isoLangs[lang]['name']
      except:
        name2 = None

      if name1 and name1 != lang:
        name = name1
      elif name2:
        name = name2
      else:
        name = lang

      id = "{}{}".format(Downloader.LANG_PREFIX, lang)
      name = "{:<20} packages and models".format(name)
      c = Collection(id=id, name=name, children=children)
      collections.append(c)

    for task in tasks:
      children = tasks[task]
      id = "{}{}".format(Downloader.TASK_PREFIX, task)
      c = Collection(id=id, name=task, children=children)
      collections.append(c)


    self._collections = dict((c.id, c) for c in collections)

    # Replace identifiers with actual children in collection.children.
    for collection in self._collections.values():
      for i, child_id in enumerate(collection.children):
        if child_id in self._packages:
          collection.children[i] = self._packages[child_id]
        if child_id in self._collections:
          collection.children[i] = self._collections[child_id]

    # Fill in collection.packages for each collection.
    for collection in self._collections.values():
      packages = {}
      queue = [collection]
      for child in queue:
        if isinstance(child, Collection):
          queue.extend(child.children)
        else:
          packages[child.id] = child
      collection.packages = packages.values()

    # Flush the status cache
    self._status_cache.clear()