Skip to content

Commit

Permalink
Code completely refactored
Browse files Browse the repository at this point in the history
Add pybuilder script in preparation to publish on PyPi. Fully backward compatible. Installation instructions changed!
  • Loading branch information
szaghi committed Feb 5, 2015
1 parent 0a85a26 commit f4da3b4
Show file tree
Hide file tree
Showing 18 changed files with 1,436 additions and 1,138 deletions.
1 change: 1 addition & 0 deletions .coverage
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
�}q(U collectorqUcoverage v3.7.1qUlinesq}u.
16 changes: 16 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
language: python

python:
- "2.7.8"
#- "3.4.1"

install:
- pip install pybuilder
- pyb install_dependencies --verbose
- pip install python-coveralls

script:
- pyb --verbose

after_success:
- coveralls
1,138 changes: 0 additions & 1,138 deletions FoBiS.py

This file was deleted.

1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include *.md
54 changes: 54 additions & 0 deletions build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python
"""Build script for MaTiSSe.py"""
import os
from pybuilder.core import Author,init,task,use_plugin
from shutil import copyfile
import re

#use_plugin('copy_resources')
use_plugin('python.core')
use_plugin('python.coverage')
use_plugin('python.install_dependencies')
#use_plugin('python.pylint')
use_plugin('python.unittest')

__source__ = open('src/main/python/fobis/config.py').read()

authors = [Author(re.search(r'^__author__\s*=\s*"(.*)"', __source__, re.M).group(1),
re.search(r'^__author_email__\s*=\s*"(.*)"', __source__, re.M).group(1))]
version = re.search(r'^__version__\s*=\s*"(.*)"', __source__, re.M).group(1)
license = re.search(r'^__license__\s*=\s*"(.*)"', __source__, re.M).group(1)
description = re.search(r'^__description__\s*=\s*"(.*)"', __source__, re.M).group(1)
url = re.search(r'^__url__\s*=\s*"(.*)"', __source__, re.M).group(1)

@init
def initialize(project):
"""Initializing the building class."""
project.version = version
project.build_depends_on('coverage')
project.build_depends_on('pylint')
project.depends_on('markdown')
project.depends_on('yattag')

project.set_property('verbose', True)

project.set_property('coverage_break_build',False)
project.set_property('coverage_threshold_warn',90)

project.set_property('dir_target','release')
project.set_property('dir_dist','release/'+project.name+'-'+project.version)
project.set_property('dir_reports','release/reports-'+project.name+'-'+project.version)
#project.set_property('copy_resources_target','$dir_dist')
#project.get_property('copy_resources_glob').append('MANIFEST.in')

project.default_task = ['analyze','publish','copy_resources']
return

