Java tutorial
/* * #%L * xcode-maven-plugin * %% * Copyright (C) 2012 SAP AG * %% * 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. * #L% */ package com.sap.prd.mobile.ios.mios; import static com.sap.prd.mobile.ios.mios.FileUtils.mkdirs; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.LogManager; import java.util.logging.Logger; import org.apache.commons.io.FileUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.ArtifactUtils; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.archiver.manager.ArchiverManager; import org.sonatype.aether.RepositorySystem; import org.sonatype.aether.RepositorySystemSession; import org.sonatype.aether.repository.RemoteRepository; class XCodePrepareBuildManager { private final static Logger LOGGER = LogManager.getLogManager().getLogger(XCodePluginLogger.getLoggerName()); private final static String TYPE_HEADERS = "headers.tar", TYPE_ARCHIVE = "a"; private final ArchiverManager archiverManager; private final XCodeDownloadManager downloadManager; private final boolean useSymbolicLinks; private Map<String, String> additionalPackagingTypes; private boolean preferFatLibs; XCodePrepareBuildManager(final ArchiverManager archiverManager, final RepositorySystemSession repoSystemSession, final RepositorySystem repoSystem, final List<RemoteRepository> projectRepos, final boolean useSymbolicLinks, final Map<String, String> additionalPackagingTypes) { this.archiverManager = archiverManager; this.downloadManager = new XCodeDownloadManager(projectRepos, repoSystem, repoSystemSession); this.useSymbolicLinks = useSymbolicLinks; if (additionalPackagingTypes == null) { this.additionalPackagingTypes = Collections.emptyMap(); } else { this.additionalPackagingTypes = additionalPackagingTypes; } } public XCodePrepareBuildManager setPreferFalLibs(boolean preferFatLibs) { this.preferFatLibs = preferFatLibs; return this; } void prepareBuild(final MavenProject project, Set<String> configurations, final Set<String> sdks) throws MojoExecutionException, XCodeException, IOException { prepareRootFolders(project, configurations, sdks); final Iterator<Artifact> dependentArtifacts = project.getArtifacts().iterator(); if (!dependentArtifacts.hasNext()) { LOGGER.info("No dependencies found."); } while (dependentArtifacts.hasNext()) { final Artifact mainArtifact = (Artifact) dependentArtifacts.next(); LOGGER.info("Preparing dependency: " + mainArtifact.getId()); if (PackagingType.LIB.getMavenPackaging().equals(mainArtifact.getType())) { prepareLibrary(project, configurations, sdks, mainArtifact); } else if (PackagingType.FRAMEWORK.getMavenPackaging().equals(mainArtifact.getType())) { prepareFramework(project, mainArtifact, configurations); } else if (additionalPackagingTypes.keySet().contains(mainArtifact.getType())) { final PackagingTypeAction packagingTypeAction = PackagingTypeAction .valueOf(additionalPackagingTypes.get(mainArtifact.getType())); LOGGER.info("Packaging type '" + mainArtifact.getType() + "' found in pom. Action: " + packagingTypeAction); packagingTypeAction.perform(archiverManager, project, mainArtifact); } else { LOGGER.warning("Unknown dependency type detected: '" + mainArtifact.getType() + "'. The corresponding dependency '" + mainArtifact.getGroupId() + ":" + mainArtifact.getArtifactId() + ":" + mainArtifact.getVersion() + "' will be ignored."); } } } private void prepareLibrary(final MavenProject project, Set<String> configurations, final Set<String> sdks, final Artifact mainArtifact) throws MojoExecutionException, IOException, XCodeException { for (final String xcodeConfiguration : configurations) { Map<String, File> thinLibs = new HashMap<String, File>(); for (final String sdk : sdks) { thinLibs.put(sdk, resolveThinLib(project, xcodeConfiguration, sdk, mainArtifact)); try { prepareHeaders(project, xcodeConfiguration, sdk, mainArtifact); } catch (SideArtifactNotFoundException e) { LOGGER.info("Headers not found for: '" + mainArtifact.getGroupId() + ":" + mainArtifact.getArtifactId() + ":" + mainArtifact.getVersion() + ":" + mainArtifact.getType() + "'."); } } File fatLib = resolveFatLib(project, xcodeConfiguration, mainArtifact); if (thinLibs.values().contains(null)) { if (fatLib != null) { provideFatLib(fatLib, project, xcodeConfiguration, mainArtifact, sdks); } else { throw new XCodeException( "Neither all thin libs nor fat lib available for " + mainArtifact.getId() + "."); } } else { if (preferFatLibs && fatLib != null) provideFatLib(fatLib, project, xcodeConfiguration, mainArtifact, sdks); else provideThinLibs(thinLibs, xcodeConfiguration, mainArtifact, project); } } try { prepareBundles(project, mainArtifact); } catch (SideArtifactNotFoundException e) { LOGGER.info("Bundle not found for: '" + mainArtifact.getGroupId() + ":" + mainArtifact.getArtifactId() + ":" + mainArtifact.getVersion() + ":" + mainArtifact.getType() + "'."); } } private static void prepareRootFolders(MavenProject project, Set<String> configurations, Set<String> sdks) throws IOException { mkdirs(FolderLayout.getFolderForExtractedMainArtifact(project)); mkdirs(FolderLayout.getFolderForExtractedBundles(project)); mkdirs(FolderLayout.getFolderForExtractedFrameworks(project)); for (String configuration : configurations) { mkdirs(FolderLayout.getFolderForExtractedFatLibs(project, configuration)); for (String sdk : sdks) { mkdirs(FolderLayout.getFolderForExtractedHeaders(project, configuration, sdk)); mkdirs(FolderLayout.getFolderForExtractedLibs(project, configuration, sdk)); } } } private File resolveThinLib(MavenProject project, final String xcodeConfiguration, final String sdk, final Artifact primaryArtifact) { try { return downloadManager .resolveSideArtifact(primaryArtifact, xcodeConfiguration + "-" + sdk, TYPE_ARCHIVE).getFile(); } catch (SideArtifactNotFoundException ex) { LOGGER.info("Library not found for: " + primaryArtifact.getGroupId() + ":" + primaryArtifact.getArtifactId() + ":" + primaryArtifact.getVersion() + ":" + primaryArtifact.getClassifier() + ":" + primaryArtifact.getType()); return null; } } void provideThinLibs(Map<String, File> thinLibs, String xcodeConfiguration, Artifact mainArtifact, MavenProject project) throws IOException { for (Map.Entry<String, File> e : thinLibs.entrySet()) { provideThinLib(e.getValue(), project, xcodeConfiguration, e.getKey(), mainArtifact); } } private void prepareBundles(MavenProject project, final Artifact primaryArtifact) throws MojoExecutionException, SideArtifactNotFoundException, IOException { List<String> bundles = readBundleInformation(project, primaryArtifact); if (bundles == null) return; for (String coords : bundles) { prepareBundle(project, primaryArtifact, coords); } } private void prepareBundle(MavenProject project, final Artifact primaryArtifact, String coords) throws SideArtifactNotFoundException, MojoExecutionException { Artifact bundleArtifact = GAVUtil.getArtifact(coords); final org.sonatype.aether.artifact.Artifact artifact = downloadManager.resolveSideArtifact(bundleArtifact); if (artifact != null) { final File source = artifact.getFile(); final File target = new File( FolderLayout.getFolderForExtractedBundlesWithGA(project, primaryArtifact.getGroupId(), primaryArtifact.getArtifactId()), bundleArtifact.getClassifier().replaceAll("~", File.separator) + ".bundle"); createDirectory(target); com.sap.prd.mobile.ios.mios.FileUtils.unarchive(archiverManager, "zip", source, target); LOGGER.info("Bundle unarchived from " + source + " to " + target); } } @SuppressWarnings("unchecked") private List<String> readBundleInformation(MavenProject project, Artifact primaryArtifact) throws IOException { final File mainArtifactExtracted = FolderLayout.getFolderForExtractedPrimaryArtifact(project, primaryArtifact); if (mainArtifactExtracted.exists()) com.sap.prd.mobile.ios.mios.FileUtils.deleteDirectory(mainArtifactExtracted); if (!mainArtifactExtracted.mkdirs()) throw new IOException( "Cannot create directory for expanded mainartefact of " + primaryArtifact.getGroupId() + ":" + primaryArtifact.getArtifactId() + " (" + mainArtifactExtracted + ")."); com.sap.prd.mobile.ios.mios.FileUtils.unarchive(archiverManager, "tar", primaryArtifact.getFile(), mainArtifactExtracted); LOGGER.info("Main artifact extracted to '" + mainArtifactExtracted + "'."); File bundleFile = new File(mainArtifactExtracted, "bundles.txt"); if (!bundleFile.exists()) return null; try { return FileUtils.readLines(bundleFile); } catch (IOException e) { throw new RuntimeException(e); } } private void provideThinLib(final File source, MavenProject project, final String xcodeConfiguration, final String sdk, final Artifact primaryArtifact) throws IOException { final File target = new File( FolderLayout.getFolderForExtractedLibsWithGA(project, xcodeConfiguration, sdk, primaryArtifact.getGroupId(), primaryArtifact.getArtifactId()), getArchiveFileName(primaryArtifact)); if (ArtifactUtils.isSnapshot(primaryArtifact.getVersion()) || !useSymbolicLinks()) { FileUtils.copyFile(source, target); } else { com.sap.prd.mobile.ios.mios.FileUtils.createSymbolicLink(source, target); } } private File resolveFatLib(MavenProject project, final String xcodeConfiguration, final Artifact primaryArtifact) { try { return downloadManager .resolveSideArtifact(primaryArtifact, xcodeConfiguration + XCodeFatLibraryMojo.FAT_LIBRARY_CLASSIFIER_SUFFIX, TYPE_ARCHIVE) .getFile(); } catch (SideArtifactNotFoundException ex) { LOGGER.info("There does not exist a fat library for the artifact " + primaryArtifact.getId()); return null; } } private void provideFatLib(File source, MavenProject project, final String xcodeConfiguration, final Artifact primaryArtifact, Set<String> sdks) throws IOException { final File target = new File( FolderLayout.getFolderForExtractedFatLibsWithGA(project, xcodeConfiguration, primaryArtifact.getGroupId(), primaryArtifact.getArtifactId()), getArchiveFileName(primaryArtifact)); if (ArtifactUtils.isSnapshot(primaryArtifact.getVersion()) || !useSymbolicLinks()) { FileUtils.copyFile(source, target); } else { com.sap.prd.mobile.ios.mios.FileUtils.createSymbolicLink(source, target); } final FatLibAnalyzer lipoHelper = new FatLibAnalyzer(target); // // TODO improve hard coded strings for iphoneos and iphonesimulator below // if (sdks.contains("iphoneos")) { if (!lipoHelper.containsArmv()) LOGGER.warning( "Fat library '" + lipoHelper.getFatLibrary() + "' does not contain a library for armv*."); else LOGGER.info("Fat library '" + lipoHelper.getFatLibrary() + "'contains a library for armv*."); } else if (sdks.contains("iphonesimulator")) { if (!lipoHelper.containsI386()) LOGGER.warning( "Fat library '" + lipoHelper.getFatLibrary() + "' does not contain a library for i386."); else LOGGER.info("Fat library '" + lipoHelper.getFatLibrary() + "'contains a library for i386."); } } private boolean useSymbolicLinks() { return this.useSymbolicLinks; } private void prepareHeaders(MavenProject project, String xcodeConfiguration, final String sdk, final Artifact primaryArtifact) throws MojoExecutionException, SideArtifactNotFoundException { final org.sonatype.aether.artifact.Artifact headersArtifact = downloadManager .resolveSideArtifact(primaryArtifact, xcodeConfiguration + "-" + sdk, TYPE_HEADERS); if (headersArtifact != null) { final File headersDirectory = FolderLayout.getFolderForExtractedHeadersWithGA(project, xcodeConfiguration, sdk, primaryArtifact.getGroupId(), primaryArtifact.getArtifactId()); createDirectory(headersDirectory); extractHeaders(headersDirectory, headersArtifact.getFile()); } } private void prepareFramework(MavenProject project, final Artifact primaryArtifact, Collection<String> configurations) throws MojoExecutionException { for (String configuration : configurations) { try { org.sonatype.aether.artifact.Artifact frameworkArtifact = downloadManager .resolveSideArtifact(primaryArtifact, configuration, Types.FRAMEWORK); extractFramework(project, primaryArtifact, configuration, frameworkArtifact.getFile()); } catch (SideArtifactNotFoundException e) { LOGGER.warning("Framework '" + primaryArtifact + "' does not contain configuration specific variant. Will download the generic framework for configuration '" + configuration + "'."); handlePrimaryArtifact(project, primaryArtifact, configurations); } } } private void extractFramework(MavenProject project, final Artifact primaryArtifact, String configuration, File frameworkArtifact) throws MojoExecutionException { File target = FolderLayout.getFolderForExtractedFrameworkswithGA(project, primaryArtifact.getGroupId(), primaryArtifact.getArtifactId(), configuration); createDirectory(target); try { extractFileWithShellScript(frameworkArtifact, target, new File(project.getBuild().getDirectory())); } catch (IOException ioe) { throw new MojoExecutionException( "Cannot unarchive framework from " + frameworkArtifact + " to " + target); } } private void handlePrimaryArtifact(MavenProject project, final Artifact primaryArtifact, Collection<String> configurations) throws MojoExecutionException { if (primaryArtifact != null) { final File source = primaryArtifact.getFile(); for (String configuration : configurations) { final File target = FolderLayout.getFolderForExtractedFrameworkswithGA(project, primaryArtifact.getGroupId(), primaryArtifact.getArtifactId()); extractFramework(project, primaryArtifact, configuration, source); try { extractFileWithShellScript(source, target, new File(project.getBuild().getDirectory())); } catch (IOException ioe) { throw new MojoExecutionException("Cannot unarchive framework from " + source + " to " + target); } LOGGER.info("Framework unarchived from " + source + " to " + target); } } } private static String getArchiveFileName(final Artifact primaryArtifact) { return "lib" + primaryArtifact.getArtifactId() + ".a"; } private void extractHeaders(final File headersDirectory, final File headers) { com.sap.prd.mobile.ios.mios.FileUtils.unarchive(archiverManager, "tar", headers, headersDirectory); } /** * Creates a directory. If the directory already exists the directory is deleted beforehand. * * @param directory * @throws MojoExecutionException */ private static void createDirectory(final File directory) throws MojoExecutionException { try { com.sap.prd.mobile.ios.mios.FileUtils.deleteDirectory(directory); } catch (IOException ex) { throw new MojoExecutionException("", ex); } if (!directory.mkdirs()) throw new MojoExecutionException("Cannot create directory (" + directory + ")"); } private void extractFileWithShellScript(File sourceFile, File destinationFolder, File tmpFolder) throws IOException { File workingDirectory = new File(tmpFolder, "scriptWorkingDir"); workingDirectory.deleteOnExit(); ScriptRunner.copyAndExecuteScript(System.out, "/com/sap/prd/mobile/ios/mios/unzip.sh", workingDirectory, sourceFile.getCanonicalPath(), destinationFolder.getCanonicalPath()); } }