Update debian changelog
[pysam.git] / setup.py
index 098cb7f47a1927736b2cbd365611a604a940cafd..979b9369ae38d0aa49a7e8f98aad08dc75c43baa 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -6,34 +6,121 @@ pysam
 
 '''
 
-import os, sys, glob, shutil
+import os, sys, glob, shutil, hashlib, re, fnmatch
+import platform
 
 name = "pysam"
-version = "0.2"
 
-samtools_exclude = ( "bamtk.c", "razip.c", "bgzip.c" )
+# collect pysam version
+sys.path.insert( 0, "pysam")
+import version
+
+version = version.__version__
+
+samtools_exclude = ( "bamtk.c", "razip.c", "bgzip.c", 
+                     "main.c", "calDepth.c", "bam2bed.c",
+                     "wgsim.c", "md5fa.c", "maq2sam.c",)
 samtools_dest = os.path.abspath( "samtools" )
+tabix_exclude = ( "main.c", )
+tabix_dest = os.path.abspath( "tabix" )
+
+def locate(pattern, root=os.curdir):
+    '''Locate all files matching supplied filename pattern in and below
+    supplied root directory.'''
+    for path, dirs, files in os.walk(os.path.abspath(root)):
+       for filename in fnmatch.filter(files, pattern):
+          yield os.path.join(path, filename)
+
+def _update_pysam_files(cf, destdir):
+    '''update pysam files applying redirection of ouput'''
+    for filename in cf:
+        if not filename: continue
+        dest = filename + ".pysam.c"
+        with open( filename ) as infile:
+            with open( dest, "w" ) as outfile:
+                outfile.write( '#include "pysam.h"\n\n' )
+                outfile.write( re.sub( "stderr", "pysamerr", "".join(infile.readlines()) ) )
+            with open( os.path.join( destdir, "pysam.h" ), "w" )as outfile:
+                outfile.write ("""#ifndef PYSAM_H
+#define PYSAM_H
+#include "stdio.h"
+extern FILE * pysamerr;
+#endif
+""")
 
 # copy samtools source
 if len(sys.argv) >= 2 and sys.argv[1] == "import":
    if len(sys.argv) < 3: raise ValueError("missing PATH to samtools source directory")
-   samtools_src = os.path.abspath( sys.argv[2] )
-   if not os.path.exists( samtools_src ): raise IOError( "samtools src dir `%s` does not exist." % samtools_src )
-
-   cfiles = glob.glob( os.path.join( samtools_src, "*.c" ) )
-   hfiles = glob.glob( os.path.join( samtools_src, "*.h" ) )
-   ncopied = 0
-   for p in cfiles + hfiles:
-      f = os.path.basename(p)
-      if f in samtools_exclude: continue
-      if os.path.exists( os.path.join( samtools_dest, f )): continue
-      shutil.copy( p, samtools_dest )
-      ncopied += 1
-   print "installed latest source code from %s: %i files copied" % (samtools_src, ncopied)
+   if len(sys.argv) < 4: raise ValueError("missing PATH to tabix source directory")
+
+   for destdir, srcdir, exclude in zip( 
+      (samtools_dest, tabix_dest), 
+      sys.argv[2:4],
+      (samtools_exclude, tabix_exclude)):
+
+      srcdir = os.path.abspath( srcdir )
+      if not os.path.exists( srcdir ): raise IOError( "samtools src dir `%s` does not exist." % srcdir )
+
+      cfiles = locate( "*.c", srcdir )
+      hfiles = locate( "*.h", srcdir )
+      ncopied = 0
+      
+      def _compareAndCopy( src, srcdir, destdir, exclude ):
+
+         d, f = os.path.split(src)
+         if f in exclude: return None
+         common_prefix = os.path.commonprefix( (d, srcdir ) )
+         subdir = re.sub( common_prefix, "", d )[1:]
+         targetdir = os.path.join( destdir, subdir )
+         if not os.path.exists( targetdir ):
+            os.makedirs( targetdir )
+         old_file = os.path.join( targetdir, f )
+         if os.path.exists( old_file ):
+            md5_old = hashlib.md5("".join(open(old_file,"r").readlines())).digest()
+            md5_new = hashlib.md5("".join(open(src,"r").readlines())).digest()
+            if md5_old != md5_new:
+               raise ValueError( "incompatible files for %s and %s" % (old_file, src ))
+
+         shutil.copy( src, targetdir )
+         return old_file
+
+      for src_file in hfiles:
+         _compareAndCopy( src_file, srcdir,destdir, exclude )
+         ncopied += 1
+
+      cf = []
+      for src_file in cfiles:
+         cf.append( _compareAndCopy( src_file, srcdir, destdir, exclude ) )
+         ncopied += 1
+         
+      sys.stdout.write("installed latest source code from %s: %i files copied" % (srcdir, ncopied))
+      # redirect stderr to pysamerr and replace bam.h with a stub.
+      sys.stdout.write("applying stderr redirection")
+     
+      _update_pysam_files(cf, destdir)
+      
+
    sys.exit(0)
 
-from distutils.core import setup, Extension
-from Pyrex.Distutils import build_ext
+if len(sys.argv) >= 2 and sys.argv[1] == "refresh":
+    sys.stdout.write("refreshing latest source code from .c to .pysam.c")
+# redirect stderr to pysamerr and replace bam.h with a stub.
+    sys.stdout.write("applying stderr redirection")
+    for destdir in ('samtools', 'tabix'):
+        pysamcfiles = locate( "*.pysam.c", destdir )
+        for f in pysamcfiles: os.remove(f)
+        cfiles = locate( "*.c", destdir )
+        _update_pysam_files(cfiles, destdir)
+
+    sys.exit(0)
+
+
+
+from distribute_setup import use_setuptools
+use_setuptools()
+
+from setuptools import Extension, setup
+from Cython.Distutils import build_ext
 
 classifiers = """
 Development Status :: 2 - Alpha
@@ -48,14 +135,57 @@ Topic :: Scientific/Engineering
 Topic :: Scientific/Engineering :: Bioinformatics
 """
 
-pysam = Extension(
-    "pysam/csamtools",                   # name of extension
+if platform.system()=='Windows':
+    include_os = ['win32']
+    os_c_files = ['win32/getopt.c']
+else:
+    include_os = []
+    os_c_files = []
+
+samtools = Extension(
+    "csamtools",                   # name of extension
     [ "pysam/csamtools.pyx" ]  +\
-       [ "pysam/%s" % x for x in (
-             "pysam_util.c", )] +\
-       glob.glob( os.path.join( "samtools", "*.c" ) ),
+        [ "pysam/%s" % x for x in (
+                "pysam_util.c", )] +\
+        glob.glob( os.path.join( "samtools", "*.pysam.c" )) +\
+        os_c_files + \
+        glob.glob( os.path.join( "samtools", "*", "*.pysam.c" ) ),
     library_dirs=[],
-    include_dirs=[ "samtools", ],
+    include_dirs=[ "samtools", "pysam" ] + include_os,
+    libraries=[ "z", ],
+    language="c",
+    define_macros = [('_FILE_OFFSET_BITS','64'),
+                     ('_USE_KNETFILE','')], 
+    )
+
+tabix = Extension(
+    "ctabix",                   # name of extension
+    [ "pysam/ctabix.pyx", ]  +\
+       [ "pysam/%s" % x for x in ( "tabix_util.c", )] +\
+        os_c_files + \
+       glob.glob( os.path.join( "tabix", "*.pysam.c" ) ),
+    library_dirs=[],
+    include_dirs=[ "tabix", "pysam" ] + include_os,
+    libraries=[ "z", ],
+    language="c",
+    define_macros = [('_FILE_OFFSET_BITS','64'),
+                     ('_USE_KNETFILE','')], 
+    )
+
+tabproxies = Extension(
+    "TabProxies",                   # name of extension
+    [ "pysam/TabProxies.pyx", ] + os_c_files,
+    library_dirs=[],
+    include_dirs= include_os,
+    libraries=[ "z", ],
+    language="c",
+    )
+
+cvcf = Extension(
+    "cvcf",                   # name of extension
+    [ "pysam/cvcf.pyx", ] + os_c_files,
+    library_dirs=[],
+    include_dirs= ["tabix",] + include_os,
     libraries=[ "z", ],
     language="c",
     )
@@ -71,9 +201,21 @@ metadata = {
     'platforms': "ALL",
     'url': "http://code.google.com/p/pysam/",
     'py_modules': [
-      "pysam/__init__", "pysam/Pileup", "pysam/namedtuple" ],
-    'ext_modules': [pysam,],
-    'cmdclass' : {'build_ext': build_ext} }
+      "pysam/__init__", 
+      "pysam/Pileup", 
+      "pysam/version" ],
+    # cython larger that 0.16 for yield support
+    'requires' : ['cython (>=0.16)'],
+    'ext_modules': [samtools, tabix, tabproxies, cvcf ],
+    'cmdclass' : {'build_ext': build_ext},
+    'install_requires' : ['cython>=0.12.1',], 
+    # do not pack in order to permit linking to csamtools.so
+    'zip_safe' :False,
+    'use_2to3': True,
+    }
+
+if sys.version_info[0] < 3:
+    metadata['py_modules'].append("pysam/namedtuple")
 
 if __name__=='__main__':
    dist = setup(**metadata)