Code drop from //branches/cupcake/...@124589

This commit is contained in:
The Android Open Source Project
2008-12-17 18:04:04 -08:00
parent 5c11852110
commit e943f2fd8e
659 changed files with 47382 additions and 9976 deletions

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="PACKAGE.tests"
android:versionCode="1"
android:versionName="1.0">
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
which is needed when building test cases. -->
<application>
<uses-library android:name="android.test.runner" />
</application>
<!--
This declares that this application uses the instrumentation test runner targeting
the package of PACKAGE. To run the tests use the command:
"adb shell am instrument -w PACKAGE.tests/android.test.InstrumentationTestRunner"
-->
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="PACKAGE"
android:label="Tests for ACTIVITY_NAME"/>
</manifest>

View File

@@ -0,0 +1,2 @@
Add-on folder.
Drop vendor supplied SDK add-on in this folder.

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" ?>
<project name="alias_rules" default="package">
<!-- No user servicable parts below. -->
<!-- Input directories -->
<property name="resource-dir" value="res" />
<!-- The final package file to generate -->
<property name="out-package" value="${ant.project.name}.apk" />
<!-- Tools -->
<condition property="aapt" value="${android-tools}/aapt.exe" else="${android-tools}/aapt" >
<os family="windows"/>
</condition>
<condition property="adb" value="${android-tools}/adb.exe" else="${android-tools}/adb" >
<os family="windows"/>
</condition>
<property name="android-jar" value="${sdk-folder}/android.jar" />
<!-- Rules -->
<!-- Packages the manifest and the resource files -->
<target name="package-res">
<echo>Packaging resources...</echo>
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-f" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
<arg value="-F" />
<arg value="${out-package}" />
</exec>
</target>
<!-- Create the package file for this project from the sources. -->
<target name="package" depends="package-res" />
<!-- Create the package and install package on the default emulator -->
<target name="install" depends="package">
<echo>Sending package to default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="install" />
<arg value="${out-package}" />
</exec>
</target>
</project>

View File

@@ -0,0 +1,280 @@
<?xml version="1.0" ?>
<project name="android_rules" default="debug">
<!-- No user servicable parts below. -->
<property name="outdir-main" value="../${outdir}" />
<property name="android-tools" value="${sdk-folder}/tools" />
<property name="android-platform" value="${sdk-folder}/platforms/${target-folder}" />
<property name="android-framework" value="${android-platform}/framework.aidl" />
<property name="android-jar" value="${android-platform}/android.jar" />
<!-- Input directories -->
<property name="resource-dir" value="res" />
<property name="asset-dir" value="assets" />
<property name="srcdir" value="src" />
<condition property="srcdir-ospath"
value="${basedir}\${srcdir}"
else="${basedir}/${srcdir}" >
<os family="windows"/>
</condition>
<!-- folder for the 3rd party java libraries -->
<property name="external-libs" value="libs" />
<condition property="external-libs-ospath"
value="${basedir}\${external-libs}"
else="${basedir}/${external-libs}" >
<os family="windows"/>
</condition>
<!-- folder for the native libraries -->
<property name="native-libs" value="libs" />
<condition property="native-libs-ospath"
value="${basedir}\${native-libs}"
else="${basedir}/${native-libs}" >
<os family="windows"/>
</condition>
<!-- Output directories -->
<property name="outdir-classes" value="${outdir}/classes" />
<condition property="outdir-classes-ospath"
value="${basedir}\${outdir-classes}"
else="${basedir}/${outdir-classes}" >
<os family="windows"/>
</condition>
<condition property="outdir-main-classes"
value="${outdir-main}/classes">
<available file="${outdir-main}/classes"
type="dir"/>
</condition>
<!-- Create R.java in the source directory -->
<property name="outdir-r" value="src" />
<!-- Intermediate files -->
<property name="dex-file" value="classes.dex" />
<property name="intermediate-dex" value="${outdir}/${dex-file}" />
<condition property="intermediate-dex-ospath"
value="${basedir}\${intermediate-dex}"
else="${basedir}/${intermediate-dex}" >
<os family="windows"/>
</condition>
<!-- The final package file to generate -->
<property name="resources-package" value="${outdir}/${ant.project.name}.ap_" />
<condition property="resources-package-ospath"
value="${basedir}\${resources-package}"
else="${basedir}/${resources-package}" >
<os family="windows"/>
</condition>
<property name="out-debug-package" value="${outdir}/${ant.project.name}-debug.apk" />
<condition property="out-debug-package-ospath"
value="${basedir}\${out-debug-package}"
else="${basedir}/${out-debug-package}" >
<os family="windows"/>
</condition>
<property name="out-unsigned-package" value="${outdir}/${ant.project.name}-unsigned.apk" />
<condition property="out-unsigned-package-ospath"
value="${basedir}\${out-unsigned-package}"
else="${basedir}/${out-unsigned-package}" >
<os family="windows"/>
</condition>
<!-- Tools -->
<condition property="aapt" value="${android-tools}/aapt.exe" else="${android-tools}/aapt" >
<os family="windows"/>
</condition>
<condition property="aidl" value="${android-tools}/aidl.exe" else="${android-tools}/aidl" >
<os family="windows"/>
</condition>
<condition property="adb" value="${android-tools}/adb.exe" else="${android-tools}/adb" >
<os family="windows"/>
</condition>
<condition property="dx" value="${android-tools}/dx.bat" else="${android-tools}/dx" >
<os family="windows"/>
</condition>
<condition property="apk-builder" value="${android-tools}/apkbuilder.bat" else="${android-tools}/apkbuilder" >
<os family="windows"/>
</condition>
<!-- Rules -->
<!-- Create the output directories if they don't exist yet. -->
<target name="dirs">
<echo>Creating output directories if needed...</echo>
<mkdir dir="${outdir}" />
<mkdir dir="${outdir-classes}" />
</target>
<!-- Generate the R.java file for this project's resources. -->
<target name="resource-src" depends="dirs">
<echo>Generating R.java / Manifest.java from the resources...</echo>
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-m" />
<arg value="-J" />
<arg value="${outdir-r}" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
</exec>
</target>
<!-- Generate java classes from .aidl files. -->
<target name="aidl" depends="dirs">
<echo>Compiling aidl files into Java classes...</echo>
<apply executable="${aidl}" failonerror="true">
<arg value="-p${android-framework}" />
<arg value="-I${srcdir}" />
<fileset dir="${srcdir}">
<include name="**/*.aidl"/>
</fileset>
</apply>
</target>
<!-- Compile this project's .java files into .class files. -->
<target name="compile" depends="dirs, resource-src, aidl">
<javac encoding="ascii" target="1.5" debug="true" extdirs=""
srcdir="${srcdir}"
destdir="${outdir-classes}"
bootclasspath="${android-jar}">
<classpath>
<fileset dir="${external-libs}" includes="*.jar"/>
<pathelement path="${outdir-main-classes}"/>
</classpath>
</javac>
</target>
<!-- Convert this project's .class files into .dex files. -->
<target name="dex" depends="compile">
<echo>Converting compiled files and external libraries into ${outdir}/${dex-file}...</echo>
<apply executable="${dx}" failonerror="true" parallel="true">
<arg value="--dex" />
<arg value="--output=${intermediate-dex-ospath}" />
<arg path="${outdir-classes-ospath}" />
<fileset dir="${external-libs}" includes="*.jar"/>
</apply>
</target>
<!-- Put the project's resources into the output package file. -->
<target name="package-res-and-assets">
<echo>Packaging resources and assets...</echo>
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-f" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-A" />
<arg value="${asset-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
<arg value="-F" />
<arg value="${resources-package}" />
</exec>
</target>
<!-- Same as package-res-and-assets, but without "-A ${asset-dir}" -->
<target name="package-res-no-assets">
<echo>Packaging resources...</echo>
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-f" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<!-- No assets directory -->
<arg value="-I" />
<arg value="${android-jar}" />
<arg value="-F" />
<arg value="${resources-package}" />
</exec>
</target>
<!-- Invoke the proper target depending on whether or not
an assets directory is present. -->
<!-- TODO: find a nicer way to include the "-A ${asset-dir}" argument
only when the assets dir exists. -->
<target name="package-res">
<available file="${asset-dir}" type="dir"
property="res-target" value="and-assets" />
<property name="res-target" value="no-assets" />
<antcall target="package-res-${res-target}" />
</target>
<!-- Package the application and sign it with a debug key.
This is the default target when building. It is used for debug. -->
<target name="debug" depends="dex, package-res">
<echo>Packaging ${out-debug-package}, and signing it with a debug key...</echo>
<exec executable="${apk-builder}" failonerror="true">
<arg value="${out-debug-package-ospath}" />
<arg value="-z" />
<arg value="${resources-package-ospath}" />
<arg value="-f" />
<arg value="${intermediate-dex-ospath}" />
<arg value="-rf" />
<arg value="${srcdir-ospath}" />
<arg value="-rj" />
<arg value="${external-libs-ospath}" />
<arg value="-nf" />
<arg value="${native-libs-ospath}" />
</exec>
</target>
<!-- Package the application without signing it.
This allows for the application to be signed later with an official publishing key. -->
<target name="release" depends="dex, package-res">
<echo>Packaging ${out-unsigned-package} for release...</echo>
<exec executable="${apk-builder}" failonerror="true">
<arg value="${out-unsigned-package-ospath}" />
<arg value="-u" />
<arg value="-z" />
<arg value="${resources-package-ospath}" />
<arg value="-f" />
<arg value="${intermediate-dex-ospath}" />
<arg value="-rf" />
<arg value="${srcdir-ospath}" />
<arg value="-rj" />
<arg value="${external-libs-ospath}" />
<arg value="-nf" />
<arg value="${native-libs-ospath}" />
</exec>
<echo>It will need to be signed with jarsigner before being published.</echo>
</target>
<!-- Install the package on the default emulator -->
<target name="install" depends="debug">
<echo>Installing ${out-debug-package} onto default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="install" />
<arg value="${out-debug-package}" />
</exec>
</target>
<target name="reinstall" depends="debug">
<echo>Installing ${out-debug-package} onto default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="install" />
<arg value="-r" />
<arg value="${out-debug-package}" />
</exec>
</target>
<!-- Uinstall the package from the default emulator -->
<target name="uninstall">
<echo>Uninstalling ${application-package} from the default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="uninstall" />
<arg value="${application-package}" />
</exec>
</target>
</project>

