mirror of
https://github.com/cp2k/cp2k.git
synced 2026-07-28 06:05:29 -04:00
Prettify: more flexible command line interface
Can now be installed as 'fprettify' and can be more easily invoked from command line and can be integrated into editors. - Fixes in reformatter for better editor support - errors / warnings to stderr and can use stdin / stdout - remove unnecessary checks - warnings can be deactivated - backup is optional - prettify has its own directory svn-origin-rev: 17300
This commit is contained in:
parent
4acc5dfc39
commit
8a4bb01b58
8 changed files with 195 additions and 129 deletions
|
|
@ -181,7 +181,7 @@ test:
|
|||
|
||||
testbg:
|
||||
@echo "testing: $(ONEVERSION) : full log in $(TSTDIR)/regtest.log "
|
||||
@$(TOOLSRC)/regtesting/do_regtest -nobuild -nosvn -arch $(ARCH) -version $(ONEVERSION) -cp2kdir ../../../ $(TESTOPTS) >& $(TSTDIR)/regtest.log
|
||||
@$(TOOLSRC)/regtesting/do_regtest -nobuild -nosvn -arch $(ARCH) -version $(ONEVERSION) -cp2kdir ../../../ $(TESTOPTS) >& $(TSTDIR)/regtest.log
|
||||
@cat `grep 'regtesting location error_summary file:' $(TSTDIR)/regtest.log | awk '{print $$NF}'`
|
||||
@cat `grep 'regtesting location summary file:' $(TSTDIR)/regtest.log | awk '{print $$NF}'`
|
||||
@grep "Number of FAILED tests 0" $(TSTDIR)/regtest.log >& /dev/null
|
||||
|
|
@ -229,8 +229,8 @@ OTHER_HELP += "install : Print installation help"
|
|||
clean:
|
||||
rm -rf $(LIBCUSMM_DIR)/libcusmm.cu $(LIBCUSMM_DIR)/libcusmm_part*.cu
|
||||
rm -rf $(foreach v, $(VERSION), $(MAINOBJDIR)/$(ARCH)/$(v)/*.o)
|
||||
rm -rf $(foreach v, $(VERSION), $(MAINOBJDIR)/$(ARCH)/$(v)/*.mod $(MAINOBJDIR)/$(ARCH)/$(v)/*.MOD $(MAINOBJDIR)/$(ARCH)/$(v)/*.smod)
|
||||
rm -rf $(foreach v, $(VERSION), $(MAINOBJDIR)/$(ARCH)/$(v)/*.dep)
|
||||
rm -rf $(foreach v, $(VERSION), $(MAINOBJDIR)/$(ARCH)/$(v)/*.mod $(MAINOBJDIR)/$(ARCH)/$(v)/*.MOD $(MAINOBJDIR)/$(ARCH)/$(v)/*.smod)
|
||||
rm -rf $(foreach v, $(VERSION), $(MAINOBJDIR)/$(ARCH)/$(v)/*.dep)
|
||||
OTHER_HELP += "clean : Remove intermediate object and mod files, but not the libraries and executables, for given ARCH and VERSION"
|
||||
|
||||
execlean:
|
||||
|
|
@ -300,7 +300,7 @@ TOOL_HELP += "prettyclean : Remove prettify marker files and preprettify directo
|
|||
|
||||
$(PRETTYOBJDIR)/%.pretty: %.F $(DOXIFYOBJDIR)/%.doxified
|
||||
@mkdir -p $(PRETTYOBJDIR)
|
||||
cd $(dir $<); $(TOOLSRC)/prettify.py --backup-dir=$(PRETTYOBJDIR) $(notdir $<)
|
||||
cd $(dir $<); $(TOOLSRC)/prettify/fprettify.py --do-backup --backup-dir=$(PRETTYOBJDIR) $(notdir $<)
|
||||
@touch $@
|
||||
|
||||
$(PRETTYOBJDIR)/%.pretty: %.c $(DOXIFYOBJDIR)/%.doxified
|
||||
|
|
@ -427,7 +427,7 @@ CPPSHELL := -D__COMPILE_ARCH="\"$(ARCH)\""\
|
|||
endif
|
||||
|
||||
ifneq ($(CPP),)
|
||||
# always add the SRCDIR to the include path (-I here might not be portable)
|
||||
# always add the SRCDIR to the include path (-I here might not be portable)
|
||||
CPPFLAGS += $(CPPSHELL) -I$(SRCDIR)
|
||||
else
|
||||
FCFLAGS += $(CPPSHELL)
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ class CharFilter(object):
|
|||
|
||||
return (pos, char)
|
||||
|
||||
|
||||
def next(self):
|
||||
""" python 2 version"""
|
||||
pos, char = self._it.next()
|
||||
|
|
@ -77,6 +76,7 @@ class CharFilter(object):
|
|||
|
||||
return (pos, char)
|
||||
|
||||
|
||||
class InputStream(object):
|
||||
"""
|
||||
Class to read logical Fortran lines from a Fortran file.
|
||||
|
|
@ -217,8 +217,10 @@ def parseRoutine(inFile):
|
|||
subF.close()
|
||||
except:
|
||||
import traceback
|
||||
print("error trying to follow include ", m.group('file'))
|
||||
print("warning this might lead to the removal of used variables")
|
||||
sys.stderr.write(
|
||||
"error trying to follow include " + m.group('file') + '\n')
|
||||
sys.stderr.write(
|
||||
"warning this might lead to the removal of used variables\n")
|
||||
traceback.print_exc()
|
||||
if jline:
|
||||
routine['begin'] = lines
|
||||
|
|
@ -357,8 +359,10 @@ def parseRoutine(inFile):
|
|||
subF.close()
|
||||
except:
|
||||
import traceback
|
||||
print("error trying to follow include ", m.group('file'))
|
||||
print("warning this might lead to the removal of used variables")
|
||||
sys.stderr.write(
|
||||
"error trying to follow include " + m.group('file') + '\n')
|
||||
sys.stderr.write(
|
||||
"warning this might lead to the removal of used variables\n")
|
||||
traceback.print_exc()
|
||||
(jline, _, lines) = stream.nextFortranLine()
|
||||
return routine
|
||||
|
|
@ -596,7 +600,7 @@ def writeDeclarations(parsedDeclarations, file):
|
|||
writeExtendedDeclaration(d, file)
|
||||
|
||||
|
||||
def cleanDeclarations(routine, logFile=sys.stdout):
|
||||
def cleanDeclarations(routine, logFile=sys.stderr):
|
||||
"""cleans up the declaration part of the given parsed routine
|
||||
removes unused variables"""
|
||||
global rVar
|
||||
|
|
@ -708,8 +712,8 @@ def cleanDeclarations(routine, logFile=sys.stdout):
|
|||
if argDeclDict.has_key(arg):
|
||||
argDecl.append(argDeclDict[arg])
|
||||
else:
|
||||
print("warning, implicitly typed argument '",
|
||||
arg, "' in routine", routine['name'])
|
||||
sys.stderr.write("warning, implicitly typed argument '" +
|
||||
arg + "' in routine " + routine['name'] + '\n')
|
||||
if routine['kind'].lower() == 'function':
|
||||
aDecl = argDecl[:-1]
|
||||
else:
|
||||
|
|
@ -868,8 +872,6 @@ def parseUse(inFile):
|
|||
# parse use
|
||||
m = useParseRe.match(jline)
|
||||
if m:
|
||||
if comments:
|
||||
print("jline", jline, "lines", lines)
|
||||
useAtt = {'module': m.group('module'), 'comments': []}
|
||||
|
||||
if m.group('only'):
|
||||
|
|
@ -1001,7 +1003,7 @@ def prepareImplicitUses(modules):
|
|||
return mods
|
||||
|
||||
|
||||
def cleanUse(modulesDict, rest, implicitUses=None, logFile=sys.stdout):
|
||||
def cleanUse(modulesDict, rest, implicitUses=None, logFile=sys.stderr):
|
||||
"""Removes the unneded modules (the ones that are not used in rest)"""
|
||||
global rUse
|
||||
exceptions = {}
|
||||
|
|
@ -1048,12 +1050,12 @@ def resetModuleN(moduleName, lines):
|
|||
flags=re.IGNORECASE)
|
||||
for i in range(len(lines)):
|
||||
lines[i] = moduleNRe.sub(
|
||||
" "*indentSize + "CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = '" +
|
||||
" " * indentSize + "CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = '" +
|
||||
moduleName + "'",
|
||||
lines[i])
|
||||
|
||||
|
||||
def rewriteFortranFile(inFile, outFile, indent, decl_linelength, decl_offset, logFile=sys.stdout, orig_filename=None):
|
||||
def rewriteFortranFile(inFile, outFile, indent, decl_linelength, decl_offset, logFile=sys.stderr, orig_filename=None):
|
||||
"""rewrites the use statements and declarations of inFile to outFile.
|
||||
It sorts them and removes the repetitions."""
|
||||
import os.path
|
||||
|
|
@ -1080,9 +1082,6 @@ def rewriteFortranFile(inFile, outFile, indent, decl_linelength, decl_offset, lo
|
|||
if not orig_filename:
|
||||
orig_filename = inFile.name
|
||||
fn = os.path.basename(orig_filename).rsplit(".", 1)[0]
|
||||
if (m.group('moduleName') != fn):
|
||||
raise SyntaxError("Module name is different from filename (" +
|
||||
m.group('moduleName') + "!=" + fn + ")")
|
||||
break
|
||||
try:
|
||||
modulesDict = parseUse(inFile)
|
||||
|
|
@ -1104,7 +1103,7 @@ def rewriteFortranFile(inFile, outFile, indent, decl_linelength, decl_offset, lo
|
|||
nonStPrep = 0
|
||||
for line in modulesDict['origLines']:
|
||||
if (re.search('^#', line) and not commonUsesRe.match(line)):
|
||||
print('noMatch', repr(line))
|
||||
sys.stderr.write('noMatch ' + repr(line) + '\n')
|
||||
nonStPrep = 1
|
||||
if nonStPrep:
|
||||
logFile.write(
|
||||
|
|
@ -1124,8 +1123,8 @@ def rewriteFortranFile(inFile, outFile, indent, decl_linelength, decl_offset, lo
|
|||
implicitUses = prepareImplicitUses(
|
||||
implicitUsesRaw['modules'])
|
||||
except:
|
||||
print ("ERROR trying to parse use statements contained in common",
|
||||
"uses precompiler file ", inc_absfn)
|
||||
sys.stderr.write(
|
||||
"ERROR trying to parse use statements contained in common uses precompiler file " + inc_absfn + '\n')
|
||||
raise
|
||||
cleanUse(modulesDict, rest,
|
||||
implicitUses=implicitUses, logFile=logFile)
|
||||
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
from formatting.normalizeFortranFile import useParseRe, typeRe, InputStream, CharFilter, ompRe, ompDirRe
|
||||
|
||||
#=========================================================================
|
||||
|
|
@ -45,7 +46,7 @@ from formatting.normalizeFortranFile import useParseRe, typeRe, InputStream, Cha
|
|||
|
||||
RE_FLAGS = re.IGNORECASE # all regex should be case insensitive
|
||||
|
||||
FORTRAN_DEFAULT_ERROR_MESSAGE = " Syntax error - this script can not handle invalid Fortran files."
|
||||
FORTRAN_DEFAULT_ERROR_MESSAGE = " Syntax error - this formatter can not handle invalid Fortran files."
|
||||
FORMATTER_ERROR_MESSAGE = " Wrong usage of formatting-specific directives '&', '!&', '!&<' or '!&>'."
|
||||
|
||||
EOL_STR = r"\s*;?\s*$" # end of fortran line
|
||||
|
|
@ -91,7 +92,8 @@ PROG_RE = re.compile(SOL_STR + r"PROGRAM\s+\w+" + EOL_STR, RE_FLAGS)
|
|||
ENDPROG_RE = re.compile(
|
||||
SOL_STR + r"END\s*PROGRAM(\s+\w+)?" + EOL_STR, RE_FLAGS)
|
||||
|
||||
INTERFACE_RE = re.compile(r"^([^\"'!]* )?INTERFACE(\s+\w+)?" + EOL_STR, RE_FLAGS)
|
||||
INTERFACE_RE = re.compile(
|
||||
r"^([^\"'!]* )?INTERFACE(\s+\w+)?" + EOL_STR, RE_FLAGS)
|
||||
ENDINTERFACE_RE = re.compile(
|
||||
SOL_STR + r"END\s*INTERFACE(\s+\w+)?" + EOL_STR, RE_FLAGS)
|
||||
|
||||
|
|
@ -178,7 +180,7 @@ class F90Indenter(object):
|
|||
valid_new = True
|
||||
scopes.append(what_new)
|
||||
if debug:
|
||||
print(f_line)
|
||||
sys.stderr.write(f_line + '\n')
|
||||
break
|
||||
|
||||
# check statements that continue scope
|
||||
|
|
@ -193,7 +195,7 @@ class F90Indenter(object):
|
|||
if what == what_con:
|
||||
valid_con = True
|
||||
if debug:
|
||||
print(f_line)
|
||||
sys.stderr.write(f_line + '\n')
|
||||
break
|
||||
|
||||
# check statements that end scope
|
||||
|
|
@ -208,7 +210,7 @@ class F90Indenter(object):
|
|||
if what == what_end:
|
||||
valid_end = True
|
||||
if debug:
|
||||
print(f_line)
|
||||
sys.stderr.write(f_line + '\n')
|
||||
break
|
||||
|
||||
# deal with line breaks
|
||||
|
|
@ -302,7 +304,7 @@ class F90Aligner(object):
|
|||
if pos + 1 < len(lines):
|
||||
self._line_indents.append(self._br_indent_list[-1])
|
||||
|
||||
if len(self._br_indent_list) > 2 or self._level:
|
||||
if (len(self._br_indent_list) > 2 or self._level):
|
||||
raise SyntaxError(self._filename + ':' + str(self._line_nr) +
|
||||
':' + FORTRAN_DEFAULT_ERROR_MESSAGE)
|
||||
|
||||
|
|
@ -416,12 +418,15 @@ def inspect_ffile_format(infile, indent_size):
|
|||
indents = []
|
||||
stream = InputStream(infile)
|
||||
prev_offset = 0
|
||||
first_indent = -1
|
||||
while 1:
|
||||
f_line, _, lines = stream.nextFortranLine()
|
||||
if not lines:
|
||||
break
|
||||
|
||||
offset = len(lines[0]) - len(lines[0].lstrip(' '))
|
||||
if f_line.strip() and first_indent == -1:
|
||||
first_indent = offset
|
||||
indents.append(offset - prev_offset)
|
||||
if not adopt: # do not adopt indentations but impose fixed rel. ind.
|
||||
# but don't impose indentation for blocked do/if constructs
|
||||
|
|
@ -432,7 +437,7 @@ def inspect_ffile_format(infile, indent_size):
|
|||
# can not handle f77 style constructs
|
||||
if F77_STYLE.search(f_line):
|
||||
is_f90 = False
|
||||
return indents, is_f90
|
||||
return indents, first_indent, is_f90
|
||||
|
||||
#=========================================================================
|
||||
|
||||
|
|
@ -441,11 +446,11 @@ def format_single_fline(f_line, whitespace, linebreak_pos, ampersand_sep, filena
|
|||
"""
|
||||
format a single Fortran line - imposes white space formatting
|
||||
and inserts linebreaks.
|
||||
Takes a logical Fortran line `f_line` as input as well as the positions
|
||||
of the linebreaks (`linebreak_pos`), and the number of separating whitespace
|
||||
characters before ampersand (`ampersand_sep`).
|
||||
Takes a logical Fortran line `f_line` as input as well as the positions
|
||||
of the linebreaks (`linebreak_pos`), and the number of separating whitespace
|
||||
characters before ampersand (`ampersand_sep`).
|
||||
`filename` and `line_nr` just for error messages.
|
||||
The higher `whitespace`, the more white space characters inserted -
|
||||
The higher `whitespace`, the more white space characters inserted -
|
||||
whitespace = 0, 1, 2 are currently supported.
|
||||
auto formatting can be turned off by setting `auto_format` to False.
|
||||
"""
|
||||
|
|
@ -664,7 +669,7 @@ def format_single_fline(f_line, whitespace, linebreak_pos, ampersand_sep, filena
|
|||
#=========================================================================
|
||||
|
||||
|
||||
def reformat_ffile(infile, outfile, logFile=sys.stdout, indent_size=2, whitespace=2, orig_filename=None):
|
||||
def reformat_ffile(infile, outfile, logFile=sys.stderr, indent_size=2, whitespace=2, orig_filename=None):
|
||||
"""
|
||||
main method to be invoked for formatting a Fortran file.
|
||||
"""
|
||||
|
|
@ -678,7 +683,8 @@ def reformat_ffile(infile, outfile, logFile=sys.stdout, indent_size=2, whitespac
|
|||
|
||||
indenter = F90Indenter(orig_filename)
|
||||
|
||||
req_indents, is_f90 = inspect_ffile_format(infile, indent_size)
|
||||
req_indents, first_indent, is_f90 = inspect_ffile_format(
|
||||
infile, indent_size)
|
||||
infile.seek(0)
|
||||
|
||||
if not is_f90:
|
||||
|
|
@ -690,6 +696,7 @@ def reformat_ffile(infile, outfile, logFile=sys.stdout, indent_size=2, whitespac
|
|||
nfl = 0 # fortran line counter
|
||||
|
||||
do_indent = True
|
||||
use_same_line = False
|
||||
stream = InputStream(infile)
|
||||
skip_blank = False
|
||||
in_manual_block = False
|
||||
|
|
@ -744,23 +751,27 @@ def reformat_ffile(infile, outfile, logFile=sys.stdout, indent_size=2, whitespac
|
|||
is_empty = EMPTY_RE.search(f_line) # blank line or comment only line
|
||||
|
||||
if useParseRe.match(f_line):
|
||||
pass # do not touch use statements cleaned up by existing prettify
|
||||
do_indent = False
|
||||
elif ompDirRe.match(f_line):
|
||||
# move '!$OMP' to line start, otherwise don't format omp directives
|
||||
lines = ['!$OMP' + (len(l) - len(l.lstrip())) *
|
||||
' ' + ompDirRe.sub('', l, count=1) for l in lines]
|
||||
pass
|
||||
do_indent = False
|
||||
elif lines[0].startswith('#'): # preprocessor macros
|
||||
assert len(lines) == 1
|
||||
do_indent = False
|
||||
elif EMPTY_RE.search(f_line): # empty lines including comment lines
|
||||
assert len(lines) == 1
|
||||
if any(comments):
|
||||
if lines[0].startswith('!'):
|
||||
pass # don't indent unindented comment lines
|
||||
# don't indent unindented comments
|
||||
do_indent = False
|
||||
else:
|
||||
indent[0] = indenter.get_fline_indent()
|
||||
elif skip_blank:
|
||||
continue
|
||||
else:
|
||||
do_indent = False
|
||||
|
||||
lines = [l.strip(' ') for l in lines]
|
||||
else:
|
||||
|
|
@ -850,9 +861,12 @@ def reformat_ffile(infile, outfile, logFile=sys.stdout, indent_size=2, whitespac
|
|||
line_length += 1
|
||||
|
||||
if do_indent:
|
||||
ind_use = ind
|
||||
ind_use = ind + first_indent
|
||||
else:
|
||||
ind_use = 1
|
||||
if use_same_line:
|
||||
ind_use = 1
|
||||
else:
|
||||
ind_use = 0
|
||||
if ind_use + line_length <= 133: # 132 plus 1 newline char
|
||||
outfile.write('!$' * is_omp_conditional + ' ' *
|
||||
(ind_use - 2 * is_omp_conditional +
|
||||
|
|
@ -869,12 +883,15 @@ def reformat_ffile(infile, outfile, logFile=sys.stdout, indent_size=2, whitespac
|
|||
logFile.write("*** " + orig_filename + ":" + str(stream.line_nr) +
|
||||
(": auto indentation and whitespace formatting failed due to 132 chars limit, line should be splitted. ***\n"))
|
||||
if debug:
|
||||
print(' ' * ind_use + line)
|
||||
# no indentation of blank lines
|
||||
sys.stderr.write(' ' * ind_use + line + '\n')
|
||||
|
||||
# no indentation of semicolon separated lines
|
||||
if re.search(r";\s*$", f_line, RE_FLAGS):
|
||||
do_indent = False
|
||||
use_same_line = True
|
||||
else:
|
||||
do_indent = True
|
||||
use_same_line = False
|
||||
|
||||
# rm subsequent blank lines
|
||||
skip_blank = is_empty and not any(comments)
|
||||
|
|
@ -11,7 +11,7 @@ specialRepl = None
|
|||
|
||||
def replaceWords(infile, outfile, replacements=repl,
|
||||
specialReplacements=specialRepl,
|
||||
logFile=sys.stdout):
|
||||
logFile=sys.stderr):
|
||||
"""Replaces the words in infile writing the output to outfile.
|
||||
|
||||
replacements is a dictionary with the words to replace.
|
||||
|
|
@ -66,7 +66,7 @@ def upcaseOMP(line):
|
|||
return toUpcaseOMPRe.sub(lambda match: match.group("toUpcase").upper(), line)
|
||||
|
||||
|
||||
def upcaseKeywords(infile, outfile, upcase_omp, logFile=sys.stdout):
|
||||
def upcaseKeywords(infile, outfile, upcase_omp, logFile=sys.stderr):
|
||||
"""Writes infile to outfile with all the fortran keywords upcased"""
|
||||
while 1:
|
||||
line = infile.readline()
|
||||
|
|
@ -79,7 +79,7 @@ def upcaseKeywords(infile, outfile, upcase_omp, logFile=sys.stdout):
|
|||
outfile.write(line)
|
||||
|
||||
|
||||
def prettifyFile(infile, normalize_use, decl_linelength, decl_offset,
|
||||
def prettifyFile(infile, filename, normalize_use, decl_linelength, decl_offset,
|
||||
reformat, indent, whitespace, upcase_keywords,
|
||||
upcase_omp, replace, logFile):
|
||||
"""prettifyes the fortran source in infile into a temporary file that is
|
||||
|
|
@ -91,7 +91,7 @@ def prettifyFile(infile, normalize_use, decl_linelength, decl_offset,
|
|||
|
||||
does not close the input file"""
|
||||
ifile = infile
|
||||
orig_filename = infile.name
|
||||
orig_filename = filename
|
||||
tmpfile = None
|
||||
max_pretty_iter = 5
|
||||
n_pretty_iter = 0
|
||||
|
|
@ -151,19 +151,34 @@ def prettifyFile(infile, normalize_use, decl_linelength, decl_offset,
|
|||
raise
|
||||
|
||||
|
||||
def prettfyInplace(fileName, bkDir, **kwargs):
|
||||
def prettfyInplace(fileName, bkDir=None, stdout=False, **kwargs):
|
||||
"""Same as prettify, but inplace, replaces only if needed"""
|
||||
if not os.path.exists(bkDir):
|
||||
|
||||
if fileName == 'stdin':
|
||||
infile = os.tmpfile()
|
||||
infile.write(sys.stdin.read())
|
||||
else:
|
||||
infile = open(fileName, 'r')
|
||||
|
||||
if stdout:
|
||||
outfile = prettifyFile(infile=infile, filename=fileName, **kwargs)
|
||||
outfile.seek(0)
|
||||
sys.stdout.write(outfile.read())
|
||||
outfile.close()
|
||||
return
|
||||
|
||||
if bkDir and not os.path.exists(bkDir):
|
||||
os.mkdir(bkDir)
|
||||
if not os.path.isdir(bkDir):
|
||||
if bkDir and not os.path.isdir(bkDir):
|
||||
raise Error("bk-dir must be a directory, was " + bkDir)
|
||||
infile = open(fileName, 'r')
|
||||
outfile = prettifyFile(infile=infile, **kwargs)
|
||||
|
||||
outfile = prettifyFile(infile=infile, filename=fileName, **kwargs)
|
||||
if (infile == outfile):
|
||||
return
|
||||
infile.seek(0)
|
||||
outfile.seek(0)
|
||||
same = 1
|
||||
|
||||
while 1:
|
||||
l1 = outfile.readline()
|
||||
l2 = infile.readline()
|
||||
|
|
@ -173,52 +188,50 @@ def prettfyInplace(fileName, bkDir, **kwargs):
|
|||
if not l1:
|
||||
break
|
||||
if (not same):
|
||||
bkName = os.path.join(bkDir, os.path.basename(fileName))
|
||||
bName = bkName
|
||||
i = 0
|
||||
while os.path.exists(bkName):
|
||||
i += 1
|
||||
bkName = bName + "." + str(i)
|
||||
bkFile = None
|
||||
if bkDir:
|
||||
bkName = os.path.join(bkDir, os.path.basename(fileName))
|
||||
bName = bkName
|
||||
i = 0
|
||||
while os.path.exists(bkName):
|
||||
i += 1
|
||||
bkName = bName + "." + str(i)
|
||||
bkFile = file(bkName, "w")
|
||||
infile.seek(0)
|
||||
bkFile = file(bkName, "w")
|
||||
while 1:
|
||||
l1 = infile.readline()
|
||||
if not l1:
|
||||
break
|
||||
bkFile.write(l1)
|
||||
bkFile.close()
|
||||
if bkFile:
|
||||
bkFile.write(infile.read())
|
||||
bkFile.close()
|
||||
outfile.seek(0)
|
||||
newFile = file(fileName, 'w')
|
||||
while 1:
|
||||
l1 = outfile.readline()
|
||||
if not l1:
|
||||
break
|
||||
newFile.write(l1)
|
||||
newFile.write(outfile.read())
|
||||
newFile.close()
|
||||
infile.close()
|
||||
outfile.close()
|
||||
|
||||
|
||||
def main(argv):
|
||||
# future defaults
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
defaultsDict = {'upcase': 1, 'normalize-use': 1, 'omp-upcase': 1,
|
||||
'decl-linelength': 100, 'decl-offset': 50,
|
||||
'reformat': 1, 'indent': 3, 'whitespace': 1,
|
||||
'replace': 1,
|
||||
'backup-dir': 'preprettify'}
|
||||
'stdout': 0,
|
||||
'do-backup': 0,
|
||||
'backup-dir': 'preprettify',
|
||||
'report-errors': 1}
|
||||
|
||||
usageDesc = ("usage:\n" + argv[0] + """
|
||||
usageDesc = ("usage:\nfprettify" +"""
|
||||
[--[no-]upcase] [--[no-]normalize-use] [--[no-]omp-upcase] [--[no-]replace]
|
||||
[--[no-]reformat] --indent=3 --whitespace=1 [--help]
|
||||
[--backup-dir=bk_dir] file1 [file2 ...]
|
||||
[--[no-]reformat] [--indent=3] [--whitespace=1] [--help]
|
||||
[--[no-]stdout] [--[no-]do-backup] [--backup-dir=bk_dir] [--[no-]report-errors] file1 [file2 ...]
|
||||
|
||||
Auto-format F90 source file1, file2, ...:
|
||||
If no files are given, stdin is used.
|
||||
--normalize-use
|
||||
Sorting and alignment of variable declarations and USE statements, removal of unused list entries.
|
||||
The line length of declarations is controlled by --decl-linelength=n, the offset of the variable list
|
||||
is controlled by --decl-offset=n.
|
||||
--upcase
|
||||
Upcasing fortran keywords.
|
||||
--reformat
|
||||
Auto-indentation, auto-alignment and whitespace formatting.
|
||||
Amount of whitespace controlled by --whitespace = 0, 1, 2.
|
||||
|
|
@ -228,22 +241,32 @@ def main(argv):
|
|||
- completely disable reformatting by adding a comment '!&'.
|
||||
For manual formatting of a code block, use:
|
||||
- start a manually formatted block with a '!&<' comment and close it with a '!&>' comment.
|
||||
--upcase
|
||||
Upcasing fortran keywords.
|
||||
--omp-upcase
|
||||
Upcasing OMP directives.
|
||||
--replace
|
||||
If requested the replacements performed by the replacer.py script are also performed. (FIXME: what replacements?)
|
||||
If requested the replacements performed by the replacer.py script are also performed. Note: these replacements are specific to CP2K.
|
||||
--stdout
|
||||
write output to stdout
|
||||
--[no-]do-backup
|
||||
store backups of original files in backup-dir (--backup-dir option)
|
||||
--[no-]report-errors
|
||||
report warnings and errors
|
||||
|
||||
Note: for editor integration, use options --no-normalize-use --no-report-errors
|
||||
|
||||
Defaults:
|
||||
""" + str(defaultsDict))
|
||||
|
||||
replace = None
|
||||
if "--help" in argv:
|
||||
print(usageDesc)
|
||||
sys.stderr.write(usageDesc + '\n')
|
||||
return(0)
|
||||
args = []
|
||||
for arg in argv[1:]:
|
||||
m = re.match(
|
||||
r"--(no-)?(normalize-use|upcase|omp-upcase|replace|reformat)", arg)
|
||||
r"--(no-)?(normalize-use|upcase|omp-upcase|replace|reformat|stdout|do-backup|report-errors)", arg)
|
||||
if m:
|
||||
defaultsDict[m.groups()[1]] = not m.groups()[0]
|
||||
else:
|
||||
|
|
@ -258,53 +281,65 @@ def main(argv):
|
|||
defaultsDict[m.groups()[0]] = path
|
||||
else:
|
||||
if arg.startswith('--'):
|
||||
print('unknown option', arg)
|
||||
sys.stderr.write('unknown option ' + arg + '\n')
|
||||
else:
|
||||
args.append(arg)
|
||||
if len(args) < 1:
|
||||
print(usageDesc)
|
||||
else:
|
||||
bkDir = ''
|
||||
if defaultsDict['do-backup']:
|
||||
bkDir = defaultsDict['backup-dir']
|
||||
if not os.path.exists(bkDir):
|
||||
# Another parallel running instance might just have created the
|
||||
# dir.
|
||||
try:
|
||||
os.mkdir(bkDir)
|
||||
except:
|
||||
assert(os.path.exists(bkDir))
|
||||
if not os.path.isdir(bkDir):
|
||||
print("bk-dir must be a directory")
|
||||
print(usageDesc)
|
||||
else:
|
||||
failure = 0
|
||||
for fileName in args:
|
||||
if not os.path.isfile(fileName):
|
||||
print("file", fileName, "does not exists!")
|
||||
else:
|
||||
try:
|
||||
prettfyInplace(fileName, bkDir=bkDir, logFile=sys.stdout,
|
||||
normalize_use=defaultsDict[
|
||||
'normalize-use'],
|
||||
decl_linelength=defaultsDict[
|
||||
'decl-linelength'],
|
||||
decl_offset=defaultsDict['decl-offset'],
|
||||
reformat=defaultsDict['reformat'],
|
||||
indent=defaultsDict['indent'],
|
||||
whitespace=defaultsDict['whitespace'],
|
||||
upcase_keywords=defaultsDict['upcase'],
|
||||
upcase_omp=defaultsDict['omp-upcase'],
|
||||
replace=defaultsDict['replace'])
|
||||
except:
|
||||
failure += 1
|
||||
import traceback
|
||||
sys.stdout.write('-' * 60 + "\n")
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
sys.stdout.write('-' * 60 + "\n")
|
||||
sys.stdout.write(
|
||||
"Processing file '" + fileName + "'\n")
|
||||
return(failure > 0)
|
||||
if bkDir and not os.path.exists(bkDir):
|
||||
# Another parallel running instance might just have created the
|
||||
# dir.
|
||||
try:
|
||||
os.mkdir(bkDir)
|
||||
except:
|
||||
assert(os.path.exists(bkDir))
|
||||
if bkDir and not os.path.isdir(bkDir):
|
||||
sys.stderr.write("bk-dir must be a directory" + '\n')
|
||||
sys.stderr.write(usageDesc + '\n')
|
||||
else:
|
||||
failure = 0
|
||||
if not args:
|
||||
args = ['stdin']
|
||||
for fileName in args:
|
||||
if not os.path.isfile(fileName) and not fileName == 'stdin':
|
||||
sys.stderr.write("file " + fileName + " does not exists!\n")
|
||||
else:
|
||||
stdout = defaultsDict['stdout'] or fileName == 'stdin'
|
||||
try:
|
||||
logFile = sys.stderr if defaultsDict[
|
||||
'report-errors'] else open(os.devnull, "w")
|
||||
prettfyInplace(fileName, bkDir=bkDir,
|
||||
stdout=stdout,
|
||||
logFile=logFile,
|
||||
normalize_use=defaultsDict[
|
||||
'normalize-use'],
|
||||
decl_linelength=defaultsDict[
|
||||
'decl-linelength'],
|
||||
decl_offset=defaultsDict[
|
||||
'decl-offset'],
|
||||
reformat=defaultsDict['reformat'],
|
||||
indent=defaultsDict['indent'],
|
||||
whitespace=defaultsDict[
|
||||
'whitespace'],
|
||||
upcase_keywords=defaultsDict[
|
||||
'upcase'],
|
||||
upcase_omp=defaultsDict[
|
||||
'omp-upcase'],
|
||||
replace=defaultsDict['replace'])
|
||||
except:
|
||||
failure += 1
|
||||
import traceback
|
||||
sys.stderr.write('-' * 60 + "\n")
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
sys.stderr.write('-' * 60 + "\n")
|
||||
sys.stderr.write(
|
||||
"Processing file '" + fileName + "'\n")
|
||||
return(failure > 0)
|
||||
|
||||
#=========================================================================
|
||||
|
||||
|
||||
def run_selftest():
|
||||
# create temporary file with example code
|
||||
fn = os.path.join(tempfile.gettempdir(), "prettify_selftest.F")
|
||||
|
|
@ -315,15 +350,15 @@ def run_selftest():
|
|||
|
||||
# call prettify
|
||||
rtn = main([sys.argv[0], fn])
|
||||
assert(rtn==0)
|
||||
assert(rtn == 0)
|
||||
|
||||
# check if file was altered
|
||||
result = open(fn).read()
|
||||
for i, (l1, l2) in enumerate(zip(result.split("\n"), ref.split("\n"))):
|
||||
if(l1 != l2):
|
||||
print("Error: Line %d is not invariant."%i)
|
||||
print("before: "+l1)
|
||||
print("after : "+l2)
|
||||
print("Error: Line %d is not invariant." % i)
|
||||
print("before: " + l1)
|
||||
print("after : " + l2)
|
||||
os.remove(fn)
|
||||
return(1)
|
||||
|
||||
|
|
@ -336,7 +371,7 @@ if(__name__ == '__main__'):
|
|||
if(len(sys.argv) == 2 and sys.argv[-1] == "--selftest"):
|
||||
rtn = run_selftest()
|
||||
else:
|
||||
rtn = main(sys.argv)
|
||||
rtn = main()
|
||||
|
||||
sys.exit(rtn)
|
||||
# EOF
|
||||
15
tools/prettify/setup.py
Executable file
15
tools/prettify/setup.py
Executable file
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
setup(name='fprettify',
|
||||
description='auto-formatter for modern fortran source code',
|
||||
author='Mohamed Fawzi, Patrick Seewald',
|
||||
license = "GPL",
|
||||
entry_points={'console_scripts': ['fprettify = fprettify:main']},
|
||||
py_modules=['fprettify',
|
||||
'formatting.normalizeFortranFile',
|
||||
'formatting.reformatFortranFile',
|
||||
'formatting.replacer',
|
||||
'formatting.selftest']
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue