Given a source directory, the path specified in an include tag, and the block name, retrieve
    the corresponding Block from the block_map (adding it to the map if necessary).

    The paths in include tags are interpreted as follows:

    1. relative to the directory of source_path.
    2. relative to the current working directory.

    If the included block is not found in either location, an exception is raised. If a cycle is
    detected, an exception is raised.

def retrieve_block_from_map(
        source_path,
        include_path,
        block_name,
        leading_whitespace,
        block_map,
        link_stack):
    """Given a source directory, the path specified in an include tag, and the block name, retrieve
    the corresponding Block from the block_map (adding it to the map if necessary).

    The paths in include tags are interpreted as follows:

    1. relative to the directory of source_path.
    2. relative to the current working directory.

    If the included block is not found in either location, an exception is raised. If a cycle is
    detected, an exception is raised.
    """
    # Check if the included file exists.
    relative_to_source = os.path.join(os.path.dirname(source_path), include_path)
    if os.path.isfile(relative_to_source):
        filename = relative_to_source
    elif os.path.isfile(include_path):
        filename = include_path
    else:
        raise IncludeNonExistentBlock(
            source_path + ' tried to include a non-existent file: ' + include_path)

    # Add included file to stack, checking for cycles in the process.
    link_stack.push(filename)

    # Process the block's file if it hasn't been processed before.
    if not block_map.has_block(filename, block_name):
        with open(filename, 'r') as f:
            content = f.read()
        convert_lines_to_block(content.splitlines(), block_map, link_stack, filename)

    # If the block is not in the map even after converting, then the block doesn't exist.
    if not block_map.has_block(filename, block_name):
        raise IncludeNonExistentBlock(
            source_path + ' tried to include a non-existent block: ' + filename + ':' + block_name)

    link_stack.pop()
    # Convert the Block to a string and indent.
    return indent(str(block_map.get_block(filename, block_name)), leading_whitespace)