├── utils ├── __init__.py ├── resources │ └── template-normal.dmg ├── Packager.py ├── FileUniversalizer.py ├── Dependency.py ├── Sandbox.py ├── Config.py ├── MacOSXPackager.py ├── file.py ├── Component.py ├── Differences.py └── Builder.py ├── components ├── libjpeg │ ├── version │ ├── patches │ │ └── libtool135update.zip │ ├── __init__.py │ └── LibJPEG.py ├── php5 │ ├── version │ ├── __init__.py │ ├── patches │ │ ├── php5_config.patch │ │ ├── php5_uni.patch │ │ └── apxs-install.patch │ └── PHP5.py ├── zlib │ ├── version │ ├── __init__.py │ └── ZLib.py ├── apache │ ├── version │ ├── __init__.py │ ├── patches │ │ ├── rm_envvars.patch │ │ └── ulimit_fix.patch │ └── Apache.py ├── expat │ ├── version │ ├── __init__.py │ └── Expat.py ├── freetds │ ├── version │ ├── __init__.py │ └── FreeTDS.py ├── freetype │ ├── version │ ├── __init__.py │ └── FreeType.py ├── libltdl │ ├── version │ ├── __init__.py │ └── LibLTDL.py ├── libpng │ ├── version │ ├── __init__.py │ └── LibPNG.py ├── libungif │ ├── version │ ├── __init__.py │ └── LibUnGIF.py ├── libxml │ ├── version │ ├── __init__.py │ └── LibXML.py ├── libxslt │ ├── version │ ├── __init__.py │ └── LibXSLT.py ├── mcrypt │ ├── version │ ├── __init__.py │ └── MCrypt.py ├── mhash │ ├── version │ ├── __init__.py │ └── MHash.py ├── mysql │ ├── version │ ├── __init__.py │ ├── patches │ │ └── mysql.server.patch │ ├── resources │ │ └── my.cnf │ └── MySQL.py ├── ncurses │ ├── version │ ├── __init__.py │ └── Ncurses.py ├── openssl │ ├── version │ ├── __init__.py │ └── OpenSSL.py ├── perl │ ├── version │ ├── __init__.py │ ├── resources │ │ ├── upgrade_modules.pl │ │ ├── Config.pm │ │ └── System.pm │ └── Perl.py ├── proftpd │ ├── version │ ├── __init__.py │ └── ProFTPd.py ├── sqlite │ ├── version │ ├── __init__.py │ └── SQLite.py ├── gettext │ ├── version │ ├── __init__.py │ └── Gettext.py ├── postgresql │ ├── version │ ├── __init__.py │ └── Postgresql.py └── __init__.py ├── .com.apple.timemachine.supported ├── AUTHORS ├── .gitignore ├── default.ini └── README.md /utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/libjpeg/version: -------------------------------------------------------------------------------- 1 | 6b -------------------------------------------------------------------------------- /components/php5/version: -------------------------------------------------------------------------------- 1 | 5.3.9 -------------------------------------------------------------------------------- /components/zlib/version: -------------------------------------------------------------------------------- 1 | 1.2.6 -------------------------------------------------------------------------------- /.com.apple.timemachine.supported: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/apache/version: -------------------------------------------------------------------------------- 1 | 2.2.19 -------------------------------------------------------------------------------- /components/expat/version: -------------------------------------------------------------------------------- 1 | 2.0.1 -------------------------------------------------------------------------------- /components/freetds/version: -------------------------------------------------------------------------------- 1 | 0.91 -------------------------------------------------------------------------------- /components/freetype/version: -------------------------------------------------------------------------------- 1 | 2.4.8 -------------------------------------------------------------------------------- /components/libltdl/version: -------------------------------------------------------------------------------- 1 | 1.5.24 -------------------------------------------------------------------------------- /components/libpng/version: -------------------------------------------------------------------------------- 1 | 1.5.7 -------------------------------------------------------------------------------- /components/libungif/version: -------------------------------------------------------------------------------- 1 | 4.1.4 -------------------------------------------------------------------------------- /components/libxml/version: -------------------------------------------------------------------------------- 1 | 2.7.8 -------------------------------------------------------------------------------- /components/libxslt/version: -------------------------------------------------------------------------------- 1 | 1.1.26 -------------------------------------------------------------------------------- /components/mcrypt/version: -------------------------------------------------------------------------------- 1 | 2.5.8 -------------------------------------------------------------------------------- /components/mhash/version: -------------------------------------------------------------------------------- 1 | 0.9.9.9 -------------------------------------------------------------------------------- /components/mysql/version: -------------------------------------------------------------------------------- 1 | 5.5.20 -------------------------------------------------------------------------------- /components/ncurses/version: -------------------------------------------------------------------------------- 1 | 5.6 -------------------------------------------------------------------------------- /components/openssl/version: -------------------------------------------------------------------------------- 1 | 1.0.0d -------------------------------------------------------------------------------- /components/perl/version: -------------------------------------------------------------------------------- 1 | 5.14.1 -------------------------------------------------------------------------------- /components/proftpd/version: -------------------------------------------------------------------------------- 1 | 1.3.3e -------------------------------------------------------------------------------- /components/sqlite/version: -------------------------------------------------------------------------------- 1 | 3070701 -------------------------------------------------------------------------------- /components/gettext/version: -------------------------------------------------------------------------------- 1 | 0.18.1.1 -------------------------------------------------------------------------------- /components/postgresql/version: -------------------------------------------------------------------------------- 1 | 9.1.2 -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Christian Speich 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.swp 4 | archives/ 5 | builds/ 6 | -------------------------------------------------------------------------------- /utils/resources/template-normal.dmg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApacheFriends/XAMPP-Builder/HEAD/utils/resources/template-normal.dmg -------------------------------------------------------------------------------- /components/libjpeg/patches/libtool135update.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApacheFriends/XAMPP-Builder/HEAD/components/libjpeg/patches/libtool135update.zip -------------------------------------------------------------------------------- /default.ini: -------------------------------------------------------------------------------- 1 | [XAMPP Builder] 2 | archives = ./archives 3 | builds = ./builds 4 | 5 | [Mac OS X] 6 | prefix = /Applications/XAMPP/xamppfiles 7 | dest = /Applications/XAMPP 8 | archs = i386, ppc 9 | -------------------------------------------------------------------------------- /components/php5/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | """ 7 | 8 | from components.php5.PHP5 import PHP5 -------------------------------------------------------------------------------- /components/zlib/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | ''' 7 | 8 | from components.zlib.ZLib import ZLib -------------------------------------------------------------------------------- /components/apache/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | """ 7 | 8 | from components.apache.Apache import Apache -------------------------------------------------------------------------------- /components/libltdl/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | """ 7 | 8 | from components.libltdl.LibLTDL import LibLTDL -------------------------------------------------------------------------------- /components/ncurses/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | """ 7 | 8 | from components.ncurses.Ncurses import Ncurses -------------------------------------------------------------------------------- /components/openssl/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | """ 7 | 8 | from components.openssl.OpenSSL import OpenSSL -------------------------------------------------------------------------------- /components/sqlite/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | """ 7 | 8 | from components.sqlite.SQLite import SQLite -------------------------------------------------------------------------------- /components/perl/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The Perl component. 7 | """ 8 | 9 | from components.perl.Perl import Perl -------------------------------------------------------------------------------- /components/expat/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The Expat component. 7 | """ 8 | 9 | from components.expat.Expat import Expat -------------------------------------------------------------------------------- /components/mysql/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The MySQL component. 7 | """ 8 | 9 | from components.mysql.MySQL import MySQL -------------------------------------------------------------------------------- /components/proftpd/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The ProFTPd component. 7 | """ 8 | 9 | from components.proftpd.ProFTPd import ProFTPd -------------------------------------------------------------------------------- /components/libpng/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The LibPNG component. 7 | """ 8 | 9 | from components.libpng.LibPNG import LibPNG -------------------------------------------------------------------------------- /components/libxml/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The LibXML component. 7 | """ 8 | 9 | from components.libxml.LibXML import LibXML -------------------------------------------------------------------------------- /components/libjpeg/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The LibJPEG component. 7 | """ 8 | 9 | from components.libjpeg.LibJPEG import LibJPEG -------------------------------------------------------------------------------- /components/libxslt/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The LibXSLT component. 7 | """ 8 | 9 | from components.libxslt.LibXSLT import LibXSLT -------------------------------------------------------------------------------- /components/freetype/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The FreeType component. 7 | """ 8 | 9 | from components.freetype.FreeType import FreeType -------------------------------------------------------------------------------- /components/libungif/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The LibUnGIF component. 7 | """ 8 | 9 | from components.libungif.LibUnGIF import LibUnGIF -------------------------------------------------------------------------------- /components/mhash/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The MHash component. 7 | """ 8 | 9 | from components.mhash.MHash import MHash 10 | -------------------------------------------------------------------------------- /components/mcrypt/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The MCrypt component. 7 | """ 8 | 9 | from components.mcrypt.MCrypt import MCrypt 10 | -------------------------------------------------------------------------------- /components/freetds/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The FreeTDS component. 7 | """ 8 | 9 | from components.freetds.FreeTDS import FreeTDS 10 | -------------------------------------------------------------------------------- /components/postgresql/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The Postgresql component. 7 | """ 8 | 9 | from components.postgresql.Postgresql import Postgresql -------------------------------------------------------------------------------- /components/gettext/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The Gettext component. 7 | """ 8 | 9 | from components.gettext.Gettext import Gettext 10 | 11 | #print repr(Gettext) -------------------------------------------------------------------------------- /utils/Packager.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | """ 7 | 8 | class Packager(object): 9 | 10 | def __init__(self, builder): 11 | self.builder = builder 12 | 13 | def pack(self, version, xamppPath, devPath, outputDirectory): 14 | raise RuntimeError("Not implemented.") -------------------------------------------------------------------------------- /components/mysql/patches/mysql.server.patch: -------------------------------------------------------------------------------- 1 | --- support-files/mysql.server.sh.ori 2006-10-13 21:36:27.000000000 +0200 2 | +++ support-files//mysql.server.sh 2006-10-13 21:37:26.000000000 +0200 3 | @@ -181,7 +181,7 @@ then 4 | print_defaults="$bindir/mysql_print_defaults" 5 | else 6 | # Try to find basedir in /etc/my.cnf 7 | - conf=/etc/my.cnf 8 | + conf=/Applications/XAMPP/etc/my.cnf 9 | print_defaults= 10 | if test -r $conf 11 | then 12 | -------------------------------------------------------------------------------- /components/apache/patches/rm_envvars.patch: -------------------------------------------------------------------------------- 1 | --- support/envvars-std.in.org 2007-09-29 20:12:03.000000000 +0200 2 | +++ support/envvars-std.in 2007-09-29 20:13:27.000000000 +0200 3 | @@ -18,7 +18,7 @@ 4 | # 5 | # This file is generated from envvars-std.in 6 | # 7 | -@SHLIBPATH_VAR@="@exp_libdir@:$@SHLIBPATH_VAR@" 8 | -export @SHLIBPATH_VAR@ 9 | +#@SHLIBPATH_VAR@="@exp_libdir@:$@SHLIBPATH_VAR@" 10 | +#export @SHLIBPATH_VAR@ 11 | # 12 | @OS_SPECIFIC_VARS@ 13 | -------------------------------------------------------------------------------- /components/zlib/ZLib.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The ZLib component. 7 | """ 8 | 9 | from utils.Component import Component 10 | 11 | import os.path 12 | 13 | class ZLib(Component): 14 | 15 | def __init__(self, config): 16 | super(ZLib, self).__init__('ZLib', os.path.dirname(__file__), config) 17 | 18 | self.download_url = 'http://www.zlib.net/zlib-%s.tar.gz' % self.version 19 | 20 | -------------------------------------------------------------------------------- /components/expat/Expat.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The Expat component. 7 | """ 8 | 9 | from utils.Component import Component 10 | 11 | import os.path 12 | 13 | class Expat(Component): 14 | 15 | def __init__(self, config): 16 | super(Expat, self).__init__('Expat', os.path.dirname(__file__), config) 17 | 18 | self.download_url = 'http://switch.dl.sourceforge.net/sourceforge/expat/expat-%s.tar.gz' % self.version 19 | -------------------------------------------------------------------------------- /components/mhash/MHash.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The MHash component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os 13 | import os.path 14 | 15 | class MHash(Component): 16 | 17 | def __init__(self, config): 18 | super(MHash, self).__init__('MHash', os.path.dirname(__file__), config) 19 | 20 | self.download_url = 'http://downloads.sourceforge.net/mhash/mhash-%s.tar.gz' % self.version 21 | 22 | -------------------------------------------------------------------------------- /components/mcrypt/MCrypt.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The MCrypt component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os 13 | import os.path 14 | 15 | class MCrypt(Component): 16 | 17 | def __init__(self, config): 18 | super(MCrypt, self).__init__('MCrypt', os.path.dirname(__file__), config) 19 | 20 | self.download_url = 'http://downloads.sourceforge.net/mcrypt/libmcrypt-%s.tar.gz' % self.version 21 | 22 | -------------------------------------------------------------------------------- /components/freetype/FreeType.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The FreeType component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os.path 13 | 14 | class FreeType(Component): 15 | 16 | def __init__(self, config): 17 | super(FreeType, self).__init__('FreeType', os.path.dirname(__file__), config) 18 | 19 | self.download_url = 'http://download.savannah.gnu.org/releases/freetype/freetype-%s.tar.gz' % self.version 20 | -------------------------------------------------------------------------------- /components/libungif/LibUnGIF.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The LibXML component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os 13 | import os.path 14 | 15 | class LibUnGIF(Component): 16 | 17 | def __init__(self, config): 18 | super(LibUnGIF, self).__init__('LibUnGIF', os.path.dirname(__file__), config) 19 | 20 | self.download_url = 'http://downloads.sourceforge.net/giflib/libungif-%s.tar.gz' % self.version 21 | 22 | -------------------------------------------------------------------------------- /components/apache/patches/ulimit_fix.patch: -------------------------------------------------------------------------------- 1 | --- support/apachectl.in.orig 2006-07-12 05:38:44.000000000 +0200 2 | +++ support/apachectl.in 2009-06-04 17:13:02.000000000 +0200 3 | @@ -66,9 +66,10 @@ 4 | # |||||||||||||||||||| END CONFIGURATION SECTION |||||||||||||||||||| 5 | 6 | # Set the maximum number of file descriptors allowed per child process. 7 | -if [ "x$ULIMIT_MAX_FILES" != "x" ] ; then 8 | - $ULIMIT_MAX_FILES 9 | -fi 10 | +#:XAMPP comment out to surpress ugly warnings 11 | +#if [ "x$ULIMIT_MAX_FILES" != "x" ] ; then 12 | +# $ULIMIT_MAX_FILES 13 | +#fi 14 | 15 | ERROR=0 16 | if [ "x$ARGV" = "x" ] ; then -------------------------------------------------------------------------------- /components/libxml/LibXML.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The LibXML component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os 13 | import os.path 14 | 15 | class LibXML(Component): 16 | 17 | def __init__(self, config): 18 | super(LibXML, self).__init__('LibXML', os.path.dirname(__file__), config) 19 | 20 | self.download_url = 'ftp://xmlsoft.org/libxml2/libxml2-%s.tar.gz' % self.version 21 | self.includeDir = "libxml2" 22 | 23 | -------------------------------------------------------------------------------- /components/postgresql/Postgresql.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The Postgresql component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os.path 13 | 14 | class Postgresql(Component): 15 | 16 | def __init__(self, config): 17 | super(Postgresql, self).__init__('Postgresql', os.path.dirname(__file__), config) 18 | 19 | self.download_url = 'http://ftp8.de.postgresql.org/pub/misc/pgsql/latest/postgresql-%s.tar.bz2' % self.version 20 | self.supportsOnPassUniversalBuild = False -------------------------------------------------------------------------------- /components/php5/patches/php5_config.patch: -------------------------------------------------------------------------------- 1 | --- scripts/php-config.in.org 2009-03-25 18:14:06.000000000 +0100 2 | +++ scripts/php-config.in 2009-03-29 18:41:45.000000000 +0200 3 | @@ -6,7 +6,7 @@ 4 | version="@PHP_VERSION@" 5 | vernum="@PHP_VERSION_ID@" 6 | include_dir="@includedir@/php" 7 | -includes="-I$include_dir -I$include_dir/main -I$include_dir/TSRM -I$include_dir/Zend -I$include_dir/ext -I$include_dir/ext/date/lib" 8 | +includes="-I@includedir@ -I$include_dir -I$include_dir/main -I$include_dir/TSRM -I$include_dir/Zend -I$include_dir/ext -I$include_dir/ext/date/lib -I$prefix/include" 9 | ldflags="@PHP_LDFLAGS@" 10 | libs="@EXTRA_LIBS@" 11 | extension_dir='@EXTENSION_DIR@' 12 | -------------------------------------------------------------------------------- /components/sqlite/SQLite.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The SQLite component. 7 | """ 8 | 9 | from utils.Component import Component 10 | 11 | import os.path 12 | 13 | class SQLite(Component): 14 | 15 | def __init__(self, config): 16 | super(SQLite, self).__init__('SQLite', os.path.dirname(__file__), config) 17 | 18 | self.download_url = 'http://www.sqlite.org/sqlite-autoconf-%s.tar.gz' % self.version 19 | 20 | def installFlags(self): 21 | return [ 22 | "install", 23 | "prefix=${DEST_DIR}" 24 | ] 25 | 26 | -------------------------------------------------------------------------------- /components/libltdl/LibLTDL.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The LibLTDL component. 7 | """ 8 | 9 | from utils.Component import Component 10 | 11 | import os.path 12 | 13 | class LibLTDL(Component): 14 | 15 | def __init__(self, config): 16 | super(LibLTDL, self).__init__('LibLTDL', os.path.dirname(__file__), config) 17 | 18 | self.download_url = 'http://ftp.gnu.org/gnu/libtool/libtool-%s.tar.gz' % self.version 19 | 20 | def extraTarFlags(self): 21 | return [ 22 | '--strip', '2', 23 | '--include', 'libtool-%s/libltdl' % self.version 24 | ] -------------------------------------------------------------------------------- /components/libpng/LibPNG.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The LibPNG component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os.path 13 | 14 | class LibPNG(Component): 15 | 16 | def __init__(self, config): 17 | super(LibPNG, self).__init__('LibPNG', os.path.dirname(__file__), config) 18 | 19 | self.download_url = 'http://switch.dl.sourceforge.net/sourceforge/libpng/libpng-%s.tar.bz2' % self.version 20 | 21 | self.dependencies = [ 22 | Dependency('ZLib', configureFlags=["--with-zlib-prefix=${COMPONENT_PATH}"]), 23 | ] 24 | 25 | -------------------------------------------------------------------------------- /components/ncurses/Ncurses.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The Ncurses component. 7 | """ 8 | 9 | from utils.Component import Component 10 | 11 | import os.path 12 | 13 | class Ncurses(Component): 14 | 15 | def __init__(self, config): 16 | super(Ncurses, self).__init__('Ncurses', os.path.dirname(__file__), config) 17 | 18 | self.download_url = 'http://ftp.gnu.org/pub/gnu/ncurses/ncurses-%s.tar.gz' % self.version 19 | 20 | def configureFlags(self): 21 | flags = super(Ncurses, self).configureFlags() 22 | 23 | flags.extend([ 24 | '--with-shared' 25 | ]) 26 | 27 | return flags -------------------------------------------------------------------------------- /components/libxslt/LibXSLT.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The LibXSLT component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os.path 13 | 14 | class LibXSLT(Component): 15 | 16 | def __init__(self, config): 17 | super(LibXSLT, self).__init__('LibXSLT', os.path.dirname(__file__), config) 18 | 19 | self.download_url = 'ftp://xmlsoft.org/libxslt/libxslt-%s.tar.gz' % self.version 20 | self.dependencies = [ 21 | Dependency('LibXML', configureFlags=["--with-libxml-prefix=${COMPONENT_PATH}", "--with-libxml-include-prefix=${INCLUDE_PATH}", "--with-libxml-libs-prefix=${LIB_PATH}"]) 22 | ] 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | XAMPP Builder 2 | ============= 3 | 4 | XAMPP Builder will be replace the current bash-based build system used for XAMPP for Mac OS X. It'll be modular and allow to declare depentencies in order to not forget rebuilding something. 5 | 6 | The Builder is written in Python and is designed to be adopted by the other *nix systems XAMPP is avaiable for. 7 | 8 | Design 9 | ------------ 10 | 11 | utils/ -- will contain the utils and all the classes used by this builder 12 | components/ -- will contain the components for XAMPP along with their dependencies and configure/build descriptions 13 | builder.py -- will be the script that is interacted with and used to build XAMPP 14 | default.ini -- will be the default config used for the paths where the zips, the builds etc. should be stored 15 | 16 | Let's hope everything works as I imagine. 17 | -------------------------------------------------------------------------------- /components/perl/resources/upgrade_modules.pl: -------------------------------------------------------------------------------- 1 | # Many thanks to BinGOs from #perl on freenode.net for this script :) 2 | 3 | use strict; 4 | use warnings; 5 | use CPANPLUS::Backend; 6 | 7 | $ENV{PERL_MM_USE_DEFAULT} = 1; # despite verbose setting 8 | $ENV{PERL_EXTUTILS_AUTOINSTALL} = '--defaultdeps'; 9 | 10 | my $cb = CPANPLUS::Backend->new(); 11 | my $conf = $cb->configure_object; 12 | 13 | $conf->set_conf( 'prereqs' => 1, 'skiptest' => 1 ); 14 | 15 | my @list = $cb->installed(); 16 | 17 | my @rv; my %seen; 18 | for my $mod (@list) { 19 | ### skip this mod if it's up to date ### 20 | next if $mod->is_uptodate; 21 | ### skip this mod if it's core ### 22 | next if $mod->package_is_perl_core; 23 | 24 | if( !$seen{$mod->package}++ ) { 25 | push @rv, $mod; 26 | } 27 | } 28 | 29 | @rv = sort { $a->module cmp $b->module } @rv; 30 | 31 | $_->install() for @rv; -------------------------------------------------------------------------------- /components/gettext/Gettext.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The Gettext component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os 13 | import os.path 14 | 15 | class Gettext(Component): 16 | 17 | def __init__(self, config): 18 | super(Gettext, self).__init__('Gettext', os.path.dirname(__file__), config) 19 | 20 | self.download_url = 'http://ftp.gnu.org/pub/gnu/gettext/gettext-%s.tar.gz' % self.version 21 | 22 | def configureFlags(self): 23 | flags = super(Gettext, self).configureFlags() 24 | 25 | flags.extend([ 26 | '--disable-java', 27 | '--disable-native-java', 28 | '--enable-relocatable', 29 | '--without-man', 30 | '--without-emacs' 31 | ]) 32 | 33 | return flags 34 | -------------------------------------------------------------------------------- /components/freetds/FreeTDS.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The FreeTDS component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os 13 | import os.path 14 | 15 | class FreeTDS(Component): 16 | 17 | def __init__(self, config): 18 | super(FreeTDS, self).__init__('FreeTDS', os.path.dirname(__file__), config) 19 | 20 | self.download_url = 'ftp://ftp.ibiblio.org/pub/Linux/ALPHA/freetds/stable/freetds-%s.tar.gz' % self.version 21 | self.dependencies = [ 22 | Dependency('OpenSSL', configureFlags=["--with-openssl=${COMPONENT_PATH}"]), 23 | Dependency('Ncurses', configureFlags=["--with-ncurses=${COMPONENT_PATH}"]) 24 | ] 25 | 26 | def configureFlags(self): 27 | flags = super(FreeTDS, self).configureFlags() 28 | 29 | flags.extend([ 30 | '--enable-shared', 31 | '--disable-odbc' 32 | ]) 33 | 34 | return flags 35 | -------------------------------------------------------------------------------- /components/openssl/OpenSSL.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The OpenSSL component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os.path 13 | 14 | class OpenSSL(Component): 15 | 16 | def __init__(self, config): 17 | super(OpenSSL, self).__init__('OpenSSL', os.path.dirname(__file__), config) 18 | 19 | self.download_url = 'http://www.openssl.org/source/openssl-%s.tar.gz' % self.version 20 | self.supportsOnPassUniversalBuild = False 21 | self.dependencies = [ 22 | Dependency('ZLib') 23 | ] 24 | 25 | def configureFlags(self): 26 | return [ 27 | './Configure', 28 | '--prefix=$PREFIX', 29 | '--openssldir=${PREFIX}/share/openssl', 30 | 'shared', 31 | 'darwin-${ARCH}-cc' 32 | ] 33 | 34 | def installFlags(self): 35 | return [ 36 | "install", 37 | "INSTALL_PREFIX=${DEST_DIR}" 38 | ] 39 | 40 | def configureCommand(self): 41 | return 'bash' 42 | 43 | -------------------------------------------------------------------------------- /utils/FileUniversalizer.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The Builder class is the main class of the builder 7 | and coordinates everything that happen during the 8 | building of XAMPP. 9 | """ 10 | import os 11 | from subprocess import check_call 12 | from utils.file import isMachO 13 | 14 | class FileUniversalizer(object): 15 | def applicableTo(self, path, arch_roots): 16 | raise NotImplemented() 17 | 18 | def universalizeFile(self, source, dest, arch_roots): 19 | raise NotImplemented() 20 | 21 | 22 | class MachOUniversalizer(FileUniversalizer): 23 | def applicableTo(self, path, arch_roots): 24 | for arch, root in arch_roots.iteritems(): 25 | if isMachO(os.path.join(root, path)) is None: 26 | return False 27 | 28 | return True 29 | 30 | def universalizeFile(self, source, dest, arch_roots): 31 | arch_flags = [] 32 | 33 | for arch, root in arch_roots.iteritems(): 34 | arch_flags.extend(['-arch', arch, os.path.join(root, source)]) 35 | 36 | check_call(["lipo", "-create"] + arch_flags + ["-output", dest]) -------------------------------------------------------------------------------- /components/proftpd/ProFTPd.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The ProFTPd component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os.path 13 | 14 | class ProFTPd(Component): 15 | 16 | def __init__(self, config): 17 | super(ProFTPd, self).__init__('ProFTPd', os.path.dirname(__file__), config) 18 | 19 | self.download_url = 'ftp://ftp.proftpd.org/distrib/source/proftpd-%s.tar.gz' % self.version 20 | 21 | self.dependencies = [ 22 | Dependency('ZLib', cFlags=['-I${INCLUDE_PATH}'], ldFlags=['-L${LIB_PATH}']), 23 | Dependency('Ncurses', cFlags=['-I${INCLUDE_PATH}'], ldFlags=['-L${LIB_PATH}']), 24 | Dependency('OpenSSL', cFlags=['-I${INCLUDE_PATH}'], ldFlags=['-L${LIB_PATH}']), 25 | Dependency('MySQL', cFlags=['-I${INCLUDE_PATH}'], ldFlags=['-L${LIB_PATH}']) 26 | ] 27 | 28 | def configureFlags(self): 29 | flags = super(ProFTPd, self).configureFlags() 30 | 31 | flags.extend([ 32 | '--with-modules=mod_sql:mod_sql_mysql:mod_tls' 33 | ]) 34 | 35 | return flags 36 | -------------------------------------------------------------------------------- /components/perl/resources/Config.pm: -------------------------------------------------------------------------------- 1 | 2 | # This is CPAN.pm's systemwide configuration file. This file provides 3 | # defaults for users, and the values can be changed in a per-user 4 | # configuration file. The user-config file is being looked for as 5 | # ~/.cpan/CPAN/MyConfig.pm. 6 | 7 | $CPAN::Config = { 8 | 'auto_commit' => q[0], 9 | 'build_cache' => q[100], 10 | 'build_dir' => q[/Applications/XAMPP/xamppfiles/var/perl/cpan/build], 11 | 'cache_metadata' => q[1], 12 | 'commandnumber_in_prompt' => q[1], 13 | 'cpan_home' => q[/Applications/XAMPP/xamppfiles/var/perl/cpan], 14 | 'ftp_passive' => q[1], 15 | 'ftp_proxy' => q[], 16 | 'http_proxy' => q[], 17 | 'inactivity_timeout' => q[0], 18 | 'index_expire' => q[1], 19 | 'inhibit_startup_message' => q[0], 20 | 'keep_source_where' => q[/Applications/XAMPP/xamppfiles/var/perl/cpan/sources], 21 | 'make_arg' => q[], 22 | 'make_install_arg' => q[], 23 | 'make_install_make_command' => q[], 24 | 'makepl_arg' => q[], 25 | 'mbuild_arg' => q[], 26 | 'mbuild_install_arg' => q[UNINST=1], 27 | 'mbuild_install_build_command' => q[./Build], 28 | 'mbuildpl_arg' => q[], 29 | 'no_proxy' => q[], 30 | 'prerequisites_policy' => q[follow], 31 | 'scan_cache' => q[atstart], 32 | 'show_upload_date' => q[0], 33 | 'term_ornaments' => q[1], 34 | 'urllist' => [], 35 | 'use_sqlite' => q[0], 36 | }; 37 | 1; 38 | __END__ 39 | -------------------------------------------------------------------------------- /components/libjpeg/LibJPEG.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | The LibJPEG component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os 13 | import os.path 14 | 15 | class LibJPEG(Component): 16 | 17 | def __init__(self, config): 18 | super(LibJPEG, self).__init__('LibJPEG', os.path.dirname(__file__), config) 19 | 20 | self.download_url = 'http://switch.dl.sourceforge.net/sourceforge/libjpeg/jpegsrc.v%s.tar.gz' % self.version 21 | 22 | self.buildSteps.insert(self.buildSteps.index('install'), self.createCommonDirectories) 23 | 24 | self.patches = [ 25 | 'libtool135update.zip' 26 | ] 27 | 28 | def configureFlags(self): 29 | flags = super(LibJPEG, self).configureFlags() 30 | 31 | flags.extend([ 32 | '--enable-shared' 33 | ]) 34 | 35 | return flags 36 | 37 | def installFlags(self): 38 | return [ 39 | "install", 40 | "prefix=${DEST_DIR}${PREFIX}" 41 | ] 42 | 43 | def createCommonDirectories(self, component, archs, builder): 44 | dirs = [ 45 | 'bin', 46 | 'lib', 47 | 'include', 48 | 'man/man1' 49 | ] 50 | 51 | for d in dirs: 52 | dir = self.buildPath + os.path.join(self.config.prefixPath, d) 53 | if not os.path.isdir(dir): 54 | path = os.makedirs(dir) 55 | 56 | -------------------------------------------------------------------------------- /components/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | """ 7 | 8 | import components.zlib.ZLib 9 | import components.openssl.OpenSSL 10 | import components.libjpeg.LibJPEG 11 | import components.libltdl.LibLTDL 12 | import components.libpng.LibPNG 13 | import components.libungif.LibUnGIF 14 | import components.libxml.LibXML 15 | import components.libxslt.LibXSLT 16 | import components.mcrypt.MCrypt 17 | import components.mhash.MHash 18 | import components.ncurses.Ncurses 19 | import components.sqlite.SQLite 20 | import components.expat.Expat 21 | import components.freetds.FreeTDS 22 | import components.freetype.FreeType 23 | import components.gettext.Gettext 24 | import components.apache.Apache 25 | import components.mysql.MySQL 26 | import components.proftpd.ProFTPd 27 | import components.perl.Perl 28 | import components.php5.PHP5 29 | import components.postgresql.Postgresql 30 | 31 | KNOWN_COMPONENTS = [ 32 | components.zlib.ZLib, 33 | components.openssl.OpenSSL, 34 | components.libjpeg.LibJPEG, 35 | # components.libltdl.LibLTDL, 36 | components.libpng.LibPNG, 37 | components.libungif.LibUnGIF, 38 | components.libxml.LibXML, 39 | components.libxslt.LibXSLT, 40 | components.mcrypt.MCrypt, 41 | components.mhash.MHash, 42 | components.ncurses.Ncurses, 43 | components.sqlite.SQLite, 44 | components.expat.Expat, 45 | components.freetds.FreeTDS, 46 | components.freetype.FreeType, 47 | # components.gettext.Gettext, 48 | components.apache.Apache, 49 | components.mysql.MySQL, 50 | components.proftpd.ProFTPd, 51 | components.perl.Perl, 52 | components.php5.PHP5 53 | # components.postgresql.Postgresql 54 | ] -------------------------------------------------------------------------------- /components/php5/patches/php5_uni.patch: -------------------------------------------------------------------------------- 1 | diff -u -p Zend/zend_strtod.c.orig Zend/zend_strtod.c 2 | --- Zend/zend_strtod.c.orig 2007-09-07 16:12:39.000000000 +0200 3 | +++ Zend/zend_strtod.c 2007-09-07 16:14:10.000000000 +0200 4 | @@ -135,6 +135,14 @@ typedef unsigned long int uint32_t; 5 | # endif 6 | #endif 7 | 8 | +#if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__)) 9 | +# if defined(__LITTLE_ENDIAN__) 10 | +# undef WORDS_BIGENDIAN 11 | +# else if defined(__BIG_ENDIAN__) 12 | +# define WORDS_BIGENDIAN 13 | +# endif 14 | +#endif 15 | + 16 | #ifdef WORDS_BIGENDIAN 17 | #define IEEE_BIG_ENDIAN 18 | #else 19 | diff -u -p ext/hash/hash_tiger.c.orig ext/hash/hash_tiger.c 20 | --- ext/hash/hash_tiger.c.orig 2007-09-07 16:16:44.000000000 +0200 21 | +++ ext/hash/hash_tiger.c 2007-09-07 16:17:37.000000000 +0200 22 | @@ -23,6 +23,14 @@ 23 | #include "php_hash_tiger.h" 24 | #include "php_hash_tiger_tables.h" 25 | 26 | +#if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__)) 27 | +# if defined(__LITTLE_ENDIAN__) 28 | +# undef WORDS_BIGENDIAN 29 | +# else if defined(__BIG_ENDIAN__) 30 | +# define WORDS_BIGENDIAN 31 | +# endif 32 | +#endif 33 | + 34 | /* {{{ */ 35 | #define save_abc \ 36 | aa = a; \ 37 | diff -u -p ext/date/lib/parse_tz.c.orig ext/date/lib/parse_tz.c 38 | --- ext/date/lib/parse_tz.c.orig 2007-09-07 16:19:56.000000000 +0200 39 | +++ ext/date/lib/parse_tz.c 2007-09-07 16:20:27.000000000 +0200 40 | @@ -33,6 +33,14 @@ 41 | #endif 42 | #include "timezonedb.h" 43 | 44 | +#if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__)) 45 | +# if defined(__LITTLE_ENDIAN__) 46 | +# undef WORDS_BIGENDIAN 47 | +# else if defined(__BIG_ENDIAN__) 48 | +# define WORDS_BIGENDIAN 49 | +# endif 50 | +#endif 51 | + 52 | #ifdef WORDS_BIGENDIAN 53 | #define timelib_conv_int(l) (l) 54 | #else 55 | -------------------------------------------------------------------------------- /utils/Dependency.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | """ 7 | 8 | import os.path 9 | from string import Template 10 | from utils.Component import Component 11 | 12 | class Dependency(object): 13 | 14 | def __init__(self, componentName, configureFlags=None, cFlags=None, ldFlags=None, environment=None): 15 | assert componentName is not None 16 | 17 | if not configureFlags: 18 | configureFlags = [] 19 | 20 | if not cFlags: 21 | cFlags = [] 22 | 23 | if not ldFlags: 24 | ldFlags = [] 25 | 26 | if not environment: 27 | environment = {} 28 | 29 | self.configureFlags = configureFlags 30 | self.componentName = componentName 31 | self.cFlags = cFlags 32 | self.ldFlags = ldFlags 33 | self.environment = environment 34 | 35 | def computedConfigureFlags(self, builder, forComponent): 36 | return self.computeValue(self.configureFlags, builder, forComponent) 37 | 38 | def computedCFlags(self, builder, forComponent): 39 | return self.computeValue(self.cFlags, builder, forComponent) 40 | 41 | def computedLDFlags(self, builder, forComponent): 42 | return self.computeValue(self.ldFlags, builder, forComponent) 43 | 44 | def computedEnvironment(self, builder, forComponent): 45 | return self.computeValue(self.environment, builder, forComponent) 46 | 47 | def computeValue(self, value, builder, forComponent): 48 | component = builder.findComponent(self.componentName) 49 | 50 | if not isinstance(component, Component): 51 | raise StandartError("Did not found a valid component for '%s'. Got '%s'" % (self.componentName, component)) 52 | 53 | c_root = os.path.join(component.buildPath, builder.config.prefixPath[1:]) 54 | 55 | vars = { 56 | 'COMPONENT_PATH': c_root, 57 | 'INCLUDE_PATH': os.path.join(c_root, 'include', component.includeDir or ''), 58 | 'LIB_PATH': os.path.join(c_root, 'lib', component.libDir or '') 59 | } 60 | 61 | return map(lambda x: Template(forComponent.substituteCommonVariables(x)).substitute(vars), value) 62 | -------------------------------------------------------------------------------- /components/php5/patches/apxs-install.patch: -------------------------------------------------------------------------------- 1 | --- sapi/apache/config.m4-orig 2005-05-29 18:16:45.000000000 -0500 2 | +++ sapi/apache/config.m4 2006-02-19 15:35:08.776668766 -0600 3 | @@ -91,7 +91,7 @@ 4 | APACHE_INSTALL="$APXS -i -a -n php5 $SAPI_SHARED" # Old apxs does not have -S option 5 | else 6 | APXS_LIBEXECDIR='$(INSTALL_ROOT)'`$APXS -q LIBEXECDIR` 7 | - if test -z `$APXS -q SYSCONFDIR`; then 8 | + if test ! -d '$(INSTALL_ROOT)'`$APXS -q SYSCONFDIR`; then 9 | APACHE_INSTALL="\$(mkinstalldirs) '$APXS_LIBEXECDIR' && \ 10 | $APXS -S LIBEXECDIR='$APXS_LIBEXECDIR' \ 11 | -i -n php5 $SAPI_SHARED" 12 | --- sapi/apache_hooks/config.m4-orig 2005-05-29 18:16:46.000000000 -0500 13 | +++ sapi/apache_hooks/config.m4 2006-02-19 15:29:13.138753131 -0600 14 | @@ -92,7 +92,7 @@ 15 | APACHE_HOOKS_INSTALL="$APXS -i -a -n php5 $SAPI_SHARED" # Old apxs does not have -S option 16 | else 17 | APXS_LIBEXECDIR='$(INSTALL_ROOT)'`$APXS -q LIBEXECDIR` 18 | - if test -z `$APXS -q SYSCONFDIR`; then 19 | + if test ! -d '$(INSTALL_ROOT)'`$APXS -q SYSCONFDIR`; then 20 | APACHE_HOOKS_INSTALL="\$(mkinstalldirs) '$APXS_LIBEXECDIR' && \ 21 | $APXS -S LIBEXECDIR='$APXS_LIBEXECDIR' \ 22 | -i -n php5 $SAPI_SHARED" 23 | --- sapi/apache2handler/config.m4-orig 2005-09-01 09:33:47.000000000 -0500 24 | +++ sapi/apache2handler/config.m4 2006-02-19 15:31:59.595098850 -0600 25 | @@ -65,7 +65,7 @@ 26 | fi 27 | 28 | APXS_LIBEXECDIR='$(INSTALL_ROOT)'`$APXS -q LIBEXECDIR` 29 | - if test -z `$APXS -q SYSCONFDIR`; then 30 | + if test ! -d '$(INSTALL_ROOT)'`$APXS -q SYSCONFDIR`; then 31 | INSTALL_IT="\$(mkinstalldirs) '$APXS_LIBEXECDIR' && \ 32 | $APXS -S LIBEXECDIR='$APXS_LIBEXECDIR' \ 33 | -i -n php5" 34 | --- sapi/apache2filter/config.m4-orig 2006-02-19 15:44:18.710306537 -0600 35 | +++ sapi/apache2filter/config.m4 2006-02-19 15:26:00.038833483 -0600 36 | @@ -66,7 +66,7 @@ 37 | fi 38 | 39 | APXS_LIBEXECDIR='$(INSTALL_ROOT)'`$APXS -q LIBEXECDIR` 40 | - if test -z `$APXS -q SYSCONFDIR`; then 41 | + if test ! -d '$(INSTALL_ROOT)'`$APXS -q SYSCONFDIR`; then 42 | INSTALL_IT="\$(mkinstalldirs) '$APXS_LIBEXECDIR' && \ 43 | $APXS -S LIBEXECDIR='$APXS_LIBEXECDIR' \ 44 | -i -n php5" 45 | -------------------------------------------------------------------------------- /utils/Sandbox.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The Builder class is the main class of the builder 7 | and coordinates everything that happen during the 8 | building of XAMPP. 9 | """ 10 | import os 11 | import shutil 12 | from utils.Component import Component 13 | from utils.Differences import differencesBetweenDigests 14 | from utils.file import digestsInPath 15 | 16 | class Sandbox(object): 17 | 18 | def __init__(self, componentsToUse, builder): 19 | self.componentsToUse = set() 20 | self.builder = builder 21 | 22 | for c in componentsToUse: 23 | if isinstance(c, str): 24 | i = self.builder.findComponent(c) 25 | 26 | if not i: 27 | raise StandardError("Component %s not found" % c) 28 | 29 | self.componentsToUse.add(i) 30 | elif isinstance(c, Component): 31 | self.componentsToUse.add(c) 32 | 33 | # Recursively add dependencies 34 | oldSet = None 35 | 36 | while oldSet != self.componentsToUse: 37 | oldSet = self.componentsToUse.copy() 38 | print("Old %s!=%s" % (str(oldSet), str(self.componentsToUse))) 39 | for c in oldSet: 40 | for d in c.dependencies: 41 | self.componentsToUse.add(self.builder.findComponent(d.componentName)) 42 | 43 | self._path = builder.config.destPath 44 | self.isSetup = False 45 | 46 | @property 47 | def path(self): 48 | return self._path 49 | 50 | def setup(self): 51 | assert not self.isSetup 52 | 53 | self.isSetup = True 54 | 55 | if os.path.isdir(self.path): 56 | raise StandardError("Sandbox path already exists %s" % self.path) 57 | 58 | for c in self.componentsToUse: 59 | self.builder.copyComponent(c, self.path) 60 | 61 | self.initialDigests = digestsInPath(self.path, relative=False) 62 | 63 | def changes(self): 64 | assert self.isSetup 65 | 66 | digests = digestsInPath(self.path, relative=False) 67 | 68 | return differencesBetweenDigests(self.initialDigests, digests) 69 | 70 | def tearDown(self): 71 | assert self.isSetup 72 | 73 | self.isSetup = False 74 | 75 | shutil.rmtree(self.path) 76 | 77 | -------------------------------------------------------------------------------- /components/apache/Apache.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The Apache component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | import os.path 13 | 14 | class Apache(Component): 15 | 16 | def __init__(self, config): 17 | super(Apache, self).__init__('Apache', os.path.dirname(__file__), config) 18 | 19 | self.download_url = 'http://mirror.checkdomain.de/apache/httpd/httpd-%s.tar.gz' % self.version 20 | 21 | self.dependencies = [ 22 | Dependency('ZLib', configureFlags=["--with-z=${COMPONENT_PATH}"]), 23 | Dependency('Expat', configureFlags=["--with-expat=${COMPONENT_PATH}"]), 24 | Dependency('OpenSSL', configureFlags=["--with-ssl=${COMPONENT_PATH}", "--enable-ssl=shared,${COMPONENT_PATH}"]) 25 | ] 26 | 27 | self.patches = [ 28 | 'rm_envvars.patch', 29 | 'ulimit_fix.patch' 30 | ] 31 | 32 | def configureFlags(self): 33 | flags = super(Apache, self).configureFlags() 34 | 35 | flags.extend([ 36 | '--enable-nonportable-atomics', 37 | '--enable-so', 38 | '--enable-cgid', 39 | '--enable-auth-anon', 40 | '--enable-auth-dbm', 41 | '--enable-auth-digest', 42 | '--enable-file-cache', 43 | '--enable-echo', 44 | '--enable-charset-lite', 45 | '--enable-cache', 46 | '--enable-disk-cache', 47 | '--enable-mem-cache', 48 | '--enable-ext-filter', 49 | '--enable-case-filter', 50 | '--enable-case-filter-in', 51 | '--enable-deflate', 52 | '--enable-mime-magic', 53 | '--enable-cern-meta', 54 | '--enable-expires', 55 | '--enable-headers', 56 | '--enable-usertrack', 57 | '--enable-unique-id', 58 | '--enable-proxy', 59 | '--enable-proxy-connect', 60 | '--enable-proxy-ftp', 61 | '--enable-proxy-http', 62 | '--enable-bucketeer', 63 | '--enable-http', 64 | '--enable-info', 65 | '--enable-suexec', 66 | '--enable-cgid', 67 | '--enable-vhost-alias', 68 | '--enable-speling', 69 | '--enable-rewrite', 70 | '--enable-so', 71 | '--enable-dav', 72 | '--enable-dav-fs', 73 | '--enable-mods-shared=most', 74 | '--with-mpm=prefork', 75 | '--with-suexec-caller=nobody', 76 | '--with-suexec-docroot=/Applications/XAMPP/htdocs', 77 | '--without-berkeley-db', 78 | '--without-pgsql', 79 | '--enable-ipv6', 80 | '--with-included-apr', 81 | '--without-ldap', 82 | '--disable-ldap' 83 | ]) 84 | 85 | return flags 86 | 87 | -------------------------------------------------------------------------------- /components/mysql/resources/my.cnf: -------------------------------------------------------------------------------- 1 | # Example MySQL config file for small systems. 2 | # 3 | # This is for a system with little memory (<= 64M) where MySQL is only used 4 | # from time to time and it's important that the mysqld daemon 5 | # doesn't use much resources. 6 | # 7 | # You can copy this file to 8 | # /etc/my.cnf to set global options, 9 | # mysql-data-dir/my.cnf to set server-specific options (in this 10 | # installation this directory is /Applications/xampp/xamppfiles/var/mysql) or 11 | # ~/.my.cnf to set user-specific options. 12 | # 13 | # In this file, you can use all long options that a program supports. 14 | # If you want to know which options a program supports, run the program 15 | # with the "--help" option. 16 | 17 | # The following options will be passed to all MySQL clients 18 | [client] 19 | #password = your_password 20 | port = 3306 21 | socket = /Applications/XAMPP/xamppfiles/var/mysql/mysql.sock 22 | 23 | # Here follows entries for some specific programs 24 | 25 | # The MySQL server 26 | [mysqld] 27 | port = 3306 28 | socket = /Applications/XAMPP/xamppfiles/var/mysql/mysql.sock 29 | user = nobody 30 | key_buffer = 16K 31 | max_allowed_packet = 1M 32 | table_cache = 4 33 | sort_buffer_size = 64K 34 | read_buffer_size = 256K 35 | read_rnd_buffer_size = 256K 36 | net_buffer_length = 2K 37 | thread_stack = 64K 38 | tmpdir = /Applications/XAMPP/xamppfiles/temp/ 39 | datadir = /Applications/XAMPP/xamppfiles/var/mysql 40 | 41 | # Don't listen on a TCP/IP port at all. This can be a security enhancement, 42 | # if all processes that need to connect to mysqld run on the same host. 43 | # All interaction with mysqld must be made via Unix sockets or named pipes. 44 | # Note that using this option without enabling named pipes on Windows 45 | # (using the "enable-named-pipe" option) will render mysqld useless! 46 | # 47 | #skip-networking 48 | server-id = 1 49 | 50 | # Uncomment the following if you want to log updates 51 | #log-bin=mysql-bin 52 | 53 | # Uncomment the following if you are NOT using BDB tables 54 | #skip-bdb 55 | 56 | # Uncomment the following if you are using InnoDB tables 57 | #innodb_data_home_dir = /Applications/XAMPP/xamppfiles/var/mysql/ 58 | #innodb_data_file_path = ibdata1:10M:autoextend 59 | #innodb_log_group_home_dir = /Applications/XAMPP/xamppfiles/var/mysql/ 60 | #innodb_log_arch_dir = /Applications/XAMPP/xamppfiles/var/mysql/ 61 | # You can set .._buffer_pool_size up to 50 - 80 % 62 | # of RAM but beware of setting memory usage too high 63 | #innodb_buffer_pool_size = 16M 64 | #innodb_additional_mem_pool_size = 2M 65 | # Set .._log_file_size to 25 % of buffer pool size 66 | #innodb_log_file_size = 5M 67 | #innodb_log_buffer_size = 8M 68 | #innodb_flush_log_at_trx_commit = 1 69 | #innodb_lock_wait_timeout = 50 70 | 71 | [mysqldump] 72 | quick 73 | max_allowed_packet = 16M 74 | 75 | [mysql] 76 | no-auto-rehash 77 | # Remove the next comment character if you are not familiar with SQL 78 | #safe-updates 79 | 80 | [isamchk] 81 | key_buffer = 8M 82 | sort_buffer_size = 8M 83 | 84 | [myisamchk] 85 | key_buffer = 8M 86 | sort_buffer_size = 8M 87 | 88 | [mysqlhotcopy] 89 | interactive-timeout 90 | -------------------------------------------------------------------------------- /components/perl/Perl.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The Perl component. 7 | """ 8 | import shutil 9 | import os.path 10 | 11 | from subprocess import check_call 12 | 13 | from utils.Component import Component 14 | from utils.Sandbox import Sandbox 15 | 16 | class Perl(Component): 17 | 18 | def __init__(self, config): 19 | super(Perl, self).__init__('Perl', os.path.dirname(__file__), config) 20 | 21 | self.download_url = 'http://www.cpan.org/src/perl-%s.tar.gz' % self.version 22 | 23 | self.buildSteps.extend([self.setupCPANP]) 24 | 25 | def configureCommand(self): 26 | return 'bash' 27 | 28 | def configureFlags(self): 29 | return [ 30 | './Configure', 31 | '-Dprefix=$PREFIX', 32 | '-A', 'ccdlflags="$ARCH_FLAGS"', 33 | '-A', 'ccflags="$ARCH_FLAGS"', 34 | '-A', 'cppflags="$ARCH_FLAGS"', 35 | '-A', 'ldflags="$ARCH_FLAGS"', 36 | '-A', 'lddlflags="$ARCH_FLAGS"', 37 | '-des' 38 | ] 39 | 40 | def setupCPANP(self, component, archs, builder): 41 | sandbox = Sandbox([self], builder) 42 | 43 | print("==> Setup CPANP") 44 | 45 | sandbox.setup() 46 | 47 | perl_lib = os.path.join(sandbox.path, 'xamppfiles', 'lib', 'perl5', self.version) 48 | 49 | # Install config files 50 | shutil.copy( 51 | os.path.join(self.resourcesPath, 'Config.pm'), 52 | os.path.join(perl_lib, 'CPAN/Config.pm') 53 | ) 54 | 55 | if not os.path.isdir(os.path.join(perl_lib, 'CPANPLUS/Config')): 56 | os.makedirs(os.path.join(perl_lib, 'CPANPLUS/Config')) 57 | shutil.copy( 58 | os.path.join(self.resourcesPath, 'System.pm'), 59 | os.path.join(perl_lib, 'CPANPLUS/Config/System.pm') 60 | ) 61 | 62 | check_call([os.path.join(sandbox.path, 'xamppfiles', 'bin/cpanp'),'s','selfupdate','core']) 63 | 64 | check_call([os.path.join(sandbox.path, 'xamppfiles', 'bin/perl'), 65 | os.path.join(self.resourcesPath, 'upgrade_modules.pl')]) 66 | 67 | modules = ['MLDBM', 'Digest::MD5', 'MLDBM::Sync', 'Apache::ASP'] 68 | for module in modules: 69 | check_call([os.path.join(sandbox.path, 'xamppfiles', 'bin/cpanp'), 'i', module, '--skiptest', '--verbose']) 70 | 71 | shutil.rmtree(os.path.join(sandbox.path, 'xamppfiles', 'var')) 72 | 73 | changes = sandbox.changes() 74 | 75 | filesToCopy = list(changes['new']) 76 | filesToCopy.extend([ file['file'] for file in changes['changed'] ]) 77 | 78 | for src in filesToCopy: 79 | dest = os.path.join(self.buildPath, src[1:]) 80 | 81 | if not os.path.isdir(os.path.dirname(dest)): 82 | os.makedirs(os.path.dirname(dest)) 83 | 84 | if os.path.exists(dest) and not os.access(dest, os.W_OK): 85 | check_call(['chmod', '+w', dest]) 86 | 87 | shutil.copy(src, dest) 88 | 89 | sandbox.tearDown() 90 | -------------------------------------------------------------------------------- /components/mysql/MySQL.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The MySQL component. 7 | """ 8 | import shutil 9 | from subprocess import check_call 10 | 11 | from utils.Component import Component 12 | from utils.Dependency import Dependency 13 | 14 | import os.path 15 | from utils.Sandbox import Sandbox 16 | 17 | class MySQL(Component): 18 | 19 | def __init__(self, config): 20 | super(MySQL, self).__init__('MySQL', os.path.dirname(__file__), config) 21 | 22 | (major, minor, patch) = self.version.split('.') 23 | 24 | self.download_url = 'http://ftp.gwdg.de/pub/misc/mysql/Downloads/MySQL-%s.%s/mysql-%s.tar.gz' % (major, minor, self.version) 25 | self.includeDir = 'mysql' 26 | 27 | self.dependencies = [ 28 | Dependency('ZLib', configureFlags=["-DWITH_ZLIB=${COMPONENT_PATH}"]) 29 | ] 30 | 31 | self.patches = [ 32 | 'mysql.server.patch' 33 | ] 34 | 35 | self.buildSteps.extend([self.completeInstallation]) 36 | 37 | def configureCommand(self): 38 | return 'cmake' 39 | 40 | def configureFlags(self): 41 | return [ 42 | '-DCMAKE_INSTALL_PREFIX=$PREFIX', 43 | '-DENABLED_LOCAL_INFILE=ON', 44 | '-DMYSQL_UNIX_ADDR=$PREFIX/var/mysql/mysql.sock', 45 | '-DSYSCONFDIR=$SYSCONFDIR' 46 | '-DMYSQL_DATADIR=$PREFIX/var/mysql/' 47 | '-DINSTALL_INFODIR=$PREFIX/info', 48 | '-DWITH_SSL=no', 49 | '-DWITH_INNOBASE_STORAGE_ENGINE=1', 50 | '-DWITH_ARCHIVE_STORAGE_ENGINE=1', 51 | '-DWITH_BLACKHOLE_STORAGE_ENGINE=1', 52 | '-DWITH_PERFSCHEMA_STORAGE_ENGINE=1', 53 | '-DWITH_FEDERATED_STORAGE_ENGINE=1', 54 | '-DWITH_PARTITION_STORAGE_ENGINE=1', 55 | '-DCMAKE_OSX_DEPLOYMENT_TARGET=10.4', 56 | '-DINSTALL_LAYOUT=RPM' 57 | ] 58 | 59 | def completeInstallation(self, component, archs, builder): 60 | sandbox = Sandbox([self], builder) 61 | 62 | print("==> Complete MySQL installation") 63 | 64 | sandbox.setup() 65 | 66 | if not os.path.isdir(os.path.join(sandbox.path, "xamppfiles", 'etc')): 67 | os.makedirs(os.path.join(sandbox.path, "xamppfiles", 'etc')) 68 | 69 | # Install config file 70 | shutil.copy( 71 | os.path.join(self.resourcesPath, 'my.cnf'), 72 | os.path.join(sandbox.path, "xamppfiles", 'etc/my.cnf') 73 | ) 74 | 75 | check_call([os.path.join(sandbox.path, "xamppfiles", "bin/mysql_install_db"), "--datadir=%s" % os.path.join(sandbox.path, "var/mysql/")]) 76 | 77 | changes = sandbox.changes() 78 | 79 | print("Changes: %s", changes) 80 | 81 | filesToCopy = list(changes['new']) 82 | filesToCopy.extend([ file['file'] for file in changes['changed'] ]) 83 | 84 | for src in filesToCopy: 85 | dest = os.path.join(self.buildPath, src[1:]) 86 | 87 | if not os.path.isdir(os.path.dirname(dest)): 88 | os.makedirs(os.path.dirname(dest)) 89 | 90 | shutil.copy(src, dest) 91 | 92 | sandbox.tearDown() 93 | -------------------------------------------------------------------------------- /utils/Config.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The Config object encapsulate everything that 7 | is configurable like the download_dir or the 8 | build_dir. 9 | """ 10 | 11 | from ConfigParser import SafeConfigParser, NoOptionError 12 | 13 | import os.path 14 | 15 | class Config(object): 16 | 17 | def __init__(self, config_file, platform, rel_base=None): 18 | self.config_file = config_file 19 | self.platform = platform 20 | 21 | self.configParser = SafeConfigParser({ 22 | 'confdir': '%(prefix)s/etc', 23 | }) 24 | self.configParser.read([self.config_file]) 25 | 26 | ## If no base for relative paths is given, we use the dir in which the config resides 27 | if rel_base is None: 28 | rel_base = os.path.dirname(config_file) 29 | 30 | self.rel_base = os.path.abspath(rel_base) 31 | 32 | @property 33 | def archivesPath(self): 34 | return self.preparePath(self.configParser.get('XAMPP Builder', 'archives')) 35 | 36 | @property 37 | def buildsPath(self): 38 | return self.preparePath(self.configParser.get('XAMPP Builder', 'builds')) 39 | 40 | @property 41 | def prefixPath(self): 42 | return self.preparePath(self.configParser.get(self.platform, 'prefix')) 43 | 44 | @property 45 | def destPath(self): 46 | return self.preparePath(self.configParser.get(self.platform, 'dest')) 47 | 48 | @property 49 | def confdirPath(self): 50 | return self.preparePath(self.configParser.get(self.platform, 'confdir')) 51 | 52 | @property 53 | def defaultCFlags(self): 54 | cflags = "" 55 | 56 | try: 57 | cflags = ' '.join([cflags, self.configParser.get('XAMPP Builder', 'cflags')]) 58 | cflags = ' '.join([cflags, self.configParser.get(self.platform, 'cflags')]) 59 | except KeyError: 60 | pass 61 | 62 | return cflags 63 | 64 | @property 65 | def defaultLDFlags(self): 66 | ldflags = '' 67 | 68 | try: 69 | ldflags = ' '.join([ldflags, self.configParser.get('XAMPP Builder', 'ldflags')]) 70 | ldflags = ' '.join([ldflags, self.configParser.get(self.platform, 'ldflags')]) 71 | except NoOptionError: 72 | pass 73 | 74 | return ldflags 75 | 76 | @property 77 | def archs(self): 78 | raw = "" 79 | archs = [] 80 | 81 | try: 82 | raw = self.configParser.get(self.platform, 'archs') 83 | except NoOptionError: 84 | pass 85 | 86 | for arch in raw.split(','): 87 | if len(arch.strip()): 88 | archs.extend([arch.strip()]) 89 | 90 | return archs 91 | 92 | def preparePath(self, path): 93 | """ 94 | Returns an normalised and absolut path for any path given. 95 | """ 96 | if not os.path.isabs(path): 97 | path = os.path.join(self.rel_base, path) 98 | 99 | return os.path.abspath(path) 100 | 101 | -------------------------------------------------------------------------------- /components/perl/resources/System.pm: -------------------------------------------------------------------------------- 1 | ############################################### 2 | ### 3 | ### Configuration structure for CPANPLUS::Config::System 4 | ### 5 | ############################################### 6 | 7 | #last changed: Fri Jul 31 21:02:02 2009 GMT 8 | 9 | ### minimal pod, so you can find it with perldoc -l, etc 10 | =pod 11 | 12 | =head1 NAME 13 | 14 | CPANPLUS::Config::System 15 | 16 | =head1 DESCRIPTION 17 | 18 | This is a CPANPLUS configuration file. Editing this 19 | config changes the way CPANPLUS will behave 20 | 21 | =cut 22 | 23 | package CPANPLUS::Config::System; 24 | 25 | use strict; 26 | 27 | sub setup { 28 | my $conf = shift; 29 | 30 | ### conf section 31 | $conf->set_conf( allow_build_interactivity => 1 ); 32 | $conf->set_conf( base => '/Applications/XAMPP/xamppfiles/var/perl/cpanplus' ); 33 | $conf->set_conf( buildflags => '' ); 34 | $conf->set_conf( cpantest => 0 ); 35 | $conf->set_conf( cpantest_mx => '' ); 36 | $conf->set_conf( debug => 0 ); 37 | $conf->set_conf( dist_type => '' ); 38 | $conf->set_conf( email => 'cpanplus@example.com' ); 39 | $conf->set_conf( extractdir => '' ); 40 | $conf->set_conf( fetchdir => '' ); 41 | $conf->set_conf( flush => 1 ); 42 | $conf->set_conf( force => 0 ); 43 | $conf->set_conf( hosts => [ 44 | { 45 | 'path' => '/pub/CPAN/', 46 | 'scheme' => 'ftp', 47 | 'host' => 'ftp.cpan.org' 48 | }, 49 | { 50 | 'path' => '/', 51 | 'scheme' => 'http', 52 | 'host' => 'www.cpan.org' 53 | }, 54 | { 55 | 'path' => '/pub/CPAN/', 56 | 'scheme' => 'ftp', 57 | 'host' => 'ftp.nl.uu.net' 58 | }, 59 | { 60 | 'path' => '/pub/CPAN/', 61 | 'scheme' => 'ftp', 62 | 'host' => 'cpan.valueclick.com' 63 | }, 64 | { 65 | 'path' => '/pub/languages/perl/CPAN/', 66 | 'scheme' => 'ftp', 67 | 'host' => 'ftp.funet.fi' 68 | } 69 | ] ); 70 | $conf->set_conf( lib => [] ); 71 | $conf->set_conf( makeflags => 'UNINST=1' ); 72 | $conf->set_conf( makemakerflags => '' ); 73 | $conf->set_conf( md5 => 1 ); 74 | $conf->set_conf( no_update => 0 ); 75 | $conf->set_conf( passive => 1 ); 76 | $conf->set_conf( prefer_bin => 0 ); 77 | $conf->set_conf( prefer_makefile => 1 ); 78 | $conf->set_conf( prereqs => 1 ); 79 | $conf->set_conf( shell => 'CPANPLUS::Shell::Default' ); 80 | $conf->set_conf( show_startup_tip => 1 ); 81 | $conf->set_conf( signature => 0 ); 82 | $conf->set_conf( skiptest => 0 ); 83 | $conf->set_conf( storable => 1 ); 84 | $conf->set_conf( timeout => 300 ); 85 | $conf->set_conf( verbose => 0 ); 86 | $conf->set_conf( write_install_logs => 1 ); 87 | 88 | 89 | ### program section 90 | $conf->set_program( editor => '/usr/bin/vi' ); 91 | $conf->set_program( make => '/usr/bin/make' ); 92 | $conf->set_program( pager => '/usr/bin/less' ); 93 | $conf->set_program( perlwrapper => '/Applications/XAMPP/xamppfiles/bin/cpanp-run-perl' ); 94 | $conf->set_program( shell => '/bin/bash' ); 95 | $conf->set_program( sudo => undef ); 96 | 97 | 98 | 99 | 100 | return 1; 101 | } 102 | 103 | 1; 104 | 105 | -------------------------------------------------------------------------------- /utils/MacOSXPackager.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011-2012 Apache Friends, GPLv2+ licensed 4 | =================================================== 5 | 6 | """ 7 | 8 | from plistlib import readPlist 9 | from io import BytesIO 10 | from utils.Packager import Packager 11 | from subprocess import check_call 12 | from tempfile import mkdtemp 13 | 14 | import os.path 15 | 16 | import subprocess 17 | def check_output(*popenargs, **kwargs): 18 | if 'stdout' in kwargs: 19 | raise ValueError('stdout argument not allowed, it will be overridden.') 20 | process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) 21 | output, unused_err = process.communicate() 22 | retcode = process.poll() 23 | if retcode: 24 | cmd = kwargs.get("args") 25 | if cmd is None: 26 | cmd = popenargs[0] 27 | raise subprocess.CalledProcessError(retcode, cmd, output=output) 28 | return output 29 | 30 | class CalledProcessError(Exception): 31 | def __init__(self, returncode, cmd, output=None): 32 | self.returncode = returncode 33 | self.cmd = cmd 34 | self.output = output 35 | def __str__(self): 36 | return "Command '%s' returned non-zero exit status %d" % ( 37 | self.cmd, self.returncode) 38 | # overwrite CalledProcessError due to `output` keyword might be not available 39 | subprocess.CalledProcessError = CalledProcessError 40 | 41 | class MacOSXPackager(Packager): 42 | 43 | 44 | def __init__(self, builder): 45 | super(MacOSXPackager, self).__init__(builder) 46 | 47 | self._workPath = None 48 | 49 | def resourcesPath(self): 50 | return os.path.join(os.path.dirname(__file__), 'resources') 51 | 52 | @property 53 | def workPath(self): 54 | if self._workPath is None: 55 | dir = mkdtemp(prefix="xampp-builder-packaging-") 56 | 57 | def remove_dir(): 58 | if os.path.isdir(dir): 59 | shutil.rmtree(dir) 60 | 61 | atexit.register(remove_dir) 62 | 63 | self._workPath = dir 64 | 65 | return self._workPath 66 | 67 | 68 | def packXAMPP(self, version, xamppDMGPath): 69 | # Get template image 70 | # Convert it to rw and resize 71 | # Render new background 72 | # Copy xampp files 73 | # Unmount, convert to readonly with compression 74 | tmpDisk = os.path.join(self.workPath, 'xampp.sparseimage') 75 | 76 | print("=> Convert template to readwrite image") 77 | self.convertImage(os.path.join(self.resourcesPath(), 'template-normal.dmg'), tmpDisk, False) 78 | print("=> Make image big enough to fit XAMPP in it") 79 | self.resizeImage(tmpDisk, '1g') 80 | 81 | print("=> Mount image") 82 | (device, dir) = self.attachImage(tmpDisk) 83 | 84 | print("=> Copy XAMPP files") 85 | for name, c in self.builder.components.iteritems(): 86 | if c.isBuild: 87 | self.builder.copyComponent(c, os.path.join(dir, 'XAMPP'), includeDevelopmentFiles=False) 88 | 89 | print("=> Set version") 90 | with open(os.path.join(dir, 'XAMPP', 'xamppfiles', 'lib', 'VERSION'), 'w') as f: 91 | f.write(version) 92 | 93 | print("=> Unmount image") 94 | self.detachImage(device) 95 | 96 | print("=> Compress and make image readonly") 97 | self.convertImage(tmpDisk, xamppDMGPath, True) 98 | 99 | 100 | def attachImage(self, imagePath): 101 | output = readPlist(BytesIO(check_output(['hdiutil', 'attach', '-plist', '-nobrowse', '-mountrandom', '/tmp', imagePath]))) 102 | 103 | mount_dict = output['system-entities'][0] 104 | 105 | return (mount_dict['dev-entry'], mount_dict['mount-point']) 106 | 107 | def convertImage(self, image, destination, readOnly): 108 | if readOnly: 109 | check_call(['hdiutil', 'convert', '-ov', '-format', 'UDZO', image, '-imagekey', 'zlib-level=9', '-o', destination]) 110 | else: 111 | check_call(['hdiutil', 'convert', '-ov', '-format', 'UDSP', image, '-o', destination]) 112 | 113 | def resizeImage(self, image, size): 114 | check_call(['hdiutil', 'resize', '-size', size, image]) 115 | 116 | def detachImage(self, device): 117 | check_call(['hdiutil', 'detach', '-force', device]) 118 | -------------------------------------------------------------------------------- /utils/file.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | """ 6 | import gzip 7 | import hashlib 8 | import os 9 | import os.path 10 | import shutil 11 | 12 | def isMachO(file): 13 | (path, ext) = os.path.splitext(file) 14 | 15 | # It's a java class file and no mach-o file. This special case is because java class files have the same magic 16 | # number as fat-binaries. 17 | if ext == '.class': 18 | return False 19 | 20 | with open(file, 'rb') as f: 21 | magic = f.read(4) 22 | 23 | if (magic == '\xca\xfe\xba\xbe' or # fat-binary magic number 24 | magic == '\xfe\xed\xfa\xce' or # mach-o binary magic number 25 | magic == '\xce\xfa\xed\xfe'): # mach-o binary magic number (reverse endianiss) 26 | return True 27 | else: 28 | return False 29 | 30 | def isAr(file): 31 | with open(file, 'rb') as f: 32 | magic = f.read(8) 33 | 34 | if magic == '!\x0a': # ar binary magic string 35 | return True 36 | else: 37 | return False 38 | 39 | def hashForFile(file): 40 | """ 41 | Returns an usefull hash for comparisions. 42 | 43 | - Links will be hashed as link and not as the file they're pointing to. 44 | - Compressed files will hashed uncompressed 45 | """ 46 | hash = hashlib.sha1() 47 | (root, ext) = os.path.splitext(file) 48 | if os.path.islink(file): 49 | hash.update(os.readlink(file)) 50 | elif ext == '.gz': 51 | f = gzip.open(file, 'rb') 52 | for data in f.read(512): 53 | hash.update(data) 54 | f.close() 55 | else: 56 | with open(file, 'rb') as f: 57 | for data in f.read(512): 58 | hash.update(data) 59 | return hash.hexdigest() 60 | 61 | def digestsInPath(path, relative=True): 62 | """ 63 | Calculate an hash for every file under an given path. 64 | """ 65 | 66 | result = {} 67 | 68 | if not os.path.isdir(path): 69 | raise StandardError('path "%s" is not a directory' % path) 70 | 71 | for root, dirs, files in os.walk(path): 72 | for file in files: 73 | rel_path = os.path.join(root, file) 74 | digest = hashForFile(rel_path) 75 | if relative: 76 | rel_path = os.path.relpath(rel_path, path) 77 | result[rel_path] = digest 78 | 79 | return result 80 | 81 | def copytree(src, dst, symlinks=False, ignore=None): 82 | names = os.listdir(src) 83 | if ignore is not None: 84 | ignored_names = ignore(src, names) 85 | else: 86 | ignored_names = set() 87 | 88 | if not os.path.exists(dst): 89 | os.makedirs(dst) 90 | elif not os.path.isdir(dst): 91 | raise StandardError('%s has to be a directory!' % dst) 92 | 93 | errors = [] 94 | for name in names: 95 | if name in ignored_names: 96 | continue 97 | srcname = os.path.join(src, name) 98 | dstname = os.path.join(dst, name) 99 | try: 100 | if symlinks and os.path.islink(srcname): 101 | linkto = os.readlink(srcname) 102 | os.symlink(linkto, dstname) 103 | elif os.path.isdir(srcname): 104 | copytree(srcname, dstname, symlinks, ignore) 105 | else: 106 | shutil.copy2(srcname, dstname) 107 | # XXX What about devices, sockets etc.? 108 | except (IOError, os.error), why: 109 | errors.append((srcname, dstname, str(why))) 110 | # catch the Error from the recursive my_copytree so that we can 111 | # continue with other files 112 | except shutil.Error, err: 113 | errors.extend(err.args[0]) 114 | try: 115 | shutil.copystat(src, dst) 116 | except shutil.WindowsError: 117 | # can't copy file access times on Windows 118 | pass 119 | except OSError, why: 120 | errors.extend((src, dst, str(why))) 121 | if errors: 122 | raise shutil.Error(errors) 123 | -------------------------------------------------------------------------------- /utils/Component.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | This class encapsulate every component that can 7 | be build or whatsoever. 8 | """ 9 | 10 | import atexit 11 | import os.path 12 | import shutil 13 | import string 14 | 15 | from tempfile import mkdtemp 16 | 17 | developmentDirectories = [ 'build', 'include', 'man', 'manual', 'info', 'share/doc', 'lib/pkgconfig', 'share/man' ] 18 | developmentExtensions = [ '.a', '.la' ] 19 | 20 | class Component(object): 21 | 22 | def __init__(self, name, path, config): 23 | assert name is not None 24 | assert config is not None 25 | 26 | self.name = name 27 | self.config = config 28 | self.download_url = None 29 | self.dependencies = [] 30 | self._workingDir = None 31 | self.supportsOnPassUniversalBuild = True 32 | self.patches = [] 33 | self.patches_dir = os.path.join(path, 'patches') 34 | self._resourcesPath = os.path.join(path, 'resources') 35 | # Rel to includes/ 36 | self.includeDir = None 37 | self.libDir = None 38 | 39 | self.buildSteps = [ 40 | 'unpack', 41 | 'patch', 42 | 'configure', 43 | 'build', 44 | 'install', 45 | 'universalize', 46 | 'createManifest' 47 | ] 48 | 49 | # Read the version of this component. 50 | version_file = os.path.join(path, 'version') 51 | 52 | if not os.path.exists(version_file): 53 | raise StandardError("Version file '%s' for '%s' does not exists!" % (version_file, self.name)) 54 | 55 | with open(version_file, 'r') as f: 56 | self.version = f.readline().strip(' \n\r\t') 57 | 58 | def configureFlags(self): 59 | """ 60 | Returns the flags used for configure or cmake. Flags from dependencies are added to this later. Possible 61 | variables are substituted later. 62 | """ 63 | return [ 64 | '--prefix=$PREFIX', 65 | '--sysconfdir=$SYSCONFDIR' 66 | ] 67 | 68 | def computedConfigureFlags(self): 69 | """ 70 | Returns the fully computable flags which can be passed in quotes and joined with an space to configure or 71 | cmake or whatever. 72 | """ 73 | return map(lambda x: self.substituteCommonVariables(x), self.configureFlags()) 74 | 75 | def configureEnvironment(self): 76 | """ 77 | Returns the environment for the configure or cmake command. 78 | """ 79 | return { 80 | "CC": "gcc $ARCH_FLAGS", 81 | "CXX": "g++ $ARCH_FLAGS", 82 | "CPP": "cpp", 83 | "CXXCPP": "cpp" 84 | } 85 | 86 | def configureCommand(self): 87 | return './configure' 88 | 89 | def substituteCommonVariables(self, s): 90 | vars = { 91 | 'PREFIX': self.config.prefixPath, 92 | 'SYSCONFDIR': self.config.confdirPath, 93 | } 94 | 95 | return string.Template(s).safe_substitute(vars) 96 | 97 | def buildCommand(self): 98 | return 'make' 99 | 100 | def buildEnvironment(self): 101 | return self.configureEnvironment() 102 | 103 | def buildFlags(self): 104 | return [] 105 | 106 | def computedBuildFlags(self): 107 | return map(lambda x: self.substituteCommonVariables(x), self.buildFlags()) 108 | 109 | def installCommand(self): 110 | return 'make' 111 | 112 | def installEnvironment(self): 113 | return self.buildEnvironment() 114 | 115 | def installFlags(self): 116 | return [ 117 | "install", 118 | "DESTDIR=${DEST_DIR}" 119 | ] 120 | 121 | def computedInstallFlags(self): 122 | return map(lambda x: self.substituteCommonVariables(x), self.installFlags()) 123 | 124 | def extraTarFlags(self): 125 | return [ 126 | '--strip', '1' 127 | ] 128 | 129 | @property 130 | def isBuild(self): 131 | if os.path.isdir(self.buildPath) and os.path.isfile(self.manifestPath): 132 | return True 133 | return False 134 | 135 | @property 136 | def sourceArchiveFile(self): 137 | archive_ext = None 138 | (j, filename) = os.path.split(self.download_url) 139 | 140 | if filename.endswith('.tar.gz') or filename.endswith('.tgz') or filename.endswith('.tar.Z'): 141 | archive_ext = 'tar.gz' 142 | elif filename.endswith('.tar.bz2'): 143 | archive_ext = 'tar.bz2' 144 | elif filename.endswith('.tar'): 145 | archive_ext = 'tar' 146 | else: 147 | raise StandardError("Unknown archive format '%s'" % archive_ext) 148 | 149 | return os.path.join(self.config.archivesPath, '%s-%s.%s' % (self.name.lower(), self.version, archive_ext)) 150 | 151 | @property 152 | def workingDir(self): 153 | if self._workingDir is None: 154 | self._workingDir = mkdtemp(prefix="xampp-builder-%s-" % self.name) 155 | 156 | # Temporary save the working dir here 157 | dir = self._workingDir 158 | 159 | def remove_dir(): 160 | if os.path.isdir(dir): 161 | shutil.rmtree(dir) 162 | 163 | atexit.register(remove_dir) 164 | 165 | return self._workingDir 166 | 167 | @property 168 | def buildPath(self): 169 | return os.path.join(self.config.buildsPath, self.name.lower()) 170 | 171 | @property 172 | def manifestPath(self): 173 | return os.path.join(self.config.buildsPath, self.name.lower()+'.manifest') 174 | 175 | @property 176 | def resourcesPath(self): 177 | return self._resourcesPath 178 | 179 | def isPathDevelopmentOnly(self, path): 180 | 181 | (path, ext) = os.path.splitext(path) 182 | if ext in developmentExtensions: 183 | return True 184 | 185 | for devDir in developmentDirectories: 186 | if path.startswith(os.path.join(self.config.prefixPath, devDir)): 187 | return True 188 | 189 | return False 190 | 191 | 192 | -------------------------------------------------------------------------------- /utils/Differences.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The Builder class is the main class of the builder 7 | and coordinates everything that happen during the 8 | building of XAMPP. 9 | """ 10 | import re 11 | 12 | def swapKeyValue(dict): 13 | for key in dict.copy(): 14 | if dict[key] in dict: 15 | dict[dict[key]].append(key) 16 | else: 17 | dict[dict[key]] = [key] 18 | del dict[key] 19 | return dict 20 | 21 | def differencesBetweenDigests(source_files, target_files, moved_files=None): 22 | if moved_files is None: 23 | moved_files = () 24 | 25 | result = { 26 | 'changed':[], 27 | 'moved':[], 28 | 'symlinks':[], 29 | 'removed':[], 30 | 'copied':[], 31 | 'new':[] 32 | } 33 | 34 | #find all removed and changed files 35 | for file in source_files.copy(): 36 | if file not in target_files: 37 | result['removed'].append(file) 38 | elif target_files[file] != source_files[file]: 39 | result['changed'].append({'file':file, 'source_digest':source_files[file], 'target_digest':target_files[file]}) 40 | # Remove them from our array, because they are handled and so 41 | # we avoid that we later work with them again. 42 | del source_files[file] 43 | del target_files[file] 44 | 45 | # find all newly added files 46 | for file in target_files: 47 | if file not in source_files: 48 | result['new'].append(file) 49 | 50 | # Ok, that was the supid part, now we make the intelegent things 51 | 52 | # First we look up, what we have as input for moved files. 53 | # If we have a mach the files are removed from source_files 54 | # and target_files so, that we do not have to care later, because they 55 | # were already handled. 56 | for pattern, replacement in moved_files: 57 | r = re.compile(pattern) 58 | for file in source_files.copy(): 59 | new_file = re.sub(r, replacement, file) 60 | 61 | if new_file is not file and \ 62 | new_file not in source_files and \ 63 | new_file in target_files: 64 | 65 | result['moved'].append({'from':file, 'to':new_file}) 66 | result['removed'].remove(file) 67 | result['new'].remove(new_file) 68 | if source_files[file] != target_files[new_file]: 69 | result['changed'].append({'file':new_file, 'source_digest':source_files[file], 'target_digest':target_files[new_file]}) 70 | 71 | # First we search for files that have not be changed but moved 72 | # to do that, we switch the keys and values of source_files and 73 | # target_files 74 | source_digests = swapKeyValue(source_files.copy()) 75 | target_digests = swapKeyValue(target_files.copy()) 76 | 77 | for digest in source_digests: 78 | # This means there are two or more files with the same content 79 | if digest in target_digests: 80 | sources = source_digests[digest][:] 81 | targets = target_digests[digest][:] 82 | 83 | to_not_remove = [] 84 | to_be_not_new = [] 85 | 86 | # Ok, first case. In either, the target and the source, exists 87 | # in each case one file with the same digest, but it path is 88 | # different 89 | if len(sources) == 1 and len(targets) == 1: 90 | if sources[0] != targets[0]: 91 | result['moved'].append({'from': sources[0], 'to':targets[0]}) 92 | to_not_remove.append(sources[0]) 93 | to_be_not_new.append(targets[0]) 94 | # Ok now we first remove all path's that occours in both. 95 | else: 96 | for path in sources[:]: 97 | if path in targets: 98 | sources.remove(path) 99 | targets.remove(path) 100 | 101 | # Ok now we can make conflict resolution 102 | if len(sources) < len(targets): 103 | for i in range(len(sources)): 104 | result['moved'].append({'from': sources[i], 'to': targets[i]}) 105 | to_not_remove.append(sources[i]) 106 | to_be_not_new.append(targets[i]) 107 | # Oh there is an additional copy of an existing file 108 | i = len(targets) - len(sources) 109 | source = source_digests[digest][0] 110 | for file in targets[i:]: 111 | result['copied'].append({'from':source, 'to':file, 'digest':digest}) 112 | to_be_not_new.append(file) 113 | elif len(sources) > len(targets): 114 | for i in range(len(targets)): 115 | result['moved'].append({'from': sources[i], 'to': targets[i]}) 116 | to_not_remove.append(sources[i]) 117 | to_be_not_new.append(targets[i]) 118 | elif len(sources) == len(targets): 119 | for i in range(len(sources)): 120 | result['moved'].append({'from': sources[i], 'to': targets[i]}) 121 | to_not_remove.append(sources[i]) 122 | to_be_not_new.append(targets[i]) 123 | else: 124 | # Do we really need this case? All should be handeled I think. 125 | raise StandardError('Case not handeled %s <=> %s' % (sources, targets)) 126 | 127 | for file in to_not_remove: 128 | try: 129 | result['removed'].remove(file) 130 | except: 131 | pass 132 | 133 | for file in to_be_not_new: 134 | try: 135 | result['new'].remove(file) 136 | except: 137 | pass 138 | return result -------------------------------------------------------------------------------- /components/php5/PHP5.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The PHP5 component. 7 | """ 8 | 9 | from utils.Component import Component 10 | from utils.Dependency import Dependency 11 | 12 | from subprocess import check_call 13 | import os.path 14 | 15 | class PHP5(Component): 16 | 17 | def __init__(self, config): 18 | super(PHP5, self).__init__('PHP5', os.path.dirname(__file__), config) 19 | 20 | self.download_url = 'http://de2.php.net/distributions/php-%s.tar.gz' % self.version 21 | 22 | self.dependencies = [ 23 | Dependency('Apache', configureFlags=["--with-apxs2=${PREFIX}/bin/apxs"]), 24 | Dependency('Ncurses', configureFlags=["--with-ncurses=${COMPONENT_PATH}"]), 25 | Dependency('LibJPEG', configureFlags=["--with-jpeg-dir=${COMPONENT_PATH}"]), 26 | Dependency('LibPNG', configureFlags=["--with-png-dir=${COMPONENT_PATH}"]), 27 | Dependency('FreeType', configureFlags=["--with-freetype-dir=${COMPONENT_PATH}"]), 28 | Dependency('ZLib', configureFlags=["--with-zlib=shared", "--with-zlib-dir=${COMPONENT_PATH}"]), 29 | Dependency('OpenSSL', configureFlags=["--with-openssl=${COMPONENT_PATH}"]), 30 | Dependency('Expat', configureFlags=["--with-expat-dir=${COMPONENT_PATH}"]), 31 | Dependency('LibXSLT', configureFlags=["--with-xsl=shared,${COMPONENT_PATH}"]), 32 | Dependency('MCrypt', configureFlags=["--with-mcrypt=${COMPONENT_PATH}"]), 33 | Dependency('MHash', configureFlags=["--with-mhash=${COMPONENT_PATH}"]), 34 | Dependency('LibXML', configureFlags=["--with-libxml-dir=${COMPONENT_PATH}"]), 35 | Dependency('FreeTDS', configureFlags=["--with-mssql=${COMPONENT_PATH}", "--with-pdo-mssql=shared,${COMPONENT_PATH}"]), 36 | Dependency('MySQL', configureFlags=[ 37 | "--with-mysql=${COMPONENT_PATH}", 38 | "--with-mysql-sock=$PREFIX/var/mysql/mysql.sock", 39 | "--with-pdo-mysql=shared,${COMPONENT_PATH}/bin/mysql_config", 40 | "--with-mysql=shared,${COMPONENT_PATH}", 41 | "--with-mysqli=shared,${COMPONENT_PATH}/bin/mysql_config" 42 | ]) 43 | ] 44 | 45 | self.patches = [ 46 | 'php5_config.patch', 47 | 'php5_uni.patch', 48 | 'apxs-install.patch' # Redhat bug 181798, this also requires autoconf --force 49 | ] 50 | 51 | self.buildSteps.insert(self.buildSteps.index("configure"), self.runAutoconf) 52 | self.buildSteps.insert(self.buildSteps.index("configure"), "setupSandbox") 53 | self.buildSteps.insert(self.buildSteps.index("install") + 1, "tearDownSandbox") 54 | 55 | def configureFlags(self): 56 | flags = super(PHP5, self).configureFlags() 57 | 58 | flags.extend([ 59 | # Support for multiple php versions 60 | '--program-suffix=-%s' % self.version, 61 | '--libdir=$PREFIX/lib/php/php-%s' % self.version, 62 | '--includedir=$PREFIX/include/php/php-%s' % self.version, 63 | 64 | # Otherwise will hang on /ext/fileinfo/libmagic/apprentice.c 65 | '--disable-fileinfo', 66 | 67 | '--with-config-file-path=$SYSCONFDIR', 68 | 69 | '--disable-debug', 70 | '--enable-cli', 71 | '--enable-cgi', 72 | '--enable-bcmath', 73 | '--enable-calendar', 74 | '--enable-ctype', 75 | '--enable-discard-path', 76 | '--enable-filepro', 77 | '--enable-filter', 78 | '--enable-force-cgi-redirect', 79 | '--enable-fastcgi', 80 | '--enable-ftp', 81 | '--enable-hash', 82 | '--enable-ipv6', 83 | '--enable-json', 84 | '--enable-odbc', 85 | '--enable-path-info-check', 86 | '--enable-gd-imgstrttf', 87 | '--enable-gd-native-ttf', 88 | '--with-ttf', 89 | '--enable-magic-quotes', 90 | '--enable-memory-limit', 91 | '--enable-safe-mode', 92 | '--enable-shmop', 93 | '--enable-sysvsem', 94 | '--enable-sysvshm', 95 | '--enable-track-vars', 96 | '--enable-trans-sid', 97 | '--enable-reflection', 98 | '--enable-session', 99 | '--enable-spl', 100 | '--enable-tokenizer', 101 | '--enable-wddx', 102 | '--enable-yp', 103 | '--enable-xmlreader', 104 | '--enable-xmlwriter', 105 | '--enable-zlib', 106 | '--enable-zts', 107 | '--with-simplexml', 108 | '--with-iconv', 109 | '--with-libxml', 110 | '--with-wddx', 111 | '--with-xml', 112 | '--with-ftp', 113 | 114 | # '--with-gdbm=$PREFIX', 115 | 116 | '--without-xpm', 117 | 118 | # Need this? '--enable-xslt=shared,$PREFIX', 119 | # Need this? '--with-dom=shared,$PREFIX', 120 | 121 | # '--with-ldap=shared,$PREFIX', 122 | '--with-gd=shared', 123 | 124 | 125 | '--enable-sockets', 126 | '--enable-zend-multibyte', 127 | 128 | '--enable-pcntl', 129 | '--enable-dbx=shared', 130 | 131 | '--with-pear=$PREFIX/lib/php/pear', 132 | # '--with-imap-dir=$PREFIX', 133 | # '--with-imap=shared,$PREFIX', 134 | '--enable-mbstring=shared,all', 135 | 136 | # Broken '--with-gettext=$PREFIX', 137 | '--enable-apache2-2filter=shared', 138 | '--enable-apache2-2handler=shared', 139 | '--with-bz2=shared', 140 | '--with-curl=shared', 141 | '--with-dba=shared', 142 | '--enable-dbase=shared', 143 | '--with-fdf=shared', 144 | '--enable-mbregex', 145 | '--enable-mbregex-backtrack', 146 | '--with-mime-magic=shared', 147 | 148 | '--enable-shmop=shared', 149 | '--with-snmp=shared', 150 | '--enable-sockets=shared', 151 | '--enable-pdo', 152 | 153 | '--enable-zip=shared,$PREFIX', 154 | '--enable-exif=shared', 155 | 156 | 157 | 158 | 159 | '--enable-soap=shared', 160 | '--with-xmlrpc=shared', 161 | '--with-oracle=shared', 162 | '--with-pdf=shared', 163 | '--with-sqlite3=shared,$PREFIX', 164 | 165 | # MySQL 166 | 167 | 168 | # Postgre 169 | # '--with-pgsql=shared,$PREFIX', 170 | # '--with-pdo-pgsql=shared,$PREFIX', 171 | 172 | # SQLITE 173 | '--with-sqlite=shared', 174 | '--with-pdo-sqlite=shared', 175 | '--with-pdo-sqlite-external=shared', 176 | 177 | ]) 178 | 179 | return flags 180 | 181 | def installFlags(self): 182 | return [ 183 | "install", 184 | "INSTALL_ROOT=${DEST_DIR}" 185 | ] 186 | 187 | def runAutoconf(self, component, archs, builder): 188 | check_call(["autoconf", "--force"]) 189 | 190 | -------------------------------------------------------------------------------- /utils/Builder.py: -------------------------------------------------------------------------------- 1 | """ 2 | XAMPP Builder 3 | Copyright 2011 Apache Friends, GPLv2+ licensed 4 | ============================================== 5 | 6 | The Builder class is the main class of the builder 7 | and coordinates everything that happen during the 8 | building of XAMPP. 9 | """ 10 | import atexit 11 | import collections 12 | import json 13 | import shutil 14 | import stat 15 | from stat import S_IRUSR, S_IRGRP, S_IXUSR, S_IWUSR, S_IXGRP, S_IROTH, S_IXOTH 16 | import string 17 | import sys 18 | import os 19 | import os.path 20 | import urllib 21 | 22 | from optparse import OptionParser, OptionGroup 23 | from subprocess import check_call 24 | from inspect import isfunction 25 | from tempfile import mkdtemp 26 | 27 | from utils.Config import Config 28 | from utils.FileUniversalizer import MachOUniversalizer 29 | from utils.file import digestsInPath, copytree 30 | from components import KNOWN_COMPONENTS 31 | from utils.Sandbox import Sandbox 32 | 33 | from utils.MacOSXPackager import MacOSXPackager 34 | 35 | chown_tool = """#!/usr/bin/python 36 | 37 | import sys 38 | import os 39 | import os.path 40 | import json 41 | 42 | log_dir="${LOG_DIR}" 43 | 44 | with open(os.path.join(log_dir, "chown.json"), "a") as f: 45 | info = {"args": sys.argv[1:], "pwd": os.getcwd()} 46 | json.dump(info, f) 47 | f.write(",\\n") 48 | 49 | """ 50 | 51 | chmod_tool = """#!/usr/bin/python 52 | 53 | import sys 54 | import os 55 | import os.path 56 | import json 57 | from subprocess import check_call 58 | 59 | log_dir="${LOG_DIR}" 60 | 61 | with open(os.path.join(log_dir, "chmod.json"), "a") as f: 62 | info = {"args": sys.argv[1:], "pwd": os.getcwd()} 63 | json.dump(info, f) 64 | f.write(",\\n") 65 | 66 | check_call(["/bin/chmod"] + sys.argv[1:]) 67 | 68 | """ 69 | 70 | install_tool = """#!/usr/bin/python 71 | 72 | import sys 73 | import os 74 | import os.path 75 | import json 76 | from subprocess import check_call 77 | 78 | from optparse import OptionParser 79 | 80 | log_dir="${LOG_DIR}" 81 | 82 | parser = OptionParser() 83 | 84 | parser.add_option("-b", action="store_true") 85 | parser.add_option("-C", action="store_true") 86 | parser.add_option("-c", action="store_true") 87 | parser.add_option("-p", action="store_true") 88 | parser.add_option("-S", action="store_true") 89 | parser.add_option("-s", action="store_true") 90 | parser.add_option("-v", action="store_true") 91 | 92 | parser.add_option("-d", action="store_true", dest="make_dir") 93 | 94 | parser.add_option("-m", dest="mode") 95 | parser.add_option("-g", dest="group") 96 | parser.add_option("-o", dest="owner") 97 | 98 | (options, args) = parser.parse_args() 99 | 100 | with open(os.path.join(log_dir, "install.json"), "a") as f: 101 | info = {"mode":options.mode, "group":options.group, "owner":options.owner, "pwd": os.getcwd(), "sources":args[:-1], "dest":args[-1]} 102 | json.dump(info, f) 103 | f.write(",\\n") 104 | 105 | if options.make_dir: 106 | for d in args: 107 | os.makedirs(d) 108 | else: 109 | check_call(["cp"] + args) 110 | 111 | """ 112 | 113 | # Helpers 114 | def commonInDict(dictA, dictB): 115 | common = dict() 116 | uncommon_keys = [] 117 | 118 | for key in dictA: 119 | if key in dictB and dictB[key] == dictA[key]: 120 | common[key] = dictA[key] 121 | else: 122 | uncommon_keys.extend([key]) 123 | 124 | return common, uncommon_keys 125 | 126 | def ignoreFilesSet(files, rel_to=None): 127 | def ignore_set(dir, dir_content): 128 | ignore = set() 129 | if rel_to is not None: 130 | dir = os.path.relpath(dir, rel_to) 131 | 132 | for file in files: 133 | (dir_component, file_component) = os.path.split(file) 134 | if (dir_component == dir and 135 | file_component in dir_content): 136 | ignore.add(file_component) 137 | 138 | return ignore 139 | 140 | return ignore_set 141 | 142 | class Builder(object): 143 | 144 | def __init__(self): 145 | self.config = None 146 | self.components = {} 147 | self.fileUniversalizer = [MachOUniversalizer()] 148 | # the build dir of these will be deleted on exit, because 149 | # they are not clean 150 | self.uncleanComponents = [] 151 | self.installToolchainPath = None 152 | 153 | atexit.register(self.cleanUp) 154 | 155 | def run(self): 156 | (action, args) = self.parseCommandlineArguments() 157 | 158 | self.setupComponents() 159 | 160 | if action == 'build': 161 | self.build(args) 162 | elif action == 'download': 163 | self.download(args) 164 | elif action == 'dep': 165 | self.dependencies(args) 166 | elif action == 'pack': 167 | self.pack(args) 168 | elif action == 'packDev': 169 | self.packDev(args) 170 | else: 171 | print "Unknown action '%s'" % action 172 | sys.exit(1) 173 | 174 | def parseCommandlineArguments(self): 175 | parser = OptionParser(usage="Usage: %prog [options] (download|build|dep [component(s)])|(pack version dest-file)|(packDev version dest-file)") 176 | 177 | parser.add_option("-c", "--config", dest="config", 178 | default="default.ini", 179 | help="The config used for building XAMPP.") 180 | 181 | parser.add_option("", "--no-clean-on-failure", 182 | dest="no_clean_on_failure", 183 | action="store_true", default=False, 184 | help="Don't remove files the build fails.") 185 | 186 | group = OptionGroup(parser, "Dependency Options (dep)") 187 | 188 | group.add_option("", "--json", dest="json", 189 | action="store_true", default=False, 190 | help="Print dependency information as parsable json list.") 191 | group.add_option("", "--missing", dest="missing", 192 | action="store_true", default=False, 193 | help="Automaticlly add components that are not builded yet.") 194 | 195 | parser.add_option_group(group) 196 | 197 | (self.options, args) = parser.parse_args() 198 | 199 | if self.options.config is None: 200 | parser.error("Use -c to specify a config file!") 201 | else: 202 | self.config = Config(self.options.config, "Mac OS X") 203 | 204 | if len(args) < 1: 205 | parser.error("Specify an action!") 206 | 207 | return args[0], args[1:] 208 | 209 | def substituteArchVariables(self, s, archs): 210 | vars = { 211 | 'ARCH_FLAGS': ' '.join(['-arch %s' % arch for arch in archs]), 212 | } 213 | 214 | if len(archs) == 1: 215 | vars['ARCH'] = archs[0] 216 | else: 217 | vars['ARCH'] = 'universal' 218 | 219 | return string.Template(s).safe_substitute(vars) 220 | 221 | def setupComponents(self): 222 | 223 | for c in KNOWN_COMPONENTS: 224 | component = c(config=self.config) 225 | 226 | if component.name in self.components: 227 | raise StandardError('Try to register %s twice!' % component.name) 228 | 229 | self.components[component.name] = component 230 | 231 | 232 | def findComponents(self, args): 233 | if len(args) == 0 or 'all' in args: 234 | return self.components.values() 235 | 236 | args = map(lambda x: x.lower(), args) 237 | components = [] 238 | 239 | for (key, value) in self.components.iteritems(): 240 | if key.lower() in args: 241 | components.append(value) 242 | 243 | return components 244 | 245 | def findComponent(self, componentName): 246 | assert componentName is not None 247 | 248 | componentList = self.findComponents([componentName]) 249 | 250 | if not len(componentList): 251 | return None 252 | else: 253 | return componentList[0] 254 | 255 | def download(self, args): 256 | components = self.findComponents(args) 257 | 258 | for c in components: 259 | self.downloadComponent(c) 260 | 261 | def downloadComponent(self, c): 262 | """ 263 | Make sure the archive dir exists and 264 | is writeable. 265 | """ 266 | 267 | if not os.path.isdir(self.config.archivesPath): 268 | os.mkdir(self.config.archivesPath) 269 | 270 | if not os.path.exists(c.sourceArchiveFile): 271 | print "%s: Download '%s'..." % (c.name, c.download_url), 272 | sys.stdout.flush() 273 | try: 274 | def reportHook(blocks, blockSize, totalSize): 275 | if totalSize == 0: 276 | totalSize = 1 277 | print "\r%s: Download '%s' %i%%" % (c.name, c.download_url, 100*blocks*blockSize/totalSize), 278 | 279 | urllib.urlretrieve(c.download_url, c.sourceArchiveFile + '.temp', reportHook) 280 | os.rename(c.sourceArchiveFile + '.temp', c.sourceArchiveFile) 281 | print "%s: Download '%s' done." % (c.name, c.download_url) 282 | except: 283 | print 'failed!' 284 | raise 285 | else: 286 | print "%s: Download already downloaded." % c.name 287 | 288 | def build(self, args): 289 | components = self.findComponents(args) 290 | 291 | self.setupInstallToolchain() 292 | 293 | for c in components: 294 | self.uncleanComponents.append(c) 295 | 296 | if c.supportsOnPassUniversalBuild or len(self.config.archs) <= 1: 297 | for step in c.buildSteps: 298 | if step == 'unpack': 299 | self.unpackComponent(c) 300 | elif step == 'patch': 301 | self.patchComponent(c) 302 | elif step == 'setupSandbox': 303 | self.setupBuildSandboxCommand(c) 304 | elif step == 'configure': 305 | self.runConfigureCommand(c, self.config.archs) 306 | elif step == 'build': 307 | self.runBuildCommand(c, self.config.archs) 308 | elif step == 'install': 309 | self.runInstallCommand(c, c.buildPath) 310 | elif step == 'tearDownSandbox': 311 | self.tearDownBuildSandboxCommand(c) 312 | elif step == 'universalize': 313 | # Universalize is not needed in one pass builds 314 | pass 315 | elif step == 'createManifest': 316 | self.createManifestAndClearLog(c) 317 | elif isinstance(step, collections.Callable): 318 | step(component=c, archs=self.config.archs, builder=self) 319 | else: 320 | raise StandardError("Don't now how to run step %s" % str(step)) 321 | else: 322 | arch_build_dirs = {} 323 | 324 | for arch in self.config.archs: 325 | arch_build_dirs[arch] = mkdtemp(prefix="xampp-builder-%s-%s-" % (c.name, arch)) 326 | 327 | def cleanUp(dirs): 328 | for (key, value) in dirs.iteritems(): 329 | shutil.rmtree(value) 330 | 331 | atexit.register(cleanUp, arch_build_dirs) 332 | 333 | archDependentSteps = c.buildSteps[0:c.buildSteps.index('universalize')] 334 | archIndependentSteps = c.buildSteps[c.buildSteps.index('universalize'):] 335 | 336 | for arch in self.config.archs: 337 | if os.path.isdir(c.workingDir): 338 | shutil.rmtree(c.workingDir) 339 | os.mkdir(c.workingDir) 340 | 341 | for step in archDependentSteps: 342 | if step == 'unpack': 343 | self.unpackComponent(c) 344 | elif step == 'patch': 345 | self.patchComponent(c) 346 | elif step == 'setupSandbox': 347 | self.setupBuildSandboxCommand(c) 348 | elif step == 'configure': 349 | self.runConfigureCommand(c, archs=[arch]) 350 | elif step == 'build': 351 | self.runBuildCommand(c, archs=[arch]) 352 | elif step == 'install': 353 | self.runInstallCommand(c, c.buildPath) 354 | elif step == 'tearDownSandbox': 355 | self.tearDownBuildSandboxCommand(c) 356 | elif isinstance(step, collections.Callable): 357 | step(component=c, archs=[arch], builder=self) 358 | else: 359 | raise StandardError("Don't now how to run arch dependent step %s" % str(step)) 360 | 361 | for step in archIndependentSteps: 362 | if step == 'universalize': 363 | self.universalizeComponent(c, arch_build_dirs) 364 | elif step == 'createManifest': 365 | self.createManifestAndClearLog(c) 366 | elif isinstance(step, collections.Callable): 367 | step(component=c, archs=self.config.archs, builder=self) 368 | else: 369 | raise StandardError("Don't now how to run step %s" % str(step)) 370 | 371 | self.uncleanComponents.remove(c) 372 | 373 | 374 | def unpackComponent(self, c): 375 | # Change our working dir to the source dir 376 | os.chdir(c.workingDir) 377 | 378 | tar_process = ['/usr/bin/tar'] 379 | (path, ext) = os.path.splitext(c.sourceArchiveFile) 380 | 381 | if ext == '.gz' or ext == '.tgz' or ext == '.Z': 382 | tar_process.append('xpzf') 383 | elif ext == '.bz2': 384 | tar_process.append('xpjf') 385 | elif ext == '.tar': 386 | tar_process.append('xpf') 387 | else: 388 | raise StandardError('Unknown archive format') 389 | 390 | tar_process.extend([c.sourceArchiveFile] + c.extraTarFlags()) 391 | 392 | print("==> Unpack %s (work dir %s)" % (c.name, c.workingDir)) 393 | check_call(tar_process) 394 | 395 | def patchComponent(self, c): 396 | if not len(c.patches): 397 | return 398 | 399 | print("==> Patch %s" % c.name) 400 | os.chdir(c.workingDir) 401 | 402 | for patch in c.patches: 403 | if patch.endswith('.zip'): 404 | check_call(['unzip','-o', os.path.join(c.patches_dir, patch), '-d', '.']) 405 | elif patch.endswith('.patch'): 406 | check_call(['patch', '-p0', '-i', os.path.join(c.patches_dir, patch)]) 407 | else: 408 | raise StandardError("Do not know how to apply %s" % patch) 409 | 410 | def runConfigureCommand(self, c, archs): 411 | commandArguments = [] 412 | 413 | command = c.configureCommand() 414 | commandArguments.extend(c.computedConfigureFlags()) 415 | environment = dict(os.environ) 416 | 417 | # TODO: This was commented out, why? 418 | environment['PATH'] = "%s/bin:%s" % (self.installToolchainPath, environment['PATH']) 419 | 420 | for (key, value) in c.configureEnvironment().iteritems(): 421 | environment[key] = value 422 | 423 | for d in c.dependencies: 424 | commandArguments.extend(d.computedConfigureFlags(self, c)) 425 | oldCFlags = "" 426 | oldLDFlags = "" 427 | 428 | try: 429 | oldCFlags = environment['CFLAGS'] 430 | oldLDFlags = environment['LDFLAGS'] 431 | except KeyError: 432 | pass 433 | 434 | environment['CFLAGS'] = ' '.join([oldCFlags] + d.computedCFlags(self, c)) 435 | environment['LDFLAGS'] = ' '.join([oldLDFlags] + d.computedLDFlags(self, c)) 436 | 437 | commandArguments = map(lambda x: self.substituteArchVariables(x, archs), commandArguments) 438 | 439 | for key in environment.copy(): 440 | environment[key] = self.substituteArchVariables(environment[key], archs) 441 | 442 | print("==> Configure %s %s" % (c.name, environment)) 443 | check_call([command] + commandArguments, env=environment) 444 | 445 | def runBuildCommand(self, c, archs): 446 | commandArguments = [] 447 | 448 | command = c.buildCommand() 449 | commandArguments.extend(c.computedBuildFlags()) 450 | environment = dict(os.environ) 451 | environment['PATH'] = "%s/bin:%s" % (self.installToolchainPath, environment['PATH']) 452 | 453 | for (key, value) in c.buildEnvironment().iteritems(): 454 | environment[key] = value 455 | 456 | for d in c.dependencies: 457 | oldCFlags = "" 458 | oldLDFlags = "" 459 | 460 | try: 461 | oldCFlags = environment['CFLAGS'] 462 | oldLDFlags = environment['LDFLAGS'] 463 | except KeyError: 464 | pass 465 | 466 | environment['CFLAGS'] = ' '.join([oldCFlags] + d.computedCFlags(self, c)) 467 | environment['LDFLAGS'] = ' '.join([oldLDFlags] + d.computedLDFlags(self, c)) 468 | 469 | commandArguments = map(lambda x: self.substituteArchVariables(x, archs), commandArguments) 470 | 471 | for key in environment.copy(): 472 | environment[key] = self.substituteArchVariables(environment[key], archs) 473 | 474 | print("==> Build %s" % c.name) 475 | check_call([command] + commandArguments, env=environment, shell=True) 476 | 477 | def runInstallCommand(self, c, dest_dir): 478 | commandArguments = [] 479 | 480 | command = c.installCommand() 481 | commandArguments.extend(c.computedInstallFlags()) 482 | environment = dict(os.environ) 483 | environment['PATH'] = "%s/bin:%s" % (self.installToolchainPath, environment['PATH']) 484 | 485 | for (key, value) in c.installEnvironment().iteritems(): 486 | environment[key] = string.Template(value).safe_substitute({'DEST_DIR': dest_dir}) 487 | 488 | commandArguments = map(lambda x: string.Template(x).safe_substitute({'DEST_DIR': dest_dir}), commandArguments) 489 | 490 | print("==> Install %s (to %s)" % (c.name, dest_dir)) 491 | check_call([command] + commandArguments, env=environment) 492 | 493 | def universalizeComponent(self, c, arch_build_dirs): 494 | digests = {} 495 | 496 | print("==> Universalize %s" % c.name) 497 | 498 | for arch, path in arch_build_dirs.iteritems(): 499 | digests[arch] = digestsInPath(path) 500 | 501 | common_dict = digests[digests.keys()[0]] 502 | 503 | arch_depend_files = [] 504 | 505 | for arch in digests: 506 | (common_dict, depend) = commonInDict(common_dict, digests[arch]) 507 | 508 | arch_depend_files.extend(depend) 509 | 510 | if os.path.isdir(c.buildPath): 511 | shutil.rmtree(c.buildPath) 512 | 513 | # Copy the common files 514 | src = arch_build_dirs[arch_build_dirs.keys()[0]] 515 | shutil.copytree(src, 516 | c.buildPath, 517 | symlinks=True, 518 | ignore=ignoreFilesSet(arch_depend_files, rel_to=src)) 519 | 520 | for file in arch_depend_files: 521 | success = False 522 | 523 | for universalizer in self.fileUniversalizer: 524 | if universalizer.applicableTo(file, arch_build_dirs): 525 | success = universalizer.universalizeFile(file, os.path.join(c.buildPath, file), arch_build_dirs) 526 | 527 | break 528 | 529 | if success is False: 530 | raise StandardError("Could not universalize %s (%s)" % (file, arch_build_dirs)) 531 | 532 | def componentsDependingOn(self, component): 533 | dependents = [] 534 | 535 | for c in self.components.values(): 536 | for d in c.dependencies: 537 | if d.componentName.lower() == component.name.lower(): 538 | dependents.append(c) 539 | 540 | return dependents 541 | 542 | def dependencies(self, args): 543 | if not len(args): 544 | components_to_consider = [] 545 | else: 546 | components_to_consider = self.findComponents(args) 547 | 548 | if self.options.missing: 549 | for c in self.components.values(): 550 | if not c.isBuild: 551 | components_to_consider.append(c) 552 | 553 | # Find all components that are directly or indirectly 554 | # depended on these components 555 | 556 | foundNew = True 557 | 558 | while foundNew: 559 | foundNew = False 560 | 561 | for c in components_to_consider: 562 | dependents = self.componentsDependingOn(c) 563 | 564 | for d in dependents: 565 | if d not in components_to_consider: 566 | components_to_consider.append(d) 567 | foundNew = True 568 | 569 | 570 | resolved = [] 571 | unhandled = list(set(components_to_consider)) 572 | 573 | while len(unhandled): 574 | for c in unhandled: 575 | satisfied = True 576 | 577 | for d in c.dependencies: 578 | if self.findComponent(d.componentName) not in resolved and \ 579 | self.findComponent(d.componentName) in unhandled: 580 | satisfied = False 581 | 582 | if satisfied: 583 | resolved.append(c) 584 | unhandled.remove(c) 585 | 586 | if self.options.json: 587 | print(json.dumps([c.name.lower() for c in resolved])) 588 | else: 589 | for c in resolved: 590 | print(c.name.lower()) 591 | 592 | def copyComponent(self, c, dest=None, includeDevelopmentFiles=True): 593 | if dest is None: 594 | dest = self.config.destPath 595 | 596 | manifest = None 597 | with open(c.manifestPath, 'r') as f: 598 | manifest = json.load(f) 599 | 600 | definitions = manifest['release'] 601 | 602 | if includeDevelopmentFiles: 603 | definitions.update(manifest['dev']) 604 | 605 | for file in sorted(definitions.keys()): 606 | srcFile = os.path.join(c.buildPath, file[1:]) 607 | destFile = os.path.join(dest, os.path.relpath(file, self.config.destPath)) 608 | 609 | if os.path.islink(srcFile): 610 | linkto = os.readlink(srcFile) 611 | os.symlink(linkto, destFile) 612 | elif os.path.isdir(srcFile) or srcFile.endswith('/'): 613 | if not os.path.isdir(destFile): 614 | os.makedirs(destFile) 615 | else: 616 | shutil.copy2(srcFile, destFile) 617 | 618 | try: 619 | os.lchmod(destFile, int(definitions[file]['mode'], 8)) 620 | except Exception, e: 621 | print "Supress lchmod error %s" % str(e) 622 | try: 623 | os.chmod(destFile, int(definitions[file]['mode'], 8)) 624 | except Exception, e: 625 | print "Supress chmod error %s" % str(e) 626 | 627 | 628 | def cleanUp(self): 629 | if self.installToolchainPath: 630 | if self.options.no_clean_on_failure: 631 | print("Wanring: won't remove %s..." % self.installToolchainPath) 632 | else: 633 | shutil.rmtree(self.installToolchainPath, ignore_errors=True) 634 | 635 | 636 | for c in self.uncleanComponents: 637 | if self.options.no_clean_on_failure: 638 | print("Wanring: won't remove %s..." % c.buildPath) 639 | else: 640 | shutil.rmtree(c.buildPath, ignore_errors=True) 641 | shutil.rmtree(c.manifestPath, ignore_errors=True) 642 | 643 | def setupInstallToolchain(self): 644 | self.installToolchainPath = mkdtemp(prefix="xampp-builder-install-toolchain") 645 | 646 | os.mkdir(os.path.join(self.installToolchainPath, "bin")) 647 | 648 | log_dir = os.path.join(self.installToolchainPath, "logs") 649 | 650 | os.mkdir(log_dir) 651 | 652 | mode755 = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH 653 | 654 | with open(os.path.join(self.installToolchainPath, "bin", "chmod"), "w") as f: 655 | f.write(string.Template(chmod_tool).safe_substitute({"LOG_DIR": log_dir})) 656 | 657 | os.chmod(os.path.join(self.installToolchainPath, "bin", "chmod"), mode755) 658 | 659 | with open(os.path.join(self.installToolchainPath, "bin", "chown"), "w") as f: 660 | f.write(string.Template(chown_tool).safe_substitute({"LOG_DIR": log_dir})) 661 | 662 | os.chmod(os.path.join(self.installToolchainPath, "bin", "chown"), mode755) 663 | 664 | with open(os.path.join(self.installToolchainPath, "bin", "install"), "w") as f: 665 | f.write(string.Template(install_tool).safe_substitute({"LOG_DIR": log_dir})) 666 | 667 | os.chmod(os.path.join(self.installToolchainPath, "bin", "install"), mode755) 668 | 669 | def createManifestAndClearLog(self, component): 670 | manifest={'dev': {}, 'release':{}} 671 | 672 | chmodLogFile = os.path.join(self.installToolchainPath, "logs", 'chmod.json') 673 | chownLogFile = os.path.join(self.installToolchainPath, "logs", 'chown.json') 674 | installLogFile = os.path.join(self.installToolchainPath, "logs", 'install.json') 675 | 676 | chmodManifest = self.manifestFromChmodLog(chmodLogFile) 677 | chownManifest = self.manifestFromChownLog(chownLogFile) 678 | installManifest = self.manifestFromInstallLog(installLogFile) 679 | 680 | for root, dirs, files in os.walk(component.buildPath): 681 | for dirname in dirs: 682 | dir = os.path.join(root, dirname) 683 | 684 | user=None 685 | group=None 686 | mode=None 687 | 688 | if dir in chmodManifest: 689 | mode = chmodManifest[dir]['mode'] 690 | 691 | if dir in chownManifest: 692 | if 'user' in chownManifest[dir]: 693 | user = chownManifest[dir]['user'] 694 | if 'group' in chownManifest[dir]: 695 | group = chownManifest[dir]['group'] 696 | 697 | if dir in installManifest: 698 | if 'user' in installManifest[dir]: 699 | user = installManifest[dir]['user'] 700 | if 'group' in installManifest[dir]: 701 | group = installManifest[dir]['group'] 702 | if 'mode' in installManifest[dir]: 703 | mode = installManifest[dir]['mode'] 704 | 705 | if user is None: 706 | user = 'nobody' 707 | if group is None: 708 | group = 'nogroup' 709 | if mode is None: 710 | mode = '%o' % stat.S_IMODE(os.lstat(dir).st_mode) 711 | else: 712 | #Ensure that the directory is always tranversable ("x") 713 | mode = '%o' % (int(mode, 8) | S_IXUSR | S_IXGRP | S_IXOTH) 714 | 715 | installPath = '/' + os.path.relpath(dir, component.buildPath) 716 | 717 | if not installPath.startswith(self.config.destPath): 718 | continue 719 | 720 | if not installPath.endswith('/'): 721 | installPath = installPath + '/' 722 | 723 | if component.isPathDevelopmentOnly(installPath): 724 | manifest['dev'][installPath] = { 725 | 'user': user, 726 | 'group': group, 727 | 'mode': mode 728 | } 729 | else: 730 | manifest['release'][installPath] = { 731 | 'user': user, 732 | 'group': group, 733 | 'mode': mode 734 | } 735 | 736 | for filename in files: 737 | file = os.path.join(root, filename) 738 | 739 | user=None 740 | group=None 741 | mode=None 742 | 743 | if file in chmodManifest: 744 | mode = chmodManifest[file]['mode'] 745 | 746 | if file in chownManifest: 747 | if 'user' in chownManifest[file]: 748 | user = chownManifest[file]['user'] 749 | if 'group' in chownManifest[file]: 750 | group = chownManifest[file]['group'] 751 | 752 | if file in installManifest: 753 | if 'user' in installManifest[file]: 754 | user = installManifest[file]['user'] 755 | if 'group' in installManifest[file]: 756 | group = installManifest[file]['group'] 757 | if 'mode' in installManifest[file]: 758 | mode = installManifest[file]['mode'] 759 | 760 | if user is None: 761 | user = 'nobody' 762 | if group is None: 763 | group = 'nogroup' 764 | if mode is None: 765 | mode = '%o' % stat.S_IMODE(os.lstat(file).st_mode) 766 | 767 | installPath = '/' + os.path.relpath(file, component.buildPath) 768 | 769 | if not installPath.startswith(self.config.destPath): 770 | continue 771 | 772 | if component.isPathDevelopmentOnly(installPath): 773 | manifest['dev'][installPath] = { 774 | 'user': user, 775 | 'group': group, 776 | 'mode': mode 777 | } 778 | else: 779 | manifest['release'][installPath] = { 780 | 'user': user, 781 | 'group': group, 782 | 'mode': mode 783 | } 784 | 785 | 786 | with open(component.manifestPath, 'w') as f: 787 | json.dump(manifest, f); 788 | 789 | if os.path.isfile(chmodLogFile): 790 | os.remove(chmodLogFile) 791 | if os.path.isfile(chownLogFile): 792 | os.remove(chownLogFile) 793 | if os.path.isfile(installLogFile): 794 | os.remove(installLogFile) 795 | 796 | def manifestFromChmodLog(self, chmodLogFile): 797 | logContent = None 798 | manifest = {} 799 | 800 | if not os.path.isfile(chmodLogFile): 801 | return manifest; 802 | 803 | with open(chmodLogFile, 'r') as f: 804 | string = f.read() 805 | logContent = json.loads('[' + string + 'null]') 806 | 807 | if logContent is not None: 808 | for command in logContent: 809 | files=[] 810 | mode=None 811 | recursive=False 812 | 813 | if command is None: 814 | continue 815 | 816 | for arg in command['args']: 817 | if arg == '-R' or arg == '-r': 818 | recursive=True 819 | elif arg.startswith('-'): 820 | # Ignore all options for now 821 | continue 822 | elif mode is None: 823 | mode = arg 824 | else: 825 | file = os.path.join(command['pwd'], arg) 826 | files.append(file) 827 | if recursive: 828 | files.extend(self.listOfPathsBelow(file)) 829 | 830 | for file in files: 831 | if file not in manifest: 832 | manifest[file] = {} 833 | 834 | manifest[file]['mode'] = mode 835 | 836 | return manifest 837 | 838 | def manifestFromChownLog(self, chmodLogFile): 839 | logContent = None 840 | manifest = {} 841 | 842 | if not os.path.isfile(chmodLogFile): 843 | return manifest; 844 | 845 | with open(chmodLogFile, 'r') as f: 846 | string = f.read() 847 | logContent = json.loads('[' + string + 'null]') 848 | 849 | if logContent is not None: 850 | for command in logContent: 851 | files=[] 852 | user=None 853 | group=None 854 | recursive=False 855 | 856 | if command is None: 857 | continue 858 | 859 | for arg in command['args']: 860 | if arg == '-R' or arg == '-r': 861 | recursive=True 862 | elif arg.startswith('-'): 863 | # Ignore all options for now 864 | continue 865 | elif user is None and group is None: 866 | (user, group) = arg.split(':') 867 | else: 868 | file = os.path.join(command['pwd'], arg) 869 | files.append(file) 870 | if recursive: 871 | files.extend(self.listOfPathsBelow(file)) 872 | 873 | 874 | for file in files: 875 | if file not in manifest: 876 | manifest[file] = {} 877 | 878 | if len(user) > 0: 879 | manifest[file]['user'] = user 880 | if group is not None and len(group) > 0: 881 | manifest[file]['group'] = group 882 | 883 | return manifest 884 | 885 | def manifestFromInstallLog(self, chmodLogFile): 886 | logContent = None 887 | manifest = {} 888 | 889 | if not os.path.isfile(chmodLogFile): 890 | return manifest; 891 | 892 | with open(chmodLogFile, 'r') as f: 893 | string = f.read() 894 | logContent = json.loads('[' + string + 'null]') 895 | 896 | if logContent is not None: 897 | for command in logContent: 898 | files=[] 899 | 900 | if command is None: 901 | continue 902 | 903 | user=command['owner'] 904 | group=command['group'] 905 | mode=command['mode'] 906 | sources=command['sources'] 907 | dest=command['dest'] 908 | 909 | if len(sources) > 1 or dest.endswith('/'): 910 | for file in sources: 911 | files.append(os.path.join(dest, os.path.basename(file))) 912 | else: 913 | files.append(dest) 914 | 915 | 916 | for file in files: 917 | if file not in manifest: 918 | manifest[file] = {} 919 | 920 | if user is not None and len(user) > 0: 921 | manifest[file]['user'] = user 922 | if group is not None and len(group) > 0: 923 | manifest[file]['group'] = group 924 | if mode is not None and len(mode) > 0: 925 | manifest[file]['mode'] = mode 926 | 927 | return manifest 928 | 929 | def listOfPathsBelow(self, path): 930 | paths=[] 931 | 932 | for root, dirs, files in os.walk(path): 933 | for dir in dirs: 934 | paths.append(os.path.join(root, dir)) 935 | for file in files: 936 | paths.append(os.path.join(root, file)) 937 | 938 | return paths 939 | 940 | def setupBuildSandboxCommand(self, component): 941 | self.sandbox = Sandbox([d.componentName for d in component.dependencies], self) 942 | 943 | print("==> Setup build sandbox") 944 | 945 | self.sandbox.setup() 946 | 947 | 948 | def tearDownBuildSandboxCommand(self, component): 949 | if self.sandbox: 950 | print("==> Tear down build sandbox") 951 | self.sandbox.tearDown() 952 | self.sandbox = None 953 | 954 | def pack(self, args): 955 | packager = MacOSXPackager(self) 956 | 957 | version=args[0] 958 | destPath=args[1] 959 | 960 | packager.packXAMPP(version, destPath) 961 | --------------------------------------------------------------------------------