def run(self): option_dict = self.distribution.get_option_dict('pbr') tree_index = options.get_boolean_option(option_dict, 'autodoc_tree_index_modules', 'AUTODOC_TREE_INDEX_MODULES') auto_index = options.get_boolean_option(option_dict, 'autodoc_index_modules', 'AUTODOC_INDEX_MODULES') if not os.getenv('SPHINX_DEBUG'): #NOTE(afazekas): These options can be used together, # but they do a very similar thing in a difffernet way if tree_index: self._sphinx_tree() if auto_index: self.generate_autoindex() for builder in self.builders: self.builder = builder self.finalize_options() self.project = self.distribution.get_name() self.version = self.distribution.get_version() self.release = self.distribution.get_version() if 'warnerrors' in option_dict: self._sphinx_run() else: setup_command.BuildDoc.run(self)
def run(self): option_dict = self.distribution.get_option_dict('pbr') if git._git_is_installed(): git.write_git_changelog(option_dict=option_dict) git.generate_authors(option_dict=option_dict) tree_index = options.get_boolean_option(option_dict, 'autodoc_tree_index_modules', 'AUTODOC_TREE_INDEX_MODULES') auto_index = options.get_boolean_option(option_dict, 'autodoc_index_modules', 'AUTODOC_INDEX_MODULES') if not os.getenv('SPHINX_DEBUG'): # NOTE(afazekas): These options can be used together, # but they do a very similar thing in a different way if tree_index: self._sphinx_tree() if auto_index: self.generate_autoindex( set( option_dict.get("autodoc_exclude_modules", [None, ""])[1].split())) for builder in self.builders: self.builder = builder self.finalize_options() self.project = self.distribution.get_name() self.version = self.distribution.get_version() self.release = self.distribution.get_version() if options.get_boolean_option(option_dict, 'warnerrors', 'WARNERRORS'): self._sphinx_run() else: setup_command.BuildDoc.run(self)
def run(self): option_dict = self.distribution.get_option_dict('pbr') if git._git_is_installed(): git.write_git_changelog(option_dict=option_dict) git.generate_authors(option_dict=option_dict) tree_index = options.get_boolean_option(option_dict, 'autodoc_tree_index_modules', 'AUTODOC_TREE_INDEX_MODULES') auto_index = options.get_boolean_option(option_dict, 'autodoc_index_modules', 'AUTODOC_INDEX_MODULES') if not os.getenv('SPHINX_DEBUG'): # NOTE(afazekas): These options can be used together, # but they do a very similar thing in a different way if tree_index: self._sphinx_tree() if auto_index: self.generate_autoindex( set(option_dict.get( "autodoc_exclude_modules", [None, ""])[1].split())) for builder in self.builders: self.builder = builder self.finalize_options() self.project = self.distribution.get_name() self.version = self.distribution.get_version() self.release = self.distribution.get_version() if options.get_boolean_option(option_dict, 'warnerrors', 'WARNERRORS'): self._sphinx_run() else: setup_command.BuildDoc.run(self)
def run(self): option_dict = self.distribution.get_option_dict('pbr') if git._git_is_installed(): git.write_git_changelog(option_dict=option_dict) git.generate_authors(option_dict=option_dict) tree_index = options.get_boolean_option(option_dict, 'autodoc_tree_index_modules', 'AUTODOC_TREE_INDEX_MODULES') auto_index = options.get_boolean_option(option_dict, 'autodoc_index_modules', 'AUTODOC_INDEX_MODULES') if not os.getenv('SPHINX_DEBUG'): # NOTE(afazekas): These options can be used together, # but they do a very similar thing in a different way if tree_index: self._sphinx_tree() if auto_index: self.generate_autoindex( set(option_dict.get( "autodoc_exclude_modules", [None, ""])[1].split())) # TODO(stephenfin): Deprecate this functionality once we depend on # Sphinx 1.6, which includes a similar feature, in g-r # https://github.com/sphinx-doc/sphinx/pull/3476 self.finalize_options() if hasattr(self, "builder_target_dirs"): # Sphinx >= 1.6.1 return setup_command.BuildDoc.run(self) # Sphinx < 1.6 for builder in self.builders: self.builder = builder self.finalize_options() self._sphinx_run()
def run(self): option_dict = self.distribution.get_option_dict('pbr') if git._git_is_installed(): git.write_git_changelog(option_dict=option_dict) git.generate_authors(option_dict=option_dict) tree_index = options.get_boolean_option(option_dict, 'autodoc_tree_index_modules', 'AUTODOC_TREE_INDEX_MODULES') auto_index = options.get_boolean_option(option_dict, 'autodoc_index_modules', 'AUTODOC_INDEX_MODULES') if not os.getenv('SPHINX_DEBUG'): # NOTE(afazekas): These options can be used together, # but they do a very similar thing in a different way if tree_index: self._sphinx_tree() if auto_index: self.generate_autoindex( set(option_dict.get( "autodoc_exclude_modules", [None, ""])[1].split())) self.finalize_options() is_multibuilder_sphinx = version.SemanticVersion.from_pip_string( sphinx.__version__) >= version.SemanticVersion(1, 6) # TODO(stephenfin): Remove support for Sphinx < 1.6 in 4.0 if not is_multibuilder_sphinx: log.warn('[pbr] Support for Sphinx < 1.6 will be dropped in ' 'pbr 4.0. Upgrade to Sphinx 1.6+') # TODO(stephenfin): Remove this at the next MAJOR version bump if self.builders != ['html']: log.warn("[pbr] Sphinx 1.6 added native support for " "specifying multiple builders in the " "'[sphinx_build] builder' configuration option, " "found in 'setup.cfg'. As a result, the " "'[sphinx_build] builders' option has been " "deprecated and will be removed in pbr 4.0. Migrate " "to the 'builder' configuration option.") if is_multibuilder_sphinx: self.builder = self.builders if is_multibuilder_sphinx: # Sphinx >= 1.6 return setup_command.BuildDoc.run(self) # Sphinx < 1.6 for builder in self.builder: self.builder = builder self.finalize_options() self._sphinx_run()
def run(self): option_dict = self.distribution.get_option_dict('pbr') if git._git_is_installed(): git.write_git_changelog(option_dict=option_dict) git.generate_authors(option_dict=option_dict) tree_index = options.get_boolean_option(option_dict, 'autodoc_tree_index_modules', 'AUTODOC_TREE_INDEX_MODULES') auto_index = options.get_boolean_option(option_dict, 'autodoc_index_modules', 'AUTODOC_INDEX_MODULES') if not os.getenv('SPHINX_DEBUG'): # NOTE(afazekas): These options can be used together, # but they do a very similar thing in a different way if tree_index: self._sphinx_tree() if auto_index: self.generate_autoindex( set( option_dict.get("autodoc_exclude_modules", [None, ""])[1].split())) self.finalize_options() is_multibuilder_sphinx = version.SemanticVersion.from_pip_string( sphinx.__version__) >= version.SemanticVersion(1, 6) # TODO(stephenfin): Remove support for Sphinx < 1.6 in 4.0 if not is_multibuilder_sphinx: log.warning('[pbr] Support for Sphinx < 1.6 will be dropped in ' 'pbr 4.0. Upgrade to Sphinx 1.6+') # TODO(stephenfin): Remove this at the next MAJOR version bump if self.builders != ['html']: log.warning("[pbr] Sphinx 1.6 added native support for " "specifying multiple builders in the " "'[sphinx_build] builder' configuration option, " "found in 'setup.cfg'. As a result, the " "'[sphinx_build] builders' option has been " "deprecated and will be removed in pbr 4.0. Migrate " "to the 'builder' configuration option.") if is_multibuilder_sphinx: self.builder = self.builders if is_multibuilder_sphinx: # Sphinx >= 1.6 return setup_command.BuildDoc.run(self) # Sphinx < 1.6 for builder in self.builder: self.builder = builder self.finalize_options() self._sphinx_run()
def hook(self): self.add_command('pbr.packaging.LocalEggInfo') self.add_command('pbr.packaging.LocalSDist') self.add_command('pbr.packaging.LocalInstallScripts') self.add_command('pbr.packaging.LocalDevelop') self.add_command('pbr.packaging.LocalRPMVersion') if os.name != 'nt': easy_install.get_script_args = packaging.override_get_script_args if packaging.have_sphinx(): self.add_command('pbr.builddoc.LocalBuildDoc') self.add_command('pbr.builddoc.LocalBuildLatex') if os.path.exists('.testr.conf') and packaging.have_testr(): # There is a .testr.conf file. We want to use it. self.add_command('pbr.packaging.TestrTest') elif self.config.get('nosetests', False) and packaging.have_nose(): # We seem to still have nose configured self.add_command('pbr.packaging.NoseTest') use_egg = options.get_boolean_option( self.pbr_config, 'use-egg', 'PBR_USE_EGG') # We always want non-egg install unless explicitly requested if 'manpages' in self.pbr_config or not use_egg: self.add_command('pbr.packaging.LocalInstall') else: self.add_command('pbr.packaging.InstallWithGit')
def add_defaults(self): """Add all the default files to self.filelist: Extends the functionality provided by distutils to also included additional sane defaults, such as the ``AUTHORS`` and ``ChangeLog`` files generated by *pbr*. Warns if (``README`` or ``README.txt``) or ``setup.py`` are missing; everything else is optional. """ option_dict = self.distribution.get_option_dict('pbr') sdist.sdist.add_defaults(self) self.filelist.append(self.template) self.filelist.append(self.manifest) self.filelist.extend(extra_files.get_extra_files()) should_skip = options.get_boolean_option(option_dict, 'skip_git_sdist', 'SKIP_GIT_SDIST') if not should_skip: rcfiles = git._find_git_files() if rcfiles: self.filelist.extend(rcfiles) elif os.path.exists(self.manifest): self.read_manifest() ei_cmd = self.get_finalized_command('egg_info') self._add_pbr_defaults() self.filelist.include_pattern("*", prefix=ei_cmd.egg_info)
def write_git_changelog(git_dir=None, dest_dir=os.path.curdir, option_dict=None, changelog=None): """Write a changelog based on the git changelog.""" start = time.time() if not option_dict: option_dict = {} should_skip = options.get_boolean_option(option_dict, 'skip_changelog', 'SKIP_WRITE_GIT_CHANGELOG') if should_skip: return if not changelog: changelog = _iter_log_oneline(git_dir=git_dir) if changelog: changelog = _iter_changelog(changelog) if not changelog: return new_changelog = os.path.join(dest_dir, 'ChangeLog') # If there's already a ChangeLog and it's not writable, just use it if (os.path.exists(new_changelog) and not os.access(new_changelog, os.W_OK)): log.info('[pbr] ChangeLog not written (file already' ' exists and it is not writeable)') return log.info('[pbr] Writing ChangeLog') with io.open(new_changelog, "w", encoding="utf-8") as changelog_file: for release, content in changelog: changelog_file.write(content) stop = time.time() log.info('[pbr] ChangeLog complete (%0.1fs)' % (stop - start))
def hook(self): self.add_command('pbr.packaging.LocalEggInfo') self.add_command('pbr.packaging.LocalSDist') self.add_command('pbr.packaging.LocalInstallScripts') self.add_command('pbr.packaging.LocalDevelop') self.add_command('pbr.packaging.LocalRPMVersion') self.add_command('pbr.packaging.LocalDebVersion') if os.name != 'nt': easy_install.get_script_args = packaging.override_get_script_args if packaging.have_sphinx(): self.add_command('pbr.builddoc.LocalBuildDoc') self.add_command('pbr.builddoc.LocalBuildLatex') if os.path.exists('.testr.conf') and packaging.have_testr(): # There is a .testr.conf file. We want to use it. self.add_command('pbr.packaging.TestrTest') elif self.config.get('nosetests', False) and packaging.have_nose(): # We seem to still have nose configured self.add_command('pbr.packaging.NoseTest') use_egg = options.get_boolean_option(self.pbr_config, 'use-egg', 'PBR_USE_EGG') # We always want non-egg install unless explicitly requested if 'manpages' in self.pbr_config or not use_egg: self.add_command('pbr.packaging.LocalInstall') else: self.add_command('pbr.packaging.InstallWithGit')
def write_git_changelog(git_dir=None, dest_dir=os.path.curdir, option_dict=dict()): """Write a changelog based on the git changelog.""" should_skip = options.get_boolean_option(option_dict, 'skip_changelog', 'SKIP_WRITE_GIT_CHANGELOG') if should_skip: return new_changelog = os.path.join(dest_dir, 'ChangeLog') # If there's already a ChangeLog and it's not writable, just use it if (os.path.exists(new_changelog) and not os.access(new_changelog, os.W_OK)): return log.info('[pbr] Writing ChangeLog') if git_dir is None: git_dir = _run_git_functions() if not git_dir: return log_cmd = ['log', '--oneline', '--decorate'] changelog = _run_git_command(log_cmd, git_dir) first_line = True with io.open(new_changelog, "w", encoding="utf-8") as changelog_file: changelog_file.write("CHANGES\n=======\n\n") for line in changelog.split('\n'): line_parts = line.split() if len(line_parts) < 2: continue # Tags are in a list contained in ()'s. If a commit # subject that is tagged happens to have ()'s in it # this will fail if line_parts[1].startswith('(') and ')' in line: msg = line.split(')')[1].strip() else: msg = " ".join(line_parts[1:]) if "tag:" in line: tags = [ tag.split(",")[0] for tag in line.split(")")[0].split("tag: ")[1:]] tag = _get_highest_tag(tags) underline = len(tag) * '-' if not first_line: changelog_file.write('\n') changelog_file.write( ("%(tag)s\n%(underline)s\n\n" % dict(tag=tag, underline=underline))) if not msg.startswith("Merge "): if msg.endswith("."): msg = msg[:-1] changelog_file.write( ("* %(msg)s\n" % dict(msg=msg))) first_line = False
def _pip_install(links, requires, root=None, option_dict=dict()): if options.get_boolean_option( option_dict, 'skip_pip_install', 'SKIP_PIP_INSTALL'): return cmd = [sys.executable, '-m', 'pip.__init__', 'install'] if root: cmd.append("--root=%s" % root) for link in links: cmd.append("-f") cmd.append(link) # NOTE(ociuhandu): popen on Windows does not accept unicode strings git._run_shell_command( cmd + requires, throw_on_error=True, buffer=False, env=dict(PIP_USE_WHEEL=b"true"))
def _pip_install(links, requires, root=None, option_dict=dict()): if options.get_boolean_option( option_dict, 'skip_pip_install', 'SKIP_PIP_INSTALL'): return cmd = [sys.executable, '-m', 'pip.__init__', 'install'] if root: cmd.append("--root=%s" % root) for link in links: cmd.append("-f") cmd.append(link) # NOTE(ociuhandu): popen on Windows does not accept unicode strings _run_shell_command( cmd + requires, throw_on_error=True, buffer=False, env=dict(PIP_USE_WHEEL=b"true"))
def add_defaults(self): option_dict = self.distribution.get_option_dict("pbr") sdist.sdist.add_defaults(self) self.filelist.append(self.template) self.filelist.append(self.manifest) self.filelist.extend(extra_files.get_extra_files()) should_skip = options.get_boolean_option(option_dict, "skip_git_sdist", "SKIP_GIT_SDIST") if not should_skip: rcfiles = git._find_git_files() if rcfiles: self.filelist.extend(rcfiles) elif os.path.exists(self.manifest): self.read_manifest() ei_cmd = self.get_finalized_command("egg_info") self._add_pbr_defaults() self.filelist.include_pattern("*", prefix=ei_cmd.egg_info)
def add_defaults(self): option_dict = self.distribution.get_option_dict('pbr') sdist.sdist.add_defaults(self) self.filelist.insertLast(self.template) self.filelist.insertLast(self.manifest) self.filelist.extend(extra_files.get_extra_files()) should_skip = options.get_boolean_option(option_dict, 'skip_git_sdist', 'SKIP_GIT_SDIST') if not should_skip: rcfiles = git._find_git_files() if rcfiles: self.filelist.extend(rcfiles) elif os.path.exists(self.manifest): self.read_manifest() ei_cmd = self.get_finalized_command('egg_info') self._add_pbr_defaults() self.filelist.include_pattern("*", prefix=ei_cmd.egg_info)
def generate_authors(git_dir=None, dest_dir='.', option_dict=dict()): """Create AUTHORS file using git commits.""" should_skip = options.get_boolean_option(option_dict, 'skip_authors', 'SKIP_GENERATE_AUTHORS') if should_skip: return start = time.time() old_authors = os.path.join(dest_dir, 'AUTHORS.in') new_authors = os.path.join(dest_dir, 'AUTHORS') if os.path.exists(new_authors) and not os.access(new_authors, os.W_OK): # If there's already an AUTHORS file and it's not writable, just use it return log.info('[pbr] Generating AUTHORS') ignore_emails = '((jenkins|zuul)@review|infra@lists|jenkins@openstack)' if git_dir is None: git_dir = _get_git_directory() if git_dir: authors = [] # don't include jenkins email address in AUTHORS file git_log_cmd = ['log', '--format=%aN <%aE>'] authors += _run_git_command(git_log_cmd, git_dir).split('\n') authors = [a for a in authors if not re.search(ignore_emails, a)] # get all co-authors from commit messages co_authors_out = _run_git_command('log', git_dir) co_authors = re.findall('Co-authored-by:.+', co_authors_out, re.MULTILINE) co_authors = [signed.split(":", 1)[1].strip() for signed in co_authors if signed] authors += co_authors authors = sorted(set(authors)) with open(new_authors, 'wb') as new_authors_fh: if os.path.exists(old_authors): with open(old_authors, "rb") as old_authors_fh: new_authors_fh.write(old_authors_fh.read()) new_authors_fh.write(('\n'.join(authors) + '\n') .encode('utf-8')) stop = time.time() log.info('[pbr] AUTHORS complete (%0.1fs)' % (stop - start))
def generate_authors(git_dir=None, dest_dir='.', option_dict=dict()): """Create AUTHORS file using git commits.""" should_skip = options.get_boolean_option(option_dict, 'skip_authors', 'SKIP_GENERATE_AUTHORS') if should_skip: return start = time.time() old_authors = os.path.join(dest_dir, 'AUTHORS.in') new_authors = os.path.join(dest_dir, 'AUTHORS') # If there's already an AUTHORS file and it's not writable, just use it if (os.path.exists(new_authors) and not os.access(new_authors, os.W_OK)): return log.info('[pbr] Generating AUTHORS') ignore_emails = '(jenkins@review|infra@lists|jenkins@openstack)' if git_dir is None: git_dir = _get_git_directory() if git_dir: authors = [] # don't include jenkins email address in AUTHORS file git_log_cmd = ['log', '--format=%aN <%aE>'] authors += _run_git_command(git_log_cmd, git_dir).split('\n') authors = [a for a in authors if not re.search(ignore_emails, a)] # get all co-authors from commit messages co_authors_out = _run_git_command('log', git_dir) co_authors = re.findall('Co-authored-by:.+', co_authors_out, re.MULTILINE) co_authors = [signed.split(":", 1)[1].strip() for signed in co_authors if signed] authors += co_authors authors = sorted(set(authors)) with open(new_authors, 'wb') as new_authors_fh: if os.path.exists(old_authors): with open(old_authors, "rb") as old_authors_fh: new_authors_fh.write(old_authors_fh.read()) new_authors_fh.write(('\n'.join(authors) + '\n') .encode('utf-8')) stop = time.time() log.info('[pbr] AUTHORS complete (%0.1fs)' % (stop - start))
def checking_reno(self): """Ensure reno is installed and configured. We can't run reno-based commands if reno isn't installed/available, and don't want to if the user isn't using it. """ if hasattr(self, '_has_reno'): return self._has_reno option_dict = self.distribution.get_option_dict('pbr') should_skip = options.get_boolean_option(option_dict, 'skip_reno', 'SKIP_GENERATE_RENO') if should_skip: self._has_reno = False return False try: # versions of reno witout this module will not have the required # feature, hence the import from reno import setup_command # noqa except ImportError: log.info('[pbr] reno was not found or is too old. Skipping ' 'release notes') self._has_reno = False return False conf, output_file, cache_file = setup_command.load_config( self.distribution) if not os.path.exists(os.path.join(conf.reporoot, conf.notespath)): log.info('[pbr] reno does not appear to be configured. Skipping ' 'release notes') self._has_reno = False return False self._files = [output_file, cache_file] log.info('[pbr] Generating release notes') self._has_reno = True return True
def _iter_log_oneline(git_dir=None, option_dict=None): """Iterate over --oneline log entries if possible. This parses the output into a structured form but does not apply presentation logic to the output - making it suitable for different uses. :return: An iterator of (hash, tags_set, 1st_line) tuples, or None if changelog generation is disabled / not available. """ if not option_dict: option_dict = {} should_skip = options.get_boolean_option(option_dict, 'skip_changelog', 'SKIP_WRITE_GIT_CHANGELOG') if should_skip: return if git_dir is None: git_dir = _get_git_directory() if not git_dir: return return _iter_log_inner(git_dir)
def run(self): option_dict = self.distribution.get_option_dict('pbr') # TODO(stephenfin): Remove this (and the entire file) when 5.0 is # released warn_opts = set(option_dict.keys()).intersection(_deprecated_options) warn_env = list(filter(lambda x: os.getenv(x), _deprecated_envs)) if warn_opts or warn_env: msg = ('The autodoc and autodoc_tree features are deprecated in ' '4.2 and will be removed in a future release. You should ' 'use the sphinxcontrib-apidoc Sphinx extension instead. ' 'Refer to the pbr documentation for more information.') if warn_opts: msg += ' Deprecated options: %s' % list(warn_opts) if warn_env: msg += ' Deprecated environment variables: %s' % warn_env log.warn(msg) if git._git_is_installed(): git.write_git_changelog(option_dict=option_dict) git.generate_authors(option_dict=option_dict) tree_index = options.get_boolean_option(option_dict, 'autodoc_tree_index_modules', 'AUTODOC_TREE_INDEX_MODULES') auto_index = options.get_boolean_option(option_dict, 'autodoc_index_modules', 'AUTODOC_INDEX_MODULES') if not os.getenv('SPHINX_DEBUG'): # NOTE(afazekas): These options can be used together, # but they do a very similar thing in a different way if tree_index: self._sphinx_tree() if auto_index: self.generate_autoindex( set(option_dict.get( "autodoc_exclude_modules", [None, ""])[1].split())) self.finalize_options() is_multibuilder_sphinx = version.SemanticVersion.from_pip_string( sphinx.__version__) >= version.SemanticVersion(1, 6) # TODO(stephenfin): Remove support for Sphinx < 1.6 in 4.0 if not is_multibuilder_sphinx: log.warn('[pbr] Support for Sphinx < 1.6 will be dropped in ' 'pbr 4.0. Upgrade to Sphinx 1.6+') # TODO(stephenfin): Remove this at the next MAJOR version bump if self.builders != ['html']: log.warn("[pbr] Sphinx 1.6 added native support for " "specifying multiple builders in the " "'[sphinx_build] builder' configuration option, " "found in 'setup.cfg'. As a result, the " "'[sphinx_build] builders' option has been " "deprecated and will be removed in pbr 4.0. Migrate " "to the 'builder' configuration option.") if is_multibuilder_sphinx: self.builder = self.builders if is_multibuilder_sphinx: # Sphinx >= 1.6 return setup_command.BuildDoc.run(self) # Sphinx < 1.6 for builder in self.builders: self.builder = builder self.finalize_options() self._sphinx_run()