@task
def copy_resources(project):
"""Copy non source resource files."""
copyfile('MANIFEST.in','release/'+project.name+'-'+project.version+'/MANIFEST.in')
for mdf in os.listdir('.'):
if mdf.endswith('.md'):
copyfile(mdf,'release/'+project.name+'-'+project.version+'/'+mdf)
return
5 changes: 5 additions & 0 deletions src/main/python/FoBiS.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env python
"""Wrapper of FoBiS.py program extracted from fobis package"""
from fobis.fobis import main
if __name__ == '__main__' :
main()
315 changes: 315 additions & 0 deletions src/main/python/fobis/Builder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
#!/usr/bin/env python
"""
Builder.py, module definition of Builder class.
This is a class designed for controlling the building phase.
"""
try:
from multiprocessing import Pool
__parallel__=True
except ImportError:
print("Module 'multiprocessing' not found: parallel compilation disabled")
__parallel__=False
import operator
import os
import sys
from .Colors import Colors
from .utils import syswork
class Builder(object):
"""Builder is an object that handles the building system, its attributes and methods."""
def __init__(self,
compiler = "Intel",
fc = "",
modsw = "",
mpi = False,
cflags = "",
lflags = "",
libs = None,
dinc = None,
preproc = "",
build_dir = "./",
mod_dir = "./",
obj_dir = "./",
quiet = False,
colors = False,
jobs = 1,
preform = False,
pfm_dir = None,
pfm_ext = []):
"""
Parameters
----------
compiler : {"Intel"}
compiler used
fc : {""}
custom compiler statement
modsw : {""}
custom compiler switch for modules searching path
mpi : {False}
use MPI enabled version of compiler
cflags : {""}
compilation flags
lflags : {""}
linking flags
libs : {None}
list of external libraries
dinc : {None}
list of directories for searching included files
preproc : {""}
preprocessor flags
build_dir : {"./"}
directory containing built files
mod_dir : {"./"}
directory containing .mod files
obj_dir : {"./"}
directory containing compiled object files
quiet : {False}
make printings less verbose than default
colors : {False}
make printings colored
jobs : {1}
concurrent compiling jobs
preform : {False}
activate PreForM.py pre-processing
pfm_dir : {None}
directory containing sources processed by PreForm.py; by default are removed after used
pfm_ext : {[]}
list of file extensions to be processed by PreForm.py; by default all files are preprocessed if PreForM.py is used
Attributes
----------
"""
self.compiler = compiler
self.fcs = fc
self.modsw = modsw
self.mpi = mpi
self.cflags = cflags
self.lflags = lflags
if libs is None:
self.libs = []
else:
self.libs = libs
if dinc is None:
self.dinc = []
else:
self.dinc = dinc
self.preproc = preproc
self.build_dir = build_dir
self.mod_dir = build_dir+mod_dir
self.obj_dir = build_dir+obj_dir
self.quiet = quiet
self.colors = Colors()
self.jobs = jobs
self.preform = preform
self.pfm_ext = pfm_ext
self.pfm_dir = pfm_dir
if self.pfm_dir:
self.pfm_dir = build_dir+self.pfm_dir
if not colors:
self.colors.disable()
if self.preform:
pfm_exist = False
for path in os.environ["PATH"].split(os.pathsep):
pfm_exist = os.path.exists(os.path.join(path, 'PreForM.py'))
if pfm_exist:
if self.pfm_dir:
if not os.path.exists(self.pfm_dir):
os.makedirs(self.pfm_dir)
break
if not pfm_exist:
print(self.colors.red+'Error: PreForM.py is not in your PATH! You cannot use --preform or -pfm switches.'+self.colors.end)
sys.exit(1)
if mpi:
self.fcs = 'mpif90'
if compiler.lower() == 'gnu':
if not mpi:
self.fcs = 'gfortran'
self.modsw = '-J'
elif compiler.lower() == 'intel':
if not mpi:
self.fcs = 'ifort'
self.modsw = '-module'
elif compiler.lower() == 'g95':
if not mpi:
self.fcs = 'g95'
self.modsw = '-fmod='
elif compiler.lower() == 'custom':
pass # all is set from CLI
if self.modsw[-1]!='=': # check necessary for g95 CLI trapping error
self.modsw += ' '
self.cmd_comp = self.fcs+' '+self.cflags+' '+self.modsw+self.mod_dir+' '+self.preproc
self.cmd_link = self.fcs+' '+self.lflags+' '+self.modsw+self.mod_dir
# checking paths integrity
if not os.path.exists(self.mod_dir):
os.makedirs(self.mod_dir)
if not os.path.exists(self.obj_dir):
os.makedirs(self.obj_dir)
if not os.path.exists(self.build_dir):
os.makedirs(self.build_dir)

