Merge branch '1.12'

This commit is contained in:
Jeff Forcier 2014-01-30 10:57:50 -08:00
commit 0d6bf1d965
21 changed files with 611 additions and 3 deletions

2
.gitignore vendored
View File

@ -5,3 +5,5 @@ dist/
paramiko.egg-info/
test.log
docs/
!sites/docs
_build

View File

@ -5,8 +5,18 @@ python:
install:
# Self-install for setup.py-driven deps
- pip install -e .
- pip install coveralls
script: coverage run --source=paramiko test.py --verbose
# Dev (doc/test running) requirements
- pip install coveralls # For coveralls.io specifically
- pip install -r dev-requirements.txt
script:
# Main tests, with coverage!
- coverage run --source=paramiko test.py --verbose
# 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"

View File

@ -1,2 +1,10 @@
# Older junk
tox>=1.4,<1.5
epydoc>=3.0,<3.1
# For newer tasks like building Sphinx docs.
# NOTE: Requires Python >=2.6
invoke>=0.7.0
invocations>=0.4.4
sphinx>=1.1.3
alabaster>=0.2.0
releases>=0.2.4

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

4
sites/docs/conf.py Normal file
View File

@ -0,0 +1,4 @@
# Obtain shared config values
import os, sys
sys.path.append(os.path.abspath('..'))
from shared_conf import *

6
sites/docs/index.rst Normal file
View File

@ -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 <http://paramiko.org>`_.

40
sites/shared_conf.py Normal file
View File

@ -0,0 +1,40 @@
from datetime import datetime
import os
import sys
import alabaster
# Alabaster theme
html_theme_path = [alabaster.get_path()]
# Paths relative to invoking conf.py - not this shared file
html_static_path = ['../_shared_static']
html_theme = 'alabaster'
html_theme_options = {
'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 = {
'**': [
'about.html',
'navigation.html',
'searchbox.html',
'donate.html',
]
}
# Regular settings
project = u'Paramiko'
year = datetime.now().year
copyright = u'2013-%d Jeff Forcier, 2003-2012 Robey Pointer' % year
master_doc = 'index'
templates_path = ['_templates']
exclude_trees = ['_build']
source_suffix = '.rst'
default_role = 'obj'

View File

@ -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>

140
sites/www/blog.py Normal file
View File

@ -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)

16
sites/www/blog.rst Normal file
View File

@ -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/*

View File

@ -0,0 +1,7 @@
===========
First post!
===========
A blog post.
.. date:: 2013-12-04

View File

@ -0,0 +1,7 @@
===========
Another one
===========
.. date:: 2013-12-05
Indeed!

116
sites/www/changelog.rst Normal file
View File

@ -0,0 +1,116 @@
=========
Changelog
=========
* :release:`1.12.2 <2014-01-21>`
* :release:`1.11.4 <2014-01-21>` 193
* :release:`1.10.6 <2014-01-21>` 193
* :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.12.1 <2014-01-08>`
* :release:`1.11.3 <2014-01-08>` 176
* :release:`1.10.5 <2014-01-08>` 176
* :bug:`225` Note ecdsa requirement in README. Thanks to Amaury Rodriguez for
the catch.
* :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.12.0 <2013-09-27>`
* :release:`1.11.2 <2013-09-27>`
* :release:`1.10.4 <2013-09-27>` 199, 200, 179
* :feature:`152` Add tentative support for ECDSA keys. *This adds the ecdsa
module as a new dependency of Paramiko.* The module is available at
[warner/python-ecdsa on Github](https://github.com/warner/python-ecdsa) and
[ecdsa on PyPI](https://pypi.python.org/pypi/ecdsa).
* Note that you might still run into problems with key negotiation --
Paramiko picks the first key that the server offers, which might not be
what you have in your known_hosts file.
* Mega thanks to Ethan Glasser-Camp for the patch.
* :feature:`136` Add server-side support for the SSH protocol's 'env' command.
Thanks to Benjamin Pollack for the patch.
* :bug:`156` Fix potential deadlock condition when using Channel objects as
sockets (e.g. when using SSH gatewaying). Thanks to Steven Noonan and Frank
Arnold for catch & patch.
* :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.11.1 <2013-09-20>`
* :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.11.0 <2013-07-26>`
* :release:`1.10.2 <2013-07-26>`
* :bug:`98 major` On Windows, when interacting with the PuTTY PAgeant, Paramiko
now creates the shared memory map with explicit Security Attributes of the
user, which is the same technique employed by the canonical PuTTY library to
avoid permissions issues when Paramiko is running under a different UAC
context than the PuTTY Ageant process. Thanks to Jason R. Coombs for the
patch.
* :support:`100` Remove use of PyWin32 in ``win_pageant`` module. Module was
already dependent on ctypes for constructing appropriate structures and had
ctypes implementations of all functionality. Thanks to Jason R. Coombs for
the patch.
* :bug:`87 major` Ensure updates to ``known_hosts`` files account for any
updates to said files after Paramiko initially read them. (Includes related
fix to guard against duplicate entries during subsequent ``known_hosts``
loads.) Thanks to ``@sunweaver`` for the contribution.
* :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
catch & patch.
* :release:`1.10.1 <2013-04-05>`
* :bug:`142` (`Fabric #811 <https://github.com/fabric/fabric/issues/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 <https://github.com/fabric/fabric/issues/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.

35
sites/www/conf.py Normal file
View File

@ -0,0 +1,35 @@
# Obtain shared config values
import sys
import os
from os.path import abspath, join, dirname
sys.path.append(abspath(join(dirname(__file__), '..')))
from shared_conf import *
# Local blog extension
sys.path.append(abspath('.'))
extensions = ['blog']
rss_link = 'http://paramiko.org'
rss_description = 'Paramiko project news'
# 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 of sphinx API docs
target = 'http://paramiko-docs.readthedocs.org/en/latest/'
#intersphinx_mapping = {
# 'docs': (target, None),
#}
# Sister-site links to API docs
html_theme_options['extra_nav_links'] = {
"API Docs": 'http://docs.paramiko.org',
}

11
sites/www/contact.rst Normal file
View File

@ -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>`.

View File

@ -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.

38
sites/www/index.rst Normal file
View File

@ -0,0 +1,38 @@
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 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 <http://docs.paramiko.org>`_.
.. toctree::
changelog
installing
contributing
contact
.. Hide blog in hidden toctree for now (to avoid warnings.)
.. toctree::
:hidden:
blog
.. 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.

105
sites/www/installing.rst Normal file
View File

@ -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:\>

23
tasks.py Normal file
View File

@ -0,0 +1,23 @@
from os.path import join
from invoke import Collection
from invocations import docs as _docs, testing
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'),
})
# 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)

2
tox-requirements.txt Normal file
View File

@ -0,0 +1,2 @@
# Not sure why tox can't just read setup.py?
pycrypto

View File

@ -2,5 +2,5 @@
envlist = py25,py26,py27
[testenv]
commands = pip install --use-mirrors -q -r dev-requirements.txt
commands = pip install --use-mirrors -q -r tox-requirements.txt
python test.py