diff --git a/.travis.yml b/.travis.yml index ba98443157a..084b8c95852 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,7 @@ env: - GIT_CI_USER=TravisCI - GIT_CI_EMAIL=TravisCI@mdanalysis.org - MDA_DOCDIR=${TRAVIS_BUILD_DIR}/package/doc/html/html + - MAINTAIN_DIR=${TRAVIS_BUILD_DIR}/maintainer # Set default python version to avoid repetition later - PYTHON_VERSION=3.6 - BUILD_DOCS=false @@ -54,7 +55,7 @@ matrix: BUILD_DOCS=true BUILD_CMD="cd ${TRAVIS_BUILD_DIR}/package && python setup.py build_ext --inplace" INSTALL_HOLE="false" - PIP_DEPENDENCIES="${PIP_DEPENDENCIES} sphinx==1.8.5 sphinx-sitemap sphinx_rtd_theme" + PIP_DEPENDENCIES="${PIP_DEPENDENCIES} sphinx==1.8.5 sphinx-sitemap sphinx_rtd_theme msmb_theme==1.2.0" - env: NAME="Lint" PYLINTRC="${TRAVIS_BUILD_DIR}/package/.pylintrc" @@ -130,6 +131,14 @@ after_success: codecov; \ fi # can't use test here since this leads to travis fails even though the build passes - - if [[ ${TRAVIS_PULL_REQUEST} == "false" ]] && [[ ${BUILD_DOCS} == "true" ]] && [[ ${TRAVIS_BRANCH} == ${GH_DOC_BRANCH} ]]; then - bash ${TRAVIS_BUILD_DIR}/maintainer/deploy_docs.sh; + # turn off blocking as it causes large writes to stdout to fail + # (see https://github.com/travis-ci/travis-ci/issues/4704) + - | + if [[ ${TRAVIS_PULL_REQUEST} == "false" ]] && [[ ${BUILD_DOCS} == "true" ]] && [[ ${TRAVIS_BRANCH} == ${GH_DOC_BRANCH} ]]; then + python -c 'import os,sys,fcntl; flags = fcntl.fcntl(sys.stdout, fcntl.F_GETFL); fcntl.fcntl(sys.stdout, fcntl.F_SETFL, flags&~os.O_NONBLOCK);' + cd ${TRAVIS_BUILD_DIR}/package/MDAnalysis + export VERSION=$(python -c "import version; print(version.__version__)") + cd - + bash ${TRAVIS_BUILD_DIR}/maintainer/deploy_docs_via_travis.sh; fi + diff --git a/README.rst b/README.rst index bd4cee395ef..cdabe47170f 100644 --- a/README.rst +++ b/README.rst @@ -128,7 +128,7 @@ to find uncovered code. .. |devdocs| image:: https://img.shields.io/badge/docs-development-yellow.svg :alt: Documentation (development version) - :target: https://www.mdanalysis.org/mdanalysis/ + :target: https://docs.mdanalysis.org/dev .. |numfocus| image:: https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A :alt: Powered by NumFOCUS diff --git a/maintainer/deploy_docs.sh b/maintainer/deploy_docs_via_travis.sh old mode 100755 new mode 100644 similarity index 75% rename from maintainer/deploy_docs.sh rename to maintainer/deploy_docs_via_travis.sh index c49f357a69c..af503e56727 --- a/maintainer/deploy_docs.sh +++ b/maintainer/deploy_docs_via_travis.sh @@ -14,6 +14,8 @@ # GIT_CI_USER name of the user to push docs as # GIT_CI_EMAIL email of the user to push docs as # MDA_DOCDIR path to the docdir from top of repo +# MAINTAIN_DIR path to maintainer/ +# VERSION version of MDAnalysis # # NOTE: If any of these environment variables are not set or # empty then the script will exit with and error (-o nounset). @@ -32,24 +34,40 @@ rev=$(git rev-parse --short HEAD) test -n "${GH_TOKEN}" || die "GH_TOKEN is empty: need OAuth GitHub token to continue" 100 test -n "${GH_REPOSITORY}" || die "GH_REPOSITORY must be set in .travis.yml" 100 test -n "${MDA_DOCDIR}" || die "MDA_DOCDIR must be set in .travis.yml" 100 +test -n "${MAINTAIN_DIR}" || die "MAINTAIN_DIR must be set in .travis.yml" 100 +test -n "${VERSION}" || die "VERSION must be set in .travis.yml" 100 + cd ${MDA_DOCDIR} || die "Failed to 'cd ${MDA_DOCDIR}'. Run from the top level of the repository" +# move into $version subdirectory +mkdir ../${VERSION} && mv * ../${VERSION} + git init git config user.name "${GIT_CI_USER}" git config user.email "${GIT_CI_EMAIL}" +mv ../${VERSION} $VERSION + git remote add upstream "https://${GH_TOKEN}@${GH_REPOSITORY}" git fetch --depth 50 upstream ${GH_DOC_BRANCH} gh-pages git reset upstream/gh-pages +# for dev, latest, home redirects +mkdir dev latest +export URL="https://docs.mdanalysis.org" +python ${MAINTAIN_DIR}/update_json_stubs_sitemap.py touch . touch .nojekyll -git add -A . +git add -A ${VERSION}/ +git add .nojekyll versions.json +git add index.html dev latest +git add *.xml + # check for anything to commit # https://stackoverflow.com/questions/3878624/how-do-i-programmatically-determine-if-there-are-uncommited-changes -git diff-index --quiet HEAD -- || git commit -m "rebuilt html docs from branch ${GH_DOC_BRANCH} with sphinx at ${rev}" +git diff-index --quiet HEAD -- || git commit -m "rebuilt html docs for version ${VERSION} from branch ${GH_DOC_BRANCH} with sphinx at ${rev}" git push -q upstream HEAD:gh-pages diff --git a/maintainer/deploy_master_docs.sh b/maintainer/deploy_master_docs.sh deleted file mode 100755 index 2c9d5b8e03a..00000000000 --- a/maintainer/deploy_master_docs.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/bash -# Deploying docs from travis-ci. -# See https://github.com/MDAnalysis/mdanalysis/issues/386 -# Script based on https://github.com/steveklabnik/automatically_update_github_pages_with_travis_example - -# Run this script from the top-level of the checked out git -# repository. A github OAuth token must be available in the evironment -# variable GH_TOKEN and is set up through the .travis.yml -# env:global:secure parameter (encrypted with travis-ci's public key)/ -# -# Additional environment variables set in .travis.yml -# GH_REPOSITORY repo to full from and push to -# GH_DOC_BRANCH branch from which the docs are built -# GIT_CI_USER name of the user to push docs as -# GIT_CI_EMAIL email of the user to push docs as -# MDA_DOCDIR path to the docdir from top of repo -# -# NOTE: If any of these environment variables are not set or -# empty then the script will exit with and error (-o nounset). - -# TESTING TO PUSH TO THE docs repo -# Assume that this is MANUALLY run from top level of repo -# and the docs were built with -# -# (cd package && python setup.py build_sphinx) -# - -# The release sitemap.xml is generated from the development -# sitemap.xml by changing MDA_DEVELOPMENT_DOCS_URL --> MDA_RELEASE_DOCS_URL -# -# See comment in package/doc/sphinx/source/conf.py for site_url. -# -MDA_RELEASE_DOCS_URL="https://www.mdanalysis.org/docs/" -MDA_DEVELOPMENT_DOCS_URL="https://www.mdanalysis.org/mdanalysis/" - -GH_REPOSITORY=github.com/MDAnalysis/docs.git -#MDA_DOCDIR=${TRAVIS_BUILD_DIR}/package/doc/html/html -MDA_DOCDIR=package/doc/html/html -GIT_CI_USER="TravisCI" -GIT_CI_EMAIL="TravisCI@mdanalysis.org" - -# for informational purposes at the moment -GH_DOC_BRANCH=$(git rev-parse --abbrev-ref HEAD) - - -set -o errexit -o nounset - -function die () { - local msg="$1" err=${2:-1} - echo "ERROR: $msg [$err]" - exit $err -} - -rev=$(git rev-parse --short HEAD) -rootdir="$(git rev-parse --show-toplevel)" - -maintainer_dir="${rootdir}/maintainer" - -# the following tests should be superfluous because of -o nounset -test -n "${GH_TOKEN}" || die "GH_TOKEN is empty: need OAuth GitHub token to continue" 100 -test -n "${GH_REPOSITORY}" || die "GH_REPOSITORY must be set in .travis.yml" 100 -test -n "${MDA_DOCDIR}" || die "MDA_DOCDIR must be set in .travis.yml" 100 - -cd ${MDA_DOCDIR} || die "Failed to 'cd ${MDA_DOCDIR}'. Run from the top level of the repository" - -# for local testing -test -d .git && rm -rf .git - -git init -git config user.name "${GIT_CI_USER}" -git config user.email "${GIT_CI_EMAIL}" - -git remote add docs "https://${GH_TOKEN}@${GH_REPOSITORY}" -git fetch --depth 10 docs master -git reset docs/master - -touch . -touch .nojekyll - -git add -A . -git commit -m "rebuilt html docs from branch ${GH_DOC_BRANCH} with sphinx at MDAnalysis/mdanalysis@${rev}" - -# fix sitemap.xml for release docs -${maintainer_dir}/adapt_sitemap.py --search ${MDA_DEVELOPMENT_DOCS_URL} --replace ${MDA_RELEASE_DOCS_URL} -o sitemap.xml sitemap.xml - -git add sitemap.xml -git commit -m "adjusted sitemap.xml for release docs at ${MDA_RELEASE_DOCS_URL}" - -git push -q docs HEAD:master - - diff --git a/maintainer/update_json_stubs_sitemap.py b/maintainer/update_json_stubs_sitemap.py new file mode 100644 index 00000000000..a699a0729a5 --- /dev/null +++ b/maintainer/update_json_stubs_sitemap.py @@ -0,0 +1,140 @@ +# Adapted from mdtraj/devtools/travis-ci/update_versions_json.py, +# by Robert T McGibbon, under the LGPLv2.1 license +# Similarly by the terms of LGPL this is also in the public domain +# Lily Wang, 2020 +# +# This script is called by deploy_docs_via_travis.sh to: +# 1. update versions.json +# 2. Write some redirect stubs +# 3. Write a sitemap.xml file for the root directory +# + +import json +import os +import shutil +import xml.etree.ElementTree as ET + +try: + from urllib.request import Request, urlopen +except ImportError: + from urllib2 import Request, urlopen + +URL = os.environ['URL'] +VERSION = os.environ['VERSION'] + + +def get_web_file(filename, callback, default): + url = os.path.join(URL, filename) + try: + page = Request(url, headers={'User-Agent': 'Mozilla/5.0'}) + data = urlopen(page).read().decode() + except Exception as e: + print(e) + try: + with open(filename, 'r') as f: + return callback(f) + except IOError as e: + print(e) + return default + else: + return callback(data) + + +# ========= WRITE JSON ========= +# Update $root/versions.json with links to the right version +versions = get_web_file('versions.json', json.loads, []) +existing = [item['version'] for item in versions] +already_exists = VERSION in existing + +if not already_exists: + latest = 'dev' not in VERSION + if latest: + for ver in versions: + ver['latest'] = False + + versions.append({ + 'version': VERSION, + 'display': VERSION, + 'url': os.path.join(URL, VERSION), + 'latest': latest + }) + +with open("versions.json", 'w') as f: + json.dump(versions, f, indent=2) + +# ========= WRITE HTML STUBS ========= +# Add HTML files to redirect: +# index.html -> latest release +# latest/index.html -> latest release +# dev/index.html -> dev docs + +REDIRECT = """ + + +Redirecting to {url} + + +""" + +for ver in versions[::-1]: + if ver['latest']: + latest_url = ver['url'] +else: + try: + latest_url = versions[-1]['url'] + except IndexError: + latest_url = None + +for ver in versions[::-1]: + if 'dev' in ver['version']: + dev_url = ver['url'] + break +else: + try: + dev_url = versions[-1]['url'] + except IndexError: + dev_url = None + +if latest_url: + with open('index.html', 'w') as f: + f.write(REDIRECT.format(url=latest_url)) + + with open('latest/index.html', 'w') as f: + f.write(REDIRECT.format(url=latest_url)) + +if dev_url: + with open('dev/index.html', 'w') as f: + f.write(REDIRECT.format(url=dev_url)) + +# ========= WRITE SUPER SITEMAP.XML ========= +# make one big sitemap.xml +ET.register_namespace('xhtml', "http://www.w3.org/1999/xhtml") + +# so we could make 1 big sitemap as commented +# below, but they must be max 50 MB / 50k URL. +# Yes, this is 100+ releases, but who knows when +# that'll happen and who'll look at this then? +# bigroot = ET.Element("urlset") +# bigroot.set("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9") +# for ver in versions: +# tree = get_web_file(ver['version']+'/sitemap.xml', ET.fromstring, +# ET.fromstring('')) +# root = tree.getroot() +# bigroot.extend(root.getchildren()) +# ET.ElementTree(bigroot).write('sitemap.xml', +# xml_declaration=True, +# encoding='utf-8', +# method="xml") + +# so instead we make a sitemap of sitemaps. +bigroot = ET.Element("sitemapindex") +bigroot.set("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9") +for ver in versions: + path = os.path.join(URL, '{}/sitemap.xml'.format(ver['version'])) + sitemap = ET.SubElement(bigroot, 'sitemap') + ET.SubElement(sitemap, 'loc').text = path + +ET.ElementTree(bigroot).write('sitemap_index.xml', + xml_declaration=True, + encoding='utf-8', + method="xml") diff --git a/package/doc/README b/package/doc/README index 13a0dff5efb..60b66f94ae4 100644 --- a/package/doc/README +++ b/package/doc/README @@ -34,12 +34,12 @@ Online html manual The documentation for the latest stable release can always be found at - https://docs.mdanalysis.org + https://www.mdanalysis.org/docs The docs for the latest development version are also on the internet at - http://devdocs.mdanalysis.org + http://docs.mdanalysis.org/dev The manual includes all the doc strings with some additional text; it is a work in progress and suggestions to improve it are welcome. File diff --git a/package/doc/sphinx/source/conf.py b/package/doc/sphinx/source/conf.py index 4155a3868ee..72c1b7e471d 100644 --- a/package/doc/sphinx/source/conf.py +++ b/package/doc/sphinx/source/conf.py @@ -15,6 +15,7 @@ import os import platform import datetime +import msmb_theme # for little versions pop-up # https://sphinx-rtd-theme.readthedocs.io/en/stable/ import sphinx_rtd_theme @@ -42,11 +43,13 @@ mathjax_path = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML' # for sitemap with https://github.com/jdillard/sphinx-sitemap -# NOTE: This sitemap is only correct for the DEVELOPMENT doccs. The RELEASE docs -# are served from https://www.mdanalysis.org/docs/ and the sitemap.xml -# is manually fixed when deploying the release docs with the -# maintainer/deploy_master_docs.sh script -site_url = "https://www.mdanalysis.org/mdanalysis/" +# This sitemap is correct both for the development and release docs, which +# are both served from docs.mdanalysis.org/$version . +# The docs used to be available automatically at mdanalysis.org/mdanalysis; +# they are now at docs.mdanalysis.org/, which requires a CNAME DNS record +# pointing to mdanalysis.github.io. To change this URL you should change/delete +# the CNAME record for "docs" and update the URL in GitHub settings +site_url = "https://docs.mdanalysis.org/" # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -78,7 +81,8 @@ # Dynamically calculate the version packageversion = __import__('MDAnalysis').__version__ # The short X.Y version. -version = '.'.join(packageversion.split('.')[:2]) +# version = '.'.join(packageversion.split('.')[:2]) +version = packageversion # needed for right sitemap.xml URLs # The full version, including alpha/beta/rc tags. release = packageversion @@ -116,14 +120,14 @@ # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] -#to include decorated objects like __init__ +# to include decorated objects like __init__ autoclass_content = 'both' # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'sphinx_rtd_theme' +html_theme = 'msmb_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -139,7 +143,7 @@ color = {'orange': '#FF9200', 'gray': '#808080', 'white': '#FFFFFF', - 'black': '#000000',} + 'black': '#000000', } html_theme_options = { 'canonical_url': '', @@ -156,8 +160,15 @@ 'titles_only': False, } +html_context = { + 'versions_json_url': 'https://docs.mdanalysis.org/versions.json' +} + # Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = ['_themes',] +html_theme_path = [ + msmb_theme.get_html_theme_path(), + sphinx_rtd_theme.get_html_theme_path() +] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". @@ -246,8 +257,8 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ - ('MDAnalysis.tex', u'MDAnalysis Documentation', - authors, 'manual'), + ('MDAnalysis.tex', u'MDAnalysis Documentation', + authors, 'manual'), ] # The name of an image file (relative to this directory) to place at the top of diff --git a/package/requirements.txt b/package/requirements.txt new file mode 100644 index 00000000000..2c22157aa5b --- /dev/null +++ b/package/requirements.txt @@ -0,0 +1,24 @@ +biopython +codecov +cython +griddataformats +gsd +hypothesis +joblib>=0.12 +matplotlib +mmtf-python +mock +msmb_theme==1.2.0 +netcdf4 +networkx +numpy +parmed +psutil +pytest +scikit-learn +scipy +seaborn>=0.7.0,<=0.9 +sphinx==1.8.5 +sphinx_rtd_theme +sphinx_sitemap +tqdm diff --git a/package/setup.py b/package/setup.py index b97524d0e85..65a355e8a90 100755 --- a/package/setup.py +++ b/package/setup.py @@ -103,6 +103,9 @@ sys.exit(1) cython_linetrace = False +def abspath(file): + return os.path.join(os.path.dirname(os.path.abspath(__file__)), + file) class Config(object): """Config wrapper class to get build options @@ -122,6 +125,7 @@ class Config(object): """ def __init__(self, fname='setup.cfg'): + fname = abspath(fname) if os.path.exists(fname): self.config = configparser.SafeConfigParser() self.config.read(fname) @@ -152,9 +156,10 @@ class MDAExtension(Extension, object): # This is accomplished by passing the get_numpy_include function # as one of the include_dirs. This derived Extension class takes # care of calling it when needed. - def __init__(self, *args, **kwargs): + def __init__(self, name, sources, *args, **kwargs): self._mda_include_dirs = [] - super(MDAExtension, self).__init__(*args, **kwargs) + sources = [abspath(s) for s in sources] + super(MDAExtension, self).__init__(name, sources, *args, **kwargs) @property def include_dirs(self): @@ -163,7 +168,8 @@ def include_dirs(self): try: self._mda_include_dirs.append(item()) #The numpy callable except TypeError: - self._mda_include_dirs.append(item) + item = abspath(item) + self._mda_include_dirs.append((item)) return self._mda_include_dirs @include_dirs.setter @@ -459,7 +465,7 @@ def dynamic_author_list(): "Chronological list of authors" title. """ authors = [] - with codecs.open('AUTHORS', encoding='utf-8') as infile: + with codecs.open(abspath('AUTHORS'), encoding='utf-8') as infile: # An author is a bullet point under the title "Chronological list of # authors". We first want move the cursor down to the title of # interest. @@ -498,7 +504,7 @@ def dynamic_author_list(): + authors + ['Oliver Beckstein']) # Write the authors.py file. - out_path = 'MDAnalysis/authors.py' + out_path = abspath('MDAnalysis/authors.py') with codecs.open(out_path, 'w', encoding='utf-8') as outfile: # Write the header header = '''\ @@ -522,7 +528,7 @@ def dynamic_author_list(): except (OSError, IOError): warnings.warn('Cannot write the list of authors.') - with open("SUMMARY.txt") as summary: + with open(abspath('SUMMARY.txt')) as summary: LONG_DESCRIPTION = summary.read() CLASSIFIERS = [ 'Development Status :: 4 - Beta', diff --git a/testsuite/README b/testsuite/README index d1c116b7163..c61fb7f75c5 100644 --- a/testsuite/README +++ b/testsuite/README @@ -50,7 +50,7 @@ Help is also available through the mailing list at https://groups.google.com/gro .. |devdocs| image:: https://img.shields.io/badge/docs-development-yellow.svg :alt: Documentation (development version) - :target: https://www.mdanalysis.org/mdanalysis/ + :target: https://docs.mdanalysis.org/dev/ .. |developergroup| image:: https://img.shields.io/badge/Google%20Group-Developers-lightgrey.svg :alt: Developer Google Group