View File

@@ -11,52 +11,9 @@
<property file="default.properties"/>
<!-- ************************************************************************************* -->
<!-- No user servicable parts below. -->
<!-- Import the default Android build rules.
This requires ant 1.6.0 or above. -->
<!-- Input directories -->
<property name="resource-dir" value="res" />
<!-- The final package file to generate -->
<property name="out-package" value="${ant.project.name}.apk" />
<!-- Tools -->
<condition property="aapt" value="${android-tools}/aapt.exe" else="${android-tools}/aapt" >
<os family="windows"/>
</condition>
<condition property="adb" value="${android-tools}/adb.exe" else="${android-tools}/adb" >
<os family="windows"/>
</condition>
<property name="android-jar" value="${sdk-folder}/android.jar" />
<!-- Rules -->
<!-- Packages the manifest and the resource files -->
<target name="package-res">
<echo>Packaging resources...</echo>
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-f" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
<arg value="-F" />
<arg value="${out-package}" />
</exec>
</target>
<!-- Create the package file for this project from the sources. -->
<target name="package" depends="package-res" />
<!-- Create the package and install package on the default emulator -->
<target name="install" depends="package">
<echo>Sending package to default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="install" />
<arg value="${out-package}" />
</exec>
</target>
<import file="${sdk-folder}/tools/lib/alias_rules.xml" />
</project>

View File

