1# 2# PCMSolver, an API for the Polarizable Continuum Model 3# Copyright (C) 2020 Roberto Di Remigio, Luca Frediani and contributors. 4# 5# This file is part of PCMSolver. 6# 7# PCMSolver is free software: you can redistribute it and/or modify 8# it under the terms of the GNU Lesser General Public License as published by 9# the Free Software Foundation, either version 3 of the License, or 10# (at your option) any later version. 11# 12# PCMSolver is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU Lesser General Public License for more details. 16# 17# You should have received a copy of the GNU Lesser General Public License 18# along with PCMSolver. If not, see <http://www.gnu.org/licenses/>. 19# 20# For information on the complete list of contributors to the 21# PCMSolver API, see: <http://pcmsolver.readthedocs.io/> 22# 23 24# Execute cloc.pl Perl script and wrap results in a nicer format. 25# cloc script by Al Danial, available at http://cloc.sourceforge.net/ 26# licensed under the GNU General Public License v2 27# (c) Roberto Di Remigio <roberto.d.remigio@uit.no> 28# licensed under the GNU Lesser General Public License 29 30import subprocess 31import os 32import time 33import sys 34import json 35import shlex 36 37 38def cloc_command(perl, cloc_script, args): 39 """Wrapper to the cloc.pl Perl script. 40 41 Keyword arguments: 42 perl -- perl executable 43 cloc_script -- the cloc.pl script 44 files -- list of files to parse 45 args -- additional list of command line arguments to cloc.pl 46 """ 47 command = [perl, cloc_script] + args 48 try: 49 retcode = subprocess.call(command, shell=False) 50 if retcode < 0: 51 sys.stderr.write('{0} terminated by signal {1}'.format(command, -retcode)) 52 except OSError as e: 53 sys.stderr.write("{0} execution failed: {1}".format(command, e)) 54 55 56def bar_chart(perl, count_dir, scratch_dir, output_dir, is_total=False): 57 """Generates matplotlib script for lines of code bar chart. 58 59 Keyword arguments: 60 perl -- perl executable 61 count_dir -- directory where to count lines of code 62 scratch_dir -- where intermediate files (JSON, matplotlib scripts) are to be saved 63 output_dir -- where the bar charts are to be saved 64 is_total -- whether this is the global counting or not 65 """ 66 if is_total: 67 template = os.path.join(os.path.dirname(__file__), 'total_bar_chart.txt') 68 with open(template, 'r') as tmp: 69 script = '\n' + tmp.read() 70 annotation = '\'PCMSolver\\nFiles: {0:d}\'.format(nr_files)' 71 else: 72 template = os.path.join(os.path.dirname(__file__), 'bar_chart.txt') 73 with open(template, 'r') as tmp: 74 script = '\n' + tmp.read() 75 annotation = '\'Folder: {0}\\nLanguage: {1}\\nFiles: {2:d}\'.format(tag, language, nr_files)' 76 tag = os.path.basename(count_dir) 77 cloc_data = count_lines_of_code(perl, count_dir, scratch_dir, tag, output_dir) 78 plot_script = os.path.join(scratch_dir, tag + '.py') 79 with open(plot_script, 'w+') as bar_plot: 80 bar_plot.write(header()) 81 bar_plot.write(script.format(svg_dir=output_dir, tag=tag, data=cloc_data, annotation=annotation)) 82 return plot_script 83 84 85def count_lines_of_code(perl, count_dir, scratch_dir, plot_name, svg_dir): 86 """Runs cloc.pl to get total count and returns data for matplotlib script. 87 88 Keyword arguments: 89 perl -- perl executable 90 count_dir -- directory where to run cloc.pl 91 scratch_dir -- where intermediate files (JSON and matplotlib script) are to be saved 92 plot_name -- name of the plot (e.g. cavity or solver) 93 svg_dir -- where the SVG will be saved 94 """ 95 # yapf: disable 96 json_report = os.path.join(scratch_dir, 'cloc_temp.json') 97 cloc_options = [ 98 count_dir 99 , '--json' 100 , '--report-file={}'.format(json_report) 101 , '--include-lang="C++","C","Fortran 77","Fortran 90","Fortran 95","Python"' 102 , '--exclude-dir="external,examples,doc,cmake"' 103 , '--fullpath', '--not-match-d="src/utils/getkw"' 104 , '--fullpath', '--not-match-d=\'/build\S[a-zA-Z0-9]+/\'' 105 , '--force-lang="C++",hpp' 106 , '--force-lang="C",h' 107 , '--force-lang="Fortran 90",f' 108 , '--force-lang="Fortran 90",F' 109 , '--force-lang="Fortran 90",f95' 110 , '--force-lang="Fortran 90",F95' 111 , '--quiet' 112 ] 113 # yapf: enable 114 cloc_command(perl, os.path.join(os.path.dirname(__file__), 'cloc.pl'), shlex.split(' '.join(cloc_options))) 115 with open(json_report, 'r') as cloc_out: 116 data = json.load(cloc_out) 117 os.remove(json_report) 118 # Prepare data for bar chart 119 cloc_data = { 120 'nr_blanks': data['SUM']['blank'], 121 'nr_comments': data['SUM']['comment'], 122 'nr_files': data['SUM']['nFiles'], 123 'nr_cpp_code': data['C++']['code'] if 'C++' in data else 0, 124 'nr_c_code': data['C']['code'] if 'C' in data else 0, 125 'nr_fortran_code': data['Fortran 90']['code'] if 'Fortran 90' in data else 0, 126 'nr_python_code': data['Python']['code'] if 'Python' in data else 0 127 } 128 return cloc_data 129 130 131def header(): 132 """Print header of matplotlib script generating bar chart. 133 134 Keyword arguments: 135 plot_script -- name of the plotting script 136 """ 137 138 header = """#!/usr/bin/env python 139# Automatically generated on {now} 140# Data obtained from the cloc.pl Perl script. 141# cloc script by Al Danial, available at http://cloc.sourceforge.net/ 142# licensed under the GNU General Public License v2 143# (c) Roberto Di Remigio <roberto.d.remigio@uit.no> 144# licensed under the GNU Lesser General Public License 145 """.format(now=time.strftime('%c')) 146 return header 147