# Author: Nic Wolfe # URL: http://code.google.com/p/sickbeard/ # # This file is part of SickRage. # # SickRage is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # SickRage is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with SickRage. If not, see . import os from subprocess import check_output, PIPE, Popen from os.path import join, split try: import json except ImportError: from lib import simplejson as json import helpers class GitHub(object): """ Simple api wrapper for the Github API v3. Currently only supports the small thing that SB needs it for - list of commits. """ def __init__(self, github_repo_user, github_repo, branch): self.github_repo_user = github_repo_user self.github_repo = github_repo self.branch = branch def _access_API(self, path, params=None): """ Access the API at the path given and with the optional params given. path: A list of the path elements to use (eg. ['repos', 'midgetspy', 'Sick-Beard', 'commits']) params: Optional dict of name/value pairs for extra params to send. (eg. {'per_page': 10}) Returns a deserialized json object of the result. Doesn't do any error checking (hope it works). """ url = 'https://api.github.com/' + '/'.join(path) if params and type(params) is dict: url += '?' + '&'.join([str(x) + '=' + str(params[x]) for x in params.keys()]) parsedJSON = helpers.getURL(url, json=True) if not parsedJSON: return [] return parsedJSON def commits(self): """ Uses the API to get a list of the 100 most recent commits from the specified user/repo/branch, starting from HEAD. user: The github username of the person whose repo you're querying repo: The repo name to query branch: Optional, the branch name to show commits from Returns a deserialized json object containing the commit info. See http://developer.github.com/v3/repos/commits/ """ access_API = self._access_API(['repos', self.github_repo_user, self.github_repo, 'commits'], params={'per_page': 100, 'sha': self.branch}) return access_API def compare(self, base, head, per_page=1): """ Uses the API to get a list of compares between base and head. user: The github username of the person whose repo you're querying repo: The repo name to query base: Start compare from branch head: Current commit sha or branch name to compare per_page: number of items per page Returns a deserialized json object containing the compare info. See http://developer.github.com/v3/repos/commits/ """ access_API = self._access_API( ['repos', self.github_repo_user, self.github_repo, 'compare', base + '...' + head], params={'per_page': per_page}) return access_API def branches(self): access_API = self._access_API( ['repos', self.github_repo_user, self.github_repo, 'branches'], params={'per_page': 100}) return access_API def installed_branch(self): installed_path = os.path.dirname(os.path.normpath(os.path.abspath(__file__))) return self.hash_dir(installed_path) def _lstree(self, files, dirs): """Make git ls-tree like output.""" for f, sha1 in files: yield "100644 blob {}\t{}\0".format(sha1, f) for d, sha1 in dirs: yield "040000 tree {}\t{}\0".format(sha1, d) def _mktree(self, files, dirs): mkt = Popen(["git", "mktree", "-z"], stdin=PIPE, stdout=PIPE) return mkt.communicate("".join(self._lstree(files, dirs)))[0].strip() def hash_file(self, path): """Write file at path to Git index, return its SHA1 as a string.""" return check_output(["git", "hash-object", "-w", "--", path]).strip() def hash_dir(self, path): """Write directory at path to Git index, return its SHA1 as a string.""" dir_hash = {} for root, dirs, files in os.walk(path, topdown=False): f_hash = ((f, self.hash_file(join(root, f))) for f in files) d_hash = ((d, dir_hash[join(root, d)]) for d in dirs) # split+join normalizes paths on Windows (note the imports) dir_hash[join(*split(root))] = self._mktree(f_hash, d_hash) return dir_hash[path]