#!/usr/bin/env python3 import argparse import os import sys import pygit2 from flake8.api import legacy as flake8_legacy def is_git_repo(abspath): """ True of abspath points to a git repo, False otherwise """ if not os.path.isdir(abspath): return False try: pygit2.Repository(abspath) return True except pygit2.GitError: return False def modifications_exist(abspath): """ True if modifications exist for git repo representing abspath False if no modifications exist pygit2.GitError raised if abspath points to illegal repo """ repo = pygit2.Repository(abspath) status = repo.status() for gfile, state in status.items(): if ( state in (pygit2.GIT_STATUS_WT_MODIFIED, pygit2.GIT_STATUS_WT_NEW, pygit2.GIT_STATUS_INDEX_NEW, pygit2.GIT_STATUS_INDEX_MODIFIED) ): return True return False def print_modification_status(abspath, status, args): """ Prints the modification status for the give abspath """ if status: if args.verbose: print(f'{abspath} -> modified') else: print(abspath) return status if args.verbose: print(f'{abspath} -> unchanged') return status def fetch_git_repos(abspath): """ Returns a list of git repo paths under abspath """ repo_list = list() for root, dirs, files in os.walk(abspath): if '.git' in dirs: try: pygit2.Repository(root) repo_list.append(root) except pygit2.GitError: continue return repo_list def fetch_git_files(args): """ Fetches new and modified .py-files using pygit2 """ git_files_list = list() try: repo = pygit2.Repository(args.repo_path) status = repo.status() except pygit2.GitError: print('{repo_path} is not a valid git repository'.format( repo_path=args.repo_path), file=sys.stderr, flush=True) sys.exit(1) if not status: return git_files_list for gfile, state in status.items(): if ( state in (pygit2.GIT_STATUS_WT_MODIFIED, pygit2.GIT_STATUS_WT_NEW, pygit2.GIT_STATUS_INDEX_NEW, pygit2.GIT_STATUS_INDEX_MODIFIED) and gfile.lower().endswith('.py') ): if args.verbose: print(gfile) git_files_list.append(gfile) return git_files_list if __name__ == '__main__': parser = argparse.ArgumentParser( description='The following options are available') parser.add_argument( 'repo_path', metavar='REPO', default=os.getcwd(), type=str, help='Git repo path (default: cwd)') parser.add_argument( '-m', '--modifications-only', action='store_true', dest='mod_only', default=False, help='Only check for git modifications') parser.add_argument( '-r', '--recursive', action='store_true', dest='recursive', default=False, help='Look for several repos recursively') parser.add_argument( '-v', '--verbose', action='store_true', dest='verbose', default=False, help='Verbosity') args = parser.parse_args() abs_repo_path = os.path.abspath(os.path.expanduser(args.repo_path)) if args.mod_only: if not args.recursive: if not is_git_repo(abs_repo_path): print(f'{abs_repo_path} is not a valid git repository', file=sys.stderr, flush=True) sys.exit(1) print_modification_status(abs_repo_path, modifications_exist(abs_repo_path), args) sys.exit(0) # resursive repo_list = fetch_git_repos(abs_repo_path) if not repo_list: print('No git-repos found') sys.exit(0) repo_list.sort() for repo_path in repo_list: print_modification_status(repo_path, modifications_exist(repo_path), args) sys.exit(0) git_files = fetch_git_files(args) if not git_files: print('No modifications') sys.exit(0) report = flake8_legacy.get_style_guide().check_files(git_files) if report.total_errors: print('Total errors: {errors}'.format(errors=report.total_errors))