__main__.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. #!/usr/bin/env python
  2. import os
  3. import sys
  4. import logging
  5. import click
  6. # TODO: Remove this check at some point in the future.
  7. # (also remove flake8's 'ignore E402' comments below)
  8. if sys.version_info[0] < 3: # pragma: no cover
  9. raise ImportError('A recent version of Python 3 is required.')
  10. from mkdocs import __version__ # noqa: E402
  11. from mkdocs import utils # noqa: E402
  12. from mkdocs import exceptions # noqa: E402
  13. from mkdocs import config # noqa: E402
  14. from mkdocs.commands import build, gh_deploy, new, serve # noqa: E402
  15. log = logging.getLogger(__name__)
  16. class State:
  17. ''' Maintain logging level.'''
  18. def __init__(self, log_name='mkdocs', level=logging.INFO):
  19. self.logger = logging.getLogger(log_name)
  20. self.logger.propagate = False
  21. stream = logging.StreamHandler()
  22. formatter = logging.Formatter("%(levelname)-7s - %(message)s ")
  23. stream.setFormatter(formatter)
  24. self.logger.addHandler(stream)
  25. self.logger.setLevel(level)
  26. pass_state = click.make_pass_decorator(State, ensure=True)
  27. clean_help = "Remove old files from the site_dir before building (the default)."
  28. config_help = "Provide a specific MkDocs config"
  29. dev_addr_help = ("IP address and port to serve documentation locally (default: "
  30. "localhost:8000)")
  31. strict_help = ("Enable strict mode. This will cause MkDocs to abort the build "
  32. "on any warnings.")
  33. theme_help = "The theme to use when building your documentation."
  34. theme_choices = utils.get_theme_names()
  35. site_dir_help = "The directory to output the result of the documentation build."
  36. use_directory_urls_help = "Use directory URLs when building pages (the default)."
  37. reload_help = "Enable the live reloading in the development server (this is the default)"
  38. no_reload_help = "Disable the live reloading in the development server."
  39. dirty_reload_help = "Enable the live reloading in the development server, but only re-build files that have changed"
  40. commit_message_help = ("A commit message to use when committing to the "
  41. "Github Pages remote branch. Commit {sha} and MkDocs {version} are available as expansions")
  42. remote_branch_help = ("The remote branch to commit to for Github Pages. This "
  43. "overrides the value specified in config")
  44. remote_name_help = ("The remote name to commit to for Github Pages. This "
  45. "overrides the value specified in config")
  46. force_help = "Force the push to the repository."
  47. ignore_version_help = "Ignore check that build is not being deployed with an older version of MkDocs."
  48. def add_options(opts):
  49. def inner(f):
  50. for i in reversed(opts):
  51. f = i(f)
  52. return f
  53. return inner
  54. def verbose_option(f):
  55. def callback(ctx, param, value):
  56. state = ctx.ensure_object(State)
  57. if value:
  58. state.logger.setLevel(logging.DEBUG)
  59. return click.option('-v', '--verbose',
  60. is_flag=True,
  61. expose_value=False,
  62. help='Enable verbose output',
  63. callback=callback)(f)
  64. def quiet_option(f):
  65. def callback(ctx, param, value):
  66. state = ctx.ensure_object(State)
  67. if value:
  68. state.logger.setLevel(logging.ERROR)
  69. return click.option('-q', '--quiet',
  70. is_flag=True,
  71. expose_value=False,
  72. help='Silence warnings',
  73. callback=callback)(f)
  74. common_options = add_options([quiet_option, verbose_option])
  75. common_config_options = add_options([
  76. click.option('-f', '--config-file', type=click.File('rb'), help=config_help),
  77. # Don't override config value if user did not specify --strict flag
  78. # Conveniently, load_config drops None values
  79. click.option('-s', '--strict', is_flag=True, default=None, help=strict_help),
  80. click.option('-t', '--theme', type=click.Choice(theme_choices), help=theme_help),
  81. # As with --strict, set the default to None so that this doesn't incorrectly
  82. # override the config file
  83. click.option('--use-directory-urls/--no-directory-urls', is_flag=True, default=None, help=use_directory_urls_help)
  84. ])
  85. pgk_dir = os.path.dirname(os.path.abspath(__file__))
  86. @click.group(context_settings={'help_option_names': ['-h', '--help']})
  87. @click.version_option(
  88. '{} from {} (Python {})'.format(__version__, pgk_dir, sys.version[:3]),
  89. '-V', '--version')
  90. @common_options
  91. def cli():
  92. """
  93. MkDocs - Project documentation with Markdown.
  94. """
  95. @cli.command(name="serve")
  96. @click.option('-a', '--dev-addr', help=dev_addr_help, metavar='<IP:PORT>')
  97. @click.option('--livereload', 'livereload', flag_value='livereload', help=reload_help, default=True)
  98. @click.option('--no-livereload', 'livereload', flag_value='no-livereload', help=no_reload_help)
  99. @click.option('--dirtyreload', 'livereload', flag_value='dirty', help=dirty_reload_help)
  100. @common_config_options
  101. @common_options
  102. def serve_command(dev_addr, livereload, **kwargs):
  103. """Run the builtin development server"""
  104. logging.getLogger('tornado').setLevel(logging.WARNING)
  105. try:
  106. serve.serve(
  107. dev_addr=dev_addr,
  108. livereload=livereload,
  109. **kwargs
  110. )
  111. except (exceptions.ConfigurationError, OSError) as e: # pragma: no cover
  112. # Avoid ugly, unhelpful traceback
  113. raise SystemExit('\n' + str(e))
  114. @cli.command(name="build")
  115. @click.option('-c', '--clean/--dirty', is_flag=True, default=True, help=clean_help)
  116. @common_config_options
  117. @click.option('-d', '--site-dir', type=click.Path(), help=site_dir_help)
  118. @common_options
  119. def build_command(clean, **kwargs):
  120. """Build the MkDocs documentation"""
  121. try:
  122. build.build(config.load_config(**kwargs), dirty=not clean)
  123. except exceptions.ConfigurationError as e: # pragma: no cover
  124. # Avoid ugly, unhelpful traceback
  125. raise SystemExit('\n' + str(e))
  126. @cli.command(name="gh-deploy")
  127. @click.option('-c', '--clean/--dirty', is_flag=True, default=True, help=clean_help)
  128. @click.option('-m', '--message', help=commit_message_help)
  129. @click.option('-b', '--remote-branch', help=remote_branch_help)
  130. @click.option('-r', '--remote-name', help=remote_name_help)
  131. @click.option('--force', is_flag=True, help=force_help)
  132. @click.option('--ignore-version', is_flag=True, help=ignore_version_help)
  133. @common_config_options
  134. @click.option('-d', '--site-dir', type=click.Path(), help=site_dir_help)
  135. @common_options
  136. def gh_deploy_command(clean, message, remote_branch, remote_name, force, ignore_version, **kwargs):
  137. """Deploy your documentation to GitHub Pages"""
  138. try:
  139. cfg = config.load_config(
  140. remote_branch=remote_branch,
  141. remote_name=remote_name,
  142. **kwargs
  143. )
  144. build.build(cfg, dirty=not clean)
  145. gh_deploy.gh_deploy(cfg, message=message, force=force, ignore_version=ignore_version)
  146. except exceptions.ConfigurationError as e: # pragma: no cover
  147. # Avoid ugly, unhelpful traceback
  148. raise SystemExit('\n' + str(e))
  149. @cli.command(name="new")
  150. @click.argument("project_directory")
  151. @common_options
  152. def new_command(project_directory):
  153. """Create a new MkDocs project"""
  154. new.new(project_directory)
  155. if __name__ == '__main__': # pragma: no cover
  156. cli()