Example #1
0
 def _my_run(cmd, msg=None):
     if msg:
         info(fmt("@{bf}@!==> @|@!" + sanitize(msg)))
     else:
         info(fmt("@{bf}@!==> @|@!" + sanitize(str(cmd))))
     from subprocess import check_call
     check_call(cmd, shell=True)
Example #2
0
 def _my_run(cmd, msg=None):
     if msg:
         info(fmt("@{bf}@!==> @|@!" + sanitize(msg)))
     else:
         info(fmt("@{bf}@!==> @|@!" + sanitize(str(cmd))))
     from subprocess import check_call
     check_call(cmd, shell=True)
Example #3
0
File: config.py Project: 130s/bloom
 def __str__(self):
     msg = fmt('@_' + sanitize(self.name) + ':@|')
     if self.spec is not None:
         for key, val in self.spec.iteritems():
             msg += '\n  ' + key
             for line in val.splitlines():
                 msg += '\n    ' + line
     else:
         msg += '\n  ' + self.prompt
     msg += '\n '
     if self.default is None:
         msg += fmt(" @![@{yf}None@|@!]@|: ")
     else:
         msg += fmt(" @!['@{yf}" + sanitize(self.default) + "@|@!']@|: ")
     return msg
Example #4
0
 def __str__(self):
     msg = fmt('@_' + sanitize(self.name) + ':@|')
     if self.spec is not None:
         for key, val in self.spec.items():
             msg += '\n  ' + key
             for line in val.splitlines():
                 msg += '\n    ' + line
     else:
         msg += '\n  ' + self.prompt
     msg += '\n '
     if self.default is None:
         msg += fmt(" @![@{yf}None@|@!]@|: ")
     else:
         msg += fmt(" @!['@{yf}" + sanitize(self.default) + "@|@!']@|: ")
     return msg
Example #5
0
def maybe_continue(default='y', msg='Continue'):
    """Prompts the user for continuation"""
    default = default.lower()
    msg = "@!{msg} ".format(msg=sanitize(msg))
    if default == 'y':
        msg += "@{yf}[Y/n]? @|"
    else:
        msg += "@{yf}[y/N]? @|"
    msg = fmt(msg)

    while True:
        response = safe_input(msg)
        if not response:
            response = default

        response = response.lower()
        if response not in ['y', 'n', 'q']:
            error_msg = 'Reponse `' + response + '` was not recognized, ' \
                        'please use one of y, Y, n, N.'
            error(error_msg)
        else:
            break

    if response in ['n', 'q']:
        return False
    return True
Example #6
0
def maybe_continue(default='y', msg='Continue'):
    """Prompts the user for continuation"""
    default = default.lower()
    msg = "@!{msg} ".format(msg=sanitize(msg))
    if default == 'y':
        msg += "@{yf}[Y/n]? @|"
    else:
        msg += "@{yf}[y/N]? @|"
    msg = fmt(msg)

    while True:
        response = safe_input(msg)
        if not response:
            response = default

        response = response.lower()
        if response not in ['y', 'n', 'q']:
            error_msg = 'Reponse `' + response + '` was not recognized, ' \
                        'please use one of y, Y, n, N.'
            error(error_msg)
        else:
            break

    if response in ['n', 'q']:
        return False
    return True
Example #7
0
def execute_track(track, track_dict, release_inc, pretend=True, debug=False, fast=False):
    info("Processing release track settings for '{0}'".format(track))
    settings = process_track_settings(track_dict, release_inc)
    # setup extra settings
    archive_dir_path = tempfile.mkdtemp()
    settings['archive_dir_path'] = archive_dir_path
    if settings['release_tag'] != ':{none}':
        archive_file = '{name}-{release_tag}.tar.gz'.format(**settings)
    else:
        archive_file = '{name}.tar.gz'.format(**settings)
    settings['archive_path'] = os.path.join(archive_dir_path, archive_file)
    # execute actions
    info("", use_prefix=False)
    info("Executing release track '{0}'".format(track))
    for action in track_dict['actions']:
        if 'bloom-export-upstream' in action and settings['vcs_type'] == 'tar':
            warning("Explicitly skipping bloom-export-upstream for tar.")
            settings['archive_path'] = settings['vcs_uri']
            continue
        templated_action = template_str(action, settings)
        info(fmt("@{bf}@!==> @|@!" + sanitize(str(templated_action))))
        if pretend:
            continue
        stdout = None
        stderr = None
        if bloom.util._quiet:
            stdout = subprocess.PIPE
            stderr = subprocess.STDOUT
        if debug and 'DEBUG' not in os.environ:
            os.environ['DEBUG'] = '1'
        if fast and 'BLOOM_UNSAFE' not in os.environ:
            os.environ['BLOOM_UNSAFE'] = '1'
        templated_action = templated_action.split()
        templated_action[0] = find_full_path(templated_action[0])
        p = subprocess.Popen(templated_action, stdout=stdout, stderr=stderr,
                             shell=False, env=os.environ.copy())
        out, err = p.communicate()
        if bloom.util._quiet:
            info(out, use_prefix=False)
        ret = p.returncode
        if ret > 0:
            error(fmt(_error + "Error running command '@!{0}'@|")
                  .format(templated_action), exit=True)
        info('', use_prefix=False)
    if not pretend:
        # Update the release_inc
        tracks_dict = get_tracks_dict_raw()
        tracks_dict['tracks'][track]['release_inc'] = settings['release_inc']
        tracks_dict['tracks'][track]['last_version'] = settings['version']
        write_tracks_dict_raw(tracks_dict,
                              'Updating release inc to: ' + str(settings['release_inc']))
