<file_sep>import sys
from shutil import which
import os
from os import path, getcwd

from flask import Flask, request, jsonify
from flask_cors import CORS

import config
from util import read_csv_file, parse_date, is_git_dir
from cli import CLI


working_dir = sys.argv[1] if len(sys.argv) > 1 else getcwd()


app = Flask(__name__)
CORS(app)
app.config.from_object(config)
app.config['GIT_DIR'] = working_dir

# Check setting
if not which(app.config['JAVA_COMMAND']):
    raise AssertionError("Java command, %s, does not exist." %
                         app.config['JAVA_COMMAND'])

if not which(app.config['GIT_COMMAND']):
    raise AssertionError("Git command, %s, does not exist." %
                         app.config['GIT_COMMAND'])

if not path.isfile(app.config['CODE_MAAT_JAR_FILE']):
    raise AssertionError("Code Maat jar file, %s, does not exist." %
                         app.config['CODE_MAAT_JAR_FILE'])

if not is_git_dir(working_dir):
    raise AssertionError("Directory, %s, is not a git repo." %
                         app.config['GIT_DIR'])


# Object
cli = CLI(
    code_maat_jar_file=app.config['CODE_MAAT_JAR_FILE'],
    git_command=app.config['GIT_COMMAND'],
    java_command=app.config['JAVA_COMMAND'],
    git_dir=app.config['GIT_DIR'])


# Routing
@app.route('/api/', methods=['GET'])
def blank():
    pass


@app.route('/api/commits', methods=['GET'])
def commit_entries():
    return jsonify(cli.get_commits())


def delete_dir_files(cache_dir):
    filelist = [f for f in os.listdir(cache_dir)]
    for f in filelist:
        os.remove(path.join(cache_dir, f))


@app.route('/api/code-maat', methods=['DELETE'])
def clear_log_files():
    cache_dir = cli.log_dir
    delete_dir_files(cache_dir)
    return jsonify({
        "message": "Log directory is now cleared.",
        "logDir": cache_dir})

@app.route('/api/code-maat', methods=['GET'])
def log_file():
    analysis = request.args.get('analysis')
    start_date = request.args.get('start-date')
    end_date = request.args.get('end-date')

    # Parameter
    try:
        start_date = parse_date(start_date)
    except:
        return ("ERROR: Start date can't be parsed by YYYY-MM-DD format.", 400)

    try:
        end_date = parse_date(end_date)
    except:
        return ("ERROR: End date can't be parsed by YYYY-MM-DD format.", 400)

    # Validate
    if start_date > end_date:
        return ("ERROR: Start date can't be ahead of the end date.", 400)

    # Logic
    log_file = cli.generate_log_file(start_date, end_date)

    if analysis is None or analysis == 'summary':
        return jsonify(read_csv_file(cli.generate_summary_file(log_file)))
    elif analysis == 'revision':
        return jsonify(read_csv_file(cli.generate_revision_file(log_file)))
    elif analysis == 'coupling':
        return jsonify(read_csv_file(cli.generate_coupling_file(log_file)))
    elif analysis == 'age':
        return jsonify(read_csv_file(cli.generate_age_file(log_file)))
    elif analysis == 'abs-churn':
        return jsonify(
            read_csv_file(cli.generate_absolute_churn_file(log_file)))
    elif analysis == 'author-churn':
        return jsonify(
            read_csv_file(cli.generate_author_churn_file(log_file)))
    elif analysis == 'entity-churn':
        return jsonify(
            read_csv_file(cli.generate_entity_churn_file(log_file)))
    elif analysis == 'entity-ownership':
        return jsonify(
            read_csv_file(cli.generate_entity_ownership_file(log_file)))
    elif analysis == 'entity-effort':
        return jsonify(
            read_csv_file(cli.generate_entity_effort_file(log_file)))
    else:
        return ("ERROR: Analysis type not in selection.", 400)


app_port = 30080

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=app_port)
<file_sep>from werkzeug.routing import BaseConverter

from datetime import datetime


class PeriodConverter(BaseConverter):
    _period_format = "%Y%m%d"

    def to_python(self, text):
        return datetime.strptime(text, PeriodConverter._period_format)

    def to_url(self, date):
        return datetime.strftime(date, PeriodConverter._period_format)
<file_sep>aniso8601==1.2.1
appdirs==1.4.3
click==6.7
Flask==0.12.1
Flask-Cors==3.0.2
itsdangerous==0.24
Jinja2==2.9.6
MarkupSafe==1.0
packaging==16.8
pyparsing==2.2.0
python-dateutil==2.6.0
pytz==2017.2
six==1.10.0
tornado==4.5.1
Werkzeug==0.12.1
<file_sep>from os.path import join
from os import getcwd

DEBUG = True

GIT_COMMAND = 'git'
JAVA_COMMAND = 'java'

CODE_MAAT_JAR_FILE = join(getcwd(), 'code-maat.jar')
<file_sep>from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from app import app, app_port

server = HTTPServer(WSGIContainer(app))
server.listen(app_port)
IOLoop.instance().start()
<file_sep>from datetime import datetime as dt
from os.path import join, isdir
import csv
import json


def read_csv_file(csv_file):
    with open(csv_file, 'r') as f:
        reader = csv.reader(f)
        headers = next(reader)
        return [dict(zip(headers, row)) for row in reader]


def parse_date(text):
    return dt.strptime(text, "%Y-%m-%d")


def is_git_dir(git_dir):
    git_dot_dir = join(git_dir, ".git")
    return isdir(git_dot_dir)