@@ -22,272 +22,9 @@
<property name="outdir" value="bin" />
<!-- ************************************************************************************* -->
<!-- No user servicable parts below. -->
<!-- Import the default Android build rules.
This requires ant 1.6.0 or above. -->
<property name="android-tools" value="${sdk-folder}/tools" />
<property name="android-framework" value="${android-tools}/lib/framework.aidl" />
<!-- Input directories -->
<property name="resource-dir" value="res" />
<property name="asset-dir" value="assets" />
<property name="srcdir" value="src" />
<condition property="srcdir-ospath"
value="${basedir}\${srcdir}"
else="${basedir}/${srcdir}" >
<os family="windows"/>
</condition>
<!-- folder for the 3rd party java libraries -->
<property name="external-libs" value="libs" />
<condition property="external-libs-ospath"
value="${basedir}\${external-libs}"
else="${basedir}/${external-libs}" >
<os family="windows"/>
</condition>
<!-- folder for the native libraries -->
<property name="native-libs" value="libs" />
<condition property="native-libs-ospath"
value="${basedir}\${native-libs}"
else="${basedir}/${native-libs}" >
<os family="windows"/>
</condition>
<!-- Output directories -->
<property name="outdir-classes" value="${outdir}/classes" />
<condition property="outdir-classes-ospath"
value="${basedir}\${outdir-classes}"
else="${basedir}/${outdir-classes}" >
<os family="windows"/>
</condition>
<!-- Create R.java in the source directory -->
<property name="outdir-r" value="src" />
<!-- Intermediate files -->
<property name="dex-file" value="classes.dex" />
<property name="intermediate-dex" value="${outdir}/${dex-file}" />
<condition property="intermediate-dex-ospath"
value="${basedir}\${intermediate-dex}"
else="${basedir}/${intermediate-dex}" >
<os family="windows"/>
</condition>
<!-- The final package file to generate -->
<property name="resources-package" value="${outdir}/${ant.project.name}.ap_" />
<condition property="resources-package-ospath"
value="${basedir}\${resources-package}"
else="${basedir}/${resources-package}" >
<os family="windows"/>
</condition>
<property name="out-debug-package" value="${outdir}/${ant.project.name}-debug.apk" />
<condition property="out-debug-package-ospath"
value="${basedir}\${out-debug-package}"
else="${basedir}/${out-debug-package}" >
<os family="windows"/>
</condition>
<property name="out-unsigned-package" value="${outdir}/${ant.project.name}-unsigned.apk" />
<condition property="out-unsigned-package-ospath"
value="${basedir}\${out-unsigned-package}"
else="${basedir}/${out-unsigned-package}" >
<os family="windows"/>
</condition>
<!-- Tools -->
<condition property="aapt" value="${android-tools}/aapt.exe" else="${android-tools}/aapt" >
<os family="windows"/>
</condition>
<condition property="aidl" value="${android-tools}/aidl.exe" else="${android-tools}/aidl" >
<os family="windows"/>
</condition>
<condition property="adb" value="${android-tools}/adb.exe" else="${android-tools}/adb" >
<os family="windows"/>
</condition>
<condition property="dx" value="${android-tools}/dx.bat" else="${android-tools}/dx" >
<os family="windows"/>
</condition>
<condition property="apk-builder" value="${android-tools}/apkbuilder.bat" else="${android-tools}/apkbuilder" >
<os family="windows"/>
</condition>
<property name="android-jar" value="${sdk-folder}/android.jar" />
<!-- Rules -->
<!-- Create the output directories if they don't exist yet. -->
<target name="dirs">
<echo>Creating output directories if needed...</echo>
<mkdir dir="${outdir}" />
<mkdir dir="${outdir-classes}" />
</target>
<!-- Generate the R.java file for this project's resources. -->
<target name="resource-src" depends="dirs">
<echo>Generating R.java / Manifest.java from the resources...</echo>
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-m" />
<arg value="-J" />
<arg value="${outdir-r}" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
</exec>
</target>
<!-- Generate java classes from .aidl files. -->
<target name="aidl" depends="dirs">
<echo>Compiling aidl files into Java classes...</echo>
<apply executable="${aidl}" failonerror="true">
<arg value="-p${android-framework}" />
<arg value="-I${srcdir}" />
<fileset dir="${srcdir}">
<include name="**/*.aidl"/>
</fileset>
</apply>
</target>
<!-- Compile this project's .java files into .class files. -->
<target name="compile" depends="dirs, resource-src, aidl">
<javac encoding="ascii" target="1.5" debug="true" extdirs=""
srcdir="."
destdir="${outdir-classes}"
bootclasspath="${android-jar}">
<classpath>
<fileset dir="${external-libs}" includes="*.jar"/>
</classpath>
</javac>
</target>
<!-- Convert this project's .class files into .dex files. -->
<target name="dex" depends="compile">
<echo>Converting compiled files and external libraries into ${outdir}/${dex-file}...</echo>
<apply executable="${dx}" failonerror="true" parallel="true">
<arg value="--dex" />
<arg value="--output=${intermediate-dex-ospath}" />
<arg path="${outdir-classes-ospath}" />
<fileset dir="${external-libs}" includes="*.jar"/>
</apply>
</target>
<!-- Put the project's resources into the output package file. -->
<target name="package-res-and-assets">
<echo>Packaging resources and assets...</echo>
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-f" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-A" />
<arg value="${asset-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
<arg value="-F" />
<arg value="${resources-package}" />
</exec>
</target>
<!-- Same as package-res-and-assets, but without "-A ${asset-dir}" -->
<target name="package-res-no-assets">
<echo>Packaging resources...</echo>
<exec executable="${aapt}" failonerror="true">
<arg value="package" />
<arg value="-f" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<!-- No assets directory -->
<arg value="-I" />
<arg value="${android-jar}" />
<arg value="-F" />
<arg value="${resources-package}" />
</exec>
</target>
<!-- Invoke the proper target depending on whether or not
an assets directory is present. -->
<!-- TODO: find a nicer way to include the "-A ${asset-dir}" argument
only when the assets dir exists. -->
<target name="package-res">
<available file="${asset-dir}" type="dir"
property="res-target" value="and-assets" />
<property name="res-target" value="no-assets" />
<antcall target="package-res-${res-target}" />
</target>
<!-- Package the application and sign it with a debug key.
This is the default target when building. It is used for debug. -->
<target name="debug" depends="dex, package-res">
<echo>Packaging ${out-debug-package}, and signing it with a debug key...</echo>
<exec executable="${apk-builder}" failonerror="true">
<arg value="${out-debug-package-ospath}" />
<arg value="-z" />
<arg value="${resources-package-ospath}" />
<arg value="-f" />
<arg value="${intermediate-dex-ospath}" />
<arg value="-rf" />
<arg value="${srcdir-ospath}" />
<arg value="-rj" />
<arg value="${external-libs-ospath}" />
<arg value="-nf" />
<arg value="${native-libs-ospath}" />
</exec>
</target>
<!-- Package the application without signing it.
This allows for the application to be signed later with an official publishing key. -->
<target name="release" depends="dex, package-res">
<echo>Packaging ${out-unsigned-package} for release...</echo>
<exec executable="${apk-builder}" failonerror="true">
<arg value="${out-unsigned-package-ospath}" />
<arg value="-u" />
<arg value="-z" />
<arg value="${resources-package-ospath}" />
<arg value="-f" />
<arg value="${intermediate-dex-ospath}" />
<arg value="-rf" />
<arg value="${srcdir-ospath}" />
<arg value="-rj" />
<arg value="${external-libs-ospath}" />
<arg value="-nf" />
<arg value="${native-libs-ospath}" />
</exec>
<echo>It will need to be signed with jarsigner before being published.</echo>
</target>
<!-- Install the package on the default emulator -->
<target name="install" depends="debug">
<echo>Installing ${out-debug-package} onto default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="install" />
<arg value="${out-debug-package}" />
</exec>
</target>
<target name="reinstall" depends="debug">
<echo>Installing ${out-debug-package} onto default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="install" />
<arg value="-r" />
<arg value="${out-debug-package}" />
</exec>
</target>
<!-- Uinstall the package from the default emulator -->
<target name="uninstall">
<echo>Uninstalling ${application-package} from the default emulator...</echo>
<exec executable="${adb}" failonerror="true">
<arg value="uninstall" />
<arg value="${application-package}" />
</exec>
</target>
<import file="${sdk-folder}/tools/lib/android_rules.xml" />
</project>

62
tools/scripts/combine_sdks.sh Executable file
View File

