joeyespo/grip

GitHub: joeyespo/grip

一个使用 Python 和 Flask 的本地服务器,用于在提交前预览和核对 GitHub README.md 文件的渲染效果。

Stars: 6783 | Forks: 438

# Grip -- GitHub Readme 即时预览 [![Current version on PyPI](http://img.shields.io/pypi/v/grip.svg)][pypi] [![Say Thanks!](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/joeyespo) 在提交到 GitHub 之前渲染本地 Readme 文件。 Grip 是一个使用 Python 编写的命令行服务器应用程序,它使用 [GitHub markdown API][markdown] 来渲染本地 Readme 文件。样式 和渲染直接来自 GitHub,因此您将确切知道它将如何显示。 对 Readme 的更改将在不 需要页面刷新的情况下即时反映在浏览器中。 ## 动机 有时您只想在提交和推送到 GitHub 之前看到确切的 Readme 结果。 尤其是在进行 [Readme 驱动开发][rdd] 时。 ## 安装 要安装 grip,只需: ``` $ pip install grip ``` 在 OS X 上,您也可以使用 Homebrew 安装: ``` $ brew install grip ``` ## 用法 要渲染存储库的 Readme: ``` $ cd myrepo $ grip * Running on http://localhost:6419/ ``` 现在打开浏览器并访问 [http://localhost:6419](http://localhost:6419/)。 或者使用 `-b` 运行,Grip 将为您打开一个新的浏览器标签页。 您也可以指定端口: ``` $ grip 80 * Running on http://localhost:80/ ``` 或者指定一个明确的文件: ``` $ grip AUTHORS.md * Running on http://localhost:6419/ ``` 或者,您可以直接运行 `grip` 并访问 [localhost:6419/AUTHORS.md][AUTHORS.md] 因为 grip 支持相对 URL。 您可以组合前面的示例。或者指定主机名而不是端口。或者同时提供两者。 ``` $ grip AUTHORS.md 80 * Running on http://localhost:80/ ``` ``` $ grip CHANGES.md 0.0.0.0 * Running on http://0.0.0.0:6419/ ``` ``` $ grip . 0.0.0.0:80 * Running on http://0.0.0.0:80/ ``` 您甚至可以绕过服务器并 **导出** 到单个 HTML 文件,其中所有样式和资源都内联: ``` $ grip --export Exporting to README.html ``` 通过第二个参数控制输出名称: ``` $ grip README.md --export index.html Exporting to index.html ``` 如果您正在导出多个文件,可以使用 `--no-inline` 防止样式内联以节省空间: ``` $ grip README.md --export --no-inline introduction.html Exporting to introduction.html ``` 也支持从 **stdin** 和 **stdout** 读写,允许您将 Grip 与其他程序结合使用: ``` $ cat README.md | grip - * Running on http://localhost:6419/ ``` ``` $ grip AUTHORS.md --export - | bcat ``` ``` $ cat README.md | grip --export - | less ``` 这使您可以通过在终端中直接输入 Markdown 来快速测试效果: ``` $ grip - Hello **world**! ^D * Running on http://localhost:6419/ ``` *注意:`^D` 表示 `Ctrl+D`,它在 Linux 和 OS X 上有效。在 Windows 上,您需要使用 `Ctrl+Z`。* 也支持渲染用户内容,例如 **评论** 和 **问题**,并带有可选的存储库上下文以链接到问题: ``` $ grip --user-content --context=joeyespo/grip * Running on http://localhost:6419/ ``` 有关更多详细信息和选项,请参阅帮助: ``` $ grip -h ``` ## 访问 Grip 力求尽可能接近 GitHub。为了实现这一点,grip 使用 [GitHub 的 Markdown API][markdown],因此对其渲染引擎的更改会立即反映出来,而无需升级 grip。 然而,由于这一点,您可能会遇到 API 的每小时速率限制。如果发生这种情况,grip 提供了一种使用您的凭据访问 API 的方式,以解锁更高的速率限制。 ``` $ grip --user --pass ``` 或者使用 [个人访问令牌][] 并设置空范围(请注意,如果您的 GitHub 账户已设置双重身份验证,则*需要*令牌): ``` $ grip --pass ``` 您可以将这些选项[保存在本地配置文件中](#configuration)。 出于安全考虑,强烈建议您**使用访问令牌而不是密码**。(您也可以通过配置 Grip 从 [密码管理器][keychain-access] 获取密码来保持密码安全。) 还有一个[进行中的分支][offline-renderer]提供 **离线渲染**。一旦这更接近 GitHub 的表现,它将在 CLI 中公开,并最终作为无法访问 API 时的无缝后备引擎使用。 Grip 始终通过 HTTPS 访问 GitHub, 因此您的 README 和凭据受到保护。 ## 提示 以下是社区其他人使用 Grip 的方式。 想分享您自己的吗?[向 joeyespo 致意][twitter] 或 [提交拉取请求](#contributing)。 #### 创建 GitHub Wiki 的本地镜像 ``` $ git clone https://github.com/YOUR_USERNAME/YOUR_REPOSITORY.wiki.git $ cd YOUR_REPOSITORY.wiki $ grip ``` *由 [Joshua Gourneau](https://twitter.com/gourneau/status/636329126643658753) 提供。* #### 从一组链接的 Readme 文件生成 HTML 文档 1. 进入目录: $ cd YOUR_DIR $ export GRIPURL=$(pwd) 2. 包含所有资源,通过设置 `CACHE_DIRECTORY` [配置变量](#configuration): $ echo "CACHE_DIRECTORY = '$(pwd)/assets'" >> ~/.grip/settings.py 3. 使用 Grip 导出所有 Markdown 文件,并将绝对资源路径替换为相对路径: $ for f in *.md; do grip --export $f --no-inline; done $ for f in *.html; do sed -i '' "s?$GRIPURL/??g" $f; done 您可以使用以下命令将 HTML 文件集压缩为 `docs.tgz`: ``` $ tar -czvf docs.tgz `ls | grep [\.]html$` assets ``` 寻找跨平台解决方案?这里有一个等效的 [Python 脚本](https://gist.github.com/mrexmelle/659abc02ae1295d60647)。 *由 [Matthew R. Tanudjaja](https://github.com/mrexmelle) 提供。* ## 配置 要自定义 Grip,请创建 `~/.grip/settings.py`,然后添加以下一个或多个变量: - `HOST`:未作为 CLI 参数提供时使用的主机,默认为 `localhost` - `PORT`:未作为 CLI 参数提供时使用的端口,默认为 `6419` - `DEBUG`:是否在发生错误时使用 Flask 的调试器,默认为 `False` - `DEBUG_GRIP`:发生错误时打印扩展信息,默认为 `False` - `API_URL`:GitHub API 的基本 URL,例如 GitHub Enterprise 实例的 URL。默认为 `https://api.github.com` - `CACHE_DIRECTORY`:相对于 `~/.grip` 的缓存资源目录(此值会通过以下过滤器运行:`CACHE_DIRECTORY.format(version=__version__)`),默认为 `'cache-{version}'` - `AUTOREFRESH`:文件更改时是否自动刷新 Readme 内容,默认为 `True` - `QUIET`:不打印扩展信息,默认为 `False` - `STYLE_URLS`:将添加到渲染页面的其他 URL,默认为 `[]` - `USERNAME`:未作为 CLI 参数提供时使用的用户名,默认为 `None` - `PASSWORD`:未作为 CLI 参数提供时使用的密码或 [个人访问令牌][](*请不要在此处保存密码*)。相反,请使用访问令牌或在此代码中从 [密码管理器][keychain-access] 获取密码,默认为 `None` 请注意这是一个 Python 文件。如果您看到 `'X' is not defined` 错误, 您可能遗漏了某些引号。例如: ``` USERNAME = 'your-username' PASSWORD = 'your-personal-access-token' ``` #### 环境变量 - `GRIPHOME`:指定替代的 `settings.py` 位置,默认为 `~/.grip` - `GRIPURL`:Grip 服务器的 URL,默认为 `/__/grip` #### 高级用法 此文件是一个正常的 Python 脚本,因此您可以添加更高级的配置。 例如,要从环境变量读取设置并在未设置时提供默认值: ``` PORT = os.environ.get('GRIP_PORT', 8080) ``` ## API 您可以直接使用 Python 访问 API,并在您自己的项目中使用它: ``` from grip import serve serve(port=8080) * Running on http://localhost:8080/ ``` 直接运行主程序: ``` from grip import main main(argv=['-b', '8080']) * Running on http://localhost:8080/ ``` 或访问底层的 Flask 应用程序以获得更大的灵活性: ``` from grip import create_app grip_app = create_app(user_content=True) # 使用于您自己的应用 ``` ### 文档 #### 服务 运行本地服务器并在浏览器中访问位于 `path` 的 Readme 文件。 ``` serve(path=None, host=None, port=None, user_content=False, context=None, username=None, password=None, render_offline=False, render_wide=False, render_inline=False, api_url=None, title=None, autorefresh=True, browser=False, grip_class=None) ``` - `path`:要渲染的文件名,或包含 Readme 文件的目录,默认为当前工作目录 - `host`:监听的主机,默认为 HOST 配置变量 - `port`:监听的端口,默认为 PORT 配置变量 - `user_content`:是否将文档渲染为 [用户内容][],例如用户评论或问题 - `context`:当 `user_content` 为 true 时使用的项目上下文, 格式为 `username/project` - `username`:用于向 GitHub 验证以扩展 API 限制的用户名 - `password`:用于向 GitHub 验证以扩展 API 限制的密码 - `render_offline`:是否使用 [Python-Markdown][] 本地渲染注意:这是一项正在进行中的工作) - `render_wide`:是否渲染宽页面,默认为 `False`(当与 `user_content` 一起使用时无效) - `render_inline`:是否将样式内联到 HTML 文件中 - `api_url`:GitHub API 的不同基本 URL,例如 GitHub Enterprise 实例。默认为公共 API https://api.github.com。 - `title`:页面标题,默认为从 `path` 推导 - `autorefresh`:当 Readme 文件更改时自动更新渲染内容,默认为 `True` - `browser`:服务器启动后打开浏览器标签页,默认为 `False` - `grip_class`:使用自定义 [Grip 类](#class-gripflask) #### 导出 将指定的 Readme 文件写入 HTML 文件,其中包含内联样式和资源。 ``` export(path=None, user_content=False, context=None, username=None, password=None, render_offline=False, render_wide=False, render_inline=True, out_filename=None, api_url=None, title=None, quiet=None, theme='light', grip_class=None) ``` - `path`:要渲染的文件名,或包含 Readme 文件的目录,默认为当前工作目录 - `user_content`:是否将文档渲染为 [用户内容][],例如用户评论或问题 - `context`:当 `user_content` 为 true 时使用的项目上下文, 格式为 `username/project` - `username`:用于向 GitHub 验证以扩展 API 限制的用户名 - `password`:用于向 GitHub 验证以扩展 API 限制的密码 - `render_offline`:是否使用 [Python-Markdown][] 本地渲染(注意:这是一项正在进行中的工作) - `render_wide`:是否渲染宽页面,默认为 `False`(当与 `user_content` 一起使用时无效) - `render_inline`:是否将样式内联到 HTML 文件中(注意:与其它 API 函数不同,默认为 `True`) - `out_filename`:要写入的文件名,默认为 `.html` - `api_url`:GitHub API 的不同基本 URL,例如 GitHub Enterprise 实例。默认为公共 API https://api.github.com。 - `title`:页面标题,默认为从 `path` 推导 - `quiet`:不打印到终端 - `theme`:查看 Markdown 文件的主题(浅色或深色模式)。有效选项为 ("light", "dark")。默认为 "light"。 - `grip_class`:使用自定义 [Grip 类](#class-gripflask) #### 创建应用 创建一个 Flask 应用程序,用于渲染和提供 Readme 文件。 这与 `serve` 和 `export` 使用相同的应用程序,并在可用时初始化缓存, 使用缓存的样式。 ``` create_app(path=None, user_content=False, context=None, username=None, password=None, render_offline=False, render_wide=False, render_inline=False, api_url=None, title=None, text=None, grip_class=None) ``` - `path`:要渲染的文件名,或包含 Readme 文件的目录,默认为当前工作目录 - `user_content`:是否将文档渲染为 [用户内容][],例如用户评论或问题 - `context`:当 `user_content` 为 true 时使用的项目上下文, 格式为 `username/project` - `username`:用于向 GitHub 验证以扩展 API 限制的用户名 - `password`:用于向 GitHub 验证以扩展 API 限制的密码 - `render_offline`:是否使用 [Python-Markdown][] 本地渲染(注意:这是一项正在进行中的工作) - `render_wide`:是否渲染宽页面,默认为 `False`(当与 `user_content` 一起使用时无效) - `render_inline`:是否将样式内联到 HTML 文件中 - `api_url`:GitHub API 的不同基本 URL,例如 GitHub Enterprise 实例。默认为公共 API https://api.github.com。 - `title`:页面标题,默认为从 `path` 推导 - `text`:要渲染的 Markdown 字符串或流,而不是从 `path` 加载(注意:`path` 可用于设置页面标题) - `grip_class`:使用自定义 [Grip 类](#class-gripflask) #### 渲染应用 渲染由 `create_app` 创建的应用程序并返回 HTML, 该 HTML 通常会出现在访问该路由时。 ``` render_app(app, route='/') ``` - `app`:要渲染的 Flask 应用程序 - `route`:要渲染的路由,默认为 `'/'` #### 渲染内容 在不使用缓存的情况下渲染指定的 Markdown 文本。 ``` render_content(text, user_content=False, context=None, username=None, password=None, render_offline=False, api_url=None, title=None) ``` - `text`:要渲染的 Markdown 文本 - `user_content`:是否将文档渲染为 [用户内容][],例如用户评论或问题 - `context`:当 `user_content` 为 true 时使用的项目上下文, 格式为 `username/project` - `username`:用于向 GitHub 验证以扩展 API 限制的用户名 - `password`:用于向 GitHub 验证以扩展 API 限制的密码 - `render_offline`:是否使用 [Python-Markdown][] 本地渲染(注意:这是一项正在进行中的工作) - `api_url`:GitHub API 的不同基本 URL,当不使用离线渲染器时这是必需的。 - `title`:页面标题,默认为从 `path` 推导 #### 渲染页面 渲染来自指定路径或文本的 Markdown,不使用缓存, 并返回一个 HTML 页面,该页面类似于 GitHub Readme 视图。 ``` render_page(path=None, user_content=False, context=None, username=None, password=None, render_offline=False, render_wide=False, render_inline=False, api_url=None, title=None, text=None, quiet=None, theme='light', grip_class=None) ``` - `path`:用于页面标题的路径,如果为 None 则渲染 `'README.md'` - `user_content`:是否将文档渲染为 [用户内容][],例如用户评论或问题 - `context`:当 `user_content` 为 true 时使用的项目上下文, 格式为 `username/project` - `username`:用于向 GitHub 验证以扩展 API 限制的用户名 - `password`:用于向 GitHub 验证以扩展 API 限制的密码 - `render_offline`:是否使用 [Python-Markdown][] 离线渲染(注意:这是一项正在进行中的工作) - `render_wide`:是否渲染宽页面,默认为 `False`(当与 `user_content` 一起使用时无效) - `render_inline`:是否将样式内联到 HTML 文件中 - `api_url`:GitHub API 的不同基本 URL,例如 GitHub Enterprise 实例。默认为公共 API https://api.github.com。 - `title`:页面标题,默认为从 `path` 推导 - `text`:要渲染的 Markdown 字符串或流,而不是从 `path` 加载(注意:`path` 可用于设置页面标题) - `quiet`:不打印到终端 - `theme`:查看 Markdown 文件的主题(浅色或深色模式)。有效选项为 ("light", "dark")。默认为 "light"。 - `grip_class`:使用自定义 [Grip 类](#class-gripflask) #### 清除缓存 清除缓存的样式和资源。 ``` clear_cache(grip_class=None) ``` #### 主函数 使用指定的参数运行 Grip。 ``` main(argv=None, force_utf8=True) ``` - `argv`:要运行的参数,默认为 `sys.argv[1:]` - `force_utf8`:将当前 Python 实例的默认编码设置为 `utf-8`。这对 Python 3 没有影响,因为 Unicode 默认已处理。 ### 类 #### 类 Grip(Flask) 一个可以服务包含 README 的文件或目录的 Flask 应用程序。 ``` Grip(source=None, auth=None, renderer=None, assets=None, render_wide=None, render_inline=None, title=None, autorefresh=None, quiet=None, theme='light', grip_url=None, static_url_path=None, instance_path=None, **kwargs) ``` ##### 默认渲染器 返回使用当前配置的默认渲染器。仅在构造函数中未设置 renderer 时使用。 ``` Grip.default_renderer() ``` ##### 默认资源管理器 返回使用当前配置的默认资源管理器。仅在构造函数中未设置 asset_manager 时使用。 ``` Grip.default_asset_manager() ``` ##### 添加内容类型 如果缺少 `application/x-font-woff` 和 `application/octet-stream` 内容类型,则添加它们。在初始化时覆盖以添加其他内容类型。 ``` Grip.add_content_types() ``` ##### 清除缓存 清除已下载的资源。 ``` Grip.clear_cache() ``` ##### 渲染 渲染应用程序并返回将通常在浏览器中显示的 HTML Unicode。 ``` Grip.render(route=None) ``` - `route`:要渲染的路由,默认为 `/` ##### 运行 启动服务器以渲染 Readme。此方法内部调用 [Flask.run][]。 ``` Grip.run(host=None, port=None, debug=None, use_reloader=None, open_browser=False) ``` - `host`:要监听的主机名。将其设置为 `'0.0.0.0'` 可使服务器对外部也可访问,默认为 `'localhost'` - `port`:Web 服务器的端口,默认为 `6419` - `debug`:如果提供,则启用或禁用调试模式。请参见 [Flask.debug][]。 - `use_reloader`:如果模块已更改,是否自动重新启动 Python 进程。默认为 `False`,除非指定 `DEBUG_GRIP` 设置。 - `open_browser`:服务器启动时打开浏览器到该地址 #### 类 AlreadyRunningError(RuntimeError) 当 `Grip.run` 在服务器已运行时调用时引发。 ``` AlreadyRunningError() ``` #### 类 ReadmeNotFoundError(NotFoundError 或 IOError) 当指定的 Readme 找不到时引发。 ``` ReadmeNotFoundError(path=None, message=None) ``` #### 类 ReadmeAssetManager(object) 管理用于 Readme 页面的样式和字体资源。这是一个抽象基类。 ``` ReadmeAssetManager(cache_path, style_urls=None) ``` #### 类 GitHubAssetManager(ReadmeAssetManager) 管理用于 Readme 页面的样式和字体资源。将 cache_path 设置为 None 以禁用缓存。 #### 类 ReadmeReader(object) 从 URL 子路径读取 Readme 内容。这是一个抽象基类。 ``` ReadmeReader() ``` #### 类 DirectoryReader(ReadmeReader) 从 URL 子路径读取 Readme 文件。 ``` DirectoryReader(path=None, silent=False) ``` #### 类 TextReader(ReadmeReader) 从提供的 Unicode 字符串读取 Readme 内容。 ``` TextReader(text, display_filename=None) ``` #### 类 StdinReader(TextReader) 从标准输入读取 Readme 文本。 ``` StdinReader(display_filename=None) ``` #### 类 ReadmeRenderer(object) 渲染 Readme。这是一个抽象基类。 ``` ReadmeRenderer(user_content=None, context=None) ``` #### 类 GitHubRenderer(ReadmeRenderer) 使用 GitHub Markdown API 渲染指定的 Readme。 ``` GitHubRenderer(user_content=None, context=None, api_url=None, raw=None) ``` #### 类 OfflineRenderer(ReadmeRenderer) 使用纯 Python 本地渲染指定的 Readme。注意:这目前是一项未完成的功能。 ``` OfflineRenderer(user_content=None, context=None) ``` ### 常量 #### SUPPORTED_TITLES GitHub 上常见的 Markdown 文件标题。 ``` SUPPORTED_TITLES = ['README', 'Home'] ``` - `filename`:要读取的 UTF-8 文件。 #### SUPPORTED_EXTENSIONS 由 [GitHub][markdown] 定义的受支持扩展名。 ``` SUPPORTED_EXTENSIONS = ['.md', '.markdown'] ``` #### DEFAULT_FILENAMES 此常量包含 Grip 查找的文件名(未提供文件时)。 ``` DEFAULT_FILENAMES = [title + ext for title in SUPPORTED_TITLES for ext in SUPPORTED_EXTENSIONS] ``` #### DEFAULT_FILENAME 此常量包含默认的 Readme 文件名,即: ``` DEFAULT_FILENAME = DEFAULT_FILENAMES[0] # README.md ``` #### DEFAULT_GRIPHOME 此常量指向如果未指定 `GRIPHOME` [环境变量](#environment-variables) 的默认值。 ``` DEFAULT_GRIPHOME = '~/.grip' ``` #### DEFAULT_GRIPURL Grip 服务器及其所有资源的默认 URL: ``` DEFAULT_GRIPURL = '/__/grip' ``` #### DEFAULT_API_URL 默认的 app_url 值: ``` DEFAULT_API_URL = 'https://api.github.com' ``` ## 测试 安装软件包和测试依赖项: ``` $ pip install -e .[tests] ``` 使用 [pytest][] 运行测试: ``` $ pytest ``` 或者在您进行修改时重新运行测试,使用 [pytest-watch][]: ``` $ ptw ``` #### 外部假设测试 如果遇到 Grip 问题,很可能是因为对 GitHub API 的假设已被破坏。要验证这一点,请运行: ``` $ pytest -m assumption ``` 由于外部假设依赖互联网连接,您可能希望在本地开发时跳过它们。使用 `-x` 在第一次失败时停止测试: ``` $ pytest -xm "not assumption" ``` 或者使用 [pytest-watch][]: ``` $ ptw -- -xm "not assumption" ``` ## 贡献 1. 查看开放问题或打开新问题以开始讨论您的功能想法或发现的错误 2. 叉出存储库并进行更改 3. 打开新的拉取请求 如果您使用此软件经常?Say Thanks! :smiley:
标签:GitHub API, Homebrew, HTTP 服务, Markdown 渲染, PyPI, Python, RDD, Readme-driven development, Readme 渲染, SEO 预览, 前端渲染, 即时预览, 开发辅助, 文档工具, 无后门, 本地服务器, 本地预览, 网页预览, 逆向工具, 静态站点