DistTar Builder

The DistTar builder can build a tarfile with an internal directory structure. It can build plain tar files or gz or bzip compressed archives. You can specify a list of directories and/or files to be included as sources for your Tarfile target. The DISTTAR_EXCLUDEEXTS environment variable allows you to specify any file extensions which should not be included in the tar file. By default this include .o and .so,.dll and a couple of others. The DISTTAR_EXCLUDEDIRS environment variable allows you to specify a list of directories that shouldn't be added, and defaults to 'CVS' and '.svn'. The DISTTAR_EXCLUDERES environment variable allows you to specify a list of regular expressions (provided as strings) which, if matched to a relative pathname (via Python's re.search function), will cause that a file to be excluded.

Save this file as 'disttar.py' and put it in your 'toolpath' directory (as defined in your 'Environment' statement in your SConstruct file).

See also the AccumulateBuilder for another approach to this problem.

   1 # DistTarBuilder: tool to generate tar files using SCons
   2 # Copyright (C) 2005, 2006  Matthew A. Nicholson
   3 # Copyright (C) 2006-2010 John Pye
   4 #
   5 # This file is free software; you can redistribute it and/or
   6 # modify it under the terms of the GNU Lesser General Public
   7 # License version 2.1 as published by the Free Software Foundation.
   8 #
   9 # This file is distributed in the hope that it will be useful,
  10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12 # Lesser General Public License for more details.
  13 #
  14 # You should have received a copy of the GNU Lesser General Public
  15 # License along with this library; if not, write to the Free Software
  16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17 #
  18 
  19 import os,sys
  20 from SCons.Script import *
  21 import re
  22 
  23 def disttar_emitter(target,source,env):
  24 
  25         source,origsource = [], source
  26 
  27         excludeexts = env.Dictionary().get('DISTTAR_EXCLUDEEXTS',[])
  28         excludedirs = env.Dictionary().get('DISTTAR_EXCLUDEDIRS',[])
  29         re1 = env.Dictionary().get('DISTTAR_EXCLUDERES',[])
  30         excluderes = [re.compile(r) for r in re1]
  31 
  32         # assume the sources are directories... need to check that
  33         for item in origsource:
  34                 for root, dirs, files in os.walk(str(item)):
  35 
  36                         # don't make directory dependences as that triggers full build
  37                         # of that directory
  38                         if root in source:
  39                                 #print "Removing directory %s" % root
  40                                 source.remove(root)
  41 
  42                         # loop through files in a directory
  43                         for name in files:
  44                                 ext = os.path.splitext(name)
  45                                 if not ext[1] in excludeexts:
  46                                         relpath = os.path.join(root,name)
  47                                         failre = False
  48                                         for r in excluderes:
  49                                                 #print "Match(  %s   against   %s)" % (r,relpath)
  50                                                 if r.search(relpath):
  51                                                         failre = True
  52                                                         #print "Excluding '%s' from tarball" % relpath
  53                                                         break
  54                                         if not failre:
  55                                                 #print "Adding source",relpath
  56                                                 source.append(relpath)
  57                         for d in excludedirs:
  58                                 if d in dirs:
  59                                         dirs.remove(d)  # don't visit CVS directories etc
  60 
  61         return target, source
  62 
  63 def disttar_string(target, source, env):
  64     """This is what gets printed on the console. We'll strip out the list
  65         or source files, since it tends to get very long. If you want to see the 
  66         contents, the easiest way is to uncomment the line 'Adding to TAR file'
  67         below. """
  68     return 'DistTar(%s,...)' % target[0]
  69 
  70 def disttar(target, source, env):
  71         """tar archive builder"""
  72 
  73         import tarfile
  74 
  75         env_dict = env.Dictionary()
  76 
  77         if env_dict.get("DISTTAR_FORMAT") in ["gz", "bz2"]:
  78                 tar_format = env_dict["DISTTAR_FORMAT"]
  79         else:
  80                 tar_format = ""
  81 
  82         # split the target directory, filename, and stuffix
  83         base_name = str(target[0]).split('.tar')[0]
  84         (target_dir, dir_name) = os.path.split(base_name)
  85 
  86         # create the target directory if it does not exist
  87         if target_dir and not os.path.exists(target_dir):
  88                 os.makedirs(target_dir)
  89 
  90         # open our tar file for writing
  91         sys.stderr.write("DistTar: Writing "+str(target[0]))
  92         tar = tarfile.open(str(target[0]), "w:%s" % tar_format)
  93 
  94         # write sources to our tar file
  95         for item in source:
  96                 item = str(item)
  97                 sys.stderr.write(".")
  98                 #print "Adding to TAR file: %s/%s" % (dir_name,item)
  99                 tar.add(item,'%s/%s' % (dir_name,item))
 100 
 101         # all done
 102         sys.stderr.write("\n") #print "Closing TAR file"
 103         tar.close()
 104 
 105 def disttar_suffix(env, sources):
 106         """tar archive suffix generator"""
 107 
 108         env_dict = env.Dictionary()
 109         if env_dict.has_key("DISTTAR_FORMAT") and env_dict["DISTTAR_FORMAT"] in ["gz", "bz2"]:
 110                 return ".tar." + env_dict["DISTTAR_FORMAT"]
 111         else:
 112                 return ".tar"
 113 
 114 def generate(env):
 115         """
 116         Add builders and construction variables for the DistTar builder.
 117         """
 118 
 119         disttar_action=SCons.Action.Action(disttar, disttar_string)
 120         env['BUILDERS']['DistTar'] =  Builder(
 121                 action=disttar_action
 122                 , emitter=disttar_emitter
 123                 , suffix = disttar_suffix
 124                 , target_factory = env.fs.Entry
 125         )
 126 
 127         env.AppendUnique(
 128             DISTTAR_FORMAT = 'gz'
 129         )
 130 
 131 def exists(env):
 132         """
 133         Make sure this tool exists.
 134         """
 135         try:
 136                 import os
 137                 import tarfile
 138         except ImportError:
 139                 return False
 140         else:
 141                 return True
 142 
 143 # vim:set ts=4 sw=4 noexpandtab:

Usage

   1 #scons buildfile
   2 
   3 # the disttar.py file needs to be in toolpath
   4 env = Environment(tools = ["default", "disttar"], toolpath = '.')
   5 env.DistTar("dist/archive", ["README", "INSTALL", env.Dir("src")])
   6 
   7 # This will build an archive using what ever DISTTAR_FORMAT that is set.
   8 # In this case this will come out to be dist/archive.tar.gz, and all
   9 # included files will be in the 'archive' directory within the tar archive.

Another example:

   1 env['DISTTAR_FORMAT']='bz2'
   2 env.Append(
   3         DISTTAR_EXCLUDEEXTS=['.o','.os','.so','.a','.dll','.cc','.cache','.pyc','.cvsignore','.dblite','.log', '.gz', '.bz2', '.zip']
   4         , DISTTAR_EXCLUDEDIRS=['CVS','.svn','.sconf_temp', 'dist']
   5         , DISTTAR_EXCLUDERES=[r'_wrap\.c$', r'python/swigwrapper\.py$']
   6 )
   7 
   8 tar = env.DistTar("dist/ascend-"+version
   9         , [env.Dir('#')]
  10 )

DistTarBuilder (last edited 2010-12-14 00:13:59 by 208)