# Copyright 2013 The LUCI Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.

"""Provides access to the recipes input properties.

Every recipe is run with a JSON object called "properties". These contain all
inputs to the recipe. Some common examples would be properties like "revision",
which the build scheduler sets to tell a recipe to build/test a certain
revision.

The properties that affect a particular recipe are defined by the recipe itself,
and this module provides access to them.

Recipe properties are read-only; the values obtained via this API reflect the
values provided to the recipe engine at the beginning of execution. There is
intentionally no API to write property values (lest they become a kind of
random-access global variable).
"""

from future.utils import iteritems

from recipe_engine import recipe_api
from recipe_engine.types import freeze
import collections

# Use RecipeApiPlain because collections.Mapping has its own metaclass.
# Additionally, nothing in this class is a composite_step (nothing in this class
# is any sort of step :).
class PropertiesApi(recipe_api.RecipeApiPlain, collections.Mapping):
  """PropertiesApi implements all the standard Mapping functions, so you
  can use it like a read-only dict."""

  properties_client = recipe_api.RequireClient('properties')

  def __init__(self, **kwargs):
    super(PropertiesApi, self).__init__(**kwargs)
    self._frozen_properties = None

  @property
  def _properties(self):
    if self._frozen_properties is None:
      self._frozen_properties = freeze(
          self.properties_client.get_properties())
    return self._frozen_properties

  def __getitem__(self, key):
    return self._properties[key]

  def __len__(self):
    return len(self._properties)

  def __iter__(self):
    return iter(self._properties)

  def legacy(self):  # pragma: no cover
    """DEPRECATED: Returns a set of properties, possibly used by legacy
    scripts.

    This excludes any recipe module-specific properties (i.e. those beginning
    with `$`).

    Instead of passing all of the properties as a blob, please consider passing
    specific arguments to scripts that need them. Doing this makes it much
    easier to debug and diagnose which scripts use which properties.
    """

    # Add all properties to this blacklist that are required for testing, but
    # not used by any lecacy scripts, in order to avoid vast expecation
    # changes.
    blacklist = set([
      'buildbotURL',
    ])
    props = {k: v for k, v in iteritems(self)
             if k not in blacklist and not k.startswith('$')}
    if props.get('bot_id') and not props.get('slavename'):
      props['slavename'] = props['bot_id']
    return props

  def thaw(self):
    """Returns a read-write copy of all of the properties."""
    return self.properties_client.get_properties()
