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)
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
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
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
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']))
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']))
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
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
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)
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
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']))
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
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