Merge branch 'apache-tour-de-flex-1.2' Conflicts: installer/src/InstallApacheFlex.mxml
diff --git a/installer/README b/installer/README index a7d7e1e..7a403fd 100644 --- a/installer/README +++ b/installer/README
@@ -19,7 +19,7 @@ ========================================================================================== Overview: -========= +========================================================================================== - The Apache Flex SDK Installer AIR application provides an easy installation of the Apache Flex SDK and all its dependencies. This will make it suitable for working with @@ -127,7 +127,7 @@ file (var: TEMP_PASS_CHANGE_THIS) ========================================================================================== -How to set up the project for working with Adobe Flash Builder (or any other IDE): +How to set up the project for working with Adobe Flash Builder 4.7: ========================================================================================== 1. Unzip the source distribution. You should see the 'installer' directory and the @@ -151,3 +151,52 @@ 7. In the installer project, add ${APACHE_FLEX_UTILITIES_ROOT}/ant_on_air/locale/{locale} as a source path. +========================================================================================== +How to set up the project for working with JetBrains IDEA 12+ +========================================================================================== + +1. Setup a new project by either unzipping the downloaded source or grabbing the source from the version control. + +2. During the project setup, DO NOT search for modules or frameworks. We will set these up later. + +3. Setup a new module by going to the File -> New Module menu. + Module Type : Flash + Target Platform : Desktop + Output Type : Application + Create Sample App : Unchecked + Create HTML Wrapper : Unchecked + + Create the new module, name it "installer" and chose the ${APACHE_FLEX_UTILITIES_ROOT}/installer directory + +4. After the module is created, go into the installer module settings (Right-Click -> Open Module Settings) + +5. Add the following Content Roots : + flex-utilities\ant_on_air + flex-utilities\common + +6. Mark the following directories as Sources : (some may already be marked as src) + flex-utilities\ant_on_air\src + flex-utilities\ant_on_air\external + flex-utilities\common\src + flex-utilities\installer\src + +7. Close the Settings dialog + +8. Open the Ant Build tab within IDEA. + Add the flex-utilities\build.xml ANT build script. + +9. Run the get-as3commons.swc ant target. This will download the required SWC to build the installer. + +10. Return to the module properties, and go to the dependencies tab. Make sure the following are listed : + Flex SDK + flex-utilities\installer\libs + flex-utilities\installer\common\bin\common.swc + flex-utilities\installer\ant_on_air\bin\ant_on_air.swc + flex-utilities\ant_on_air\external\libs\as3commons-zip-1.0.0-alpha.1.swc + +11. Apply and close the dialog box. + +12. Update the flex-utilities\installer\build.properties to match your settings. In theory you should only + have to update the FLEX_HOME_WIN or FLEX_HOME_MAC property to point to your SDK with AIR 4.0 overlaid. + +You should now be able to build and debug the installer.
diff --git a/mavenizer/src/main/java/SDKGenerator.java b/mavenizer/src/main/java/SDKGenerator.java new file mode 100644 index 0000000..c69eda6 --- /dev/null +++ b/mavenizer/src/main/java/SDKGenerator.java
@@ -0,0 +1,249 @@ +/* + * 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. + */ +import java.io.*; +import javax.xml.parsers.*; + +import air.AirCompilerGenerator; +import common.ConversionPlan; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; +import air.AirFrameworkGenerator; +import air.AirRuntimeGenerator; +import flex.FlexCompilerGenerator; +import flex.FlexFrameworkGenerator; +import flex.FlexRuntimeGenerator; + +/** + * Created with IntelliJ IDEA. + * User: cdutz + * Date: 11.05.12 + * Time: 12:03 + */ +public class SDKGenerator { + + protected void buildAirConversionPlan(ConversionPlan plan, File sdkSourceDirectory) { + final File sdkDirectories[] = sdkSourceDirectory.listFiles(new FileFilter() { + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + }); + if (sdkDirectories != null) { + for (final File sdkDirectory : sdkDirectories) { + final String sdkVersion = getAirSdkVersion(sdkDirectory); + if(sdkVersion != null) { + plan.addVersion(sdkVersion, sdkDirectory, false); + } + } + } + } + + /** + * All this little helper does is list up all directories in the given base directory and + * trigger the actual import on that. If a flex sdk comes with an air runtime, the structure + * is identical to that of an ordinary air sdk. Therefore the import works if a flex sdk or + * an air sdk directory is passed to this method. + * + * @param plan conversion plan for converting the air sdks containing the air content + * @param sdkTargetDirectory directory where to copy the content + * @throws Exception + */ + public void generateAllAir(ConversionPlan plan, File sdkTargetDirectory) throws Exception { + for(final String airVersion : plan.getVersionIterator()) { + final File airDirectory = plan.getDirectory(airVersion); + + System.out.println("---------------------------------------------"); + System.out.println("-- Generating Air SDK version: " + airVersion); + System.out.println("---------------------------------------------"); + + generateAir(airDirectory, sdkTargetDirectory, airVersion); + } + } + + public void generateAir(final File sdkSourceDirectory, final File sdkTargetDirectory, final String sdkVersion) throws Exception { + // Generate the artifacts, needed by the air compiler. + new AirCompilerGenerator().process(sdkSourceDirectory, false, sdkTargetDirectory, sdkVersion, false); + + // Generate the artifacts, needed by the flex application. + new AirFrameworkGenerator().process(sdkSourceDirectory, false, sdkTargetDirectory, sdkVersion, false); + + // Deploy the FlashPlayer and AIR runtime binaries. + new AirRuntimeGenerator().process(sdkSourceDirectory, false, sdkTargetDirectory, sdkVersion, false); + } + + protected void buildFlexConversionPlan(ConversionPlan plan, File sdkSourceDirectory) { + final File sdkDirectories[] = sdkSourceDirectory.listFiles(new FileFilter() { + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + }); + if (sdkDirectories != null) { + // Build a sorted set of versions as well as maps for the additional information + // to allow sorted conversion of the Flex SDKs. + for (final File sdkDirectory : sdkDirectories) { + String fdkVersion = getFlexSdkVersion(sdkDirectory); + // Apache FDKs have the version prefix "Apache-" + // So this is what we use in order to determine what type of FDK it is. + final boolean isApache = fdkVersion.startsWith("Apache-"); + if (isApache) { + fdkVersion = fdkVersion.substring("Apache-".length()); + } + plan.addVersion(fdkVersion, sdkDirectory, isApache); + } + } + } + + public void generateAllFlex(ConversionPlan plan, File sdkTargetDirectory, boolean useApache) throws Exception { + for(final String fdkVersion : plan.getVersionIterator()) { + final File fdkDirectory = plan.getDirectory(fdkVersion); + final boolean isApache = plan.getApacheFlag(fdkVersion); + + System.out.println("---------------------------------------------"); + System.out.println("-- Generating Flex SDK version: " + fdkVersion); + System.out.println("---------------------------------------------"); + + generateFlex(fdkDirectory, isApache, sdkTargetDirectory, fdkVersion, useApache); + } + } + + public void generateFlex(final File sdkSourceDirectory, final boolean isApache, final File sdkTargetDirectory, + final String sdkVersion, final boolean useApache) throws Exception { + // Generate the artifacts, needed by the flex compiler. + new FlexCompilerGenerator().process(sdkSourceDirectory, isApache, sdkTargetDirectory, sdkVersion, useApache); + + // Generate the artifacts, needed by the flex application. + new FlexFrameworkGenerator().process(sdkSourceDirectory, isApache, sdkTargetDirectory, sdkVersion, useApache); + + // Deploy the FlashPlayer and AIR runtime binaries. + new FlexRuntimeGenerator().process(sdkSourceDirectory, isApache, sdkTargetDirectory, sdkVersion, useApache); + } + + public static void main(String[] args) throws Exception { + + if (args.length != 3) { + System.out.println("Usage: SDKGenerator {source-directory} {target-directory} {use-apache-gid}"); + System.exit(0); + } + + final String sdkSourceDirectoryName = args[0]; + final String sdkTargetDirectoryName = args[1]; + final boolean useApache = Boolean.valueOf(args[2]); + + final File sdkSourceDirectory = new File(sdkSourceDirectoryName); + final File sdkTargetDirectory = new File(sdkTargetDirectoryName); + + // When generating the fdks the generator tries to figure out the flashplayer-version and air-version + // by comparing the hash of the playerglobal.swc and airglobal.swc with some hashes. This list of + // hashes has to be created first. Therefore the Generator generates air artifacts by processing air + // sdk directories and then by extracting the needed artifacts from the flex fdks. + final SDKGenerator generator = new SDKGenerator(); + final ConversionPlan airPlan = new ConversionPlan(); + generator.buildAirConversionPlan(airPlan, new File(sdkSourceDirectory, "air")); + generator.buildAirConversionPlan(airPlan, new File(sdkSourceDirectory, "flex")); + generator.generateAllAir(airPlan, sdkTargetDirectory); + + // After the air artifacts are generated and + final ConversionPlan flexPlan = new ConversionPlan(); + generator.buildFlexConversionPlan(flexPlan, new File(sdkSourceDirectory, "flex")); + generator.generateAllFlex(flexPlan, sdkTargetDirectory, useApache); + } + + /** + * The only place I found where to extract the version of an Air SDK was the "AIR SDK Readme.txt" file. + * In order to get the version we need to cut out the version-part from the title-row of that text file. + * This file is present in the root of a pure air sdk or in the root of a flex sdk, therefore the same + * algorithm works if sdkSourceDirectory points to a flex sdk or an air sdk. + * + * @param sdkSourceDirectory directory in which to look for the sdk descriptor file of an air sdk + * @return version of the sdk in th given directory + */ + public static String getAirSdkVersion(final File sdkSourceDirectory) { + final File sdkDescriptor = new File(sdkSourceDirectory, "AIR SDK Readme.txt"); + + if (sdkDescriptor.exists()) { + DataInputStream in = null; + try { + final FileInputStream fstream = new FileInputStream(sdkDescriptor); + in = new DataInputStream(fstream); + final BufferedReader br = new BufferedReader(new InputStreamReader(in)); + final String strLine = br.readLine(); + return strLine.substring("Adobe AIR ".length(), strLine.indexOf(" ", "Adobe AIR ".length())); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ioe) { + // Ignore. + } + } + } + } + return null; + } + + /** + * The Flex SDK version is contained in the flex-sdk-description.xml file. + * + * @param sdkSourceDirectory directory where to look for the fdk descriptor file + * @return version string of the fdk + */ + public static String getFlexSdkVersion(final File sdkSourceDirectory) { + final File sdkDescriptor = new File(sdkSourceDirectory, "flex-sdk-description.xml"); + + final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + try { + // Parse the document + final DocumentBuilder db = dbf.newDocumentBuilder(); + final Document dom = db.parse(sdkDescriptor); + + // Get name, version and build nodes + final Element root = dom.getDocumentElement(); + final String name = root.getElementsByTagName("name").item(0).getTextContent(); + final String version = root.getElementsByTagName("version").item(0).getTextContent(); + final String build = root.getElementsByTagName("build").item(0).getTextContent(); + + // In general the version consists of the content of the version element with an appended build-number. + String sdkVersion = (build.equals("0")) ? version + "-SNAPSHOT" : version + "." + build; + + // Deal with the patched re-releases of all older SDKs: + // The patched versions have A or B appended to their name and not a modified version or build number. + // In order to differentiate the patched versions from the un-patched ones, we appnd A or B to the + // version string. + if (name.endsWith("A")) { + sdkVersion += "A"; + } else if (name.endsWith("B")) { + sdkVersion += "B"; + } + + // If the name contains "Apache", we prefix the version with "Apache-". This is cut off + // again later on. + if (name.contains("Apache")) { + sdkVersion = "Apache-" + sdkVersion; + } + + return sdkVersion; + } catch (ParserConfigurationException pce) { + throw new RuntimeException(pce); + } catch (SAXException se) { + throw new RuntimeException(se); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } +}
diff --git a/mavenizer/src/main/java/SDKInVMDeployer.java b/mavenizer/src/main/java/SDKInVMDeployer.java new file mode 100644 index 0000000..d1643ab --- /dev/null +++ b/mavenizer/src/main/java/SDKInVMDeployer.java
@@ -0,0 +1,241 @@ +/* + * 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. + */ + +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.apache.maven.repository.internal.DefaultArtifactDescriptorReader; +import org.apache.maven.repository.internal.DefaultVersionRangeResolver; +import org.apache.maven.repository.internal.DefaultVersionResolver; +import org.apache.maven.repository.internal.MavenRepositorySystemUtils; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; +import org.eclipse.aether.deployment.DeployRequest; +import org.eclipse.aether.deployment.DeploymentException; +import org.eclipse.aether.impl.*; +import org.eclipse.aether.installation.InstallationException; +import org.eclipse.aether.internal.impl.DefaultDependencyCollector; +import org.eclipse.aether.internal.impl.DefaultTransporterProvider; +import org.eclipse.aether.repository.Authentication; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.spi.connector.transport.TransporterProvider; +import org.eclipse.aether.transport.file.FileTransporterFactory; +import org.eclipse.aether.transport.http.HttpTransporterFactory; +import org.eclipse.aether.transport.wagon.WagonTransporterFactory; +import org.eclipse.aether.util.repository.AuthenticationBuilder; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; + +/** + * Updated Version of the SDKDeployer which no longer relies on an installed Maven + * system and which performs the deployment inside the VM without having to spawn new + * VMs for each artifact in order to deploy the files using a Maven commandline + * execution. + * + * Created with IntelliJ IDEA. + * User: cdutz + * Date: 03.11.13 + * + * @author Christofer Dutz + */ +public class SDKInVMDeployer { + + private String directory; + private String url; + private String username; + private String password; + + + public SDKInVMDeployer(String[] parameters) { + this.directory = parameters[0]; + this.url = parameters[1]; + if (parameters.length > 2) { + this.username = parameters[2]; + this.password = parameters[3]; + } + } + + public static void main(String[] args) { + if ((args.length != 2) && (args.length != 4)) { + printUsage(); + System.exit(0); + } + + final SDKInVMDeployer deployer = new SDKInVMDeployer(args); + deployer.start(); + } + + private static void printUsage() { + System.out.println("\nUsage: java -cp flex-sdk-converter-1.0.jar SDKInVMDeployer \"directory\" \"url\" [\"username\", \"password\"]\n"); + System.out.println("The SDKDeployer needs at least 2 ordered parameters separated by spaces:"); + System.out.println("\t1- directory: The path to the directory containing the artifacts that should be deployed."); + System.out.println("\t2- url: URL where the artifacts will be deployed."); + System.out.println("If the targeted repository requires authentication two more parameters have to be provided:"); + System.out.println("\t3- username: The username used to authenticate on the target repository."); + System.out.println("\t4- password: The password used to authenticate on the target repository."); + } + + private void start() { + try { + final DefaultServiceLocator locator = new DefaultServiceLocator(); + locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class); + locator.addService(VersionResolver.class, DefaultVersionResolver.class); + locator.addService(VersionRangeResolver.class, DefaultVersionRangeResolver.class); + locator.addService(ArtifactDescriptorReader.class, DefaultArtifactDescriptorReader.class); + locator.addService(DependencyCollector.class, DefaultDependencyCollector.class); + locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class); + locator.addService(TransporterProvider.class, DefaultTransporterProvider.class); + locator.addService(TransporterFactory.class, FileTransporterFactory.class); + locator.addService(TransporterFactory.class, HttpTransporterFactory.class); + locator.addService(TransporterFactory.class, WagonTransporterFactory.class); + + final RepositorySystem repositorySystem = locator.getService(RepositorySystem.class); + + if (repositorySystem == null) { + System.out.println("Couldn't initialize local maven repository system."); + System.exit(0); + } else { + // Setup the repository system session based upon the current maven settings.xml. + final DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); + final LocalRepository localRepo = new LocalRepository(directory); + RemoteRepository.Builder repoBuilder = new RemoteRepository.Builder("repo", "default", url); + if ((username != null) && (password != null)) { + final Authentication authentication = new AuthenticationBuilder().addUsername( + username).addPassword(password).build(); + repoBuilder.setAuthentication(authentication); + } + final RemoteRepository remoteRepository = repoBuilder.build(); + + session.setLocalRepositoryManager(repositorySystem.newLocalRepositoryManager(session, localRepo)); + + // Process all content of the mavenizer target directory. + final File rootDir = new File(directory); + processDir(rootDir, repositorySystem, session, remoteRepository); + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + + private void processDir(File curDir, RepositorySystem repositorySystem, RepositorySystemSession session, + RemoteRepository remoteRepository) + throws IOException, XmlPullParserException, InstallationException, DeploymentException { + // If the current directory contained any poms, + // process them as artifacts. + final File[] poms = curDir.listFiles(new PomFilter()); + if (poms != null) { + for (File pom : poms) { + processArtifact(pom, repositorySystem, session, remoteRepository); + } + } + + // If the current directory contained any directories, + // continue processing their content. + final File[] dirs = curDir.listFiles(new DirFilter()); + if (dirs != null) { + for (File dir : dirs) { + processDir(dir, repositorySystem, session, remoteRepository); + } + } + } + + private void processArtifact(File pomFile, RepositorySystem repositorySystem, RepositorySystemSession session, + RemoteRepository remoteRepository) + throws IOException, XmlPullParserException, InstallationException, DeploymentException { + final Reader reader = new FileReader(pomFile); + try { + final File artifactDirectory = pomFile.getParentFile(); + final MavenXpp3Reader xpp3Reader = new MavenXpp3Reader(); + final Model model = xpp3Reader.read(reader); + + // Make the deployer deploy the pom itself. + final DeployRequest artifactInstallRequest = new DeployRequest(); + artifactInstallRequest.setRepository(remoteRepository); + Artifact pomArtifact = new DefaultArtifact( + model.getGroupId(), model.getArtifactId(), "pom", model.getVersion()); + pomArtifact = pomArtifact.setFile(pomFile); + artifactInstallRequest.addArtifact(pomArtifact); + + // Add any additional files to this installation. + final String artifactBaseName = model.getArtifactId() + "-" + model.getVersion(); + final File artifactFiles[] = artifactDirectory.listFiles(new ArtifactFilter()); + for (final File artifactFile : artifactFiles) { + final String fileName = artifactFile.getName(); + final String classifier; + // This file has a classifier. + if (fileName.charAt(artifactBaseName.length()) == '-') { + classifier = fileName.substring(artifactBaseName.length() + 1, + fileName.indexOf(".", artifactBaseName.length())); + } + // This file doesn't have a classifier. + else { + classifier = ""; + } + final String extension = fileName.substring( + artifactBaseName.length() + 1 + ((classifier.length() > 0) ? classifier.length() + 1 : 0)); + Artifact fileArtifact = new DefaultArtifact(model.getGroupId(), model.getArtifactId(), + classifier, extension, model.getVersion()); + fileArtifact = fileArtifact.setFile(artifactFile); + artifactInstallRequest.addArtifact(fileArtifact); + } + + // Actually install the artifact. + System.out.println("Installing Artifact: " + pomArtifact.getGroupId() + ":" + + pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion()); + for (final Artifact artifact : artifactInstallRequest.getArtifacts()) { + System.out.println(" - File with extension " + artifact.getExtension() + + ((artifact.getClassifier().length() > 0) ? " and classifier " + artifact.getClassifier() : "")); + } + + repositorySystem.deploy(session, artifactInstallRequest); + } finally { + reader.close(); + } + } + + private class PomFilter implements java.io.FileFilter { + @Override + public boolean accept(File pathname) { + return pathname.getName().endsWith(".pom"); + } + } + + private class DirFilter implements java.io.FileFilter { + @Override + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + } + + private class ArtifactFilter implements java.io.FileFilter { + @Override + public boolean accept(File pathname) { + return !pathname.getName().endsWith(".pom") && !pathname.isDirectory(); + } + } + +}
diff --git a/mavenizer/src/main/java/common/ConversionPlan.java b/mavenizer/src/main/java/common/ConversionPlan.java new file mode 100644 index 0000000..3897b0e --- /dev/null +++ b/mavenizer/src/main/java/common/ConversionPlan.java
@@ -0,0 +1,57 @@ +package common; + +import java.io.File; +import java.util.*; + +/** + * Created by cdutz on 01.11.13. + */ +public class ConversionPlan { + + private final Set<String> versions; + private final Map<String, File> directories; + private final Map<String, Boolean> apacheFlags; + + public ConversionPlan() { + final Comparator<String> versionComparator = new Comparator<String>() { + public int compare(String o1, String o2) { + final String[] versionSegments1 = o1.split("\\."); + final String[] versionSegments2 = o2.split("\\."); + final int length = Math.min(versionSegments1.length, versionSegments2.length); + // Compare each of the segments. + for(int i = 0; i < length; i++) { + final int result = new Integer(versionSegments1[i]).compareTo(Integer.parseInt(versionSegments2[i])); + if(result != 0) { + return result; + } + } + // If all segments were equal, the string that has more segments wins. + return Integer.valueOf(versionSegments1.length).compareTo(versionSegments2.length); + } + }; + versions = new TreeSet<String>(versionComparator); + directories = new HashMap<String, File>(); + apacheFlags = new HashMap<String, Boolean>(); + } + + public void addVersion(String version, File directory, Boolean apacheFlag) { + if(!versions.contains(version)) { + versions.add(version); + directories.put(version, directory); + apacheFlags.put(version, apacheFlag); + } + } + + public Set<String> getVersionIterator() { + return versions; + } + + public File getDirectory(String version) { + return directories.get(version); + } + + public Boolean getApacheFlag(String version) { + return apacheFlags.get(version); + } + +}