Browse Source

adding Mac OS X .pkg installer generation in build, PR 55899

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@1553066 13f79535-47bb-0310-9956-ffa450edef68
master
Antoine Levy-Lambert 11 years ago
parent
commit
99dcdaae87
5 changed files with 212 additions and 2 deletions
  1. +1
    -0
      CONTRIBUTORS
  2. +3
    -0
      WHATSNEW
  3. +25
    -2
      build.xml
  4. +4
    -0
      contributors.xml
  5. +179
    -0
      release/build-osx-pkg.py

+ 1
- 0
CONTRIBUTORS View File

@@ -36,6 +36,7 @@ Balazs Fejes 2
Bart Vanhaute
Benjamin Burgess
Ben Galbraith
Ben Gertzfield
Benoit Moussaud
Bernd Dutkowski
Bernhard Rosenkraenzer


+ 3
- 0
WHATSNEW View File

@@ -46,6 +46,9 @@ Other changes:
* <xslt>'s params can now be typed.
Bugzilla Report 21525.

* build of Mac OS X pkg installer
Bugzilla Report 55899.

Changes from Ant 1.9.1 TO Ant 1.9.2
===================================



+ 25
- 2
build.xml View File

@@ -1148,8 +1148,7 @@
Create the binary distribution
===================================================================
-->
<target name="main_distribution" depends="jars-sources,test-jar-source"
description="--> creates the zip and tar distributions">
<target name="-distribution_prep">
<delete dir="${dist.base}"/>
<delete dir="${dist.name}"/>
<delete dir="${java-repository.dir}"/>
@@ -1161,6 +1160,10 @@
<antcall inheritAll="false" target="internal_dist">
<param name="dist.dir" value="${dist.name}"/>
</antcall>
</target>

<target name="zip_distribution" depends="jars,-distribution_prep"
description="--> creates the zip distribution">
<zip destfile="${dist.base.binaries}/${dist.name}-bin.zip">
<zipfileset dir="${dist.name}/.." filemode="755">
<include name="${dist.name}/bin/ant"/>
@@ -1176,6 +1179,22 @@
<exclude name="${dist.name}/bin/*.py"/>
</fileset>
</zip>
</target>

<condition property="buildosxpackage">
<os family="mac"/>
</condition>

<target name="pkg_distribution" depends="zip_distribution" if="buildosxpackage">
<exec executable="release/build-osx-pkg.py">
<arg value="--output-dir"/>
<arg value="${dist.base.binaries}"/>
<arg value="${dist.base.binaries}/${dist.name}-bin.zip"/>
</exec>
</target>

<target name="tar_distribution" depends="jars,-distribution_prep"
description="--> creates the tar distribution">
<tar longfile="gnu"
destfile="${dist.base.binaries}/${dist.name}-bin.tar">
<!-- removes redundant definition of permissions, but seems to
@@ -1201,6 +1220,10 @@
<bzip2 destfile="${dist.base.binaries}/${dist.name}-bin.tar.bz2"
src="${dist.base.binaries}/${dist.name}-bin.tar"/>
<delete file="${dist.base.binaries}/${dist.name}-bin.tar"/>
</target>

<target name="main_distribution" depends="zip_distribution,pkg_distribution,tar_distribution,jars-sources,test-jar-source"
description="--> creates the zip, pkg, and tar distributions">

<copy todir="${java-repository.dir}">
<fileset dir="${dist.name}/lib">


+ 4
- 0
contributors.xml View File

@@ -168,6 +168,10 @@
<first>Ben</first>
<last>Galbraith</last>
</name>
<name>
<first>Ben</first>
<last>Gertzfield</last>
</name>
<name>
<first>Benoit</first>
<last>Moussaud</last>


+ 179
- 0
release/build-osx-pkg.py View File

@@ -0,0 +1,179 @@
#!/usr/bin/env python

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Builds a Mac OS X .pkg from a binary ZIP archive of Apache Ant.

import collections
import contextlib
import os

ApacheAntURL = collections.namedtuple(
'ApacheAntURL',
('url', 'url_scheme', 'version', 'directory_name'))

@contextlib.contextmanager
def make_temp_directory():
'''Creates a temporary directory which is recursively deleted when out of scope.'''
import shutil
import tempfile
temp_dir = tempfile.mkdtemp()
yield temp_dir
shutil.rmtree(temp_dir)

@contextlib.contextmanager
def self_closing_url(url):
'''Opens a URL and returns a self-closing file-like object.'''
import urllib2
url_fp = urllib2.urlopen(url)
yield url_fp
url_fp.close()

def apache_ant_url(url_string):
'''Parses a URL string into an ApacheAntURL object.'''
import argparse, collections, os.path, urlparse
parse_result = urlparse.urlparse(url_string)
filename = os.path.split(parse_result.path)[1]
if not (filename.startswith('apache-ant-') and filename.endswith('-bin.zip')):
raise argparse.ArgumentTypeError(
'Expected [%s] to end with apache-ant-X.Y.Z-bin.zip' % (url_string))
extracted_directory = filename.replace('-bin.zip', '')
extracted_version = extracted_directory.replace('apache-ant-', '')
return ApacheAntURL(
url=url_string,
url_scheme=parse_result.scheme,
version=extracted_version,
directory_name=extracted_directory)

