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 java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.nio.charset.Charset; import java.util.HashSet; import java.util.Set; import java.util.logging.LogManager; import java.util.logging.Logger; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProjectHelper; import org.codehaus.plexus.archiver.Archiver; import org.codehaus.plexus.archiver.ArchiverException; import org.codehaus.plexus.archiver.manager.ArchiverManager; import org.codehaus.plexus.archiver.manager.NoSuchArchiverException; class XCodePackageManager { private final static Logger LOGGER = LogManager.getLogManager().getLogger(XCodePluginLogger.getLoggerName()); final ArchiverManager archiverManager; final MavenProjectHelper projectHelper; private static final String ZIPPED_BUNDLE_SUFFIX = "xcode-bundle-zip"; XCodePackageManager(final ArchiverManager archiverManager, final MavenProjectHelper projectHelper) { this.archiverManager = archiverManager; this.projectHelper = projectHelper; } /** * Packages all the artifacts. The main artifact is set and all side artifacts are attached for * deployment. * * @param bundles * * @param buildDir */ void packageArtifacts(final File compileDir, final MavenProject project, final Set<String> bundles) throws IOException, XCodeException { File mainArtifact = createMainArtifactFile(project); attachBundle(compileDir, project, bundles, mainArtifact); final File mainArtifactFile = archiveMainArtifact(project, mainArtifact); setMainArtifact(project, mainArtifactFile); } private void attachBundle(File compileDir, MavenProject project, Set<String> bundles, File mainArtifact) throws IOException { final Set<String> bundleNames = new HashSet<String>(); for (String bundleName : bundles) { File bundleDirectory = XCodeBuildLayout.getBundleDirectory(compileDir, bundleName); if (!bundleDirectory.exists()) { LOGGER.info( "Bundle directory '" + bundleDirectory + "' does not exist. Bundle will not be attached."); continue; } final File bundleFile = new File(new File(project.getBuild().getDirectory()), bundleName + ".bundle"); try { archive("zip", bundleDirectory, bundleFile, new String[] { "**/*" }, null); LOGGER.info("Bundle zip file created (" + bundleFile + ")"); } catch (XCodeException ex) { throw new RuntimeException("Could not archive header directory '" + bundleDirectory + "'", ex); } catch (NoSuchArchiverException ex) { throw new RuntimeException("Could not archive header directory '" + bundleDirectory + "'", ex); } String escapedBundleName = escapeBundleName(bundleName); prepareBundleFileForDeployment(project, bundleFile, escapedBundleName); bundleNames.add(getBundleReference(project, escapedBundleName)); } addBundleInfoToMainArtifact(bundleNames, new File(mainArtifact, "bundles.txt")); } private String getBundleReference(MavenProject project, String escapedBundleName) { return GAVUtil.toColonNotation(project.getGroupId(), project.getArtifactId(), project.getVersion(), ZIPPED_BUNDLE_SUFFIX, escapedBundleName); } private File createMainArtifactFile(final MavenProject project) throws IOException { File mainArtifact = FolderLayout.getFolderForExtractedMainArtifact(project); if (mainArtifact.exists()) com.sap.prd.mobile.ios.mios.FileUtils.deleteDirectory(mainArtifact); if (!mainArtifact.mkdirs()) throw new IOException("Could not create directory '" + mainArtifact + "'."); FileUtils.writeStringToFile(new File(mainArtifact, "README.TXT"), "This zip file may contain additonal information about the depoyed artifacts. \n"); return mainArtifact; } private File archiveMainArtifact(final MavenProject project, File mainArtifact) throws IOException { final File mainArtifactTarFile = new File(new File(project.getBuild().getDirectory()), "main.artifact.tar"); try { archive("tar", mainArtifact, mainArtifactTarFile, new String[] { "**/*" }, null); LOGGER.info("header tar file created (" + mainArtifactTarFile + ")"); } catch (XCodeException ex) { throw new RuntimeException("Could not archive main artifact directory '" + mainArtifact + "'", ex); } catch (NoSuchArchiverException ex) { throw new RuntimeException("Could not archive main artifact directory '" + mainArtifact + "'", ex); } return mainArtifactTarFile; } private void setMainArtifact(final MavenProject project, final File mainArtifactTarFile) { project.getArtifact().setFile(mainArtifactTarFile); LOGGER.info("Main artifact file '" + mainArtifactTarFile + "' attached for " + project.getArtifact()); } void packageHeaders(final XCodeContext xcodeContext, MavenProject project, String relativeAlternatePublicHeaderFolderPath) throws IOException, XCodeException { final File publicHeaderFolderPath = getPublicHeaderFolderPath( EffectiveBuildSettings.getBuildSetting(xcodeContext, EffectiveBuildSettings.BUILT_PRODUCTS_DIR), EffectiveBuildSettings.getBuildSetting(xcodeContext, EffectiveBuildSettings.PUBLIC_HEADERS_FOLDER_PATH), relativeAlternatePublicHeaderFolderPath); if (!publicHeaderFolderPath.canRead()) { LOGGER.warning("Public header folder path '" + publicHeaderFolderPath + "' cannot be read. Unable to package headers."); return; } final File headersFile = new File(new File(new File(project.getBuild().getDirectory()), xcodeContext.getConfiguration() + "-" + xcodeContext.getSDK()), "headers.tar"); try { archive("tar", publicHeaderFolderPath, headersFile, new String[] { "**/*.h" }, null); LOGGER.info("header tar file created (" + headersFile + ")"); } catch (XCodeException ex) { throw new RuntimeException("Could not archive header directory '" + publicHeaderFolderPath + "'", ex); } catch (NoSuchArchiverException ex) { throw new RuntimeException("Could not archive header directory '" + publicHeaderFolderPath + "'", ex); } prepareHeaderFileForDeployment(project, xcodeContext.getConfiguration(), xcodeContext.getSDK(), headersFile); } private void prepareHeaderFileForDeployment(final MavenProject mavenProject, final String configuration, final String sdk, final File headersFile) { projectHelper.attachArtifact(mavenProject, "headers.tar", configuration + "-" + sdk, headersFile); } private void prepareBundleFileForDeployment(MavenProject mavenProject, File bundleFile, String escapedBundleName) { projectHelper.attachArtifact(mavenProject, ZIPPED_BUNDLE_SUFFIX, escapedBundleName, bundleFile); } String escapeBundleName(String bundleName) { return bundleName.replaceAll("/", "~"); } private void addBundleInfoToMainArtifact(Set<String> bundleNames, File bundlesFile) throws IOException { final PrintWriter pw = new PrintWriter( new OutputStreamWriter(new FileOutputStream(bundlesFile), Charset.defaultCharset().name())); try { for (final String bundleName : bundleNames) { pw.println(bundleName); } } finally { pw.close(); } } static void attachLibrary(final XCodeContext xcodeContext, File buildDir, final MavenProject project, final MavenProjectHelper projectHelper) { final File fatBinary = XCodeBuildLayout.getBinary(buildDir, xcodeContext.getConfiguration(), xcodeContext.getSDK(), project.getArtifactId()); if (!fatBinary.exists()) throw new RuntimeException(fatBinary + " should be attached but does not exist."); final String classifier = xcodeContext.getConfiguration() + "-" + xcodeContext.getSDK(); projectHelper.attachArtifact(project, "a", classifier, fatBinary); LOGGER.info("Archive file '" + fatBinary + "' attached as side artifact for '" + project.getArtifact() + "' with classifier '" + classifier + "'."); } private final void archive(final String archiverType, final File rootDir, final File archive, final String[] includes, final String[] excludes) throws NoSuchArchiverException, IOException, XCodeException { try { final Archiver archiver = archiverManager.getArchiver(archiverType); archiver.addDirectory(rootDir, includes, excludes); archiver.setDestFile(archive); archiver.createArchive(); } catch (ArchiverException ex) { throw new XCodeException( "Could not archive folder '" + rootDir + "' into '" + archive + "': " + ex.getMessage(), ex); } } static File getPublicHeaderFolderPath(String builtProductDirInsideXcodeProject, String publicHeaderFolderPathInsideXcodeProject, String relativeAlternatePublicHeaderFolderPath) throws XCodeException { final String relativePublicHeaderFolderPathInXcodeProject = publicHeaderFolderPathInsideXcodeProject; final String relativePublicHeaderFolderPath; if (StringUtils.isEmpty(relativeAlternatePublicHeaderFolderPath)) { relativePublicHeaderFolderPath = relativePublicHeaderFolderPathInXcodeProject; LOGGER.info("Using public header folder path as it is configured in the xcode project: '" + relativePublicHeaderFolderPathInXcodeProject + "'."); } else { relativePublicHeaderFolderPath = relativeAlternatePublicHeaderFolderPath; if (!com.sap.prd.mobile.ios.mios.FileUtils.isChild( new File(com.sap.prd.mobile.ios.mios.FileUtils .ensureLeadingSlash(relativeAlternatePublicHeaderFolderPath)), new File(com.sap.prd.mobile.ios.mios.FileUtils .ensureLeadingSlash(relativePublicHeaderFolderPathInXcodeProject)))) throw new InvalidAlternatePublicHeaderPathException( "Public header folder path configured on the level of xcode-maven-plugin configuration (" + relativeAlternatePublicHeaderFolderPath + ") is not a parent folder of the public header path configured inside the xcode project (" + relativePublicHeaderFolderPathInXcodeProject + ")."); LOGGER.info("Using public header folder path as it is defined inside the xcode-maven-plugin (" + relativeAlternatePublicHeaderFolderPath + "). In the xcode project '" + relativePublicHeaderFolderPathInXcodeProject + "' is configured as public header folder path."); } return new File(builtProductDirInsideXcodeProject, com.sap.prd.mobile.ios.mios.FileUtils.ensureLeadingSlash(relativePublicHeaderFolderPath)); } }