.. versionchanged:: 2018.3.0
        If the built image should be tagged, then the repository and tag must
        now be passed separately using the ``repository`` and ``tag``
        arguments, rather than together in the (now deprecated) ``image``
        argument.

    Builds a docker image from a Dockerfile or a URL

    path
        Path to directory on the Minion containing a Dockerfile

    repository
        Optional repository name for the image being built

        .. versionadded:: 2018.3.0

    tag : latest
        Tag name for the image (required if ``repository`` is passed)

        .. versionadded:: 2018.3.0

    image
        .. deprecated:: 2018.3.0
            Use both ``repository`` and ``tag`` instead

    cache : True
        Set to ``False`` to force the build process not to use the Docker image
        cache, and pull all required intermediate image layers

    rm : True
        Remove intermediate containers created during build

    api_response : False
        If ``True``: an ``API_Response`` key will be present in the return
        data, containing the raw output from the Docker API.

    fileobj
        Allows for a file-like object containing the contents of the Dockerfile
        to be passed in place of a file ``path`` argument. This argument should
        not be used from the CLI, only from other Salt code.

    dockerfile
        Allows for an alternative Dockerfile to be specified. Path to
        alternative Dockefile is relative to the build path for the Docker
        container.

        .. versionadded:: 2016.11.0

    buildargs
        A dictionary of build arguments provided to the docker build process.

    network_mode
        networking mode(or name of docker network) to use when executing RUN commands.

    labels
        A dictionary of labels to set for the image

    cache_from
        list of image names to use a sources of cached layers(when cache is True)

    target
        Name of build stage to build for a multi-stage Dockerfile.

    **RETURN DATA**

    A dictionary containing one or more of the following keys:

    - ``Id`` - ID of the newly-built image
    - ``Time_Elapsed`` - Time in seconds taken to perform the build
    - ``Intermediate_Containers`` - IDs of containers created during the course
      of the build process

      *(Only present if rm=False)*
    - ``Images`` - A dictionary containing one or more of the following keys:
        - ``Already_Pulled`` - Layers that that were already present on the
          Minion
        - ``Pulled`` - Layers that that were pulled

      *(Only present if the image specified by the "repository" and "tag"
      arguments was not present on the Minion, or if cache=False)*
    - ``Status`` - A string containing a summary of the pull action (usually a
      message saying that an image was downloaded, or that it was up to date).

      *(Only present if the image specified by the "repository" and "tag"
      arguments was not present on the Minion, or if cache=False)*


    CLI Example:

    .. code-block:: bash

        salt myminion docker.build /path/to/docker/build/dir
        salt myminion docker.build https://github.com/myuser/myrepo.git repository=myimage tag=latest
        salt myminion docker.build /path/to/docker/build/dir dockerfile=Dockefile.different repository=myimage tag=dev