def compile_command(self,file_to_compile):
"""
The method compile_command returns the OS command for compiling file_to_compile.
Parameters
----------
file_to_compile : ParsedFile object
file to be compiled
Returns
-------
str
string containing the compile command
"""
if self.preform:
if len(self.pfm_ext)>0:
if file_to_compile.extension in self.pfm_ext:
if self.pfm_dir:
if len(self.dinc)>0:
comp_cmd = 'PreForM.py '+file_to_compile.name+' -o '+self.pfm_dir+file_to_compile.basename+'.pfm.f90'+' ; '+self.cmd_comp+' '+''.join(['-I'+s+' ' for s in self.dinc])+self.pfm_dir+file_to_compile.basename+'.pfm.f90'+' -o '+self.obj_dir+file_to_compile.basename+'.o'
else:
comp_cmd = 'PreForM.py '+file_to_compile.name+' -o '+self.pfm_dir+file_to_compile.basename+'.pfm.f90'+' ; '+self.cmd_comp+' '+ self.pfm_dir+file_to_compile.basename+'.pfm.f90'+' -o '+self.obj_dir+file_to_compile.basename+'.o'
else:
if len(self.dinc)>0:
comp_cmd = 'PreForM.py '+file_to_compile.name+' -o '+file_to_compile.basename+'.pfm.f90'+' ; '+self.cmd_comp+' '+''.join(['-I'+s+' ' for s in self.dinc])+file_to_compile.basename+'.pfm.f90'+' -o '+self.obj_dir+file_to_compile.basename+'.o'+' ; rm -f '+file_to_compile.basename+'.pfm.f90'
else:
comp_cmd = 'PreForM.py '+file_to_compile.name+' -o '+file_to_compile.basename+'.pfm.f90'+' ; '+self.cmd_comp+' '+ file_to_compile.basename+'.pfm.f90'+' -o '+self.obj_dir+file_to_compile.basename+'.o'+' ; rm -f '+file_to_compile.basename+'.pfm.f90'
else:
if len(self.dinc)>0:
comp_cmd = self.cmd_comp+' '+''.join(['-I'+s+' ' for s in self.dinc])+file_to_compile.name+' -o '+self.obj_dir+file_to_compile.basename+'.o'
else:
comp_cmd = self.cmd_comp+' ' +file_to_compile.name+' -o '+self.obj_dir+file_to_compile.basename+'.o'
else:
if self.pfm_dir:
if len(self.dinc)>0:
comp_cmd = 'PreForM.py '+file_to_compile.name+' -o '+self.pfm_dir+file_to_compile.basename+'.pfm'+file_to_compile.extension+' ; '+self.cmd_comp+' '+''.join(['-I'+s+' ' for s in self.dinc])+self.pfm_dir+file_to_compile.basename+'.pfm'+file_to_compile.extension+' -o '+self.obj_dir+file_to_compile.basename+'.o'
else:
comp_cmd = 'PreForM.py '+file_to_compile.name+' -o '+self.pfm_dir+file_to_compile.basename+'.pfm'+file_to_compile.extension+' ; '+self.cmd_comp+' '+ self.pfm_dir+file_to_compile.basename+'.pfm'+file_to_compile.extension+' -o '+self.obj_dir+file_to_compile.basename+'.o'
else:
if len(self.dinc)>0:
comp_cmd = 'PreForM.py '+file_to_compile.name+' -o '+file_to_compile.basename+'.pfm'+file_to_compile.extension+' ; '+self.cmd_comp+' '+''.join(['-I'+s+' ' for s in self.dinc])+file_to_compile.basename+'.pfm'+file_to_compile.extension+' -o '+self.obj_dir+file_to_compile.basename+'.o'+' ; rm -f '+file_to_compile.basename+'.pfm'+file_to_compile.extension
else:
comp_cmd = 'PreForM.py '+file_to_compile.name+' -o '+file_to_compile.basename+'.pfm'+file_to_compile.extension+' ; '+self.cmd_comp+' '+ file_to_compile.basename+'.pfm'+file_to_compile.extension+' -o '+self.obj_dir+file_to_compile.basename+'.o'+' ; rm -f '+file_to_compile.basename+'.pfm'+file_to_compile.extension
else:
if len(self.dinc)>0:
comp_cmd = self.cmd_comp+' '+''.join(['-I'+s+' ' for s in self.dinc])+file_to_compile.name+' -o '+self.obj_dir+file_to_compile.basename+'.o'
else:
comp_cmd = self.cmd_comp+' ' +file_to_compile.name+' -o '+self.obj_dir+file_to_compile.basename+'.o'
return comp_cmd