Example #8
0
def execute_track(track, track_dict, release_inc, pretend=True, debug=False, fast=False):
    info("Processing release track settings for '{0}'".format(track))
    settings = process_track_settings(track_dict, release_inc)
    # setup extra settings
    archive_dir_path = tempfile.mkdtemp()
    settings['archive_dir_path'] = archive_dir_path
    if settings['release_tag'] != ':{none}':
        archive_file = '{name}-{release_tag}.tar.gz'.format(**settings)
    else:
        archive_file = '{name}.tar.gz'.format(**settings)
    settings['archive_path'] = os.path.join(archive_dir_path, archive_file)
    # execute actions
    info("", use_prefix=False)
    info("Executing release track '{0}'".format(track))
    for action in track_dict['actions']:
        if 'bloom-export-upstream' in action and settings['vcs_type'] == 'tar':
            warning("Explicitly skipping bloom-export-upstream for tar.")
            settings['archive_path'] = settings['vcs_uri']
            continue
        templated_action = template_str(action, settings)
        info(fmt("@{bf}@!==> @|@!" + sanitize(str(templated_action))))
        if pretend:
            continue
        stdout = None
        stderr = None
        if bloom.util._quiet:
            stdout = subprocess.PIPE
            stderr = subprocess.STDOUT
        if debug and 'DEBUG' not in os.environ:
            os.environ['DEBUG'] = '1'
        if fast and 'BLOOM_UNSAFE' not in os.environ:
            os.environ['BLOOM_UNSAFE'] = '1'
        templated_action = templated_action.split()
        templated_action[0] = find_full_path(templated_action[0])
        p = subprocess.Popen(templated_action, stdout=stdout, stderr=stderr,
                             shell=False, env=os.environ.copy())
        out, err = p.communicate()
        if bloom.util._quiet:
            info(out, use_prefix=False)
        ret = p.returncode
        if ret > 0:
            error(fmt(_error + "Error running command '@!{0}'@|")
                  .format(templated_action), exit=True)
        info('', use_prefix=False)
    if not pretend:
        # Update the release_inc
        tracks_dict = get_tracks_dict_raw()
        tracks_dict['tracks'][track]['release_inc'] = settings['release_inc']
        tracks_dict['tracks'][track]['last_version'] = settings['version']
        write_tracks_dict_raw(tracks_dict,
                              'Updating release inc to: ' + str(settings['release_inc']))
Example #9
0
def execute_track(track,
                  track_dict,
                  release_inc,
                  pretend=True,
                  debug=False,
                  fast=False):
    info("Processing release track settings for '{0}'".format(track))
    settings = process_track_settings(track_dict, release_inc)
    # setup extra settings
    archive_dir_path = tempfile.mkdtemp()
    settings['archive_dir_path'] = archive_dir_path
    if settings['release_tag'] != ':{none}':
        archive_file = '{name}-{release_tag}.tar.gz'.format(**settings)
    else:
        archive_file = '{name}.tar.gz'.format(**settings)
    settings['archive_path'] = os.path.join(archive_dir_path, archive_file)
    # execute actions
    info("", use_prefix=False)
    info("Executing release track '{0}'".format(track))
    for action in track_dict['actions']:
        if 'bloom-export-upstream' in action and settings['vcs_type'] == 'tar':
            warning("Explicitly skipping bloom-export-upstream for tar.")
            settings['archive_path'] = settings['vcs_uri']
            continue
        templated_action = template_str(action, settings)
        info(fmt("@{bf}@!==> @|@!" + sanitize(str(templated_action))))
        if pretend:
            continue
        stdout = None
        stderr = None
        if bloom.util._quiet:
            stdout = subprocess.PIPE
            stderr = subprocess.STDOUT
        if debug and 'DEBUG' not in os.environ:
            os.environ['DEBUG'] = '1'
        if fast and 'BLOOM_UNSAFE' not in os.environ:
            os.environ['BLOOM_UNSAFE'] = '1'
        templated_action = templated_action.split()
        templated_action[0] = find_full_path(templated_action[0])
        p = subprocess.Popen(templated_action,
                             stdout=stdout,
                             stderr=stderr,
                             shell=False,
                             env=os.environ.copy())
        out, err = p.communicate()
        if bloom.util._quiet:
            info(out, use_prefix=False)
        ret = p.returncode
        if ret > 0:
            if 'bloom-generate' in templated_action[
                    0] and ret == code.GENERATOR_NO_ROSDEP_KEY_FOR_DISTRO:
                error(
                    fmt(_error +
                        "The following generator action reported that it is missing one or more"
                        ))
                error(
                    fmt("    @|rosdep keys, but that the key exists in other platforms:"
                        ))
                error(fmt("@|'@!{0}'@|").format(templated_action))
                info('', use_prefix=False)
                error(
                    fmt("@|If you are @!@_@{rf}absolutely@| sure that this key is unavailable for the platform in"
                        ))
                error(
                    fmt("@|question, the generator can be skipped and you can proceed with the release."
                        ))
                if maybe_continue(
                        'n',
                        'Skip generator action and continue with release'):
                    info("\nAction skipped, continuing with release.\n")
                    continue

                info('', use_prefix=False)

            error(fmt(_error + "Error running command '@!{0}'@|").format(
                templated_action),
                  exit=True)
        info('', use_prefix=False)
    if not pretend:
        # Update the release_inc
        tracks_dict = get_tracks_dict_raw()
        tracks_dict['tracks'][track]['release_inc'] = settings['release_inc']
        tracks_dict['tracks'][track]['last_version'] = settings['version']
        # if release tag is set to ask and a custom value is used
        if settings['version'] != settings['release_tag']:
            tracks_dict['tracks'][track]['last_release'] = settings[
                'release_tag']
        write_tracks_dict_raw(
            tracks_dict,
            'Updating release inc to: ' + str(settings['release_inc']))
