From c74ff2a16e47bdf31f8ad17bbfbe2da5d03803c6 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 10 Jan 2014 19:26:04 -0800 Subject: [PATCH 01/18] Import paramiko.org repository @ 3ac370054ef10fb060fe75fff25fe3a70ecc02c0 --- site/_static/logo.png | Bin 0 -> 6401 bytes site/_templates/rss.xml | 19 ++++++ site/blog.py | 140 ++++++++++++++++++++++++++++++++++++++ site/blog.rst | 16 +++++ site/blog/first-post.rst | 7 ++ site/blog/second-post.rst | 7 ++ site/conf.py | 55 +++++++++++++++ site/contact.rst | 11 +++ site/contributing.rst | 19 ++++++ site/dev-requirements.txt | 3 + site/index.rst | 31 +++++++++ site/installing.rst | 105 ++++++++++++++++++++++++++++ site/tasks.py | 19 ++++++ 13 files changed, 432 insertions(+) create mode 100644 site/_static/logo.png create mode 100644 site/_templates/rss.xml create mode 100644 site/blog.py create mode 100644 site/blog.rst create mode 100644 site/blog/first-post.rst create mode 100644 site/blog/second-post.rst create mode 100644 site/conf.py create mode 100644 site/contact.rst create mode 100644 site/contributing.rst create mode 100644 site/dev-requirements.txt create mode 100644 site/index.rst create mode 100644 site/installing.rst create mode 100644 site/tasks.py diff --git a/site/_static/logo.png b/site/_static/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..bc76697e6ac461a259dcbf0bb04edea99b161341 GIT binary patch literal 6401 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 + + + + {{ title }} + {{ link }} + {{ description }} + {{ date }} + {% for link, title, desc, date in posts %} + + {{ link }} + {{ link }} + <![CDATA[{{ title }}]]> + + {{ date }} + + {% endfor %} + + diff --git a/site/blog.py b/site/blog.py new file mode 100644 index 0000000..3b129eb --- /dev/null +++ b/site/blog.py @@ -0,0 +1,140 @@ +from collections import namedtuple +from datetime import datetime +import time +import email.utils + +from sphinx.util.compat import Directive +from docutils import nodes + + +class BlogDateDirective(Directive): + """ + Used to parse/attach date info to blog post documents. + + No nodes generated, since none are needed. + """ + has_content = True + + def run(self): + # Tag parent document with parsed date value. + self.state.document.blog_date = datetime.strptime( + self.content[0], "%Y-%m-%d" + ) + # Don't actually insert any nodes, we're already done. + return [] + +class blog_post_list(nodes.General, nodes.Element): + pass + +class BlogPostListDirective(Directive): + """ + Simply spits out a 'blog_post_list' temporary node for replacement. + + Gets replaced at doctree-resolved time - only then will all blog post + documents be written out (& their date directives executed). + """ + def run(self): + return [blog_post_list('')] + + +Post = namedtuple('Post', 'name doc title date opener') + +def get_posts(app): + # Obtain blog posts + post_names = filter(lambda x: x.startswith('blog/'), app.env.found_docs) + posts = map(lambda x: (x, app.env.get_doctree(x)), post_names) + # Obtain common data used for list page & RSS + data = [] + for post, doc in sorted(posts, key=lambda x: x[1].blog_date, reverse=True): + # Welp. No "nice" way to get post title. Thanks Sphinx. + title = doc[0][0][0] + # Date. This may or may not end up reflecting the required + # *input* format, but doing it here gives us flexibility. + date = doc.blog_date + # 1st paragraph as opener. TODO: allow a role or something marking + # where to actually pull from? + opener = doc.traverse(nodes.paragraph)[0] + data.append(Post(post, doc, title, date, opener)) + return data + +def replace_blog_post_lists(app, doctree, fromdocname): + """ + Replace blog_post_list nodes with ordered list-o-links to posts. + """ + # Obtain blog posts + post_names = filter(lambda x: x.startswith('blog/'), app.env.found_docs) + posts = map(lambda x: (x, app.env.get_doctree(x)), post_names) + # Build "list" of links/etc + post_links = [] + for post, doc, title, date, opener in get_posts(app): + # Link itself + uri = app.builder.get_relative_uri(fromdocname, post) + link = nodes.reference('', '', refdocname=post, refuri=uri) + # Title, bolded. TODO: use 'topic' or something maybe? + link.append(nodes.strong('', title)) + date = date.strftime("%Y-%m-%d") + # Meh @ not having great docutils nodes which map to this. + html = '
%s
' % date + timestamp = nodes.raw(text=html, format='html') + # NOTE: may group these within another element later if styling + # necessitates it + group = [timestamp, nodes.paragraph('', '', link), opener] + post_links.extend(group) + + # Replace temp node(s) w/ expanded list-o-links + for node in doctree.traverse(blog_post_list): + node.replace_self(post_links) + +def rss_timestamp(timestamp): + # Use horribly inappropriate module for its magical daylight-savings-aware + # timezone madness. Props to Tinkerer for the idea. + return email.utils.formatdate( + time.mktime(timestamp.timetuple()), + localtime=True + ) + +def generate_rss(app): + # Meh at having to run this subroutine like 3x per build. Not worth trying + # to be clever for now tho. + posts_ = get_posts(app) + # LOL URLs + root = app.config.rss_link + if not root.endswith('/'): + root += '/' + # Oh boy + posts = [ + ( + root + app.builder.get_target_uri(x.name), + x.title, + str(x.opener[0]), # Grab inner text element from paragraph + rss_timestamp(x.date), + ) + for x in posts_ + ] + location = 'blog/rss.xml' + context = { + 'title': app.config.project, + 'link': root, + 'atom': root + location, + 'description': app.config.rss_description, + # 'posts' is sorted by date already + 'date': rss_timestamp(posts_[0].date), + 'posts': posts, + } + yield (location, context, 'rss.xml') + +def setup(app): + # Link in RSS feed back to main website, e.g. 'http://paramiko.org' + app.add_config_value('rss_link', None, '') + # Ditto for RSS description field + app.add_config_value('rss_description', None, '') + # Interprets date metadata in blog post documents + app.add_directive('date', BlogDateDirective) + # Inserts blog post list node (in e.g. a listing page) for replacement + # below + app.add_node(blog_post_list) + app.add_directive('blog-posts', BlogPostListDirective) + # Performs abovementioned replacement + app.connect('doctree-resolved', replace_blog_post_lists) + # Generates RSS page from whole cloth at page generation step + app.connect('html-collect-pages', generate_rss) diff --git a/site/blog.rst b/site/blog.rst new file mode 100644 index 0000000..af9651e --- /dev/null +++ b/site/blog.rst @@ -0,0 +1,16 @@ +==== +Blog +==== + +.. blog-posts directive gets replaced with an ordered list of blog posts. + +.. blog-posts:: + + +.. The following toctree ensures blog posts get processed. + +.. toctree:: + :hidden: + :glob: + + blog/* diff --git a/site/blog/first-post.rst b/site/blog/first-post.rst new file mode 100644 index 0000000..7b07507 --- /dev/null +++ b/site/blog/first-post.rst @@ -0,0 +1,7 @@ +=========== +First post! +=========== + +A blog post. + +.. date:: 2013-12-04 diff --git a/site/blog/second-post.rst b/site/blog/second-post.rst new file mode 100644 index 0000000..c4463f3 --- /dev/null +++ b/site/blog/second-post.rst @@ -0,0 +1,7 @@ +=========== +Another one +=========== + +.. date:: 2013-12-05 + +Indeed! diff --git a/site/conf.py b/site/conf.py new file mode 100644 index 0000000..8c6f3aa --- /dev/null +++ b/site/conf.py @@ -0,0 +1,55 @@ +from datetime import datetime +import os +import sys + +import alabaster + + +# Add local blog extension +sys.path.append(os.path.abspath('.')) +extensions = ['blog'] +rss_link = 'http://paramiko.org' +rss_description = 'Paramiko project news' + +# Alabaster theme +html_theme_path = [alabaster.get_path()] +html_static_path = ['_static'] +html_theme = 'alabaster' +html_theme_options = { + 'logo': 'logo.png', + 'logo_name': 'true', + 'description': "A Python implementation of SSHv2.", + 'github_user': 'paramiko', + 'github_repo': 'paramiko', + 'gittip_user': 'bitprophet', + 'analytics_id': 'UA-18486793-2', + + 'link': '#3782BE', + 'link_hover': '#3782BE', + +} +html_sidebars = { + # Landing page (no ToC) + 'index': [ + 'about.html', + 'searchbox.html', + 'donate.html', + ], + # Inner pages get a ToC + '**': [ + 'about.html', + 'localtoc.html', + 'searchbox.html', + 'donate.html', + ] +} + +# Regular settings +project = u'Paramiko' +year = datetime.now().year +copyright = u'%d Jeff Forcier, 2003-2012 Robey Pointer' % year +master_doc = 'index' +templates_path = ['_templates'] +exclude_trees = ['_build'] +source_suffix = '.rst' +default_role = 'obj' diff --git a/site/contact.rst b/site/contact.rst new file mode 100644 index 0000000..b479f17 --- /dev/null +++ b/site/contact.rst @@ -0,0 +1,11 @@ +======= +Contact +======= + +You can get in touch with the developer & user community in any of the +following ways: + +* IRC: ``#paramiko`` on Freenode +* Mailing list: ``paramiko@librelist.com`` (see `the LibreList homepage + `_ for usage details). +* This website's :doc:`blog `. diff --git a/site/contributing.rst b/site/contributing.rst new file mode 100644 index 0000000..b121e64 --- /dev/null +++ b/site/contributing.rst @@ -0,0 +1,19 @@ +============ +Contributing +============ + +How to get the code +=================== + +Our primary Git repository is on Github at `paramiko/paramiko +`; please follow their instruction for +cloning to your local system. (If you intend to submit patches/pull requests, +we recommend forking first, then cloning your fork. Github has excellent +documentation for all this.) + + +How to submit bug reports or new code +===================================== + +Please see `this project-agnostic contribution guide +`_ - we follow it explicitly. diff --git a/site/dev-requirements.txt b/site/dev-requirements.txt new file mode 100644 index 0000000..524b806 --- /dev/null +++ b/site/dev-requirements.txt @@ -0,0 +1,3 @@ +invoke>=0.6.1 +invocations>=0.4.4 +sphinx==1.1.3 diff --git a/site/index.rst b/site/index.rst new file mode 100644 index 0000000..7d203b6 --- /dev/null +++ b/site/index.rst @@ -0,0 +1,31 @@ +Welcome to Paramiko! +==================== + +Paramiko is a Python (2.5+) implementation of the SSHv2 protocol [#]_, +providing both client and server functionality. While it leverages a Python C +extension for low level cryptography (`PyCrypto `_), +Paramiko itself is a pure Python interface around SSH networking concepts. + +This website covers project information for Paramiko such as contribution +guidelines, development roadmap, news/blog, and so forth. Detailed +usage and API documentation can be found at our code documentation site, +`docs.paramiko.org `_. + +.. toctree:: + blog + installing + contributing + contact + + +.. rubric:: Footnotes + +.. [#] + SSH is defined in RFCs + `4251 `_, + `4252 `_, + `4253 `_, and + `4254 `_; + the primary working implementation of the protocol is the `OpenSSH project + `_. Paramiko implements a large portion of the SSH + feature set, but there are occasional gaps. diff --git a/site/installing.rst b/site/installing.rst new file mode 100644 index 0000000..0d4dc1a --- /dev/null +++ b/site/installing.rst @@ -0,0 +1,105 @@ +========== +Installing +========== + +Paramiko itself +=============== + +The recommended way to get Invoke is to **install the latest stable release** +via `pip `_:: + + $ pip install paramiko + +.. note:: + Users who want the bleeding edge can install the development version via + ``pip install paramiko==dev``. + +We currently support **Python 2.5/2.6/2.7**, with support for Python 3 coming +soon. Users on Python 2.4 or older are urged to upgrade. Paramiko *may* work on +Python 2.4 still, but there is no longer any support guarantee. + +Paramiko has two dependencies: the pure-Python ECDSA module `ecdsa`, and the +PyCrypto C extension. `ecdsa` is easily installable from wherever you +obtained Paramiko's package; PyCrypto may require more work. Read on for +details. + +PyCrypto +======== + +`PyCrypto `_ provides the low-level +(C-based) encryption algorithms we need to implement the SSH protocol. There +are a couple gotchas associated with installing PyCrypto: its compatibility +with Python's package tools, and the fact that it is a C-based extension. + +.. _pycrypto-and-pip: + +Possible gotcha on older Python and/or pip versions +--------------------------------------------------- + +We strongly recommend using ``pip`` to as it is newer and generally better than +``easy_install``. However, a combination of bugs in specific (now rather old) +versions of Python, ``pip`` and PyCrypto can prevent installation of PyCrypto. +Specifically: + +* Python = 2.5.x +* PyCrypto >= 2.1 (required for most modern versions of Paramiko) +* ``pip`` < 0.8.1 + +When all three criteria are met, you may encounter ``No such file or +directory`` IOErrors when trying to ``pip install paramiko`` or ``pip install +PyCrypto``. + +The fix is to make sure at least one of the above criteria is not met, by doing +the following (in order of preference): + +* Upgrade to ``pip`` 0.8.1 or above, e.g. by running ``pip install -U pip``. +* Upgrade to Python 2.6 or above. +* Downgrade to Paramiko 1.7.6 or 1.7.7, which do not require PyCrypto >= 2.1, + and install PyCrypto 2.0.1 (the oldest version on PyPI which works with + Paramiko 1.7.6/1.7.7) + + +C extension +----------- + +Unless you are installing from a precompiled source such as a Debian apt +repository or RedHat RPM, or using :ref:`pypm `, you will also need the +ability to build Python C-based modules from source in order to install +PyCrypto. Users on **Unix-based platforms** such as Ubuntu or Mac OS X will +need the traditional C build toolchain installed (e.g. Developer Tools / XCode +Tools on the Mac, or the ``build-essential`` package on Ubuntu or Debian Linux +-- basically, anything with ``gcc``, ``make`` and so forth) as well as the +Python development libraries, often named ``python-dev`` or similar. + +For **Windows** users we recommend using :ref:`pypm`, installing a C +development environment such as `Cygwin `_ or obtaining a +precompiled Win32 PyCrypto package from `voidspace's Python modules page +`_. + +.. note:: + Some Windows users whose Python is 64-bit have found that the PyCrypto + dependency ``winrandom`` may not install properly, leading to ImportErrors. + In this scenario, you'll probably need to compile ``winrandom`` yourself + via e.g. MS Visual Studio. See `Fabric #194 + `_ for info. + + +.. _pypm: + +ActivePython and PyPM +===================== + +Windows users who already have ActiveState's `ActivePython +`_ distribution installed +may find Paramiko is best installed with `its package manager, PyPM +`_. Below is example output from an +installation of Paramiko via ``pypm``:: + + C:\> pypm install paramiko + The following packages will be installed into "%APPDATA%\Python" (2.7): + paramiko-1.7.8 pycrypto-2.4 + Get: [pypm-free.activestate.com] paramiko 1.7.8 + Get: [pypm-free.activestate.com] pycrypto 2.4 + Installing paramiko-1.7.8 + Installing pycrypto-2.4 + C:\> diff --git a/site/tasks.py b/site/tasks.py new file mode 100644 index 0000000..e2d952b --- /dev/null +++ b/site/tasks.py @@ -0,0 +1,19 @@ +from invoke import Collection +from invocations import docs, testing + +# TODO: let from_module specify new name +api = Collection.from_module(docs) +# TODO: maybe allow rolling configuration into it too heh +api.configure({ + 'sphinx.source': 'api', + 'sphinx.target': 'api/_build', +}) +api.name = 'api' +site = Collection.from_module(docs) +site.name = 'site' +site.configure({ + 'sphinx.source': 'site', + 'sphinx.target': 'site/_build', +}) + +ns = Collection(testing.test, api=api, site=site) From 7d56ecb1a7d1654ae971e9896aa26e938454d3ea Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Fri, 10 Jan 2014 20:07:43 -0800 Subject: [PATCH 02/18] Meta prep work (reqs.txt, tasks.py) --- .gitignore | 1 + .travis.yml | 4 +++- dev-requirements.txt | 6 ++++++ requirements.txt | 2 -- site/dev-requirements.txt | 3 --- site/tasks.py => tasks.py | 1 + tox-requirements.txt | 2 ++ tox.ini | 2 +- 8 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 dev-requirements.txt delete mode 100644 requirements.txt delete mode 100644 site/dev-requirements.txt rename site/tasks.py => tasks.py (99%) create mode 100644 tox-requirements.txt diff --git a/.gitignore b/.gitignore index 4b57895..a125b27 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ dist/ paramiko.egg-info/ test.log docs/ +_build diff --git a/.travis.yml b/.travis.yml index c9802a8..29e44e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,9 @@ python: install: # Self-install for setup.py-driven deps - pip install -e . - - pip install coveralls + # Dev (doc/test running) requirements + - pip install coveralls # For coveralls.io specifically + - pip install -r dev-requirements.txt script: coverage run --source=paramiko test.py --verbose notifications: irc: diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 0000000..59a1f14 --- /dev/null +++ b/dev-requirements.txt @@ -0,0 +1,6 @@ +# For newer tasks like building Sphinx docs. +# NOTE: Requires Python >=2.6 +invoke>=0.6.1 +invocations>=0.4.4 +sphinx>=1.1.3 +alabaster>=0.1.0 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 75112a2..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pycrypto -tox diff --git a/site/dev-requirements.txt b/site/dev-requirements.txt deleted file mode 100644 index 524b806..0000000 --- a/site/dev-requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -invoke>=0.6.1 -invocations>=0.4.4 -sphinx==1.1.3 diff --git a/site/tasks.py b/tasks.py similarity index 99% rename from site/tasks.py rename to tasks.py index e2d952b..d470dab 100644 --- a/site/tasks.py +++ b/tasks.py @@ -1,6 +1,7 @@ from invoke import Collection from invocations import docs, testing + # TODO: let from_module specify new name api = Collection.from_module(docs) # TODO: maybe allow rolling configuration into it too heh diff --git a/tox-requirements.txt b/tox-requirements.txt new file mode 100644 index 0000000..26224ce --- /dev/null +++ b/tox-requirements.txt @@ -0,0 +1,2 @@ +# Not sure why tox can't just read setup.py? +pycrypto diff --git a/tox.ini b/tox.ini index 6cb8001..af4fbf2 100644 --- a/tox.ini +++ b/tox.ini @@ -2,5 +2,5 @@ envlist = py25,py26,py27 [testenv] -commands = pip install --use-mirrors -q -r requirements.txt +commands = pip install --use-mirrors -q -r tox-requirements.txt python test.py From ccb7a6c2cd22689d363a03da2c7a2bcf4e27a0c8 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Mon, 13 Jan 2014 12:17:46 -0800 Subject: [PATCH 03/18] Start fleshing out two-site setup --- .gitignore | 1 + .../_static => sites/_shared_static}/logo.png | Bin sites/docs/conf.py | 4 ++++ sites/docs/index.rst | 6 ++++++ {site => sites/main}/_templates/rss.xml | 0 {site => sites/main}/blog.py | 0 {site => sites/main}/blog.rst | 0 {site => sites/main}/blog/first-post.rst | 0 {site => sites/main}/blog/second-post.rst | 0 sites/main/conf.py | 4 ++++ {site => sites/main}/contact.rst | 0 {site => sites/main}/contributing.rst | 0 {site => sites/main}/index.rst | 0 {site => sites/main}/installing.rst | 0 site/conf.py => sites/shared_conf.py | 3 ++- tasks.py | 18 +++++++++--------- 16 files changed, 26 insertions(+), 10 deletions(-) rename {site/_static => sites/_shared_static}/logo.png (100%) create mode 100644 sites/docs/conf.py create mode 100644 sites/docs/index.rst rename {site => sites/main}/_templates/rss.xml (100%) rename {site => sites/main}/blog.py (100%) rename {site => sites/main}/blog.rst (100%) rename {site => sites/main}/blog/first-post.rst (100%) rename {site => sites/main}/blog/second-post.rst (100%) create mode 100644 sites/main/conf.py rename {site => sites/main}/contact.rst (100%) rename {site => sites/main}/contributing.rst (100%) rename {site => sites/main}/index.rst (100%) rename {site => sites/main}/installing.rst (100%) rename site/conf.py => sites/shared_conf.py (92%) diff --git a/.gitignore b/.gitignore index a125b27..9e1febf 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ dist/ paramiko.egg-info/ test.log docs/ +!sites/docs _build diff --git a/site/_static/logo.png b/sites/_shared_static/logo.png similarity index 100% rename from site/_static/logo.png rename to sites/_shared_static/logo.png diff --git a/sites/docs/conf.py b/sites/docs/conf.py new file mode 100644 index 0000000..0c7ffe5 --- /dev/null +++ b/sites/docs/conf.py @@ -0,0 +1,4 @@ +# Obtain shared config values +import os, sys +sys.path.append(os.path.abspath('..')) +from shared_conf import * diff --git a/sites/docs/index.rst b/sites/docs/index.rst new file mode 100644 index 0000000..08b3432 --- /dev/null +++ b/sites/docs/index.rst @@ -0,0 +1,6 @@ +Welcome to Paramiko's documentation! +==================================== + +This site covers Paramiko's usage & API documentation. For basic info on what +Paramiko is, including its public changelog & how the project is maintained, +please see `the main website `_. diff --git a/site/_templates/rss.xml b/sites/main/_templates/rss.xml similarity index 100% rename from site/_templates/rss.xml rename to sites/main/_templates/rss.xml diff --git a/site/blog.py b/sites/main/blog.py similarity index 100% rename from site/blog.py rename to sites/main/blog.py diff --git a/site/blog.rst b/sites/main/blog.rst similarity index 100% rename from site/blog.rst rename to sites/main/blog.rst diff --git a/site/blog/first-post.rst b/sites/main/blog/first-post.rst similarity index 100% rename from site/blog/first-post.rst rename to sites/main/blog/first-post.rst diff --git a/site/blog/second-post.rst b/sites/main/blog/second-post.rst similarity index 100% rename from site/blog/second-post.rst rename to sites/main/blog/second-post.rst diff --git a/sites/main/conf.py b/sites/main/conf.py new file mode 100644 index 0000000..0c7ffe5 --- /dev/null +++ b/sites/main/conf.py @@ -0,0 +1,4 @@ +# Obtain shared config values +import os, sys +sys.path.append(os.path.abspath('..')) +from shared_conf import * diff --git a/site/contact.rst b/sites/main/contact.rst similarity index 100% rename from site/contact.rst rename to sites/main/contact.rst diff --git a/site/contributing.rst b/sites/main/contributing.rst similarity index 100% rename from site/contributing.rst rename to sites/main/contributing.rst diff --git a/site/index.rst b/sites/main/index.rst similarity index 100% rename from site/index.rst rename to sites/main/index.rst diff --git a/site/installing.rst b/sites/main/installing.rst similarity index 100% rename from site/installing.rst rename to sites/main/installing.rst diff --git a/site/conf.py b/sites/shared_conf.py similarity index 92% rename from site/conf.py rename to sites/shared_conf.py index 8c6f3aa..333db54 100644 --- a/site/conf.py +++ b/sites/shared_conf.py @@ -13,7 +13,8 @@ rss_description = 'Paramiko project news' # Alabaster theme html_theme_path = [alabaster.get_path()] -html_static_path = ['_static'] +# Paths relative to invoking conf.py - not this shared file +html_static_path = ['../_shared_static'] html_theme = 'alabaster' html_theme_options = { 'logo': 'logo.png', diff --git a/tasks.py b/tasks.py index d470dab..e8cbd3e 100644 --- a/tasks.py +++ b/tasks.py @@ -6,15 +6,15 @@ from invocations import docs, testing api = Collection.from_module(docs) # TODO: maybe allow rolling configuration into it too heh api.configure({ - 'sphinx.source': 'api', - 'sphinx.target': 'api/_build', + 'sphinx.source': 'sites/docs', + 'sphinx.target': 'sites/docs/_build', }) -api.name = 'api' -site = Collection.from_module(docs) -site.name = 'site' -site.configure({ - 'sphinx.source': 'site', - 'sphinx.target': 'site/_build', +api.name = 'docs' +main = Collection.from_module(docs) +main.name = 'main' +main.configure({ + 'sphinx.source': 'sites/main', + 'sphinx.target': 'sites/main/_build', }) -ns = Collection(testing.test, api=api, site=site) +ns = Collection(testing.test, docs=api, main=main) From c224fdecf174077f3b7a15f056e65b10282fed38 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Mon, 13 Jan 2014 16:16:30 -0800 Subject: [PATCH 04/18] Use new behavior from newer Invoke --- tasks.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tasks.py b/tasks.py index e8cbd3e..3326a77 100644 --- a/tasks.py +++ b/tasks.py @@ -2,17 +2,13 @@ from invoke import Collection from invocations import docs, testing -# TODO: let from_module specify new name -api = Collection.from_module(docs) -# TODO: maybe allow rolling configuration into it too heh -api.configure({ +# Usage doc/API site +api = Collection.from_module(docs, name='docs', config={ 'sphinx.source': 'sites/docs', 'sphinx.target': 'sites/docs/_build', }) -api.name = 'docs' -main = Collection.from_module(docs) -main.name = 'main' -main.configure({ +# Main/about/changelog site +main = Collection.from_module(docs, name='main', config={ 'sphinx.source': 'sites/main', 'sphinx.target': 'sites/main/_build', }) From 2da914252064af8dc419b49a423ab57fdb0617c4 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Tue, 21 Jan 2014 16:59:21 -0800 Subject: [PATCH 05/18] Rename 'main' doctree to 'www'; refactor sphinx task conf --- sites/{main => www}/_templates/rss.xml | 0 sites/{main => www}/blog.py | 0 sites/{main => www}/blog.rst | 0 sites/{main => www}/blog/first-post.rst | 0 sites/{main => www}/blog/second-post.rst | 0 sites/{main => www}/conf.py | 0 sites/{main => www}/contact.rst | 0 sites/{main => www}/contributing.rst | 0 sites/{main => www}/index.rst | 0 sites/{main => www}/installing.rst | 0 tasks.py | 29 +++++++++++++++--------- 11 files changed, 18 insertions(+), 11 deletions(-) rename sites/{main => www}/_templates/rss.xml (100%) rename sites/{main => www}/blog.py (100%) rename sites/{main => www}/blog.rst (100%) rename sites/{main => www}/blog/first-post.rst (100%) rename sites/{main => www}/blog/second-post.rst (100%) rename sites/{main => www}/conf.py (100%) rename sites/{main => www}/contact.rst (100%) rename sites/{main => www}/contributing.rst (100%) rename sites/{main => www}/index.rst (100%) rename sites/{main => www}/installing.rst (100%) diff --git a/sites/main/_templates/rss.xml b/sites/www/_templates/rss.xml similarity index 100% rename from sites/main/_templates/rss.xml rename to sites/www/_templates/rss.xml diff --git a/sites/main/blog.py b/sites/www/blog.py similarity index 100% rename from sites/main/blog.py rename to sites/www/blog.py diff --git a/sites/main/blog.rst b/sites/www/blog.rst similarity index 100% rename from sites/main/blog.rst rename to sites/www/blog.rst diff --git a/sites/main/blog/first-post.rst b/sites/www/blog/first-post.rst similarity index 100% rename from sites/main/blog/first-post.rst rename to sites/www/blog/first-post.rst diff --git a/sites/main/blog/second-post.rst b/sites/www/blog/second-post.rst similarity index 100% rename from sites/main/blog/second-post.rst rename to sites/www/blog/second-post.rst diff --git a/sites/main/conf.py b/sites/www/conf.py similarity index 100% rename from sites/main/conf.py rename to sites/www/conf.py diff --git a/sites/main/contact.rst b/sites/www/contact.rst similarity index 100% rename from sites/main/contact.rst rename to sites/www/contact.rst diff --git a/sites/main/contributing.rst b/sites/www/contributing.rst similarity index 100% rename from sites/main/contributing.rst rename to sites/www/contributing.rst diff --git a/sites/main/index.rst b/sites/www/index.rst similarity index 100% rename from sites/main/index.rst rename to sites/www/index.rst diff --git a/sites/main/installing.rst b/sites/www/installing.rst similarity index 100% rename from sites/main/installing.rst rename to sites/www/installing.rst diff --git a/tasks.py b/tasks.py index 3326a77..c716415 100644 --- a/tasks.py +++ b/tasks.py @@ -1,16 +1,23 @@ +from os.path import join + from invoke import Collection -from invocations import docs, testing +from invocations import docs as _docs, testing -# Usage doc/API site -api = Collection.from_module(docs, name='docs', config={ - 'sphinx.source': 'sites/docs', - 'sphinx.target': 'sites/docs/_build', -}) -# Main/about/changelog site -main = Collection.from_module(docs, name='main', config={ - 'sphinx.source': 'sites/main', - 'sphinx.target': 'sites/main/_build', +d = 'sites' + +# Usage doc/API site (published as docs.paramiko.org) +path = join(d, 'docs') +docs = Collection.from_module(_docs, name='docs', config={ + 'sphinx.source': path, + 'sphinx.target': join(path, '_build'), }) -ns = Collection(testing.test, docs=api, main=main) +# Main/about/changelog site ((www.)?paramiko.org) +path = join(d, 'www') +www = Collection.from_module(_docs, name='www', config={ + 'sphinx.source': path, + 'sphinx.target': join(path, '_build'), +}) + +ns = Collection(testing.test, docs=docs, www=www) From 5a1f927310414ca47408c3f2f81a0b43beb8cb19 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Wed, 22 Jan 2014 10:55:39 -0800 Subject: [PATCH 06/18] Blog only used/exists in www, don't import it in docs site --- sites/shared_conf.py | 6 ------ sites/www/conf.py | 7 +++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/sites/shared_conf.py b/sites/shared_conf.py index 333db54..89e0a56 100644 --- a/sites/shared_conf.py +++ b/sites/shared_conf.py @@ -5,12 +5,6 @@ import sys import alabaster -# Add local blog extension -sys.path.append(os.path.abspath('.')) -extensions = ['blog'] -rss_link = 'http://paramiko.org' -rss_description = 'Paramiko project news' - # Alabaster theme html_theme_path = [alabaster.get_path()] # Paths relative to invoking conf.py - not this shared file diff --git a/sites/www/conf.py b/sites/www/conf.py index 0c7ffe5..e504ec7 100644 --- a/sites/www/conf.py +++ b/sites/www/conf.py @@ -2,3 +2,10 @@ import os, sys sys.path.append(os.path.abspath('..')) from shared_conf import * + +# Add local blog extension +sys.path.append(os.path.abspath('.')) +extensions = ['blog'] +rss_link = 'http://paramiko.org' +rss_description = 'Paramiko project news' + From 03768eadcafbbab93f9c5c6c67479e97249e7a09 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Wed, 22 Jan 2014 12:48:32 -0800 Subject: [PATCH 07/18] Migrate 1.10.x NEWS entries to Sphinx changelog --- dev-requirements.txt | 1 + sites/www/changelog.rst | 77 +++++++++++++++++++++++++++++++++++++++++ sites/www/conf.py | 4 +++ sites/www/index.rst | 5 +-- 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 sites/www/changelog.rst diff --git a/dev-requirements.txt b/dev-requirements.txt index 59a1f14..a2b9a4e 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -4,3 +4,4 @@ invoke>=0.6.1 invocations>=0.4.4 sphinx>=1.1.3 alabaster>=0.1.0 +releases>=0.2.4 diff --git a/sites/www/changelog.rst b/sites/www/changelog.rst new file mode 100644 index 0000000..d83de54 --- /dev/null +++ b/sites/www/changelog.rst @@ -0,0 +1,77 @@ +========= +Changelog +========= + +* :release:`1.10.6 <2014-01-21>` +* :bug:`193` (and its attentant PRs :issue:`230` & :issue:`253`): Fix SSH agent + problems present on Windows. Thanks to David Hobbs for initial report and to + Aarni Koskela & Olle Lundberg for the patches. +* :release:`1.10.5 <2014-01-08>` +* :bug:`176`: Fix AttributeError bugs in known_hosts file (re)loading. Thanks + to Nathan Scowcroft for the patch & Martin Blumenstingl for the initial test + case. +* :release:`1.10.4 <2013-09-27>` +* :bug:`179`: Fix a missing variable causing errors when an ssh_config file has + a non-default AddressFamily set. Thanks to Ed Marshall & Tomaz Muraus for + catch & patch. +* :bug:`200`: Fix an exception-causing typo in `demo_simple.py`. Thanks to Alex + Buchanan for catch & Dave Foster for patch. +* :bug:`199`: Typo fix in the license header cross-project. Thanks to Armin + Ronacher for catch & patch. +* :release:`1.10.3 <2013-09-20>` +* :bug:`162`: Clean up HMAC module import to avoid deadlocks in certain uses of + SSHClient. Thanks to Gernot Hillier for the catch & suggested fix. +* :bug:`36`: Fix the port-forwarding demo to avoid file descriptor errors. + Thanks to Jonathan Halcrow for catch & patch. +* :bug:`168`: Update config handling to properly handle multiple 'localforward' + and 'remoteforward' keys. Thanks to Emre Yılmaz for the patch. +* :release:`1.10.2 <2013-07-26>` +* :bug:`153`, :issue:`67`: Warn on parse failure when reading known_hosts + file. Thanks to `@glasserc` for patch. +* :bug:`146`: Indentation fixes for readability. Thanks to Abhinav Upadhyay for + catch & patch. +* :release:`1.10.1 <2013-04-05>` +* :bug:`142`: (`Fabric #811 `_) + SFTP put of empty file will still return the attributes of the put file. + Thanks to Jason R. Coombs for the patch. +* :bug:`154`: (`Fabric #876 `_) + Forwarded SSH agent connections left stale local pipes lying around, which + could cause local (and sometimes remote or network) resource starvation when + running many agent-using remote commands. Thanks to Kevin Tegtmeier for catch + & patch. +* :release:`1.10.0 <2013-03-01>` +* :feature:`66`: Batch SFTP writes to help speed up file transfers. Thanks to + Olle Lundberg for the patch. +* :bug:`133 major`: Fix handling of window-change events to be on-spec and not + attempt to wait for a response from the remote sshd; this fixes problems with + less common targets such as some Cisco devices. Thanks to Phillip Heller for + catch & patch. +* :feature:`93`: Overhaul SSH config parsing to be in line with `man + ssh_config` (& the behavior of `ssh` itself), including addition of parameter + expansion within config values. Thanks to Olle Lundberg for the patch. +* :feature:`110`: Honor SSH config `AddressFamily` setting when looking up + local host's FQDN. Thanks to John Hensley for the patch. +* :feature:`128`: Defer FQDN resolution until needed, when parsing SSH config + files. Thanks to Parantapa Bhattacharya for catch & patch. +* :bug:`102 major`: Forego random padding for packets when running under + `*-ctr` ciphers. This corrects some slowdowns on platforms where random byte + generation is inefficient (e.g. Windows). Thanks to `@warthog618` for catch + & patch, and Michael van der Kolff for code/technique review. +* :feature:`127`: Turn `SFTPFile` into a context manager. Thanks to Michael + Williamson for the patch. +* :feature:`116`: Limit `Message.get_bytes` to an upper bound of 1MB to protect + against potential DoS vectors. Thanks to `@mvschaik` for catch & patch. +* :feature:`115`: Add convenience `get_pty` kwarg to `Client.exec_command` so + users not manually controlling a channel object can still toggle PTY + creation. Thanks to Michael van der Kolff for the patch. +* :feature:`71`: Add `SFTPClient.putfo` and `.getfo` methods to allow direct + uploading/downloading of file-like objects. Thanks to Eric Buehl for the + patch. +* :feature:`113`: Add `timeout` parameter to `SSHClient.exec_command` for + easier setting of the command's internal channel object's timeout. Thanks to + Cernov Vladimir for the patch. +* :support:`94`: Remove duplication of SSH port constant. Thanks to Olle + Lundberg for the catch. +* :feature:`80`: Expose the internal "is closed" property of the file transfer + class `BufferedFile` as `.closed`, better conforming to Python's file + interface. Thanks to `@smunaut` and James Hiscock for catch & patch. diff --git a/sites/www/conf.py b/sites/www/conf.py index e504ec7..c144b5b 100644 --- a/sites/www/conf.py +++ b/sites/www/conf.py @@ -9,3 +9,7 @@ extensions = ['blog'] rss_link = 'http://paramiko.org' rss_description = 'Paramiko project news' +# Add Releases changelog extension +extensions.append('releases') +releases_release_uri = "https://github.com/paramiko/paramiko/tree/%s" +releases_issue_uri = "https://github.com/paramiko/paramiko/issues/%s" diff --git a/sites/www/index.rst b/sites/www/index.rst index 7d203b6..f8db6fd 100644 --- a/sites/www/index.rst +++ b/sites/www/index.rst @@ -6,13 +6,14 @@ providing both client and server functionality. While it leverages a Python C extension for low level cryptography (`PyCrypto `_), Paramiko itself is a pure Python interface around SSH networking concepts. -This website covers project information for Paramiko such as contribution -guidelines, development roadmap, news/blog, and so forth. Detailed +This website covers project information for Paramiko such as the changelog, +contribution guidelines, development roadmap, news/blog, and so forth. Detailed usage and API documentation can be found at our code documentation site, `docs.paramiko.org `_. .. toctree:: blog + changelog installing contributing contact From dde21a7de09bd92a6a362a26009a56a942b3d246 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Wed, 22 Jan 2014 14:25:08 -0800 Subject: [PATCH 08/18] Nuke extraneous colons, add 'major' notes --- sites/www/changelog.rst | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/sites/www/changelog.rst b/sites/www/changelog.rst index d83de54..bba7894 100644 --- a/sites/www/changelog.rst +++ b/sites/www/changelog.rst @@ -7,71 +7,71 @@ Changelog problems present on Windows. Thanks to David Hobbs for initial report and to Aarni Koskela & Olle Lundberg for the patches. * :release:`1.10.5 <2014-01-08>` -* :bug:`176`: Fix AttributeError bugs in known_hosts file (re)loading. Thanks +* :bug:`176` Fix AttributeError bugs in known_hosts file (re)loading. Thanks to Nathan Scowcroft for the patch & Martin Blumenstingl for the initial test case. * :release:`1.10.4 <2013-09-27>` -* :bug:`179`: Fix a missing variable causing errors when an ssh_config file has +* :bug:`179` Fix a missing variable causing errors when an ssh_config file has a non-default AddressFamily set. Thanks to Ed Marshall & Tomaz Muraus for catch & patch. -* :bug:`200`: Fix an exception-causing typo in `demo_simple.py`. Thanks to Alex +* :bug:`200` Fix an exception-causing typo in `demo_simple.py`. Thanks to Alex Buchanan for catch & Dave Foster for patch. -* :bug:`199`: Typo fix in the license header cross-project. Thanks to Armin +* :bug:`199` Typo fix in the license header cross-project. Thanks to Armin Ronacher for catch & patch. * :release:`1.10.3 <2013-09-20>` -* :bug:`162`: Clean up HMAC module import to avoid deadlocks in certain uses of +* :bug:`162` Clean up HMAC module import to avoid deadlocks in certain uses of SSHClient. Thanks to Gernot Hillier for the catch & suggested fix. -* :bug:`36`: Fix the port-forwarding demo to avoid file descriptor errors. +* :bug:`36` Fix the port-forwarding demo to avoid file descriptor errors. Thanks to Jonathan Halcrow for catch & patch. -* :bug:`168`: Update config handling to properly handle multiple 'localforward' +* :bug:`168` Update config handling to properly handle multiple 'localforward' and 'remoteforward' keys. Thanks to Emre Yılmaz for the patch. * :release:`1.10.2 <2013-07-26>` -* :bug:`153`, :issue:`67`: Warn on parse failure when reading known_hosts +* :bug:`153` (also :issue:`67`) Warn on parse failure when reading known_hosts file. Thanks to `@glasserc` for patch. -* :bug:`146`: Indentation fixes for readability. Thanks to Abhinav Upadhyay for +* :bug:`146` Indentation fixes for readability. Thanks to Abhinav Upadhyay for catch & patch. * :release:`1.10.1 <2013-04-05>` -* :bug:`142`: (`Fabric #811 `_) +* :bug:`142` (`Fabric #811 `_) SFTP put of empty file will still return the attributes of the put file. Thanks to Jason R. Coombs for the patch. -* :bug:`154`: (`Fabric #876 `_) +* :bug:`154` (`Fabric #876 `_) Forwarded SSH agent connections left stale local pipes lying around, which could cause local (and sometimes remote or network) resource starvation when running many agent-using remote commands. Thanks to Kevin Tegtmeier for catch & patch. * :release:`1.10.0 <2013-03-01>` -* :feature:`66`: Batch SFTP writes to help speed up file transfers. Thanks to +* :feature:`66` Batch SFTP writes to help speed up file transfers. Thanks to Olle Lundberg for the patch. -* :bug:`133 major`: Fix handling of window-change events to be on-spec and not +* :bug:`133 major` Fix handling of window-change events to be on-spec and not attempt to wait for a response from the remote sshd; this fixes problems with less common targets such as some Cisco devices. Thanks to Phillip Heller for catch & patch. -* :feature:`93`: Overhaul SSH config parsing to be in line with `man +* :feature:`93` Overhaul SSH config parsing to be in line with `man ssh_config` (& the behavior of `ssh` itself), including addition of parameter expansion within config values. Thanks to Olle Lundberg for the patch. -* :feature:`110`: Honor SSH config `AddressFamily` setting when looking up +* :feature:`110` Honor SSH config `AddressFamily` setting when looking up local host's FQDN. Thanks to John Hensley for the patch. -* :feature:`128`: Defer FQDN resolution until needed, when parsing SSH config +* :feature:`128` Defer FQDN resolution until needed, when parsing SSH config files. Thanks to Parantapa Bhattacharya for catch & patch. -* :bug:`102 major`: Forego random padding for packets when running under +* :bug:`102 major` Forego random padding for packets when running under `*-ctr` ciphers. This corrects some slowdowns on platforms where random byte generation is inefficient (e.g. Windows). Thanks to `@warthog618` for catch & patch, and Michael van der Kolff for code/technique review. -* :feature:`127`: Turn `SFTPFile` into a context manager. Thanks to Michael +* :feature:`127` Turn `SFTPFile` into a context manager. Thanks to Michael Williamson for the patch. -* :feature:`116`: Limit `Message.get_bytes` to an upper bound of 1MB to protect +* :feature:`116` Limit `Message.get_bytes` to an upper bound of 1MB to protect against potential DoS vectors. Thanks to `@mvschaik` for catch & patch. -* :feature:`115`: Add convenience `get_pty` kwarg to `Client.exec_command` so +* :feature:`115` Add convenience `get_pty` kwarg to `Client.exec_command` so users not manually controlling a channel object can still toggle PTY creation. Thanks to Michael van der Kolff for the patch. -* :feature:`71`: Add `SFTPClient.putfo` and `.getfo` methods to allow direct +* :feature:`71` Add `SFTPClient.putfo` and `.getfo` methods to allow direct uploading/downloading of file-like objects. Thanks to Eric Buehl for the patch. -* :feature:`113`: Add `timeout` parameter to `SSHClient.exec_command` for +* :feature:`113` Add `timeout` parameter to `SSHClient.exec_command` for easier setting of the command's internal channel object's timeout. Thanks to Cernov Vladimir for the patch. -* :support:`94`: Remove duplication of SSH port constant. Thanks to Olle +* :support:`94` Remove duplication of SSH port constant. Thanks to Olle Lundberg for the catch. -* :feature:`80`: Expose the internal "is closed" property of the file transfer +* :feature:`80` Expose the internal "is closed" property of the file transfer class `BufferedFile` as `.closed`, better conforming to Python's file interface. Thanks to `@smunaut` and James Hiscock for catch & patch. From 87cd72c144c54fc9c6f05ff7482bd6e9e7622730 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Thu, 23 Jan 2014 11:43:34 -0800 Subject: [PATCH 09/18] Set up Intersphinx so www can ref docs --- sites/shared_conf.py | 2 +- sites/www/conf.py | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/sites/shared_conf.py b/sites/shared_conf.py index 89e0a56..c48dcdc 100644 --- a/sites/shared_conf.py +++ b/sites/shared_conf.py @@ -42,7 +42,7 @@ html_sidebars = { # Regular settings project = u'Paramiko' year = datetime.now().year -copyright = u'%d Jeff Forcier, 2003-2012 Robey Pointer' % year +copyright = u'2013-%d Jeff Forcier, 2003-2012 Robey Pointer' % year master_doc = 'index' templates_path = ['_templates'] exclude_trees = ['_build'] diff --git a/sites/www/conf.py b/sites/www/conf.py index c144b5b..b2f9618 100644 --- a/sites/www/conf.py +++ b/sites/www/conf.py @@ -1,15 +1,30 @@ # Obtain shared config values -import os, sys -sys.path.append(os.path.abspath('..')) +import sys +import os +from os.path import abspath, join, dirname + +sys.path.append(abspath(join(dirname(__file__), '..'))) from shared_conf import * -# Add local blog extension -sys.path.append(os.path.abspath('.')) +# Local blog extension +sys.path.append(abspath('.')) extensions = ['blog'] rss_link = 'http://paramiko.org' rss_description = 'Paramiko project news' -# Add Releases changelog extension +# Releases changelog extension extensions.append('releases') releases_release_uri = "https://github.com/paramiko/paramiko/tree/%s" releases_issue_uri = "https://github.com/paramiko/paramiko/issues/%s" + +# Intersphinx for referencing API/usage docs +extensions.append('sphinx.ext.intersphinx') +# Default is 'local' building, but reference the public docs site when building +# under RTD. +target = join(dirname(__file__), '..', 'docs', '_build') +if os.environ.get('READTHEDOCS') == 'True': + # TODO: switch to docs.paramiko.org post go-live + target = 'http://paramiko-docs.readthedocs.org/en/latest/' +intersphinx_mapping = { + 'docs': (target, None), +} From 69d40710dc55373f9bbeb9f2721c6942a5250bbd Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Tue, 28 Jan 2014 08:46:21 -0800 Subject: [PATCH 10/18] Tweak logo settings (& rely on new alabaster defaults) --- dev-requirements.txt | 2 +- sites/shared_conf.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index a2b9a4e..a967765 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -3,5 +3,5 @@ invoke>=0.6.1 invocations>=0.4.4 sphinx>=1.1.3 -alabaster>=0.1.0 +alabaster>=0.2.0 releases>=0.2.4 diff --git a/sites/shared_conf.py b/sites/shared_conf.py index c48dcdc..d6852cc 100644 --- a/sites/shared_conf.py +++ b/sites/shared_conf.py @@ -11,8 +11,6 @@ html_theme_path = [alabaster.get_path()] html_static_path = ['../_shared_static'] html_theme = 'alabaster' html_theme_options = { - 'logo': 'logo.png', - 'logo_name': 'true', 'description': "A Python implementation of SSHv2.", 'github_user': 'paramiko', 'github_repo': 'paramiko', From da51cd8b14231a3fa9850d0d1b939168ae7b0534 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Tue, 28 Jan 2014 12:50:19 -0800 Subject: [PATCH 11/18] Update to new alabaster-driven nav sidebar --- sites/shared_conf.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sites/shared_conf.py b/sites/shared_conf.py index d6852cc..267b3bc 100644 --- a/sites/shared_conf.py +++ b/sites/shared_conf.py @@ -17,21 +17,18 @@ html_theme_options = { 'gittip_user': 'bitprophet', 'analytics_id': 'UA-18486793-2', + 'extra_nav_links': { + "API Docs": 'http://docs.paramiko.org', + }, + 'link': '#3782BE', 'link_hover': '#3782BE', } html_sidebars = { - # Landing page (no ToC) - 'index': [ - 'about.html', - 'searchbox.html', - 'donate.html', - ], - # Inner pages get a ToC '**': [ 'about.html', - 'localtoc.html', + 'navigation.html', 'searchbox.html', 'donate.html', ] From 7b690707dd81a80c7550c1f537b870805418d6df Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Tue, 28 Jan 2014 12:50:24 -0800 Subject: [PATCH 12/18] Don't display blog for now --- sites/www/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/sites/www/index.rst b/sites/www/index.rst index f8db6fd..43c060b 100644 --- a/sites/www/index.rst +++ b/sites/www/index.rst @@ -12,7 +12,6 @@ usage and API documentation can be found at our code documentation site, `docs.paramiko.org `_. .. toctree:: - blog changelog installing contributing From 414fec8f273e6807a8ee97253a5a82d0c8b787ab Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Tue, 28 Jan 2014 15:12:33 -0800 Subject: [PATCH 13/18] Bump Invoke requirement to newly released version w/ better Collection.from_module --- dev-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index a967765..2fe1e77 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,6 +1,6 @@ # For newer tasks like building Sphinx docs. # NOTE: Requires Python >=2.6 -invoke>=0.6.1 +invoke>=0.7.0 invocations>=0.4.4 sphinx>=1.1.3 alabaster>=0.2.0 From fee04a39ec45baefff84c8a58540fa3401b4a826 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Tue, 28 Jan 2014 15:23:11 -0800 Subject: [PATCH 14/18] Add sites/docs building to Travis --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 29e44e5..98a5482 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,12 @@ install: # Dev (doc/test running) requirements - pip install coveralls # For coveralls.io specifically - pip install -r dev-requirements.txt -script: coverage run --source=paramiko test.py --verbose +script: + # Main tests, with coverage! + - coverage run --source=paramiko test.py --verbose + # Ensure documentation & invoke pipeline run OK + - invoke www + - invoke docs notifications: irc: channels: "irc.freenode.org#paramiko" From d1d65b4ddde17a97d25a79aeaad6c3068846cb36 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Tue, 28 Jan 2014 15:53:26 -0800 Subject: [PATCH 15/18] Stricter/more useful doc builds in Travis --- .travis.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 98a5482..df7c225 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,12 @@ install: script: # Main tests, with coverage! - coverage run --source=paramiko test.py --verbose - # Ensure documentation & invoke pipeline run OK - - invoke www - - invoke docs + # Ensure documentation & invoke pipeline run OK. + # Run 'docs' first since its objects.inv is referred to by 'www'. + # Also force warnings to be errors since most of them tend to be actual + # problems. + - invoke docs -o -W + - invoke www -o -W notifications: irc: channels: "irc.freenode.org#paramiko" From b60075c7cd2fb4dd67701382f953e454d3db1848 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Tue, 28 Jan 2014 16:00:03 -0800 Subject: [PATCH 16/18] Prevent warning about unlinked blog page --- sites/www/index.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sites/www/index.rst b/sites/www/index.rst index 43c060b..7fefedd 100644 --- a/sites/www/index.rst +++ b/sites/www/index.rst @@ -17,6 +17,13 @@ usage and API documentation can be found at our code documentation site, contributing contact +.. Hide blog in hidden toctree for now (to avoid warnings.) + +.. toctree:: + :hidden: + + blog + .. rubric:: Footnotes From 2b0f834c1660c8865300e27b46a85de2edf4d556 Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Wed, 29 Jan 2014 14:23:46 -0800 Subject: [PATCH 17/18] Move API doc sister link to www site only, derp --- sites/shared_conf.py | 5 ----- sites/www/conf.py | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sites/shared_conf.py b/sites/shared_conf.py index 267b3bc..2b98654 100644 --- a/sites/shared_conf.py +++ b/sites/shared_conf.py @@ -17,13 +17,8 @@ html_theme_options = { 'gittip_user': 'bitprophet', 'analytics_id': 'UA-18486793-2', - 'extra_nav_links': { - "API Docs": 'http://docs.paramiko.org', - }, - 'link': '#3782BE', 'link_hover': '#3782BE', - } html_sidebars = { '**': [ diff --git a/sites/www/conf.py b/sites/www/conf.py index b2f9618..58132d7 100644 --- a/sites/www/conf.py +++ b/sites/www/conf.py @@ -28,3 +28,8 @@ if os.environ.get('READTHEDOCS') == 'True': intersphinx_mapping = { 'docs': (target, None), } + +# Sister-site links to API docs +html_theme_options['extra_nav_links'] = { + "API Docs": 'http://docs.paramiko.org', +} From b8d1724f5714c27ad02ae013e87f5531aec041ea Mon Sep 17 00:00:00 2001 From: Jeff Forcier Date: Wed, 29 Jan 2014 14:24:54 -0800 Subject: [PATCH 18/18] Comment out intersphinx pending #256 --- sites/www/conf.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sites/www/conf.py b/sites/www/conf.py index 58132d7..1f11c1e 100644 --- a/sites/www/conf.py +++ b/sites/www/conf.py @@ -23,11 +23,11 @@ extensions.append('sphinx.ext.intersphinx') # under RTD. target = join(dirname(__file__), '..', 'docs', '_build') if os.environ.get('READTHEDOCS') == 'True': - # TODO: switch to docs.paramiko.org post go-live + # TODO: switch to docs.paramiko.org post go-live of sphinx API docs target = 'http://paramiko-docs.readthedocs.org/en/latest/' -intersphinx_mapping = { - 'docs': (target, None), -} +#intersphinx_mapping = { +# 'docs': (target, None), +#} # Sister-site links to API docs html_theme_options['extra_nav_links'] = {