def fetch_url(url, local_output_file):
'''Downloads the contents of 'url' and writes them the opened file 'output_file'.'''
import shutil
import urllib2
CHUNK_SIZE = 16 * 1024
print 'Fetching {url}...'.format(url=url)
with self_closing_url(url) as url_input_file:
while True:
chunk = url_input_file.read(CHUNK_SIZE)
if not chunk:
break
local_output_file.write(chunk)
local_output_file.seek(0)

def fetch_apache_ant_url(apache_ant_url, temp_dir):
'''If the ApacheAntURL object is remote, fetches and returns the local file object.
Otherwise, opens and returns a file object.'''
import tempfile
if apache_ant_url.url_scheme == '' or apache_ant_url.url_scheme == 'file':
return open(apache_ant_url.url, 'rb')
else:
fp = tempfile.TemporaryFile(dir=temp_dir)
fetch_url(apache_ant_url.url, fp)
return fp

def uncompress_contents(temp_dir, archive_file, directory_name, path_prefix):
'''Uncompresses the contents of 'archive_file' to 'temp_dir'.

Strips the prefix 'directory_name' and prepends 'path_prefix' to each entry
of the zip file.
'''
import shutil, zipfile
output_path = os.path.join(temp_dir, 'pkg')
os.mkdir(output_path)
z = zipfile.ZipFile(archive_file)
print 'Extracting archive to {output_path}...'.format(
output_path=output_path)
for entry in z.infolist():
# We can't just extract directly, since we want to map:
#
# apache-ant-X.Y.Z/bin/foo
#
# to
#
# usr/local/ant/bin/foo
#
# So, we strip out the apache-ant-X.Y.Z prefix, then instead of
# using ZipFile.extract(), we use ZipFile.open() to get a read fd to
# the source file, then os.fdopen() with the appropriate permissions
# to geta write fd to the modified destination path.
expected_prefix = directory_name + '/'
if not entry.filename.startswith(expected_prefix):
raise Exeption('Unexpected entry in zip file: [{filename}]'.format(
filename=entry.filename))
entry_path = entry.filename.replace(expected_prefix, '', 1)

# Using os.path.join is annoying here (we'd have to explode output_path
# and entry_path).
entry_output_path = output_path + path_prefix + '/' + entry_path

# Zip file paths are normalized with '/' at the end for directories.
if entry_output_path.endswith('/'):
print 'Creating directory {path}'.format(path=entry_output_path)
os.makedirs(entry_output_path)
else:
# Yes, this is really how you extract permissions from a ZipInfo entry.
perms = (entry.external_attr >> 16L) & 0777
print 'Extracting {entry_filename} to {path} with mode 0{mode:o}'.format(
entry_filename=entry.filename, path=entry_output_path, mode=perms)
with z.open(entry) as source:
with os.fdopen(
os.open(entry_output_path, os.O_WRONLY | os.O_CREAT, perms), 'w') \
as destination:
shutil.copyfileobj(source, destination)
return output_path

def write_paths_d_entry(paths_d_directory, filename):
os.makedirs(paths_d_directory)
output_file = os.path.join(paths_d_directory, filename)
with open(output_file, 'w') as f:
print >>f, '/usr/local/ant/bin'

def make_pkg(pkg_dir, pkg_identifier, pkg_version, output_pkg_path):
import subprocess
print 'Building package at {output_pkg_path}...'.format(
output_pkg_path=output_pkg_path)
subprocess.call(
['pkgbuild',
'--root', pkg_dir,
'--identifier', pkg_identifier,
'--version', pkg_version,
output_pkg_path])

def main():
import argparse
parser = argparse.ArgumentParser(description='Builds a Mac OS X .pkg of ant.')
parser.add_argument(
'apache_ant_url',
metavar='file-or-url',
help='Source file or URL from which to uncompress apache-ant-X.Y.Z-bin.zip',
type=apache_ant_url)
parser.add_argument(
'--output-dir',
default='.',
help='Directory to which .pkg will be written. Defaults to current directory.')
args = parser.parse_args()
with make_temp_directory() as temp_dir:
archive_file = fetch_apache_ant_url(args.apache_ant_url, temp_dir)
pkg_dir = uncompress_contents(
temp_dir, archive_file, args.apache_ant_url.directory_name, '/usr/local/ant')
etc_paths_d_dir = os.path.join(pkg_dir, 'etc', 'paths.d')
write_paths_d_entry(etc_paths_d_dir, 'org.apache.ant')
pkg_identifier = 'org.apache.ant'
output_pkg_path = os.path.join(
args.output_dir, args.apache_ant_url.directory_name + '.pkg')
make_pkg(pkg_dir, pkg_identifier, args.apache_ant_url.version, output_pkg_path)

if __name__ == '__main__':
main()

Loading…
Cancel
Save