def build(path=None,
          repository=None,
          tag=None,
          cache=True,
          rm=True,
          api_response=False,
          fileobj=None,
          dockerfile=None,
          buildargs=None,
          network_mode=None,
          labels=None,
          cache_from=None,
          target=None):
    '''
    .. versionchanged:: 2018.3.0
        If the built image should be tagged, then the repository and tag must
        now be passed separately using the ``repository`` and ``tag``
        arguments, rather than together in the (now deprecated) ``image``
        argument.

    Builds a docker image from a Dockerfile or a URL

    path
        Path to directory on the Minion containing a Dockerfile

    repository
        Optional repository name for the image being built

        .. versionadded:: 2018.3.0

    tag : latest
        Tag name for the image (required if ``repository`` is passed)

        .. versionadded:: 2018.3.0

    image
        .. deprecated:: 2018.3.0
            Use both ``repository`` and ``tag`` instead

    cache : True
        Set to ``False`` to force the build process not to use the Docker image
        cache, and pull all required intermediate image layers

    rm : True
        Remove intermediate containers created during build

    api_response : False
        If ``True``: an ``API_Response`` key will be present in the return
        data, containing the raw output from the Docker API.

    fileobj
        Allows for a file-like object containing the contents of the Dockerfile
        to be passed in place of a file ``path`` argument. This argument should
        not be used from the CLI, only from other Salt code.

    dockerfile
        Allows for an alternative Dockerfile to be specified. Path to
        alternative Dockefile is relative to the build path for the Docker
        container.

        .. versionadded:: 2016.11.0

    buildargs
        A dictionary of build arguments provided to the docker build process.

    network_mode
        networking mode(or name of docker network) to use when executing RUN commands.

    labels
        A dictionary of labels to set for the image

    cache_from
        list of image names to use a sources of cached layers(when cache is True)

    target
        Name of build stage to build for a multi-stage Dockerfile.

    **RETURN DATA**

    A dictionary containing one or more of the following keys:

    - ``Id`` - ID of the newly-built image
    - ``Time_Elapsed`` - Time in seconds taken to perform the build
    - ``Intermediate_Containers`` - IDs of containers created during the course
      of the build process

      *(Only present if rm=False)*
    - ``Images`` - A dictionary containing one or more of the following keys:
        - ``Already_Pulled`` - Layers that that were already present on the
          Minion
        - ``Pulled`` - Layers that that were pulled

      *(Only present if the image specified by the "repository" and "tag"
      arguments was not present on the Minion, or if cache=False)*
    - ``Status`` - A string containing a summary of the pull action (usually a
      message saying that an image was downloaded, or that it was up to date).

      *(Only present if the image specified by the "repository" and "tag"
      arguments was not present on the Minion, or if cache=False)*


    CLI Example:

    .. code-block:: bash

        salt myminion docker.build /path/to/docker/build/dir
        salt myminion docker.build https://github.com/myuser/myrepo.git repository=myimage tag=latest
        salt myminion docker.build /path/to/docker/build/dir dockerfile=Dockefile.different repository=myimage tag=dev
    '''
    _prep_pull()

    if repository or tag:
        if not repository and tag:
            # Have to have both or neither
            raise SaltInvocationError(
                'If tagging, both a repository and tag are required'
            )
        else:
            if not isinstance(repository, six.string_types):
                repository = six.text_type(repository)
            if not isinstance(tag, six.string_types):
                tag = six.text_type(tag)

    # For the build function in the low-level API, the "tag" refers to the full
    # tag (e.g. myuser/myimage:mytag). This is different than in other
    # functions, where the repo and tag are passed separately.
    image_tag = '{0}:{1}'.format(
        repository, tag) if repository and tag else None

    time_started = time.time()
    response = _client_wrapper('build',
                               path=path,
                               tag=image_tag,
                               quiet=False,
                               fileobj=fileobj,
                               rm=rm,
                               nocache=not cache,
                               dockerfile=dockerfile,
                               buildargs=buildargs,
                               network_mode=network_mode,
                               labels=labels,
                               cache_from=cache_from,
                               target=target)
    ret = {'Time_Elapsed': time.time() - time_started}
    _clear_context()

    if not response:
        raise CommandExecutionError(
            'Build failed for {0}, no response returned from Docker API'
            .format(path)
        )

    stream_data = []
    for line in response:
        stream_data.extend(salt.utils.json.loads(line, cls=DockerJSONDecoder))
    errors = []
    # Iterate through API response and collect information
    for item in stream_data:
        try:
            item_type = next(iter(item))
        except StopIteration:
            continue
        if item_type == 'status':
            _pull_status(ret, item)
        if item_type == 'stream':
            _build_status(ret, item)
        elif item_type == 'errorDetail':
            _error_detail(errors, item)

    if 'Id' not in ret:
        # API returned information, but there was no confirmation of a
        # successful build.
        msg = 'Build failed for {0}'.format(path)
        log.error(msg)
        log.error(stream_data)
        if errors:
            msg += '. Error(s) follow:\n\n{0}'.format(
                '\n\n'.join(errors)
            )
        raise CommandExecutionError(msg)

    resolved_tag = resolve_tag(ret['Id'], all=True)
    if resolved_tag:
        ret['Image'] = resolved_tag
    else:
        ret['Warning'] = \
            'Failed to tag image as {0}'.format(image_tag)

    if api_response:
        ret['API_Response'] = stream_data

    if rm:
        ret.pop('Intermediate_Containers', None)
    return ret