Import paramiko.org repository @ 3ac370054ef10fb060fe75fff25fe3a70ecc02c0
This commit is contained in:
parent
5c5bf6e844
commit
c74ff2a16e
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||||
|
<channel>
|
||||||
|
<atom:link href="{{ atom }}" rel="self" type="application/rss+xml" />
|
||||||
|
<title>{{ title }}</title>
|
||||||
|
<link>{{ link }}</link>
|
||||||
|
<description>{{ description }}</description>
|
||||||
|
<pubDate>{{ date }}</pubDate>
|
||||||
|
{% for link, title, desc, date in posts %}
|
||||||
|
<item>
|
||||||
|
<link>{{ link }}</link>
|
||||||
|
<guid>{{ link }}</guid>
|
||||||
|
<title><![CDATA[{{ title }}]]></title>
|
||||||
|
<description><![CDATA[{{ desc }}]]></description>
|
||||||
|
<pubDate>{{ date }}</pubDate>
|
||||||
|
</item>
|
||||||
|
{% endfor %}
|
||||||
|
</channel>
|
||||||
|
</rss>
|
|
@ -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 = '<div class="timestamp"><span>%s</span></div>' % 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)
|
|
@ -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/*
|
|
@ -0,0 +1,7 @@
|
||||||
|
===========
|
||||||
|
First post!
|
||||||
|
===========
|
||||||
|
|
||||||
|
A blog post.
|
||||||
|
|
||||||
|
.. date:: 2013-12-04
|
|
@ -0,0 +1,7 @@
|
||||||
|
===========
|
||||||
|
Another one
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. date:: 2013-12-05
|
||||||
|
|
||||||
|
Indeed!
|
|
@ -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'
|
|
@ -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
|
||||||
|
<http://librelist.com>`_ for usage details).
|
||||||
|
* This website's :doc:`blog </blog>`.
|
|
@ -0,0 +1,19 @@
|
||||||
|
============
|
||||||
|
Contributing
|
||||||
|
============
|
||||||
|
|
||||||
|
How to get the code
|
||||||
|
===================
|
||||||
|
|
||||||
|
Our primary Git repository is on Github at `paramiko/paramiko
|
||||||
|
<https://github.com/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
|
||||||
|
<http://contribution-guide.org>`_ - we follow it explicitly.
|
|
@ -0,0 +1,3 @@
|
||||||
|
invoke>=0.6.1
|
||||||
|
invocations>=0.4.4
|
||||||
|
sphinx==1.1.3
|
|
@ -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 <http://pycrypto.org>`_),
|
||||||
|
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 <http://docs.paramiko.org>`_.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
blog
|
||||||
|
installing
|
||||||
|
contributing
|
||||||
|
contact
|
||||||
|
|
||||||
|
|
||||||
|
.. rubric:: Footnotes
|
||||||
|
|
||||||
|
.. [#]
|
||||||
|
SSH is defined in RFCs
|
||||||
|
`4251 <http://www.rfc-editor.org/rfc/rfc4251.txt>`_,
|
||||||
|
`4252 <http://www.rfc-editor.org/rfc/rfc4252.txt>`_,
|
||||||
|
`4253 <http://www.rfc-editor.org/rfc/rfc4253.txt>`_, and
|
||||||
|
`4254 <http://www.rfc-editor.org/rfc/rfc4254.txt>`_;
|
||||||
|
the primary working implementation of the protocol is the `OpenSSH project
|
||||||
|
<http://openssh.org>`_. Paramiko implements a large portion of the SSH
|
||||||
|
feature set, but there are occasional gaps.
|
|
@ -0,0 +1,105 @@
|
||||||
|
==========
|
||||||
|
Installing
|
||||||
|
==========
|
||||||
|
|
||||||
|
Paramiko itself
|
||||||
|
===============
|
||||||
|
|
||||||
|
The recommended way to get Invoke is to **install the latest stable release**
|
||||||
|
via `pip <http://pip-installer.org>`_::
|
||||||
|
|
||||||
|
$ 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 <https://www.dlitz.net/software/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 <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 <http://cygwin.com>`_ or obtaining a
|
||||||
|
precompiled Win32 PyCrypto package from `voidspace's Python modules page
|
||||||
|
<http://www.voidspace.org.uk/python/modules.shtml#pycrypto>`_.
|
||||||
|
|
||||||
|
.. 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
|
||||||
|
<https://github.com/fabric/fabric/issues/194>`_ for info.
|
||||||
|
|
||||||
|
|
||||||
|
.. _pypm:
|
||||||
|
|
||||||
|
ActivePython and PyPM
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Windows users who already have ActiveState's `ActivePython
|
||||||
|
<http://www.activestate.com/activepython/downloads>`_ distribution installed
|
||||||
|
may find Paramiko is best installed with `its package manager, PyPM
|
||||||
|
<http://code.activestate.com/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:\>
|
|
@ -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)
|
Loading…
Reference in New Issue