Source code for punx.github_handler

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#-----------------------------------------------------------------------------
# :author:    Pete R. Jemian
# :email:     prjemian@gmail.com
# :copyright: (c) 2016, Pete R. Jemian
#
# Distributed under the terms of the Creative Commons Attribution 4.0 International Public License.
#
# The full license is in the file LICENSE.txt, distributed with this software.
#-----------------------------------------------------------------------------

"""
manages the communications with GitHub


.. autosummary::

    ~GitHub_Repository_Reference

USAGE::

    grr = punx.github_handler.GitHub_Repository_Reference()
    grr.connect_repo()
    if grr.request_info(u'v3.2') is not None:
        d = grr.download()

"""

import os

import datetime
import requests
from requests.packages.urllib3 import disable_warnings
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import github

from . import utils


logger = utils.setup_logger(__name__)

CREDS_FILE_NAME = u'__github_creds__.txt'
DEFAULT_BRANCH_NAME = u'master'
DEFAULT_RELEASE_NAME = u'v2018.5'
#DEFAULT_TAG_NAME = u'NXroot-1.0'
DEFAULT_TAG_NAME = u'Schema-3.3'
DEFAULT_COMMIT_NAME = u'a4fd52d'
DEFAULT_NXDL_SET = DEFAULT_RELEASE_NAME
GITHUB_RETRY_COUNT = 3

GITHUB_NXDL_ORGANIZATION = 'nexusformat'
GITHUB_NXDL_REPOSITORY = 'definitions'
GITHUB_NXDL_BRANCH = 'master'
GITHUB_RETRY_COUNT = 3
#NXDL_CACHE_SUBDIR = GITHUB_NXDL_REPOSITORY + '-' + GITHUB_NXDL_BRANCH


[docs]def get_BasicAuth_credentials(creds_file_name = None): """ get the Github Basic Authentication credentials from a local file GitHub requests can use *Basic Authentication* if the credentials (username and password) are provided in the local file ``__github_creds__.txt`` which is placed in the same directory as this file. The credentials file is not placed under version control since it has GitHub credentials. If found, the file is parsed for ``username password`` as shown below. Be sure to make the file readable only by the user and not others. """ # TODO: also look in user's .config directory, use a for loop to pick first matching path if creds_file_name is None: path = os.path.dirname(__file__) creds_file_name = os.path.join(path, CREDS_FILE_NAME) if not os.path.exists(creds_file_name): return uname, pwd = open(creds_file_name, 'r').read().strip().split() return dict(user=uname, password=pwd)
[docs]class GitHub_Repository_Reference(object): """ all information necessary to describe and download a repository branch, release, tag, or SHA hash ROUTINES .. autosummary:: ~connect_repo ~request_info ~download :see: https://github.com/PyGithub/PyGithub/tree/master/github """ def __init__(self): self.orgName = GITHUB_NXDL_ORGANIZATION self.appName = GITHUB_NXDL_REPOSITORY self.repo = None self.ref = None self.ref_type = None self.sha = None self.zip_url = None self.last_modified = None
[docs] def connect_repo(self, repo_name=None): """ connect with the GitHub repository :param str repo_name: name of repository in https://github.com/nexusformat (default: *definitions*) :returns bool: True if using GitHub credentials """ repo_name = repo_name or self.appName creds = get_BasicAuth_credentials() if creds is None: gh = github.Github() self.repo = gh.get_repo(repo_name) else: gh = github.Github(creds['user'], creds['password']) user = gh.get_user(self.orgName) self.repo = user.get_repo(repo_name) return creds is not None
[docs] def request_info(self, ref=None): """ request download information about ``ref`` :param str ref: name of branch, release, tag, or SHA hash (default: *v3.2*) download URLs * base: https://github.com * master: https://github.com/nexusformat/definitions/archive/master.zip * branch (www_page_486): https://github.com/nexusformat/definitions/archive/www_page_486.zip * hash (83ce630): https://github.com/nexusformat/definitions/archive/83ce630.zip * release (v3.2): see hash c0b9500 * tag (NXcanSAS-1.0): see hash 83ce630 """ ref = ref or DEFAULT_NXDL_SET if self.repo is None: raise ValueError('call connect_repo() first') node = self.get_branch(ref) \ or self.get_release(ref) \ or self.get_tag(ref) \ or self.get_commit(ref) return node
[docs] def download(self): """ download the NXDL definitions described by ``ref`` """ _msg = u'disabling warnings about GitHub self-signed https certificates' #requests.packages.urllib3.disable_warnings(InsecureRequestWarning) disable_warnings(InsecureRequestWarning) creds = get_BasicAuth_credentials() content = None for _retry in range(GITHUB_RETRY_COUNT): # noqa try: if creds is None: content = requests.get(self.zip_url, verify=False) else: content = requests.get(self.zip_url, auth=(creds['user'], creds['password']), verify=False, ) except requests.exceptions.ConnectionError as _exc: _msg = 'ConnectionError from ' + self.zip_url _msg += '\n' + str(_exc) raise IOError(_msg) else: break return content
def _make_zip_url(self, ref=DEFAULT_BRANCH_NAME): """create the download URL for the ``ref``""" url = u'https://github.com/' url += u'/'.join([self.orgName, self.appName, u'archive', ref]) url += u'.zip' return url def _get_last_modified(self): """get the ``last_modified`` date from the SHA's commit""" if self.sha is not None: commit = self.repo.get_commit(self.sha) mod_date_time = commit.last_modified # Tue, 20 Dec 2016 18:30:29 GMT fmt = '%a, %d %b %Y %H:%M:%S %Z' # --> 2016-11-19 01:04:28 mod_date_time = datetime.datetime.strptime(commit.last_modified, fmt) self.last_modified = str(mod_date_time)
[docs] def get_branch(self, ref=DEFAULT_BRANCH_NAME): """ learn the download information about the named branch :param str ref: name of branch in repository """ try: node = self.repo.get_branch(ref) self.ref = ref self.ref_type = u'branch' self.sha = node.commit.sha self.zip_url = self._make_zip_url(self.sha[:7]) self._get_last_modified() return node except github.GithubException: return None
[docs] def get_release(self, ref=DEFAULT_RELEASE_NAME): """ learn the download information about the named release :param str ref: name of release in repository """ try: node = self.repo.get_release(ref) self.get_tag(node.tag_name) self.ref = ref self.ref_type = u'release' return node except github.GithubException: return None
[docs] def get_tag(self, ref=DEFAULT_TAG_NAME): """ learn the download information about the named tag :param str ref: name of tag in repository """ try: for tag in self.repo.get_tags(): if tag.name == ref: self.ref = ref self.ref_type = u'tag' self.sha = tag.commit.sha # self.zip_url = self._make_zip_url(self.sha[:7]) self.zip_url = tag.zipball_url self._get_last_modified() return tag except github.GithubException: return None
[docs] def get_commit(self, ref=DEFAULT_COMMIT_NAME): """ learn the download information about the referenced commit :param str ref: name of SHA hash, first unique characters are sufficient, usually 7 or less """ try: node = self.repo.get_commit(ref) self.ref = ref self.ref_type = u'commit' self.sha = node.commit.sha self.zip_url = self._make_zip_url(self.sha[:7]) self._get_last_modified() return node except github.GithubException: return None