def build(self,file_to_build,output=None,nomodlibs=None,mklib=None):
"""
Method for building file.
Parameters
----------
file_to_build : ParsedFile
output :
nomodlibs : {None}
list of old-Fortran style libraries objects
mklib : {None}
"""
print(self.colors.bld+'Building '+file_to_build.name+self.colors.end)
# correct the list ordering accordingly to indirect dependency
for dep in file_to_build.pfile_dep_all:
for other_dep in file_to_build.pfile_dep_all:
if other_dep != dep:
if dep in other_dep.pfile_dep_all:
dep.order+=1
file_to_build.pfile_dep_all.sort(key=operator.attrgetter('order'),reverse=True)
# creating a hierarchy list of compiling commands accordingly to the order of all dependencies
if len([p for p in file_to_build.pfile_dep_all if not p.include and p.to_compile])>0:
order_max = max([p for p in file_to_build.pfile_dep_all if not p.include and p.to_compile],key=operator.attrgetter('order')).order + 1
hierarchy = [[] for i in range(order_max)]
for dep in file_to_build.pfile_dep_all:
if dep.to_compile and not dep.include:
hierarchy[dep.order].append([dep.name,self.compile_command(file_to_compile=dep)])
dep.to_compile = False
hierarchy = [h for h in hierarchy if len(h)>0]
for deps in reversed(hierarchy):
files_to_compile = ''
cmds = []
for dep in deps:
files_to_compile = files_to_compile+" "+dep[0]
cmds.append(dep[1])
if len(deps)>1 and self.jobs>1 and __parallel__:
jobs = min(len(deps),self.jobs)
print(self.colors.bld+"Compiling"+files_to_compile+" using "+str(jobs)+" concurrent processes"+self.colors.end)
pool = Pool(processes=jobs)
results = pool.map(syswork,cmds)
pool.close()
pool.join()
if not all(v[0] == 0 for v in results):
for result in results:
if result[0] != 0:
print(self.colors.red+result[1]+self.colors.end)
sys.exit(1)
if not all(v[1] == '' for v in results):
for result in results:
if result[1] != '':
print(self.colors.red+result[1]+self.colors.end)
else:
print(self.colors.bld+"Compiling"+files_to_compile+" serially "+self.colors.end)
for cmd in cmds:
result = syswork(cmd)
if result[0] != 0:
print(self.colors.red+result[1]+self.colors.end)
sys.exit(1)
else:
print(self.colors.bld+'Nothing to compile, all objects are up-to-date'+self.colors.end)
if file_to_build.program:
if nomodlibs is not None:
objs = nomodlibs + file_to_build.obj_dependencies()
else:
objs = file_to_build.obj_dependencies()
if output:
exe=self.build_dir+output
else:
exe=self.build_dir+file_to_build.basename
link_cmd = self.cmd_link+" "+"".join([self.obj_dir+s+" " for s in objs])+"".join([s+" " for s in self.libs])+"-o "+exe
print(self.colors.bld+"Linking "+exe+self.colors.end)
result = syswork(link_cmd)
if result[0] != 0:
print(self.colors.red+result[1]+self.colors.end)
sys.exit(1)
print(self.colors.bld+'Target '+file_to_build.name+' has been successfully built'+self.colors.end)
elif mklib:
if output:
lib=self.build_dir+output
else:
if mklib.lower()=='shared':
lib=self.build_dir+file_to_build.basename+'.so'
elif mklib.lower()=='static':
lib=self.build_dir+file_to_build.basename+'.a'
if mklib.lower()=='shared':
link_cmd = self.cmd_link+" "+"".join([s+" " for s in self.libs])+self.obj_dir+file_to_build.basename+".o -o "+lib
elif mklib.lower()=='static':
link_cmd = "ar -rcs "+lib+" "+self.obj_dir+file_to_build.basename+".o ; ranlib "+lib
print(self.colors.bld+"Linking "+lib+self.colors.end)
result = syswork(link_cmd)
if result[0] != 0:
print(self.colors.red+result[1]+self.colors.end)
sys.exit(1)
print(self.colors.bld+'Target '+file_to_build.name+' has been successfully built'+self.colors.end)

def verbose(self):
"""
The method verbose returns a verbose message containing builder infos.
"""
message = ''
if not self.quiet:
message = "Builder options"+"\n"
message+= " Compiled-objects .o directory: "+self.obj_dir+"\n"
message+= " Compiled-objects .mod directory: "+self.mod_dir+"\n"
message+= " Building directory: "+self.build_dir+"\n"
message+= " Included paths: "+"".join([s+" " for s in self.dinc])+"\n"
message+= " Linked libraries: "+"".join([s+" " for s in self.libs])+"\n"
message+= " Compiler class: "+self.compiler+"\n"
message+= " Compiler: "+self.fcs+"\n"
message+= " Compiler module switch: "+self.modsw+"\n"
message+= " Compilation flags: "+self.cflags+"\n"
message+= " Linking flags: "+self.lflags+"\n"
message+= " Preprocessing flags: "+self.preproc+"\n"
message+= " PreForM.py used: "+str(self.preform)+"\n"
message+= " PreForM.py output directory: "+str(self.pfm_dir)+"\n"
message+= " PreForM.py extensions processed: "+str(self.pfm_ext)+"\n"
return message
Loading

0 comments on commit f4da3b4

Please sign in to comment.