@@ -0,0 +1,62 @@
#!/bin/bash
function replace()
{
echo replacing $1
rm -rf $UNZIPPED_BASE_DIR/$1
cp -rf $UNZIPPED_IMAGE_DIR/$1 $UNZIPPED_BASE_DIR/$1
}
BASE=$1
IMAGES=$2
OUTPUT=$3
if [[ -z $BASE || -z $IMAGES || -z $OUTPUT ]] ; then
echo "usage: combine_sdks.sh BASE IMAGES OUTPUT"
echo
echo " BASE and IMAGES should be sdk zip files. The system image files,"
echo " emulator and other runtime files will be copied from IMAGES and"
echo " everything else will be copied from BASE. All of this will be"
echo " bundled into OUTPUT and zipped up again."
echo
exit 1
fi
TMP=$(mktemp -d)
TMP_ZIP=tmp.zip
BASE_DIR=$TMP/base
IMAGES_DIR=$TMP/images
OUTPUT_TMP_ZIP=$BASE_DIR/$TMP_ZIP
unzip -q $BASE -d $BASE_DIR
unzip -q $IMAGES -d $IMAGES_DIR
UNZIPPED_BASE_DIR=$(echo $BASE_DIR/*)
UNZIPPED_IMAGE_DIR=$(echo $IMAGES_DIR/*)
#
# The commands to copy over the files that we want
#
# replace tools/emulator # at this time we do not want the exe from SDK1.x
replace tools/lib/images
replace docs
replace android.jar
#
# end
#
pushd $BASE_DIR &> /dev/null
# rename the directory to the leaf minus the .zip of OUTPUT
LEAF=$(echo $OUTPUT | sed -e "s:.*\.zip/::" | sed -e "s:.zip$::")
mv * $LEAF
# zip it
zip -qr $TMP_ZIP $LEAF
popd &> /dev/null
cp $OUTPUT_TMP_ZIP $OUTPUT
rm -rf $TMP

View File

@@ -2,4 +2,17 @@
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
# Instead customize values in a "build.properties" file.
# location of the SDK
sdk-folder=ANDROID_SDK_FOLDER
# target mode. Value can be "platform" or "add-on"
target-mode=TARGET_MODE
# target API level.
target-api=TARGET_API
# target name, if target-mode=add-on
target-name=TARGET_NAME
# target platform. This is either the target itself or the platform the add-on is based on.
target-folder=TARGET_FOLDER

View File

@@ -0,0 +1,352 @@
#!/usr/bin/python2.4
#
# Copyright (C) 2008 Google Inc.
#
# Licensed 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.
#
"""Module to compress directories in to series of zip files.
This module will take a directory and compress all its contents, including
child directories into a series of zip files named N.zip where 'N' ranges from
0 to infinity. The zip files will all be below a certain specified maximum
threshold.
The directory is compressed with a depth first traversal, each directory's
file contents being compressed as it is visisted, before the compression of any
child directory's contents. In this way the files within an archive are ordered
and the archives themselves are ordered.
The class also constructs a 'main.py' file intended for use with Google App
Engine with a custom App Engine program not currently distributed with this
code base. The custom App Engine runtime can leverage the index files written
out by this class to more quickly locate which zip file to serve a given URL
from.
"""
__author__ = 'jmatt@google.com (Justin Mattson)'
from optparse import OptionParser
import os
import stat
import sys
import zipfile
from zipfile import ZipFile
import divide_and_compress_constants
def Main(argv):
parser = CreateOptionsParser()
(options, args) = parser.parse_args()
VerifyArguments(options, parser)
zipper = DirectoryZipper(options.destination,
options.sourcefiles,
ParseSize(options.filesize),
options.compress)
zipper.StartCompress()
def CreateOptionsParser():
rtn = OptionParser()
rtn.add_option('-s', '--sourcefiles', dest='sourcefiles', default=None,
help='The directory containing the files to compress')
rtn.add_option('-d', '--destination', dest='destination', default=None,
help=('Where to put the archive files, this should not be'
' a child of where the source files exist.'))
rtn.add_option('-f', '--filesize', dest='filesize', default='1M',
help=('Maximum size of archive files. A number followed by'
'a magnitude indicator, eg. 1000000B == one million '
'BYTES, 500K == five hundred KILOBYTES, 1.2M == one '
'point two MEGABYTES. 1M == 1048576 BYTES'))
rtn.add_option('-n', '--nocompress', action='store_false', dest='compress',
default=True,
help=('Whether the archive files should be compressed, or '
'just a concatenation of the source files'))
return rtn
def VerifyArguments(options, parser):
try:
if options.sourcefiles is None or options.destination is None:
parser.print_help()
sys.exit(-1)
except (AttributeError), err:
parser.print_help()
sys.exit(-1)
def ParseSize(size_str):
if len(size_str) < 2:
raise ValueError(('filesize argument not understood, please include'
' a numeric value and magnitude indicator'))
magnitude = size_str[len(size_str)-1:]
if not magnitude in ('K', 'B', 'M'):
raise ValueError(('filesize magnitude indicator not valid, must be \'K\','
'\'B\', or \'M\''))
numeral = float(size_str[0:len(size_str)-1])
if magnitude == 'K':
numeral *= 1024
elif magnitude == 'M':
numeral *= 1048576
return int(numeral)
class DirectoryZipper(object):
"""Class to compress a directory and all its sub-directories."""
current_archive = None
output_dir = None
base_path = None
max_size = None
compress = None
index_fp = None
def __init__(self, output_path, base_dir, archive_size, enable_compression):
"""DirectoryZipper constructor.
Args:
output_path: the path to write the archives and index file to
base_dir: the directory to compress
archive_size: the maximum size, in bytes, of a single archive file
enable_compression: whether or not compression should be enabled, if
disabled, the files will be written into an uncompresed zip
"""
self.output_dir = output_path
self.current_archive = '0.zip'
self.base_path = base_dir
self.max_size = archive_size
self.compress = enable_compression
def StartCompress(self):
"""Start compress of the directory.
This will start the compression process and write the archives to the
specified output directory. It will also produce an 'index.txt' file in the
output directory that maps from file to archive.
"""
self.index_fp = open(''.join([self.output_dir, 'main.py']), 'w')
self.index_fp.write(divide_and_compress_constants.file_preamble)
os.path.walk(self.base_path, self.CompressDirectory, 1)
self.index_fp.write(divide_and_compress_constants.file_endpiece)
self.index_fp.close()
def RemoveLastFile(self, archive_path=None):
"""Removes the last item in the archive.
This removes the last item in the archive by reading the items out of the
archive, adding them to a new archive, deleting the old archive, and
moving the new archive to the location of the old archive.
Args:
archive_path: Path to the archive to modify. This archive should not be
open elsewhere, since it will need to be deleted.
Return:
A new ZipFile object that points to the modified archive file
"""
if archive_path is None:
archive_path = ''.join([self.output_dir, self.current_archive])
# Move the old file and create a new one at its old location
ext_offset = archive_path.rfind('.')
old_archive = ''.join([archive_path[0:ext_offset], '-old',
archive_path[ext_offset:]])
os.rename(archive_path, old_archive)
old_fp = self.OpenZipFileAtPath(old_archive, mode='r')
if self.compress:
new_fp = self.OpenZipFileAtPath(archive_path,
mode='w',
compress=zipfile.ZIP_DEFLATED)
else:
new_fp = self.OpenZipFileAtPath(archive_path,
mode='w',
compress=zipfile.ZIP_STORED)
# Read the old archive in a new archive, except the last one
zip_members = enumerate(old_fp.infolist())
num_members = len(old_fp.infolist())
while num_members > 1:
this_member = zip_members.next()[1]
new_fp.writestr(this_member.filename, old_fp.read(this_member.filename))
num_members -= 1
# Close files and delete the old one
old_fp.close()
new_fp.close()
os.unlink(old_archive)
def OpenZipFileAtPath(self, path, mode=None, compress=zipfile.ZIP_DEFLATED):
"""This method is mainly for testing purposes, eg dependency injection."""
if mode is None:
if os.path.exists(path):
mode = 'a'
else:
mode = 'w'
if mode == 'r':
return ZipFile(path, mode)
else:
return ZipFile(path, mode, compress)
def CompressDirectory(self, irrelevant, dir_path, dir_contents):
"""Method to compress the given directory.
This method compresses the directory 'dir_path'. It will add to an existing
zip file that still has space and create new ones as necessary to keep zip
file sizes under the maximum specified size. This also writes out the
mapping of files to archives to the self.index_fp file descriptor
Args:
irrelevant: a numeric identifier passed by the os.path.walk method, this
is not used by this method
dir_path: the path to the directory to compress
dir_contents: a list of directory contents to be compressed
"""
# construct the queue of files to be added that this method will use
# it seems that dir_contents is given in reverse alphabetical order,
# so put them in alphabetical order by inserting to front of the list
dir_contents.sort()
zip_queue = []
if dir_path[len(dir_path) - 1:] == os.sep:
for filename in dir_contents:
zip_queue.append(''.join([dir_path, filename]))
else:
for filename in dir_contents:
zip_queue.append(''.join([dir_path, os.sep, filename]))
compress_bit = zipfile.ZIP_DEFLATED
if not self.compress:
compress_bit = zipfile.ZIP_STORED
# zip all files in this directory, adding to existing archives and creating
# as necessary
while len(zip_queue) > 0:
target_file = zip_queue[0]
if os.path.isfile(target_file):
self.AddFileToArchive(target_file, compress_bit)
# see if adding the new file made our archive too large
if not self.ArchiveIsValid():
# IF fixing fails, the last added file was to large, skip it
# ELSE the current archive filled normally, make a new one and try
# adding the file again
if not self.FixArchive('SIZE'):
zip_queue.pop(0)
else:
self.current_archive = '%i.zip' % (
int(self.current_archive[
0:self.current_archive.rfind('.zip')]) + 1)
else:
# if this the first file in the archive, write an index record
self.WriteIndexRecord()
zip_queue.pop(0)
else:
zip_queue.pop(0)
def WriteIndexRecord(self):
"""Write an index record to the index file.
Only write an index record if this is the first file to go into archive
Returns:
True if an archive record is written, False if it isn't
"""
archive = self.OpenZipFileAtPath(
''.join([self.output_dir, self.current_archive]), 'r')
archive_index = archive.infolist()
if len(archive_index) == 1:
self.index_fp.write(
'[\'%s\', \'%s\'],\n' % (self.current_archive,
archive_index[0].filename))
archive.close()
return True
else:
archive.close()
return False
def FixArchive(self, problem):
"""Make the archive compliant.
Args:
problem: the reason the archive is invalid
Returns:
Whether the file(s) removed to fix the archive could conceivably be
in an archive, but for some reason can't be added to this one.
"""
archive_path = ''.join([self.output_dir, self.current_archive])
rtn_value = None
if problem == 'SIZE':
archive_obj = self.OpenZipFileAtPath(archive_path, mode='r')
num_archive_files = len(archive_obj.infolist())
# IF there is a single file, that means its too large to compress,
# delete the created archive
# ELSE do normal finalization
if num_archive_files == 1:
print ('WARNING: %s%s is too large to store.' % (
self.base_path, archive_obj.infolist()[0].filename))
archive_obj.close()
os.unlink(archive_path)
rtn_value = False
else:
self.RemoveLastFile(''.join([self.output_dir, self.current_archive]))
archive_obj.close()
print 'Final archive size for %s is %i' % (
self.current_archive, os.stat(archive_path)[stat.ST_SIZE])
rtn_value = True
return rtn_value
def AddFileToArchive(self, filepath, compress_bit):
"""Add the file at filepath to the current archive.
Args:
filepath: the path of the file to add
compress_bit: whether or not this fiel should be compressed when added
Returns:
True if the file could be added (typically because this is a file) or
False if it couldn't be added (typically because its a directory)
"""
curr_archive_path = ''.join([self.output_dir, self.current_archive])
if os.path.isfile(filepath):
if os.stat(filepath)[stat.ST_SIZE] > 1048576:
print 'Warning: %s is potentially too large to serve on GAE' % filepath
archive = self.OpenZipFileAtPath(curr_archive_path,
compress=compress_bit)
# add the file to the archive
archive.write(filepath, filepath[len(self.base_path):])
archive.close()
return True
else:
return False
def ArchiveIsValid(self):
"""Check whether the archive is valid.
Currently this only checks whether the archive is under the required size.
The thought is that eventually this will do additional validation
Returns:
True if the archive is valid, False if its not
"""
archive_path = ''.join([self.output_dir, self.current_archive])
if os.stat(archive_path)[stat.ST_SIZE] > self.max_size:
return False
else:
return True
if __name__ == '__main__':
Main(sys.argv)

View File

@@ -0,0 +1,60 @@
#!/usr/bin/python2.4
#
# Copyright (C) 2008 Google Inc.
#
# Licensed 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.
#
"""Constants for the divide_and_compress script and DirectoryZipper class."""
__author__ = 'jmatt@google.com (Justin Mattson)'
file_preamble = ('#!/usr/bin/env python\n'
'#\n'
'# Copyright 2008 Google Inc.\n'
'#\n'
'# Licensed under the Apache License, Version 2.0 (the'
'\"License");\n'
'# you may not use this file except in compliance with the '
'License.\n'
'# You may obtain a copy of the License at\n'
'#\n'
'# http://www.apache.org/licenses/LICENSE-2.0\n'
'#\n'
'# Unless required by applicable law or agreed to in writing,'
' software\n'
'# distributed under the License is distributed on an \"AS'
'IS\" BASIS,\n'
'# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either '
'express or implied.\n'
'# See the License for the specific language governing'
' permissions and\n'
'# limitations under the License.\n'
'#\n\n'
'import wsgiref.handlers\n'
'from google.appengine.ext import zipserve\n'
'from google.appengine.ext import webapp\n'
'import memcache_zipserve\n\n\n'
'class MainHandler(webapp.RequestHandler):\n\n'
' def get(self):\n'
' self.response.out.write(\'Hello world!\')\n\n'
'def main():\n'
' application = webapp.WSGIApplication([(\'/(.*)\','
' memcache_zipserve.create_handler([')
file_endpiece = ('])),\n'
'],\n'
'debug=False)\n'
' wsgiref.handlers.CGIHandler().run(application)\n\n'
'if __name__ == \'__main__\':\n'
' main()')

View File

@@ -0,0 +1,21 @@
package PACKAGE;
import android.test.ActivityInstrumentationTestCase;
/**
* This is a simple framework for a test of an Application. See
* {@link android.test.ApplicationTestCase ApplicationTestCase} for more information on
* how to write and extend Application tests.
* <p/>
* To run this test, you can type:
* adb shell am instrument -w \
* -e class PACKAGE.ACTIVITY_NAMETest \
* PACKAGE.tests/android.test.InstrumentationTestRunner
*/
public class ACTIVITY_NAMETest extends ActivityInstrumentationTestCase<ACTIVITY_NAME> {
public ACTIVITY_NAMETest() {
super("PACKAGE", ACTIVITY_NAME.class);
}
}

View File

@@ -1,4 +1,4 @@
# begin plugin.prop
plugin.version=0.8.0
plugin.version=0.9.0
plugin.platform=android
# end plugin.prop

View File

@@ -0,0 +1,490 @@
#!/usr/bin/python2.4
#
# Copyright (C) 2008 Google Inc.
#
# Licensed 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.
#
"""Tests for divide_and_compress.py.
TODO: Add tests for module methods.
"""
__author__ = 'jmatt@google.com (Justin Mattson)'
import os
import stat
import unittest
import zipfile
from zipfile import ZipFile
import divide_and_compress
from mox import mox
class BagOfParts(object):
"""Just a generic class that I can use to assign random attributes to."""
def NoOp(self):
x = 1
class ValidAndRemoveTests(unittest.TestCase):
"""Test the ArchiveIsValid and RemoveLastFile methods."""
def setUp(self):
"""Prepare the test.
Construct some mock objects for use with the tests.
"""
self.my_mox = mox.Mox()
file1 = BagOfParts()
file1.filename = 'file1.txt'
file1.contents = 'This is a test file'
file2 = BagOfParts()
file2.filename = 'file2.txt'
file2.contents = ('akdjfk;djsf;kljdslkfjslkdfjlsfjkdvn;kn;2389rtu4i'
'tn;ghf8:89H*hp748FJw80fu9WJFpwf39pujens;fihkhjfk'
'sdjfljkgsc n;iself')
self.files = {'file1': file1, 'file2': file2}
def testArchiveIsValid(self):
"""Test the DirectoryZipper.ArchiveIsValid method.
Run two tests, one that we expect to pass and one that we expect to fail
"""
test_file_size = 1056730
self.my_mox.StubOutWithMock(os, 'stat')
os.stat('/foo/0.zip').AndReturn([test_file_size])
self.my_mox.StubOutWithMock(stat, 'ST_SIZE')
stat.ST_SIZE = 0
os.stat('/baz/0.zip').AndReturn([test_file_size])
mox.Replay(os.stat)
test_target = divide_and_compress.DirectoryZipper('/foo/', 'bar',
test_file_size - 1, True)
self.assertEqual(False, test_target.ArchiveIsValid(),
msg=('ERROR: Test failed, ArchiveIsValid should have '
'returned false, but returned true'))
test_target = divide_and_compress.DirectoryZipper('/baz/', 'bar',
test_file_size + 1, True)
self.assertEqual(True, test_target.ArchiveIsValid(),
msg=('ERROR: Test failed, ArchiveIsValid should have'
' returned true, but returned false'))
def testRemoveLastFile(self):
"""Test DirectoryZipper.RemoveLastFile method.
Construct a ZipInfo mock object with two records, verify that write is
only called once on the new ZipFile object.
"""
source = self.CreateZipSource()
dest = self.CreateZipDestination()
source_path = ''.join([os.getcwd(), '/0-old.zip'])
dest_path = ''.join([os.getcwd(), '/0.zip'])
test_target = divide_and_compress.DirectoryZipper(
''.join([os.getcwd(), '/']), 'dummy', 1024*1024, True)
self.my_mox.StubOutWithMock(test_target, 'OpenZipFileAtPath')
test_target.OpenZipFileAtPath(source_path, mode='r').AndReturn(source)
test_target.OpenZipFileAtPath(dest_path,
compress=zipfile.ZIP_DEFLATED,
mode='w').AndReturn(dest)
self.my_mox.StubOutWithMock(os, 'rename')
os.rename(dest_path, source_path)
self.my_mox.StubOutWithMock(os, 'unlink')
os.unlink(source_path)
self.my_mox.ReplayAll()
test_target.RemoveLastFile()
self.my_mox.VerifyAll()
def CreateZipSource(self):
"""Create a mock zip sourec object.
Read should only be called once, because the second file is the one
being removed.
Returns:
A configured mocked
"""
source_zip = self.my_mox.CreateMock(ZipFile)
source_zip.infolist().AndReturn([self.files['file1'], self.files['file1']])
source_zip.infolist().AndReturn([self.files['file1'], self.files['file1']])
source_zip.read(self.files['file1'].filename).AndReturn(
self.files['file1'].contents)
source_zip.close()
return source_zip
def CreateZipDestination(self):
"""Create mock destination zip.
Write should only be called once, because there are two files in the
source zip and we expect the second to be removed.
Returns:
A configured mocked
"""
dest_zip = mox.MockObject(ZipFile)
dest_zip.writestr(self.files['file1'].filename,
self.files['file1'].contents)
dest_zip.close()
return dest_zip
def tearDown(self):
"""Remove any stubs we've created."""
self.my_mox.UnsetStubs()
class FixArchiveTests(unittest.TestCase):
"""Tests for the DirectoryZipper.FixArchive method."""
def setUp(self):
"""Create a mock file object."""
self.my_mox = mox.Mox()
self.file1 = BagOfParts()
self.file1.filename = 'file1.txt'
self.file1.contents = 'This is a test file'
def _InitMultiFileData(self):
"""Create an array of mock file objects.
Create three mock file objects that we can use for testing.
"""
self.multi_file_dir = []
file1 = BagOfParts()
file1.filename = 'file1.txt'
file1.contents = 'kjaskl;jkdjfkja;kjsnbvjnvnbuewklriujalvjsd'
self.multi_file_dir.append(file1)
file2 = BagOfParts()
file2.filename = 'file2.txt'
file2.contents = ('He entered the room and there in the center, it was.'
' Looking upon the thing, suddenly he could not remember'
' whether he had actually seen it before or whether'
' his memory of it was merely the effect of something'
' so often being imagined that it had long since become '
' manifest in his mind.')
self.multi_file_dir.append(file2)
file3 = BagOfParts()
file3.filename = 'file3.txt'
file3.contents = 'Whoa, what is \'file2.txt\' all about?'
self.multi_file_dir.append(file3)
def testSingleFileArchive(self):
"""Test behavior of FixArchive when the archive has a single member.
We expect that when this method is called with an archive that has a
single member that it will return False and unlink the archive.
"""
test_target = divide_and_compress.DirectoryZipper(
''.join([os.getcwd(), '/']), 'dummy', 1024*1024, True)
self.my_mox.StubOutWithMock(test_target, 'OpenZipFileAtPath')
test_target.OpenZipFileAtPath(
''.join([os.getcwd(), '/0.zip']), mode='r').AndReturn(
self.CreateSingleFileMock())
self.my_mox.StubOutWithMock(os, 'unlink')
os.unlink(''.join([os.getcwd(), '/0.zip']))
self.my_mox.ReplayAll()
self.assertEqual(False, test_target.FixArchive('SIZE'))
self.my_mox.VerifyAll()
def CreateSingleFileMock(self):
"""Create a mock ZipFile object for testSingleFileArchive.
We just need it to return a single member infolist twice
Returns:
A configured mock object
"""
mock_zip = self.my_mox.CreateMock(ZipFile)
mock_zip.infolist().AndReturn([self.file1])
mock_zip.infolist().AndReturn([self.file1])
mock_zip.close()
return mock_zip
def testMultiFileArchive(self):
"""Test behavior of DirectoryZipper.FixArchive with a multi-file archive.
We expect that FixArchive will rename the old archive, adding '-old' before
'.zip', read all the members except the last one of '-old' into a new
archive with the same name as the original, and then unlink the '-old' copy
"""
test_target = divide_and_compress.DirectoryZipper(
''.join([os.getcwd(), '/']), 'dummy', 1024*1024, True)
self.my_mox.StubOutWithMock(test_target, 'OpenZipFileAtPath')
test_target.OpenZipFileAtPath(
''.join([os.getcwd(), '/0.zip']), mode='r').AndReturn(
self.CreateMultiFileMock())
self.my_mox.StubOutWithMock(test_target, 'RemoveLastFile')
test_target.RemoveLastFile(''.join([os.getcwd(), '/0.zip']))
self.my_mox.StubOutWithMock(os, 'stat')
os.stat(''.join([os.getcwd(), '/0.zip'])).AndReturn([49302])
self.my_mox.StubOutWithMock(stat, 'ST_SIZE')
stat.ST_SIZE = 0
self.my_mox.ReplayAll()
self.assertEqual(True, test_target.FixArchive('SIZE'))
self.my_mox.VerifyAll()
def CreateMultiFileMock(self):
"""Create mock ZipFile object for use with testMultiFileArchive.
The mock just needs to return the infolist mock that is prepared in
InitMultiFileData()
Returns:
A configured mock object
"""
self._InitMultiFileData()
mock_zip = self.my_mox.CreateMock(ZipFile)
mock_zip.infolist().AndReturn(self.multi_file_dir)
mock_zip.close()
return mock_zip
def tearDown(self):
"""Unset any mocks that we've created."""
self.my_mox.UnsetStubs()
class AddFileToArchiveTest(unittest.TestCase):
"""Test behavior of method to add a file to an archive."""
def setUp(self):
"""Setup the arguments for the DirectoryZipper object."""
self.my_mox = mox.Mox()
self.output_dir = '%s/' % os.getcwd()
self.file_to_add = 'file.txt'
self.input_dir = '/foo/bar/baz/'
def testAddFileToArchive(self):
"""Test the DirectoryZipper.AddFileToArchive method.
We are testing a pretty trivial method, we just expect it to look at the
file its adding, so that it possible can through out a warning.
"""
test_target = divide_and_compress.DirectoryZipper(self.output_dir,
self.input_dir,
1024*1024, True)
self.my_mox.StubOutWithMock(test_target, 'OpenZipFileAtPath')
archive_mock = self.CreateArchiveMock()
test_target.OpenZipFileAtPath(
''.join([self.output_dir, '0.zip']),
compress=zipfile.ZIP_DEFLATED).AndReturn(archive_mock)
self.StubOutOsModule()
self.my_mox.ReplayAll()
test_target.AddFileToArchive(''.join([self.input_dir, self.file_to_add]),
zipfile.ZIP_DEFLATED)
self.my_mox.VerifyAll()
def StubOutOsModule(self):
"""Create a mock for the os.path and os.stat objects.
Create a stub that will return the type (file or directory) and size of the
object that is to be added.
"""
self.my_mox.StubOutWithMock(os.path, 'isfile')
os.path.isfile(''.join([self.input_dir, self.file_to_add])).AndReturn(True)
self.my_mox.StubOutWithMock(os, 'stat')
os.stat(''.join([self.input_dir, self.file_to_add])).AndReturn([39480])
self.my_mox.StubOutWithMock(stat, 'ST_SIZE')
stat.ST_SIZE = 0
def CreateArchiveMock(self):
"""Create a mock ZipFile for use with testAddFileToArchive.
Just verify that write is called with the file we expect and that the
archive is closed after the file addition
Returns:
A configured mock object
"""
archive_mock = self.my_mox.CreateMock(ZipFile)
archive_mock.write(''.join([self.input_dir, self.file_to_add]),
self.file_to_add)
archive_mock.close()
return archive_mock
def tearDown(self):
self.my_mox.UnsetStubs()
class CompressDirectoryTest(unittest.TestCase):
"""Test the master method of the class.
Testing with the following directory structure.
/dir1/
/dir1/file1.txt
/dir1/file2.txt
/dir1/dir2/
/dir1/dir2/dir3/
/dir1/dir2/dir4/
/dir1/dir2/dir4/file3.txt
/dir1/dir5/
/dir1/dir5/file4.txt
/dir1/dir5/file5.txt
/dir1/dir5/file6.txt
/dir1/dir5/file7.txt
/dir1/dir6/
/dir1/dir6/file8.txt
file1.txt., file2.txt, file3.txt should be in 0.zip
file4.txt should be in 1.zip
file5.txt, file6.txt should be in 2.zip
file7.txt will not be stored since it will be too large compressed
file8.txt should b in 3.zip
"""
def setUp(self):
"""Setup all the mocks for this test."""
self.my_mox = mox.Mox()
self.base_dir = '/dir1'
self.output_path = '/out_dir/'
self.test_target = divide_and_compress.DirectoryZipper(
self.output_path, self.base_dir, 1024*1024, True)
self.InitArgLists()
self.InitOsDotPath()
self.InitArchiveIsValid()
self.InitWriteIndexRecord()
self.InitAddFileToArchive()
def tearDown(self):
self.my_mox.UnsetStubs()
def testCompressDirectory(self):
"""Test the DirectoryZipper.CompressDirectory method."""
self.my_mox.ReplayAll()
for arguments in self.argument_lists:
self.test_target.CompressDirectory(None, arguments[0], arguments[1])
self.my_mox.VerifyAll()
def InitAddFileToArchive(self):
"""Setup mock for DirectoryZipper.AddFileToArchive.
Make sure that the files are added in the order we expect.
"""
self.my_mox.StubOutWithMock(self.test_target, 'AddFileToArchive')
self.test_target.AddFileToArchive('/dir1/file1.txt', zipfile.ZIP_DEFLATED)
self.test_target.AddFileToArchive('/dir1/file2.txt', zipfile.ZIP_DEFLATED)
self.test_target.AddFileToArchive('/dir1/dir2/dir4/file3.txt',
zipfile.ZIP_DEFLATED)
self.test_target.AddFileToArchive('/dir1/dir5/file4.txt',
zipfile.ZIP_DEFLATED)
self.test_target.AddFileToArchive('/dir1/dir5/file4.txt',
zipfile.ZIP_DEFLATED)
self.test_target.AddFileToArchive('/dir1/dir5/file5.txt',
zipfile.ZIP_DEFLATED)
self.test_target.AddFileToArchive('/dir1/dir5/file5.txt',
zipfile.ZIP_DEFLATED)
self.test_target.AddFileToArchive('/dir1/dir5/file6.txt',
zipfile.ZIP_DEFLATED)
self.test_target.AddFileToArchive('/dir1/dir5/file7.txt',
zipfile.ZIP_DEFLATED)
self.test_target.AddFileToArchive('/dir1/dir5/file7.txt',
zipfile.ZIP_DEFLATED)
self.test_target.AddFileToArchive('/dir1/dir6/file8.txt',
zipfile.ZIP_DEFLATED)
def InitWriteIndexRecord(self):
"""Setup mock for DirectoryZipper.WriteIndexRecord."""
self.my_mox.StubOutWithMock(self.test_target, 'WriteIndexRecord')
# we are trying to compress 8 files, but we should only attempt to
# write an index record 7 times, because one file is too large to be stored
self.test_target.WriteIndexRecord().AndReturn(True)
self.test_target.WriteIndexRecord().AndReturn(False)
self.test_target.WriteIndexRecord().AndReturn(False)
self.test_target.WriteIndexRecord().AndReturn(True)
self.test_target.WriteIndexRecord().AndReturn(True)
self.test_target.WriteIndexRecord().AndReturn(False)
self.test_target.WriteIndexRecord().AndReturn(True)
def InitArchiveIsValid(self):
"""Mock out DirectoryZipper.ArchiveIsValid and DirectoryZipper.FixArchive.
Mock these methods out such that file1, file2, and file3 go into one
archive. file4 then goes into the next archive, file5 and file6 in the
next, file 7 should appear too large to compress into an archive, and
file8 goes into the final archive
"""
self.my_mox.StubOutWithMock(self.test_target, 'ArchiveIsValid')
self.my_mox.StubOutWithMock(self.test_target, 'FixArchive')
self.test_target.ArchiveIsValid().AndReturn(True)
self.test_target.ArchiveIsValid().AndReturn(True)
self.test_target.ArchiveIsValid().AndReturn(True)
# should be file4.txt
self.test_target.ArchiveIsValid().AndReturn(False)
self.test_target.FixArchive('SIZE').AndReturn(True)
self.test_target.ArchiveIsValid().AndReturn(True)
# should be file5.txt
self.test_target.ArchiveIsValid().AndReturn(False)
self.test_target.FixArchive('SIZE').AndReturn(True)
self.test_target.ArchiveIsValid().AndReturn(True)
self.test_target.ArchiveIsValid().AndReturn(True)
# should be file7.txt
self.test_target.ArchiveIsValid().AndReturn(False)
self.test_target.FixArchive('SIZE').AndReturn(True)
self.test_target.ArchiveIsValid().AndReturn(False)
self.test_target.FixArchive('SIZE').AndReturn(False)
self.test_target.ArchiveIsValid().AndReturn(True)
def InitOsDotPath(self):
"""Mock out os.path.isfile.
Mock this out so the things we want to appear as files appear as files and
the things we want to appear as directories appear as directories. Also
make sure that the order of file visits is as we expect (which is why
InAnyOrder isn't used here).
"""
self.my_mox.StubOutWithMock(os.path, 'isfile')
os.path.isfile('/dir1/dir2').AndReturn(False)
os.path.isfile('/dir1/dir5').AndReturn(False)
os.path.isfile('/dir1/dir6').AndReturn(False)
os.path.isfile('/dir1/file1.txt').AndReturn(True)
os.path.isfile('/dir1/file2.txt').AndReturn(True)
os.path.isfile('/dir1/dir2/dir3').AndReturn(False)
os.path.isfile('/dir1/dir2/dir4').AndReturn(False)
os.path.isfile('/dir1/dir2/dir4/file3.txt').AndReturn(True)
os.path.isfile('/dir1/dir5/file4.txt').AndReturn(True)
os.path.isfile('/dir1/dir5/file4.txt').AndReturn(True)
os.path.isfile('/dir1/dir5/file5.txt').AndReturn(True)
os.path.isfile('/dir1/dir5/file5.txt').AndReturn(True)
os.path.isfile('/dir1/dir5/file6.txt').AndReturn(True)
os.path.isfile('/dir1/dir5/file7.txt').AndReturn(True)
os.path.isfile('/dir1/dir5/file7.txt').AndReturn(True)
os.path.isfile('/dir1/dir6/file8.txt').AndReturn(True)
def InitArgLists(self):
"""Create the directory path => directory contents mappings."""
self.argument_lists = []
self.argument_lists.append(['/dir1',
['file1.txt', 'file2.txt', 'dir2', 'dir5',
'dir6']])
self.argument_lists.append(['/dir1/dir2', ['dir3', 'dir4']])
self.argument_lists.append(['/dir1/dir2/dir3', []])
self.argument_lists.append(['/dir1/dir2/dir4', ['file3.txt']])
self.argument_lists.append(['/dir1/dir5',
['file4.txt', 'file5.txt', 'file6.txt',
'file7.txt']])
self.argument_lists.append(['/dir1/dir6', ['file8.txt']])
if __name__ == '__main__':
unittest.main()