Home | History | Annotate | Download | only in sourcedr
      1 #!/usr/bin/env python3
      2 
      3 import collections
      4 import functools
      5 import json
      6 import os
      7 import re
      8 
      9 from flask import (
     10     Blueprint, Flask, current_app, jsonify, render_template, request)
     11 
     12 
     13 codereview = Blueprint('codereview', '__name__', 'templates')
     14 
     15 
     16 # whether the code segment is exactly in file
     17 def same(fl, code, source_dir):
     18     fl = os.path.join(source_dir, fl)
     19     with open(fl, 'r') as f:
     20         fc = f.read()
     21         return code in fc
     22 
     23 
     24 # check if the file needes to be reiewed again
     25 def check(codes, source_dir):
     26     ret = []
     27     for item in codes:
     28         fl = item.split(':')[0]
     29         code = item[len(fl) + 1:]
     30         ret.append(same(fl, code, source_dir))
     31     return ret
     32 
     33 
     34 @codereview.route('/get_started')
     35 def _get_started():
     36     project = current_app.config.project
     37     source_dir = project.source_dir
     38     review_db = project.review_db
     39 
     40     lst, done= [], []
     41     for key, item in sorted(review_db.data.items()):
     42         lst.append(key)
     43         if item[0]:
     44             done.append(all(check(item[1], source_dir)))
     45         else:
     46             done.append(False)
     47 
     48     pattern_lst = project.pattern_db.load()[0]
     49     abs_path = os.path.abspath(source_dir)
     50 
     51     return jsonify(lst=json.dumps(lst),
     52                    done=json.dumps(done),
     53                    pattern_lst=json.dumps(pattern_lst),
     54                    path_prefix=os.path.join(abs_path, ''))
     55 
     56 
     57 @codereview.route('/load_file')
     58 def _load_file():
     59     project = current_app.config.project
     60     source_dir = project.source_dir
     61     review_db = project.review_db
     62 
     63     path = request.args.get('path')
     64 
     65     if path not in review_db.data.keys():
     66         print('No such entry', path)
     67         return jsonify(result='')
     68     deps, codes = review_db.data[path]
     69 
     70     return jsonify(deps=json.dumps(deps), codes=json.dumps(codes),
     71                    okays=json.dumps(check(codes, source_dir)))
     72 
     73 
     74 @codereview.route('/get_file')
     75 def _get_file():
     76     path = request.args.get('path')
     77     path = os.path.join(current_app.config.project.source_dir, path)
     78 
     79     if not os.path.exists(path):
     80         return jsonify(result='No such file')
     81     with open(path, 'r') as f:
     82         code = f.read()
     83 
     84     return jsonify(result=code)
     85 
     86 
     87 @codereview.route('/save_all')
     88 def _save_all():
     89     label = request.args.get('label')
     90     deps = json.loads(request.args.get('deps'))
     91     codes = json.loads(request.args.get('codes'))
     92 
     93     project = current_app.config.project
     94     review_db = project.review_db
     95     review_db.add_label(label, deps, codes)
     96 
     97     return jsonify(result='done')
     98 
     99 
    100 # This function add pattern to grep
    101 @codereview.route('/add_pattern')
    102 def _add_pattern():
    103     patt = request.args.get('pattern')
    104     is_regex = request.args.get('is_regex')
    105     engine = current_app.config.project.review_db
    106     engine.add_pattern(patt, is_regex)
    107 
    108     project = current_app.config.project
    109     project.pattern_db.save_new_pattern(patt, is_regex)
    110     return jsonify(result='done')
    111 
    112 
    113 # This function does a temporary grep to the directory
    114 # Not adding the result to database
    115 @codereview.route('/temporary_search')
    116 def _temporary_search():
    117     path = request.args.get('path')
    118     patt = request.args.get('pattern')
    119     is_regex = request.args.get('is_regex')
    120     codesearch = current_app.config.project.codesearch
    121     result = codesearch.raw_search(patt, is_regex).decode('utf-8')
    122     dic = collections.defaultdict(list)
    123     patt = re.compile('([^:]+):(\\d+):(.*)$')
    124     for line in result.split('\n'):
    125         match = patt.match(line)
    126         if not match:
    127             continue
    128 
    129         file_path = match.group(1)
    130         line_no = match.group(2)
    131         code = match.group(3)
    132         dic[file_path].append((line_no, code))
    133 
    134     def compare(item1, item2):
    135         key1, value1 = item1
    136         key2, value2 = item2
    137         cnt1 = os.path.commonprefix([path, key1]).count('/')
    138         cnt2 = os.path.commonprefix([path, key2]).count('/')
    139         e1 = os.path.relpath(key1, path).count('/')
    140         e2 = os.path.relpath(key2, path).count('/')
    141         # prefer smaller edit distance
    142         if e1 < e2: return -1
    143         if e2 < e1: return 1
    144         # prefer deeper common ancestor
    145         if cnt1 > cnt2: return -1
    146         if cnt2 > cnt1: return 1
    147         # lexicographical order
    148         if key1 < key2: return -1
    149         if key2 < key1: return 1
    150         return 0
    151 
    152     result = sorted(dic.items(), key=functools.cmp_to_key(compare))
    153     return jsonify(result=json.dumps(result))
    154 
    155 
    156 @codereview.route('/')
    157 def render():
    158     return render_template('index.html')
    159 
    160 
    161 def create_app(project):
    162     app = Flask(__name__)
    163     app.register_blueprint(codereview)
    164     app.config.project = project
    165     return app
    166