Example #10
0
def generate_ros_distro_diff(track, repository, distro):
    distribution_dict = get_distribution_file(distro).get_data()
    # Get packages
    packages = get_packages()
    if len(packages) == 0:
        warning("No packages found, will not generate 'package: path' entries for rosdistro.")
    # Get version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    last_version = track_dict['last_version']
    release_inc = track_dict['release_inc']
    version = '{0}-{1}'.format(last_version, release_inc)
    # Create a repository if there isn't already one
    if repository not in distribution_dict['repositories']:
        global _user_provided_release_url
        distribution_dict['repositories'][repository] = {}
    # Create a release entry if there isn't already one
    if 'release' not in distribution_dict['repositories'][repository]:
        distribution_dict['repositories'][repository]['release'] = {
            'url': _user_provided_release_url
        }
    # Update the repository
    repo = distribution_dict['repositories'][repository]['release']
    if 'tags' not in repo:
        repo['tags'] = {}
    repo['tags']['release'] = generate_release_tag(distro)
    repo['version'] = version
    if 'packages' not in repo:
        repo['packages'] = []
    for path, pkg in packages.items():
        if pkg.name not in repo['packages']:
            repo['packages'].append(pkg.name)
    # Remove any missing packages
    packages_being_released = [p.name for p in packages.values()]
    for pkg_name in list(repo['packages']):
        if pkg_name not in packages_being_released:
            repo['packages'].remove(pkg_name)
    repo['packages'].sort()

    # Do the diff
    distro_file_name = get_relative_distribution_file_path(distro)
    updated_distribution_file = rosdistro.DistributionFile(distro, distribution_dict)
    distro_dump = yaml_from_distribution_file(updated_distribution_file)
    distro_file_raw = load_url_to_file_handle(get_disitrbution_file_url(distro)).read()
    if distro_file_raw != distro_dump:
        # Calculate the diff
        udiff = difflib.unified_diff(distro_file_raw.splitlines(), distro_dump.splitlines(),
                                     fromfile=distro_file_name, tofile=distro_file_name)
        temp_dir = tempfile.mkdtemp()
        udiff_file = os.path.join(temp_dir, repository + '-' + version + '.patch')
        udiff_raw = ''
        info("Unified diff for the ROS distro file located at '{0}':".format(udiff_file))
        for line in udiff:
            if line.startswith('@@'):
                udiff_raw += line
                line = fmt('@{cf}' + sanitize(line))
            if line.startswith('+'):
                if not line.startswith('+++'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{gf}' + sanitize(line))
            if line.startswith('-'):
                if not line.startswith('---'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{rf}' + sanitize(line))
            if line.startswith(' '):
                line += '\n'
                udiff_raw += line
            info(line, use_prefix=False, end='')
        # Assert that only this repository is being changed
        distro_file_yaml = yaml.load(distro_file_raw)
        distro_yaml = yaml.load(distro_dump)
        if 'repositories' in distro_file_yaml:
            distro_file_repos = distro_file_yaml['repositories']
            for repo in distro_yaml['repositories']:
                if repo == repository:
                    continue
                if repo not in distro_file_repos or distro_file_repos[repo] != distro_yaml['repositories'][repo]:
                    error("This generated pull request modifies a repository entry other than the one being released.")
                    error("This likely occured because the upstream rosdistro changed during this release.")
                    error("This pull request will abort, please re-run this command with the -p option to try again.",
                          exit=True)
        # Write the diff out to file
        with open(udiff_file, 'w+') as f:
            f.write(udiff_raw)
        # Return the diff
        return updated_distribution_file
    else:
        warning("This release resulted in no changes to the ROS distro file...")
    return None
Example #11
0
def generate_ros_distro_diff(track, repository, distro):
    release_dict = get_release_file(distro).get_data()
    # Get packages
    packages = get_packages()
    if len(packages) == 0:
        warning("No packages found, will not generate 'package: path' entries for rosdistro.")
    # Get version
    track_dict = get_tracks_dict_raw()["tracks"][track]
    last_version = track_dict["last_version"]
    release_inc = track_dict["release_inc"]
    version = "{0}-{1}".format(last_version, release_inc)
    # Create a repository if there isn't already one
    if repository not in release_dict["repositories"]:
        global _user_provided_release_url
        release_dict["repositories"][repository] = {"url": _user_provided_release_url}
    # Update the repository
    repo = release_dict["repositories"][repository]
    if "tags" not in repo:
        repo["tags"] = {}
    repo["tags"]["release"] = "release/%s/{package}/{version}" % distro
    repo["version"] = version
    if "packages" not in repo:
        repo["packages"] = {}
    for path, pkg in packages.items():
        if pkg.name not in repo["packages"]:
            repo["packages"][pkg.name] = {}
        repo["packages"][pkg.name]["subfolder"] = path  # This will be shortened
    # Remove any missing packages
    for pkg_name in dict(repo["packages"]):
        if pkg_name not in [p.name for p in packages.values()]:
            if pkg_name in repo["packages"]:
                del repo["packages"][pkg_name]
    # Do the diff
    distro_file_name = get_relative_release_file_path(distro)
    updated_release_file = rosdistro.ReleaseFile("distro", release_dict)
    distro_dump = yaml_from_release_file(updated_release_file)
    distro_file_raw = load_url_to_file_handle(get_release_file_url(distro)).read()
    if distro_file_raw != distro_dump:
        udiff = difflib.unified_diff(
            distro_file_raw.splitlines(), distro_dump.splitlines(), fromfile=distro_file_name, tofile=distro_file_name
        )
        temp_dir = tempfile.mkdtemp()
        udiff_file = os.path.join(temp_dir, repository + "-" + version + ".patch")
        udiff_raw = ""
        info("Unified diff for the ROS distro file located at '{0}':".format(udiff_file))
        for line in udiff:
            if line.startswith("@@"):
                udiff_raw += line
                line = fmt("@{cf}" + sanitize(line))
            if line.startswith("+"):
                if not line.startswith("+++"):
                    line += "\n"
                udiff_raw += line
                line = fmt("@{gf}" + sanitize(line))
            if line.startswith("-"):
                if not line.startswith("---"):
                    line += "\n"
                udiff_raw += line
                line = fmt("@{rf}" + sanitize(line))
            if line.startswith(" "):
                line += "\n"
                udiff_raw += line
            info(line, use_prefix=False, end="")
        with open(udiff_file, "w+") as f:
            f.write(udiff_raw)
        return updated_release_file
    else:
        warning("This release resulted in no changes to the ROS distro file...")
    return None
Example #12
0
def open_pull_request(track, repository, distro):
    # Get the diff
    distribution_file = get_distribution_file(distro)
    if repository in distribution_file.repositories and \
       distribution_file.repositories[repository].release_repository is not None:
        orig_version = distribution_file.repositories[repository].release_repository.version
    else:
        orig_version = None
    updated_distribution_file = generate_ros_distro_diff(track, repository, distro)
    if updated_distribution_file is None:
        # There were no changes, no pull request required
        return None
    version = updated_distribution_file.repositories[repository].release_repository.version
    updated_distro_file_yaml = yaml_from_distribution_file(updated_distribution_file)
    # Determine if the distro file is hosted on github...
    base_org, base_repo, base_branch, base_path = get_gh_info(get_disitrbution_file_url(distro))
    if None in [base_org, base_repo, base_branch, base_path]:
        warning("Automated pull request only available via github.com")
        return
    # Get the github interface
    gh = get_github_interface()
    # Determine the head org/repo for the pull request
    head_org = gh.username  # The head org will always be gh user
    head_repo = None
    # Check if the github user and the base org are the same
    if gh.username == base_org:
        # If it is, then a fork is not necessary
        head_repo = base_repo
    else:
        info(fmt("@{bf}@!==> @|@!Checking on github for a fork to make the pull request from..."))
        # It is not, so a fork will be required
        # Check if a fork already exists on the user's account with the same name
        base_full_name = '{base_org}/{base_repo}'.format(**locals())
        try:
            repo_data = gh.get_repo(gh.username, base_repo)
            if repo_data.get('fork', False):  # Check if it is a fork
                # If it is, check that it is a fork of the destination
                parent = repo_data.get('parent', {}).get('full_name', None)
                if parent == base_full_name:
                    # This is a valid fork
                    head_repo = base_repo
        except GithubException as exc:
            debug("Received GithubException while checking for fork: {exc}".format(**locals()))
            pass  # 404 or unauthorized, but unauthorized should have been caught above
        # If not head_repo, then either the fork has a different name, or there isn't one
        if head_repo is None:
            info(fmt("@{bf}@!==> @|@!" + "{head_org}/{base_repo} is not a fork, searching...".format(**locals())))
            # First we should look at every repository for the user and see if they are a fork
            user_repos = gh.list_repos(gh.username)
            for repo in user_repos:
                # If it is a fork and the parent is base_org/base_repo
                if repo.get('fork', False) and repo.get('parent', {}).get('full_name', '') == base_full_name:
                    # Then this is a valid fork
                    head_repo = repo['name']
        # If not head_repo still, a fork does not exist and must be created
        if head_repo is None:
            warning("Could not find a fork of {base_full_name} on the {gh.username} Github account."
                    .format(**locals()))
            warning("Would you like to create one now?")
            if not maybe_continue():
                warning("Skipping the pull request...")
                return
            # Create a fork
            try:
                gh.create_fork(base_org, base_repo)  # Will raise if not successful
                head_repo = base_repo
            except GithubException as exc:
                error("Aborting pull request: {0}".format(exc))
                return
    info(fmt("@{bf}@!==> @|@!" +
             "Using this fork to make a pull request from: {head_org}/{head_repo}".format(**locals())))
    # Clone the fork
    info(fmt("@{bf}@!==> @|@!" + "Cloning {0}/{1}...".format(head_org, head_repo)))
    new_branch = None
    title = "{0}: {1} in '{2}' [bloom]".format(repository, version, base_path)
    body = """\
Increasing version of package(s) in repository `{0}` to `{2}`:

- distro file: `{3}`
- bloom version: `{4}`
- previous version for package: `{1}`
""".format(repository, orig_version or 'null', version, base_path, bloom.__version__)
    body += get_changelog_summary(generate_release_tag(distro))
    with temporary_directory() as temp_dir:
        def _my_run(cmd, msg=None):
            if msg:
                info(fmt("@{bf}@!==> @|@!" + sanitize(msg)))
            else:
                info(fmt("@{bf}@!==> @|@!" + sanitize(str(cmd))))
            from subprocess import check_call
            check_call(cmd, shell=True)
        # Use the oauth token to clone
        rosdistro_url = 'https://{gh.token}:[email protected]/{base_org}/{base_repo}.git'.format(**locals())
        rosdistro_fork_url = 'https://{gh.token}:[email protected]/{head_org}/{head_repo}.git'.format(**locals())
        _my_run('mkdir -p {base_repo}'.format(**locals()))
        with change_directory(base_repo):
            _my_run('git init')
            branches = [x['name'] for x in gh.list_branches(head_org, head_repo)]
            new_branch = 'bloom-{repository}-{count}'
            count = 0
            while new_branch.format(repository=repository, count=count) in branches:
                count += 1
            new_branch = new_branch.format(repository=repository, count=count)
            # Final check
            info(fmt("@{cf}Pull Request Title: @{yf}" + sanitize(title)))
            info(fmt("@{cf}Pull Request Body : \n@{yf}" + sanitize(body)))
            msg = fmt("@!Open a @|@{cf}pull request@| @!@{kf}from@| @!'@|@!@{bf}" +
                      "{head_repo}/{head_repo}:{new_branch}".format(**locals()) +
                      "@|@!' @!@{kf}into@| @!'@|@!@{bf}" +
                      "{base_org}/{base_repo}:{base_branch}".format(**locals()) +
                      "@|@!'?")
            info(msg)
            if not maybe_continue():
                warning("Skipping the pull request...")
                return
            _my_run('git checkout -b {new_branch}'.format(**locals()))
            _my_run('git pull {rosdistro_url} {base_branch}'.format(**locals()), "Pulling latest rosdistro branch")
            with open('{0}'.format(base_path), 'w') as f:
                info(fmt("@{bf}@!==> @|@!Writing new distribution file: ") + str(base_path))
                f.write(updated_distro_file_yaml)
            _my_run('git add {0}'.format(base_path))
            _my_run('git commit -m "{0}"'.format(title))
            _my_run('git push {rosdistro_fork_url} {new_branch}'.format(**locals()), "Pushing changes to fork")
    # Open the pull request
    return gh.create_pull_request(base_org, base_repo, base_branch, head_org, new_branch, title, body)
Example #13
0
def generate_ros_distro_diff(track, repository, distro):
    distribution_dict = get_distribution_file(distro).get_data()
    # Get packages
    packages = get_packages()
    if len(packages) == 0:
        warning("No packages found, will not generate 'package: path' entries for rosdistro.")
    # Get version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    last_version = track_dict['last_version']
    release_inc = track_dict['release_inc']
    version = '{0}-{1}'.format(last_version, release_inc).encode('utf-8')
    # Create a repository if there isn't already one
    if repository not in distribution_dict['repositories']:
        global _user_provided_release_url
        distribution_dict['repositories'][repository] = {}
    # Create a release entry if there isn't already one
    if 'release' not in distribution_dict['repositories'][repository]:
        distribution_dict['repositories'][repository]['release'.encode('utf-8')] = {
            'url'.encode('utf-8'): _user_provided_release_url
        }
    # Update the repository
    repo = distribution_dict['repositories'][repository]['release']
    if 'tags' not in repo:
        repo['tags'.encode('utf-8')] = {}
    repo['tags']['release'.encode('utf-8')] = generate_release_tag(distro)
    repo['version'.encode('utf-8')] = version
    if 'packages' not in repo:
        repo['packages'.encode('utf-8')] = []
    for path, pkg in packages.items():
        if pkg.name not in repo['packages']:
            repo['packages'].append(pkg.name)
    # Remove any missing packages
    packages_being_released = [p.name for p in packages.values()]
    for pkg_name in list(repo['packages']):
        if pkg_name not in packages_being_released:
            repo['packages'].remove(pkg_name)
    repo['packages'].sort()

    def get_repository_info_from_user():
        data = {}
        while True:
            vcs_type = safe_input('VCS type [git, svn, hg, bzr]: ')
            if vcs_type in ['git', 'svn', 'hg', 'bzr']:
                break
            error("'{0}' is not a valid vcs type.".format(vcs_type))
            if not maybe_continue(msg='Try again'):
                return {}
        data['type'] = vcs_type
        while True:
            url = safe_input('VCS url: ')
            if url:
                break
            error("Nothing entered for url.")
            if not maybe_continue(msg='Try again'):
                return {}
        data['url'] = url
        while True:
            version = safe_input('VCS version [commit, tag, branch, etc]: ')
            if version:
                break
            error("Nothing entered for version.")
            if not maybe_continue(msg='Try again'):
                return {}
        data['version'] = version
        return data

    # Ask for doc entry
    if 'BLOOM_DONT_ASK_FOR_DOCS' not in os.environ:
        docs = distribution_dict['repositories'][repository].get('doc', {})
        if not docs and maybe_continue(msg='Would you like to add documentation information for this repository?'):
            info("Please enter your repository information for the doc generation job.")
            info("This information should point to the repository from which documentation should be generated.")
            docs = get_repository_info_from_user()
        distribution_dict['repositories'][repository]['doc'] = docs

    # Ask for source entry
    if 'BLOOM_DONT_ASK_FOR_SOURCE' not in os.environ:
        source = distribution_dict['repositories'][repository].get('source', {})
        if not source and maybe_continue(msg='Would you like to add source information for this repository?'):
            info("Please enter information which points ot the active development branch for this repository.")
            info("This information is used to run continuous integration jobs and for developers to checkout from.")
            source = get_repository_info_from_user()
        distribution_dict['repositories'][repository]['source'] = source

    # Ask for maintainership information
    if 'BLOOM_DONT_ASK_FOR_MAINTENANCE_STATUS' not in os.environ:
        status = distribution_dict['repositories'][repository].get('status', None)
        description = distribution_dict['repositories'][repository].get('status_description', None)
        if status is None and maybe_continue(msg='Would you like to add a maintenance status for this repository?'):
            info("Please enter a maintenance status.")
            info("Valid maintenance statuses:")
            info("- developed: active development is in progress")
            info("- maintained: no new development, but bug fixes and pull requests are addressed")
            info("- end-of-life: should not be used, will disapear at some point")
            while True:
                status = safe_input('Status: ')
                if status in ['developed', 'maintained', 'end-of-life']:
                    break
                error("'{0}' is not a valid status.".format(status))
                if not maybe_continue(msg='Try again'):
                    status = None
                    break
            if status is not None:
                info("You can also enter a status description.")
                info("This is usually reserved for giving a reason when a status is 'end-of-life'.")
                if description is not None:
                    info("Current status description: {0}".format(description))
                description_in = safe_input('Status Description [press Enter for no change]: ')
                if description_in:
                    description = description_in
        if status is not None:
            distribution_dict['repositories'][repository]['status'] = status
            if description is not None:
                distribution_dict['repositories'][repository]['status_description'] = description

    # Do the diff
    distro_file_name = get_relative_distribution_file_path(distro)
    updated_distribution_file = rosdistro.DistributionFile(distro, distribution_dict)
    distro_dump = yaml_from_distribution_file(updated_distribution_file)
    distro_file_raw = load_url_to_file_handle(get_disitrbution_file_url(distro)).read()
    if distro_file_raw != distro_dump:
        # Calculate the diff
        udiff = difflib.unified_diff(distro_file_raw.splitlines(), distro_dump.splitlines(),
                                     fromfile=distro_file_name, tofile=distro_file_name)
        temp_dir = tempfile.mkdtemp()
        udiff_file = os.path.join(temp_dir, repository + '-' + version + '.patch')
        udiff_raw = ''
        info("Unified diff for the ROS distro file located at '{0}':".format(udiff_file))
        for line in udiff:
            if line.startswith('@@'):
                udiff_raw += line
                line = fmt('@{cf}' + sanitize(line))
            if line.startswith('+'):
                if not line.startswith('+++'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{gf}' + sanitize(line))
            if line.startswith('-'):
                if not line.startswith('---'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{rf}' + sanitize(line))
            if line.startswith(' '):
                line += '\n'
                udiff_raw += line
            info(line, use_prefix=False, end='')
        # Assert that only this repository is being changed
        distro_file_yaml = yaml.load(distro_file_raw)
        distro_yaml = yaml.load(distro_dump)
        if 'repositories' in distro_file_yaml:
            distro_file_repos = distro_file_yaml['repositories']
            for repo in distro_yaml['repositories']:
                if repo == repository:
                    continue
                if repo not in distro_file_repos or distro_file_repos[repo] != distro_yaml['repositories'][repo]:
                    error("This generated pull request modifies a repository entry other than the one being released.")
                    error("This likely occured because the upstream rosdistro changed during this release.")
                    error("This pull request will abort, please re-run this command with the -p option to try again.",
                          exit=True)
        # Write the diff out to file
        with open(udiff_file, 'w+') as f:
            f.write(udiff_raw)
        # Return the diff
        return updated_distribution_file
    else:
        warning("This release resulted in no changes to the ROS distro file...")
    return None
Example #14
0
def execute_track(track, track_dict, release_inc, pretend=True, debug=False, fast=False):
    info("Processing release track settings for '{0}'".format(track))
    settings = process_track_settings(track_dict, release_inc)
    # setup extra settings
    archive_dir_path = tempfile.mkdtemp()
    settings['archive_dir_path'] = archive_dir_path
    if settings['release_tag'] != ':{none}':
        archive_file = '{name}-{release_tag}.tar.gz'.format(**settings)
    else:
        archive_file = '{name}.tar.gz'.format(**settings)
    settings['archive_path'] = os.path.join(archive_dir_path, archive_file)
    # execute actions
    info("", use_prefix=False)
    info("Executing release track '{0}'".format(track))
    for action in track_dict['actions']:
        if 'bloom-export-upstream' in action and settings['vcs_type'] == 'tar':
            warning("Explicitly skipping bloom-export-upstream for tar.")
            settings['archive_path'] = settings['vcs_uri']
            continue
        templated_action = template_str(action, settings)
        info(fmt("@{bf}@!==> @|@!" + sanitize(str(templated_action))))
        if pretend:
            continue
        stdout = None
        stderr = None
        if bloom.util._quiet:
            stdout = subprocess.PIPE
            stderr = subprocess.STDOUT
        if debug and 'DEBUG' not in os.environ:
            os.environ['DEBUG'] = '1'
        if fast and 'BLOOM_UNSAFE' not in os.environ:
            os.environ['BLOOM_UNSAFE'] = '1'
        templated_action = templated_action.split()
        templated_action[0] = find_full_path(templated_action[0])
        p = subprocess.Popen(templated_action, stdout=stdout, stderr=stderr,
                             shell=False, env=os.environ.copy())
        out, err = p.communicate()
        if bloom.util._quiet:
            info(out, use_prefix=False)
        ret = p.returncode
        if ret > 0:
            if 'bloom-generate' in templated_action[0] and ret == code.GENERATOR_NO_ROSDEP_KEY_FOR_DISTRO:
                error(fmt(_error + "The following generator action reported that it is missing one or more"))
                error(fmt("    @|rosdep keys, but that the key exists in other platforms:"))
                error(fmt("@|'@!{0}'@|").format(templated_action))
                info('', use_prefix=False)
                error(fmt("@|If you are @!@_@{rf}absolutely@| sure that this key is unavailable for the platform in"))
                error(fmt("@|question, the generator can be skipped and you can proceed with the release."))
                if maybe_continue('n', 'Skip generator action and continue with release'):
                    info("\nAction skipped, continuing with release.\n")
                    continue

                info('', use_prefix=False)

            error(fmt(_error + "Error running command '@!{0}'@|")
                  .format(templated_action), exit=True)
        info('', use_prefix=False)
    if not pretend:
        # Update the release_inc
        tracks_dict = get_tracks_dict_raw()
        tracks_dict['tracks'][track]['release_inc'] = settings['release_inc']
        tracks_dict['tracks'][track]['last_version'] = settings['version']
        write_tracks_dict_raw(tracks_dict,
                              'Updating release inc to: ' + str(settings['release_inc']))
Example #15
0
def generate_ros_distro_diff(track, repository, distro):
    distribution_dict = get_distribution_file(distro).get_data()
    # Get packages
    packages = get_packages()
    if len(packages) == 0:
        warning("No packages found, will not generate 'package: path' entries for rosdistro.")
    # Get version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    last_version = track_dict['last_version']
    release_inc = track_dict['release_inc']
    version = '{0}-{1}'.format(last_version, release_inc)
    # Create a repository if there isn't already one
    if repository not in distribution_dict['repositories']:
        global _user_provided_release_url
        distribution_dict['repositories'][repository] = {}
    # Create a release entry if there isn't already one
    if 'release' not in distribution_dict['repositories'][repository]:
        distribution_dict['repositories'][repository]['release'] = {
            'url': _user_provided_release_url
        }
    # Update the repository
    repo = distribution_dict['repositories'][repository]['release']
    if 'tags' not in repo:
        repo['tags'] = {}
    repo['tags']['release'] = 'release/%s/{package}/{version}' % distro
    repo['version'] = version
    if 'packages' not in repo:
        repo['packages'] = []
    for path, pkg in packages.items():
        if pkg.name not in repo['packages']:
            repo['packages'].append(pkg.name)
    # Remove any missing packages
    packages_being_released = [p.name for p in packages.values()]
    for pkg_name in list(repo['packages']):
        if pkg_name not in packages_being_released:
            repo['packages'].remove(pkg_name)
    repo['packages'].sort()

    # Do the diff
    distro_file_name = get_relative_distribution_file_path(distro)
    updated_distribution_file = rosdistro.DistributionFile(distro, distribution_dict)
    distro_dump = yaml_from_distribution_file(updated_distribution_file)
    distro_file_raw = load_url_to_file_handle(get_disitrbution_file_url(distro)).read()
    if distro_file_raw != distro_dump:
        udiff = difflib.unified_diff(distro_file_raw.splitlines(), distro_dump.splitlines(),
                                     fromfile=distro_file_name, tofile=distro_file_name)
        temp_dir = tempfile.mkdtemp()
        udiff_file = os.path.join(temp_dir, repository + '-' + version + '.patch')
        udiff_raw = ''
        info("Unified diff for the ROS distro file located at '{0}':".format(udiff_file))
        for line in udiff:
            if line.startswith('@@'):
                udiff_raw += line
                line = fmt('@{cf}' + sanitize(line))
            if line.startswith('+'):
                if not line.startswith('+++'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{gf}' + sanitize(line))
            if line.startswith('-'):
                if not line.startswith('---'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{rf}' + sanitize(line))
            if line.startswith(' '):
                line += '\n'
                udiff_raw += line
            info(line, use_prefix=False, end='')
        with open(udiff_file, 'w+') as f:
            f.write(udiff_raw)
        return updated_distribution_file
    else:
        warning("This release resulted in no changes to the ROS distro file...")
    return None
Example #16
0
def generate_ros_distro_diff(track, repository, distro):
    release_dict = get_release_file(distro).get_data()
    # Get packages
    packages = get_packages()
    if len(packages) == 0:
        warning(
            "No packages found, will not generate 'package: path' entries for rosdistro."
        )
    # Get version
    track_dict = get_tracks_dict_raw()['tracks'][track]
    last_version = track_dict['last_version']
    release_inc = track_dict['release_inc']
    version = '{0}-{1}'.format(last_version, release_inc)
    # Create a repository if there isn't already one
    if repository not in release_dict['repositories']:
        global _user_provided_release_url
        release_dict['repositories'][repository] = {
            'url': _user_provided_release_url
        }
    # Update the repository
    repo = release_dict['repositories'][repository]
    if 'tags' not in repo:
        repo['tags'] = {}
    repo['tags']['release'] = 'release/%s/{package}/{version}' % distro
    repo['version'] = version
    if 'packages' not in repo:
        repo['packages'] = {}
    for path, pkg in packages.items():
        if pkg.name not in repo['packages']:
            repo['packages'][pkg.name] = {}
        repo['packages'][
            pkg.name]['subfolder'] = path  # This will be shortened
    # Remove any missing packages
    for pkg_name in dict(repo['packages']):
        if pkg_name not in [p.name for p in packages.values()]:
            if pkg_name in repo['packages']:
                del repo['packages'][pkg_name]
    # Do the diff
    distro_file_name = get_relative_release_file_path(distro)
    updated_release_file = rosdistro.ReleaseFile('distro', release_dict)
    distro_dump = yaml_from_release_file(updated_release_file)
    distro_file_raw = load_url_to_file_handle(
        get_release_file_url(distro)).read()
    if distro_file_raw != distro_dump:
        udiff = difflib.unified_diff(distro_file_raw.splitlines(),
                                     distro_dump.splitlines(),
                                     fromfile=distro_file_name,
                                     tofile=distro_file_name)
        temp_dir = tempfile.mkdtemp()
        udiff_file = os.path.join(temp_dir,
                                  repository + '-' + version + '.patch')
        udiff_raw = ''
        info("Unified diff for the ROS distro file located at '{0}':".format(
            udiff_file))
        for line in udiff:
            if line.startswith('@@'):
                udiff_raw += line
                line = fmt('@{cf}' + sanitize(line))
            if line.startswith('+'):
                if not line.startswith('+++'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{gf}' + sanitize(line))
            if line.startswith('-'):
                if not line.startswith('---'):
                    line += '\n'
                udiff_raw += line
                line = fmt('@{rf}' + sanitize(line))
            if line.startswith(' '):
                line += '\n'
                udiff_raw += line
            info(line, use_prefix=False, end='')
        with open(udiff_file, 'w+') as f:
            f.write(udiff_raw)
        return updated_release_file
    else:
        warning(
            "This release resulted in no changes to the ROS distro file...")
    return None