diff options
author | JensDiemer <git@jensdiemer.de> | 2020-01-29 14:16:15 +0100 |
---|---|---|
committer | JensDiemer <git@jensdiemer.de> | 2020-02-01 13:22:09 +0100 |
commit | 67c192d8e852979fae9d264b32e86a5de63b3318 (patch) | |
tree | 7721735702f853703c149c1c82ff24db7937b71d | |
parent | 5c2ac71e9f92692dfcd152b8b449c7775bda9319 (diff) | |
download | creole-67c192d8e852979fae9d264b32e86a5de63b3318.tar.gz |
Helper to build and upload to PyPi, with prechecks and update README.rst from README.creole
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | creole/__init__.py | 11 | ||||
-rw-r--r-- | creole/setup_utils.py | 254 | ||||
-rw-r--r-- | pyproject.toml | 12 |
4 files changed, 238 insertions, 43 deletions
@@ -4,9 +4,13 @@ *.egg-info /dist /build +/publish.log .idea /poetry.lock /.coverage .tox + +# Will be generated from README.creole and added to sdist +/README.rst diff --git a/creole/__init__.py b/creole/__init__.py index 25dd09c..e5d6324 100644 --- a/creole/__init__.py +++ b/creole/__init__.py @@ -1,18 +1,13 @@ -# coding: utf-8 - """ python-creole ~~~~~~~~~~~~~ - :homepage: - http://code.google.com/p/python-creole/ - :sourcecode: - http://github.com/jedie/python-creole + https://github.com/jedie/python-creole :PyPi: - http://pypi.python.org/pypi/python-creole/ + https://pypi.org/project/python-creole/ :copyleft: 2008-2020 by python-creole team, see AUTHORS for more details. :license: GNU GPL v3 or above, see LICENSE for more details. @@ -28,7 +23,7 @@ from creole.emitter.html2textile_emitter import TextileEmitter from creole.parser.creol2html_parser import CreoleParser from creole.parser.html_parser import HtmlParser -__version__ = "1.4.1" +__version__ = "1.4.2.dev1" __api__ = "1.0" # Creole 1.0 spec - http://wikicreole.org/ VERSION_STRING = __version__ # remove in future diff --git a/creole/setup_utils.py b/creole/setup_utils.py index 17623f5..c45e194 100644 --- a/creole/setup_utils.py +++ b/creole/setup_utils.py @@ -1,5 +1,3 @@ -# coding: utf-8 - """ utils for distutils setup ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -23,9 +21,9 @@ try: from creole.setup_utils import get_long_description except ImportError: - if "register" in sys.argv or "sdist" in sys.argv or "--long-description" in sys.argv: + if 'register' in sys.argv or 'sdist' in sys.argv or '--long-description' in sys.argv: etype, evalue, etb = sys.exc_info() - evalue = etype("%s - Please install python-creole >= v0.8 - e.g.: pip install python-creole" % evalue) + evalue = etype('%s - Please install python-creole >= v0.8 - e.g.: pip install python-creole' % evalue) raise etype, evalue, etb long_description = None else: @@ -44,15 +42,18 @@ import codecs import os +import shutil +import subprocess import sys import warnings +from pathlib import Path -from creole import creole2html, html2rest +from creole import __version__, creole2html, html2rest from creole.shared.unknown_tags import raise_unknown_node, transparent_unknown_nodes RAISE_ERRORS_ARGS = ( - "check", "register", "sdist", "bdist", "upload", - "--long-description", "--restructuredtext", + 'check', 'register', 'sdist', 'bdist', 'upload', + '--long-description', '--restructuredtext', ) @@ -70,13 +71,16 @@ def should_raise_errors(): return False -def get_long_description(package_root, filename="README.creole", raise_errors=None): +def get_long_description(package_root, filename='README.creole', raise_errors=None): """ read README file and convert it on-the-fly to ReStructuredText. """ + + warnings.warn('get_long_description() will be removed in the future', DeprecationWarning) + if raise_errors is None: raise_errors = should_raise_errors() if raise_errors: - sys.stderr.write("Test creole2rest and raise an error, if rendering failed...\n") + sys.stderr.write('Test creole2rest and raise an error, if rendering failed...\n') # raise a error if a unknown node found unknown_emit = raise_unknown_node else: @@ -84,10 +88,10 @@ def get_long_description(package_root, filename="README.creole", raise_errors=No unknown_emit = transparent_unknown_nodes filepath = os.path.join(package_root, filename) - long_description_origin = "" + long_description_origin = '' try: # Read creole README - f = codecs.open(filepath, "r", encoding="utf-8") + f = codecs.open(filepath, 'r', encoding='utf-8') long_description_origin = f.read().strip() f.close() @@ -97,14 +101,14 @@ def get_long_description(package_root, filename="README.creole", raise_errors=No # convert html to ReSt long_description_rest = html2rest( long_description_html, - emitter_kwargs={"unknown_emit": unknown_emit} + emitter_kwargs={'unknown_emit': unknown_emit} ) except Exception: if raise_errors: raise # Don't raise the error e.g. in ./setup install process evalue = sys.exc_info()[1] - long_description_rest = f"[Error: {evalue}]\n{long_description_origin}" + long_description_rest = f'[Error: {evalue}]\n{long_description_origin}' else: if raise_errors: # Test created ReSt code like PyPi does it. @@ -112,31 +116,225 @@ def get_long_description(package_root, filename="README.creole", raise_errors=No try: pypi_rest2html(long_description_rest) except SystemExit as e: - msg = f"Error creole2rest self test failed: rest2html() exist with status code: {e.args[0]}\n" + msg = f'Error creole2rest self test failed: rest2html() exist with status code: {e.args[0]}\n' sys.stderr.write(msg) sys.exit(msg) except Exception as e: - sys.exit(f"ReSt2html error: {e}") + sys.exit(f'ReSt2html error: {e}') else: - if "check" in sys.argv: - print("Generating creole to ReSt to html, ok.") + if 'check' in sys.argv: + print('Generating creole to ReSt to html, ok.') return long_description_rest -def _get_long_description(*args, **kwargs): - msg = "'GetLongDescription' is deprecated, use 'get_long_description' instead." - if should_raise_errors(): - raise DeprecationWarning(msg) +def update_rst_readme(package_root, filename='README.creole'): + """ + Generate README.rst from README.creole + """ + assert isinstance(package_root, Path) + assert package_root.is_dir(), f'Directory not found: {package_root}' + creole_readme_path = Path(package_root, filename) + assert creole_readme_path.is_file(), f'File not found: {creole_readme_path}' + + rest_readme_path = creole_readme_path.with_suffix('.rst') + print( + f'Generate {rest_readme_path.name} from {creole_readme_path.name}', + end='...', flush=True + ) + + with creole_readme_path.open('r') as f: + creole_readme = f.read().strip() + + # convert creole into html + html_readme = creole2html(creole_readme) + + # convert html to ReSt + rest_readme = html2rest( + html_readme, + emitter_kwargs={ + 'unknown_emit': raise_unknown_node # raise a error if a unknown node found + } + ) + + with rest_readme_path.open('w') as f: + f.write(rest_readme) + + print('done.') + + +def update_creole_rst_readme(): + update_rst_readme( + package_root=Path(__file__).parent.parent, + filename='README.creole' + ) + + +def verbose_check_output(*args, log=None): + """ 'verbose' version of subprocess.check_output() """ + call_info = 'Call: %r' % ' '.join(args) + try: + output = subprocess.check_output( + args, universal_newlines=True, stderr=subprocess.STDOUT + ) + except subprocess.CalledProcessError as err: + print('\n***ERROR:') + print(err.output) + if log is not None: + log.write(err.output) + raise + return call_info, output + + +def verbose_check_call(*args): + """ 'verbose' version of subprocess.check_call() """ + print('\tCall: %r\n' % ' '.join(args)) + subprocess.check_call(args, universal_newlines=True) + + +def confirm(txt): + print(f'\n{txt}') + if input('\nPublish anyhow? (Y/N)').lower() not in ('y', 'j'): + print('Bye.') + sys.exit(-1) + + +def poetry_publish(package_root, version, filename='README.creole', log_filename='publish.log'): + """ + Helper to build and upload to PyPi, with prechecks and update README.rst from README.creole + + Optional arguments are passed to `poetry publish` e.g.: + + $ poetry config repositories.testpypi https://test.pypi.org/simple + $ poetry run publish --repository=testpypi + + Build and upload to PyPi, if... + ... __version__ doesn't contains 'dev' + ... we are on git "master" branch + ... git repository is 'clean' (no changed files) + + Upload with 'poetry', git tag the current version and git push --tag + + The cli arguments will be pass to 'twine'. So this is possible: + * Display 'twine' help page...: ./setup.py publish --help + * use testpypi................: ./setup.py publish --repository=test + + add this to poetry pyproject.toml, e.g.: + + [tool.poetry.scripts] + publish = 'foo.bar:publish' + + based on: + https://github.com/jedie/python-code-snippets/blob/master/CodeSnippets/setup_publish.py + """ + update_rst_readme(package_root=package_root, filename=filename) + + for key in ('dev', 'rc'): + if key in version: + confirm(f'WARNING: Version contains {key!r}: v{version}\n') + break + + print('\nCheck if we are on "master" branch:') + call_info, output = verbose_check_output('git', 'branch', '--no-color') + print(f'\t{call_info}') + if '* master' in output: + print('OK') + else: + confirm(f'\nNOTE: It seems you are not on "master":\n{output}') + + print('\ncheck if if git repro is clean:') + call_info, output = verbose_check_output('git', 'status', '--porcelain') + print(f'\t{call_info}') + if output == '': + print('OK') + else: + print('\n *** ERROR: git repro not clean:') + print(output) + sys.exit(-1) + + print('\nRun "poetry check":') + call_info, output = verbose_check_output('poetry', 'check') + if 'All set!' not in output: + print(output) + confirm('Check failed!') + else: + print('OK') + + print('\ncheck if pull is needed') + verbose_check_call('git', 'fetch', '--all') + call_info, output = verbose_check_output('git', 'log', 'HEAD..origin/master', '--oneline') + print(f'\t{call_info}') + if output == '': + print('OK') + else: + print('\n *** ERROR: git repro is not up-to-date:') + print(output) + sys.exit(-1) + verbose_check_call('git', 'push') + + print('\nCleanup old builds:') + + def rmtree(path): + path = os.path.abspath(path) + if os.path.isdir(path): + print('\tremove tree:', path) + shutil.rmtree(path) + rmtree('./dist') + rmtree('./build') + + print(f'\nSet new version to: v{version}') + verbose_check_call('poetry', 'version', version) + + print('\nbuild but do not upload...') + + with open(log_filename, 'a') as log: + log.write('\n') + log.write('-' * 100) + log.write('\n') + call_info, output = verbose_check_output('poetry', 'build', log=log) + print(f'\t{call_info}') + log.write(call_info) + log.write(output) + + print(f'Build log file is here: {log_filename!r}') + + git_tag = f'v{version}' + + print('\ncheck git tag') + call_info, output = verbose_check_output( + 'git', 'log', 'HEAD..origin/master', '--oneline', + ) + if git_tag in output: + print(f'\n *** ERROR: git tag {git_tag!r} already exists!') + print(output) + sys.exit(-1) else: - warnings.warn(msg, DeprecationWarning) - return get_long_description(*args, **kwargs) + print('OK') + print('\nUpload to PyPi via poetry:') + args = ['poetry', 'publish'] + sys.argv[1:] + verbose_check_call(*args) -GetLongDescription = _get_long_description # for backward-compatibility + print('\ngit tag version') + verbose_check_call('git', 'tag', git_tag) + + print('\ngit push tag to server') + verbose_check_call('git', 'push', '--tags') + + sys.exit(0) + + +def publish_python_creole(): + """ + Publish python-creole to PyPi + Call this via: + $ poetry run publish + """ + poetry_publish( + package_root=Path(__file__).parent.parent, + version=__version__, + ) -if __name__ == "__main__": - package_root = os.path.abspath("../") - long_description = get_long_description(package_root) - print(long_description) +if __name__ == '__main__': + update_creole_rst_readme() diff --git a/pyproject.toml b/pyproject.toml index b821124..cb88369 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,14 +1,10 @@ [tool.poetry] name = 'python-creole' -version = '1.4.1' +version = "1.4.2.dev1" description = 'python-creole is an open-source (GPL) markup converter in pure Python for: creole2html, html2creole, html2ReSt, html2textile' -# TODO: convert it: -readme='README.creole' - -# on the way, see: https://github.com/python-poetry/poetry/pull/1166/ -# https://packaging.python.org/guides/making-a-pypi-friendly-readme/#including-your-readme-in-your-package-s-metadata -# long_description_content_type = 'text/plain' +# Will be generated from README.creole with: 'poetry run update_rst_readme' +readme='README.rst' license = 'GPL-3.0-or-later' authors = ['Jens Diemer <python-creole@jensdiemer.de>'] @@ -57,6 +53,8 @@ creole2html = 'creole.cmdline:cli_creole2html' html2creole = 'creole.cmdline:cli_html2creole' html2rest = 'creole.cmdline:cli_html2rest' html2textile = 'creole.cmdline:cli_html2textile' +update_rst_readme = 'creole.setup_utils:update_creole_rst_readme' +publish = 'creole.setup_utils:publish_python_creole' [build-system] requires = ['poetry>=0.12'] |