/*
* 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.
*
* Modified for usage within IntelliJ IDEA.
*/
package org.jetbrains.osgi.jps.build;
import aQute.bnd.osgi.Analyzer;
import aQute.bnd.osgi.Constants;
import com.intellij.openapi.util.text.StringUtil;
import org.codehaus.plexus.util.DirectoryScanner;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Map;
/**
* Helper class which collects local packages from the output path. This is copied code from the
* felix bnd maven plugin.
*/
public class LocalPackageCollector {
private static final String LOCAL_PACKAGES = "{local-packages}";
/**
* Adds the local packages to the headers in the given manifest.
* @param outputDirectory the output directory where the compiled classes are located
* @param currentManifest the currently calculated manifest contents.
*/
public static void addLocalPackages(File outputDirectory, Map<String, String> currentManifest) {
Analyzer fakeAnalyzer = new FakeAnalyzer(currentManifest);
addLocalPackages(outputDirectory, fakeAnalyzer);
}
private static void addLocalPackages(File outputDirectory, Analyzer analyzer) {
Collection<String> packages = new LinkedHashSet<String>();
if (outputDirectory != null && outputDirectory.isDirectory()) {
// scan classes directory for potential packages
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir(outputDirectory);
scanner.setIncludes(new String[] {"**/*.class"});
scanner.addDefaultExcludes();
scanner.scan();
String[] paths = scanner.getIncludedFiles();
for (String path : paths) {
packages.add(getPackageName(path));
}
}
StringBuilder exportedPackages = new StringBuilder();
StringBuilder privatePackages = new StringBuilder();
boolean noPrivatePackages = "!*".equals(analyzer.getProperty(Constants.PRIVATE_PACKAGE));
for (Object aPackage : packages) {
String pkg = (String)aPackage;
// mark all source packages as private by default (can be overridden by export list)
if (privatePackages.length() > 0) {
privatePackages.append(';');
}
privatePackages.append(pkg);
// we can't export the default package (".") and we shouldn't export internal packages
if (noPrivatePackages || !(".".equals(pkg) || pkg.contains(".internal") || pkg.contains(".impl"))) {
if (exportedPackages.length() > 0) {
exportedPackages.append(';');
}
exportedPackages.append(pkg);
}
}
if (analyzer.getProperty(Constants.EXPORT_PACKAGE) == null) {
if (analyzer.getProperty(Constants.EXPORT_CONTENTS) == null) {
// no -exportcontents overriding the exports, so use our computed list
analyzer.setProperty(Constants.EXPORT_PACKAGE, exportedPackages + ";-split-package:=merge-first");
}
else {
// leave Export-Package empty (but non-null) as we have -exportcontents
analyzer.setProperty(Constants.EXPORT_PACKAGE, "");
}
}
else {
String exported = analyzer.getProperty(Constants.EXPORT_PACKAGE);
if (exported.contains(LOCAL_PACKAGES)) {
String newExported = StringUtil.replace(exported, LOCAL_PACKAGES, exportedPackages.toString());
analyzer.setProperty(Constants.EXPORT_PACKAGE, newExported);
}
}
String internal = analyzer.getProperty(Constants.PRIVATE_PACKAGE);
if (internal == null) {
if (privatePackages.length() > 0) {
analyzer.setProperty(Constants.PRIVATE_PACKAGE, privatePackages + ";-split-package:=merge-first");
}
else {
// if there are really no private packages then use "!*" as this will keep the Bnd Tool happy
analyzer.setProperty(Constants.PRIVATE_PACKAGE, "!*");
}
}
else if (internal.contains(LOCAL_PACKAGES)) {
String newInternal = StringUtil.replace(internal, LOCAL_PACKAGES, privatePackages.toString());
analyzer.setProperty(Constants.PRIVATE_PACKAGE, newInternal);
}
}
/**
* Returns the package name of the given file name.
* @param filename the filename
* @return the package name.
*/
@NotNull
private static String getPackageName(@NotNull String filename) {
int n = filename.lastIndexOf(File.separatorChar);
return n < 0 ? "." : filename.substring(0, n).replace(File.separatorChar, '.');
}
}