<file_sep>from datetime import datetime
from os.path import join, isfile, isdir, splitext
from os import getcwd, makedirs, chdir
from subprocess import check_output


class CLI:
    def __init__(self,
                 code_maat_jar_file=join(getcwd(),  'code-maat.jar'),
                 git_command='git',
                 java_command='java',
                 log_dir=None,
                 git_dir=getcwd(),
                 **_keywords):
        self.git_dir = git_dir
        self.log_dir = log_dir if log_dir else join(git_dir, '.logs')
        self.git_command = git_command
        self.java_command = java_command
        self.code_maat_jar_file = code_maat_jar_file
        self.cache = True

        if not isdir(self.log_dir):
            makedirs(self.log_dir)

    def generate_log_file(self,
                          start_date=datetime.now(),
                          end_date=datetime.now()):
        start_format = datetime.strftime(start_date, "%Y-%m-%d")
        end_format = datetime.strftime(end_date, "%Y-%m-%d")
        log_file_name = "log--%s--%s.log" % (start_format, end_format)
        log_file = join(self.log_dir, log_file_name)

        if self.cache and isfile(log_file):
            return log_file

        log_output = self._execute_git(
            "log",
            "--pretty=format:[%h] %aN %ad %s",
            "--date=short",
            "--numstat",
            ("--after=%s" % start_format),
            ("--before=%s" % end_format))

        with open(log_file, 'wb') as f:
            f.write(log_output)

        return log_file

    def generate_summary_file(self, log_file):
        command_file = self._rename_extension(log_file, "--summary.csv")

        if self.cache and isfile(command_file):
            return command_file

        command_output = self._execute_code_maat(
            log_file,
            "summary")

        with open(command_file, 'wb') as f:
            f.write(command_output)

        return command_file

    def generate_coupling_file(self, log_file):
        command_file = self._rename_extension(log_file, "--coupling.csv")

        if self.cache and isfile(command_file):
            return command_file

        command_output = self._execute_code_maat(
            log_file,
            "coupling")

        with open(command_file, 'wb') as f:
            f.write(command_output)

        return command_file

    def generate_revision_file(self, log_file):
        command_file = self._rename_extension(log_file, "--revision.csv")

        if self.cache and isfile(command_file):
            return command_file

        command_output = self._execute_code_maat(
            log_file,
            "revisions")

        with open(command_file, 'wb') as f:
            f.write(command_output)

        return command_file

    def generate_age_file(self, log_file):
        command_file = self._rename_extension(log_file, "--age.csv")

        if self.cache and isfile(command_file):
            return command_file

        command_output = self._execute_code_maat(
            log_file,
            "age")

        with open(command_file, 'wb') as f:
            f.write(command_output)

        return command_file

    def generate_absolute_churn_file(self, log_file):
        command_file = self._rename_extension(log_file, "--absolute-churn.csv")

        if self.cache and isfile(command_file):
            return command_file

        command_output = self._execute_code_maat(
            log_file,
            "abs-churn")

        with open(command_file, 'wb') as f:
            f.write(command_output)

        return command_file

    def generate_author_churn_file(self, log_file):
        command_file = self._rename_extension(log_file, "--author-churn.csv")

        if self.cache and isfile(command_file):
            return command_file

        command_output = self._execute_code_maat(
            log_file,
            "author-churn")

        with open(command_file, 'wb') as f:
            f.write(command_output)

        return command_file

    def generate_entity_churn_file(self, log_file):
        command_file = self._rename_extension(log_file, "--entity-churn.csv")

        if self.cache and isfile(command_file):
            return command_file

        command_output = self._execute_code_maat(
            log_file,
            "entity-churn")

        with open(command_file, 'wb') as f:
            f.write(command_output)

        return command_file

    def generate_entity_ownership_file(self, log_file):
        command_file = self._rename_extension(
            log_file, "--entity-ownership.csv")

        if self.cache and isfile(command_file):
            return command_file

        command_output = self._execute_code_maat(
            log_file,
            "entity-ownership")

        with open(command_file, 'wb') as f:
            f.write(command_output)

        return command_file

    def generate_entity_effort_file(self, log_file):
        command_file = self._rename_extension(
            log_file, "--entity-effort.csv")

        if self.cache and isfile(command_file):
            return command_file

        command_output = self._execute_code_maat(
            log_file,
            "entity-effort")

        with open(command_file, 'wb') as f:
            f.write(command_output)

        return command_file

    def get_commits(self):
        text = self._execute_git('log', '--format=%cI,%H').decode('utf-8')
        lines = text.split("\n")
        entries = [line.split(",") for line in lines]

        return [dict([
            ['commitDate', entry[0]],
            ['commitHash', entry[1]]
        ]) for entry in entries]

    def _rename_extension(self, raw_file, new_extension):
        return splitext(raw_file)[0] + new_extension

    def _execute_git(self, command, *cli_args):
        temp_dir = getcwd()
        chdir(self.git_dir)

        output = check_output([
            self.git_command,
            command,
            *cli_args]).strip()

        chdir(temp_dir)

        return output

    def _execute_code_maat(self, log_file, command, *extra_args):
        temp_dir = getcwd()
        chdir(self.git_dir)

        output = check_output([
            self.java_command,
            "-jar",
            self.code_maat_jar_file,
            "-l",
            log_file,
            "-c",
            "git",
            "-a",
            command,
            *extra_args]).strip()

        chdir(temp_dir)

        return output
