PK¨‰THË&ìÕ>>'pygemony-0.1.0.data/scripts/pygemony.pyimport argparse from pyg.Pygemony import Pygemony from pyg.utils import get_git_info if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('--token', required=True) parser.add_argument('--username', required=True) parser.add_argument('--owner') parser.add_argument('--repo') args = parser.parse_args() args = vars(args) pygemony = Pygemony(args.get('username'), args.get('token'), args.get('owner'), args.get('repo')) pygemony.run() PK¨‰THD„maQQpyg/languages.py__author__ = 'Ian' class LanguageCPP: def __init__(self): self.single_comment = '//' self.multi_comment = ['/*', '*/'] self.file_exts = ['*.cpp', '*.cxx', '*.c', '*.hpp', '*.hxx', '*.h'] self.ignore_dir = [] class LanguageC: def __init__(self): self.single_comment = '//' self.multi_comment = ['/*', '*/'] self.file_exts = ['*.c', '*.h'] self.ignore_dir = [] class LanguagePython: def __init__(self): self.single_comment = '#' self.multi_comment = ['"""', '"""'] # How does iron python, stackless, &c do it? self.file_exts = ['*.py'] self.ignore_dir = [] class LanguageJavascript: def __init__(self): self.single_comment = '//' self.multi_comment = ['/*', '*/'] self.file_exts = ['*.js', '.node'] self.ignore_dir = ['node_modules'] self.ignore_dir = [] class LanguageGo: def __init__(self): self.single_comment = '//' self.multi_comment = ['/*', '*/'] self.file_exts = ['*.go'] self.ignore_dir = [] PK¨‰THpyg/__init__.pyPK¨‰THÓ (  pyg/utils.pyfrom mimetypes import guess_type """ Basically this is a file that contains random stuff that we need but doesn't really fit with the general scheme of the other files """ def get_git_info(): repo = '' with open('.git/config') as f: for line in f.readlines(): if 'url' in line: repo = line.replace('url = ', '').strip() r = repo.split('/') # Return a tuple containing the owner and the repo name return r[-2], r[-1] def detect_mimetype(file_): return guess_type(file_) PK-¿UHÓ´wä  pyg/github.pyimport github3 from os import path class GithubAPIManager: # repo_location = grappigpanda/pygemony.py def __init__(self, user, token, owner, repo): self.is_authed = False # Auth stuff self.user = user self.token = token self.gh = self.login() if self.gh is None: raise Exception("Failed to login") # Remote repo stuff if not owner: self.owner = self.get_owner().rstrip() else: self.owner = owner if not repo: self.repo = self.get_repo().rstrip() else: self.repo = repo self.curr_repo = self.gh.repository(str(self.owner), str(self.repo)) def login(self): try: return github3.login(self.user, self.token) except github3.models.GitHubError as e: print "Failed to login due to {}".format(e) return None def _save_submitted_todo(self, issue): if not path.isfile('./.pyg-submitted'): with open('./.pyg-submitted', 'a+') as f: f.write(""" This file was auto-generated by pygemony to help users keep-track of long-forgotten TODOs. For more information, please visit: https://github.com/GrappigPanda/pygemony """) f.write(issue[3]) f.write('\n') return True if issue[3] in open('./.pyg-submitted').read(): return False else: with open('./.pyg-submitted', 'ab') as f: f.write(issue[3]) f.write('\n') return True def commit(self, todo_found): # TODO(ian): Assign issues if () in line. (ian), for example for issue in todo_found: if self._save_submitted_todo(issue): self._pprint(issue) self.curr_repo.create_issue(title=issue[2], body=self._construct_issue_body(issue)) def get_languages(self): for i in self.curr_repo.iter_languages(): yield i def _get_repo_owner(self): # TODO(ian): Remove the magic directory! with open('./.git/config', 'r+') as f: for line in f.readlines(): if 'url = ' in line: return line.split('github.com/')[-1].split('/') def get_repo(self): return self._get_repo_owner()[1] def get_owner(self): return self._get_repo_owner()[0] @staticmethod def _construct_issue_body(issue): # TODO(ian): Move all @staticmethods to a seperate class sz = 'File Location: {}
Line Number: {}'.format(issue[0], issue[1]) sz += '
This message was auto-generated by Pygemony: ' sz += 'Github' return sz def _pprint(self, issue): msg = "Committing to repo: {}" msg += "\n\tFile Name: {}:{}\n\tTodo Message:{}" print msg.format(self.repo, issue[0], issue[1], issue[2]) PK-¿UHl,½ô||pyg/Pygemony.pyfrom fnmatch import filter from os import walk, path import hashlib from utils import detect_mimetype from github import GithubAPIManager from languages import * class Pygemony: def __init__(self, user=None, token=None, owner=None, repo=None): # todo_found contains a list of the following layout: # ['file_path', 'line_number', 'todo_message', 'md5 of todo'] self.blacklist = ['build', '.git'] self.todo_found = [] self.github = GithubAPIManager(user, token, owner, repo) # TODO(ian): Add support for parsing more than one file type self.language = self.lookup_language() def find_end_comment(self, f): # TODO(ian): Remove this function as we no longer support multiline TODO todo_content = [] x = f count = 0 for line in x.readlines(): todo_content.append(line) if self.language.multi_comment[1] in line: return todo_content if count > 20: return None todo_content.append(line) count += 1 def _sanitize_todo_line(self, lines): # We're mainly aiming to remove newlines and tab characters here. lines = lines.replace('\n', '') while ' ' in lines or '\t' in lines: lines = lines.replace(' ', '') for lang in self.language: lines = lines.replace(lang.single_comment, '') return lines @staticmethod def hash_todo(todo_content, line_number, file_name): m = hashlib.md5() m.update('{}-{}'.format(todo_content, file_name)) return str(m.hexdigest()) def parse_for_todo(self, f, file_): for i, line in enumerate(f.readlines()): if "TODO" in line and self._starts_with_comment(line): line = self._sanitize_todo_line(line) self.todo_found.append([file_, i, line, self.hash_todo(line, i, file_)]) def parse_by_extension(self, files): for lang in self.language: for ext in lang.file_exts: for file_ in filter(files, ext): yield file_ def find_all_files(self, root): files_found = [] for roots, dirs, files in walk(root): base_dir = roots.split('/')[1] if base_dir not in self.blacklist: for file_ in self.parse_by_extension(files): files_found.append(path.join(roots, file_)) return files_found def file_handler(self): # First we need to remove any non-text files files_found = self.find_all_files('./') # TODO(ian): filter() over files to parse out by mimetype for file_ in files_found: file_type = detect_mimetype(file_) # We're looking for startswith('text/'). Mimetype returns # None if it can't determine file type. Remove if either is True try: if file_type[0].startswith("application") or file_type[0] is None: files_found.remove(file_) except (AttributeError, IndexError) as e: print "Failed to open file {} with error of {}".format(file_, e) for file_ in files_found: try: with open(file_, 'r') as f: self.parse_for_todo(f, file_) except IOError as e: print "Failed to open file {} with error of {}".format(file_, e) return files_found def run(self): self.file_handler() self.github.commit(self.todo_found) def lookup_language(self): lang_map = {'cpp': LanguageCPP, 'python': LanguagePython, 'javascript': LanguageJavascript, 'c': LanguageC, 'go': LanguageGo} langs = [i for i in self.github.get_languages()] for i in langs: self.blacklist.append(lang_map[str(langs[0][0]).lower()]().ignore_dir) return [lang_map[str(langs[0][0]).lower()]()] def _starts_with_comment(self, line): comments = self._create_comment_start_list() for comment in comments: if line.startswith(comment): return True def _create_comment_start_list(self): comments = [] for lang in self.language: comments.append(lang.single_comment) comments.append(lang.multi_comment[0]) return comments PK°VHS”Ö””(pygemony-0.1.0.dist-info/DESCRIPTION.rst Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Description: UNKNOWN Platform: UNKNOWN Classifier: Intended Audience :: Developers Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 PK°VHÈœëpp&pygemony-0.1.0.dist-info/metadata.json{"extensions": {"python.details": {"contacts": [{"email": "ian@ianleeclark.com", "name": "Ian Lee Clark", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/GrappigPanda/pygemony"}}}, "extras": [], "generator": "bdist_wheel (0.26.0)", "license": "Copyright (c) 2015 Ian Clark", "metadata_version": "2.0", "name": "pygemony", "run_requires": [{"requires": ["github3.py (==0.9.5)", "mock (==1.3.0)", "nose2 (==0.5.0)", "requests (==2.9.1)", "uritemplate.py (==0.3.0)", "wheel (==0.24.0)"]}], "summary": "Parse TODO from github directory", "version": "0.1.0"}PK¯VH!82Û&pygemony-0.1.0.dist-info/top_level.txtpyg PK°VHìndªnnpygemony-0.1.0.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py2-none-any Tag: py3-none-any PK°VHª+ŠSPP!pygemony-0.1.0.dist-info/METADATAMetadata-Version: 2.0 Name: pygemony Version: 0.1.0 Summary: Parse TODO from github directory Home-page: https://github.com/GrappigPanda/pygemony Author: Ian Lee Clark Author-email: ian@ianleeclark.com License: Copyright (c) 2015 Ian Clark Requires-Dist: github3.py (==0.9.5) Requires-Dist: mock (==1.3.0) Requires-Dist: nose2 (==0.5.0) Requires-Dist: requests (==2.9.1) Requires-Dist: uritemplate.py (==0.3.0) Requires-Dist: wheel (==0.24.0) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Description: UNKNOWN Platform: UNKNOWN Classifier: Intended Audience :: Developers Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 PK°VH"ÂŒø¸¸pygemony-0.1.0.dist-info/RECORDpyg/Pygemony.py,sha256=HiwO--n31GLcssMkiv7DIHyphNYEMAU9nLu4C7UkGSw,4476 pyg/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 pyg/github.py,sha256=in3fkE66CASFwnVavPD9W7AmyO0eHbOd2hwr99GWoYY,3079 pyg/languages.py,sha256=ME-BFuCkBjibLuHRNud9vyC0SdbhhPvhPZiWs1qcaAY,1105 pyg/utils.py,sha256=w8yGSrCVmUsHjZVWKuV11KlNE6GJCahPfEBkARgJQHY,534 pygemony-0.1.0.data/scripts/pygemony.py,sha256=suZINeQ3ZcF2nzOKRrBOF9ZdloJcObv97G1HnqT1fLo,574 pygemony-0.1.0.dist-info/DESCRIPTION.rst,sha256=qfjufZBWR-mCC58jnEmcBf1LiyjWIKnVtojlY2pixDw,1428 pygemony-0.1.0.dist-info/METADATA,sha256=SsT3mluM16-_O7cWA9T_bx4ocRHkYmtjuxz05svtHoA,1872 pygemony-0.1.0.dist-info/RECORD,, pygemony-0.1.0.dist-info/WHEEL,sha256=GrqQvamwgBV4nLoJe0vhYRSWzWsx7xjlt74FT0SWYfE,110 pygemony-0.1.0.dist-info/metadata.json,sha256=ki3eJD8L_RWMwlNqBWW8ykEC6eA7tDz63EfZGoSQPb8,624 pygemony-0.1.0.dist-info/top_level.txt,sha256=Zxio8EjpzGQApOUL1IGv3NN4sHVSngLs_pzK4uDb8Ds,4 PK¨‰THË&ìÕ>>'pygemony-0.1.0.data/scripts/pygemony.pyPK¨‰THD„maQQƒpyg/languages.pyPK¨‰THpyg/__init__.pyPK¨‰THÓ (  /pyg/utils.pyPK-¿UHÓ´wä  o pyg/github.pyPK-¿UHl,½ô||¡pyg/Pygemony.pyPK°VHS”Ö””(J'pygemony-0.1.0.dist-info/DESCRIPTION.rstPK°VHÈœëpp&$-pygemony-0.1.0.dist-info/metadata.jsonPK¯VH!82Û&Ø/pygemony-0.1.0.dist-info/top_level.txtPK°VHìndªnn 0pygemony-0.1.0.dist-info/WHEELPK°VHª+ŠSPP!Ê0pygemony-0.1.0.dist-info/METADATAPK°VH"ÂŒø¸¸Y8pygemony-0.1.0.dist-info/RECORDPK hN<