import re


def split_repo_dver(build, known_repos=None):
    """Split out the dist tag from the NVR of a build, returning a tuple
    containing (NVR (without dist tag), repo, dver).
    For example, split_repo_dver("foobar-1-1.osg32.el5") returns
    ("foobar-1-1", "osg32", "el5").
    The empty string is returned for any of the components that aren't present.

    Since the dist tag isn't a well-defined entity, I'm using the following
    heuristic to distinguish it:
        1. If the dist tag exists, it's at the end of the release.
            (only known exception: gridsite-1.7.15-4.osg.3. This is not
            handled, but it's not worth the extra code)
        2. If the dver is in the release, it is at the end of the dist tag.
        3. The dist tag contains at most 2 components, separated by '.'
    If known_repos is specified (as a list), then the repo component must be
    one of the strings in that list. Otherwise, the repo component must start
    with [a-z]. This is a workaround to prevent misidentifying the repo
    tag on a release like "1.11".

    """
    build_no_dist = build
    repo = ""
    dver = ""

    build_no_dist_pat = r"(?P<build_no_dist>.+)"
    repo_pat = r"(?P<repo>[a-z]\w+)"
    dver_pat = r"(?P<dver>el\d+)"
    if known_repos is not None:
        repo_pat = r"(?P<repo>" + "|".join(known_repos) + ")"

    # order matters since later patterns are less specific and would match more
    pat_1_repo_and_dver = re.compile(build_no_dist_pat + r"\." + repo_pat + r"\." + dver_pat + "$")
    pat_2_dver_only = re.compile(build_no_dist_pat + r"\." + dver_pat + "$")
    pat_3_repo_only = re.compile(build_no_dist_pat + r"\." + repo_pat + "$")

    match = (pat_1_repo_and_dver.match(build) or
             pat_2_dver_only.match(build) or
             pat_3_repo_only.match(build))

    if match:
        groupdict = match.groupdict()
        build_no_dist, repo, dver = groupdict['build_no_dist'], groupdict.get('repo', ''), groupdict.get('dver', '')

    return build_no_dist, repo, dver