All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aQute.bnd.build.PackageInfo Maven / Gradle / Ivy

The newest version!
package aQute.bnd.build;

import java.io.File;
import java.io.IOException;
import java.util.Formatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import aQute.bnd.osgi.Constants;
import aQute.bnd.osgi.Verifier;
import aQute.bnd.version.Version;
import aQute.lib.io.IO;

/*
 * Hides the differences and handling of packageinfo and package-info.java 
 * where we store versions and attributes.
 */
class PackageInfo {
	private static final String		PACKAGE_INFO_JAVA	= "package-info.java";
	private static final String		PACKAGEINFO			= "packageinfo";
	private final static Pattern	MODERN_P			= Pattern
		.compile("@\\s*[a-zA-Z0-9_$.]*\\s*Version\\((?:\\s*value\\s*=\\s*)?\"(" + Verifier.VERSION_S + ")\"\\)");
	private final static Pattern	CLASSIC_P			= Pattern
		.compile("\\s*version\\s*(?:\\s|:|=)\\s*(" + Verifier.VERSION_S + ")");
	private final static Pattern	MODERN_PACKAGE_P	= Pattern.compile("package[^;]*;");
	private final Project			project;

	PackageInfo(Project project) {
		this.project = project;
	}

	/**
	 * Get the version for a package name. This traverse the source paths and
	 * will stop at the first source directory that has a packageinfo or
	 * 
	 * @param packageName
	 * @throws Exception
	 */
	public Version getPackageInfo(String packageName) throws Exception {
		File target = getFile(packageName);
		if (target != null && target.isFile()) {
			Version v = getVersion(target, getPattern(target));
			if (v == null && isModern(target)) {
				target = new File(target.getParentFile(), PACKAGEINFO);
				v = getVersion(target, getPattern(target));
			}
			if (v != null)
				return v;
		}

		return Version.emptyVersion;
	}

	/**
	 * Sets the package version on an exported package. If package-info.java
	 * exists then we use that one, otherwise we try the packageinfo file. If
	 * neither exists, we create a package-info.java file. You can set the
	 * annotation to use. Default is bnd. setting it to 'osgi' sets it to the
	 * OSGi annotations.
	 * 
	 * @param packageName The package name
	 * @param version The new package version
	 * @throws Exception
	 */
	public boolean setPackageInfo(String packageName, Version version) throws Exception {

		File target = getFile(packageName);

		//
		// The directory MUST exist. we should not add packages for
		// packages that do not exist.
		//

		if (target == null || !target.getParentFile()
			.isDirectory())
			return false;

		//
		// If the file already exists then we use a modern/classic
		// style pattern to replace the version.
		//

		String content;
		if (target.isFile()) {
			if (replace(target, version, getPattern(target)))
				return true;

			//
			// if have a modern file without a version then we only add the
			// version
			// if we are instructed by the version annotation.
			//

			if (isModern(target)) {
				String versionAnnotation = getVersionAnnotation();
				if (versionAnnotation != null) {
					content = IO.collect(target);
					Matcher m = MODERN_PACKAGE_P.matcher(content);
					if (m.find()) {
						content = m
							.replaceFirst("@Version(\"" + version + "\")\n$0\nimport " + versionAnnotation + ";");
						IO.store(content, target);
						return true;
					}
					return false;
				}
			}

			//
			// If we failed, we always overwrite packageinfo
			//

			target = new File(target.getParentFile(), PACKAGEINFO);
		}

		content = getContent(isModern(target), packageName, version);
		IO.store(content, target);
		return true;
	}

	/**
	 * Check what version annotation to use for new content:
	 * 
    *
  • not set -> use packageinfo *
  • osgi -> use the OSGi Version ann. *
  • bnd -> use the bnd version ann. *
  • other -> use the content as the version annotation, must have the * same prototype as the bnd/osgi ann. *
*/ private String getVersionAnnotation() { String versionAnnotation = project.getProperty(Constants.PACKAGEINFOTYPE); if (versionAnnotation == null) return null; if ("osgi".equals(versionAnnotation)) return "org.osgi.annotation.versioning.Version"; else if ("bnd".equals(versionAnnotation)) return "aQute.bnd.annotation.Version"; else if ("packageinfo".equals(versionAnnotation)) { return null; } else return versionAnnotation; } /* * Calculate the new content for a package info file. */ private String getContent(boolean modern, String packageName, Version version) { try (Formatter f = new Formatter()) { if (modern) { f.format("@Version(\"%s\")\n", version); f.format("package %s;\n", packageName); f.format("import %s;\n", getVersionAnnotation()); } else { f.format("version %s\n", version); } return f.toString(); } } /* * get the pattern to find the version. */ private Pattern getPattern(File target) { if (isModern(target)) return MODERN_P; else return CLASSIC_P; } private boolean isModern(File target) { return target.getName() .endsWith(".java"); } /* * Replace a version in a file based on a pattern. We search the pattern and * if found we replace group 1 with the new version. If the found version * matches the new version we bail out early. */ private boolean replace(File target, final Version newVersion, Pattern pattern) throws IOException { String content = IO.collect(target); Matcher m = pattern.matcher(content); if (!m.find()) { return false; } Version oldVersion = new Version(m.group(1)); if (newVersion.compareTo(oldVersion) == 0) { return true; } return replace(newVersion, content, m, target); } private boolean replace(Version newVersion, String content, Matcher m, File target) throws IOException { StringBuilder output = new StringBuilder(); output.append(content, 0, m.start(1)); output.append(newVersion); output.append(content, m.end(1), m.regionEnd()); IO.store(output, target); return true; } /* * Try to locate the file for the given package name and file type. */ private File getFile(String packageName) throws Exception { String relativePackagePath = packageName.replace('.', '/'); File first = null; for (File srcDir : project.getSourcePath()) { if (!srcDir.isDirectory()) continue; File packageDir = IO.getFile(srcDir, relativePackagePath); if (!packageDir.isDirectory()) continue; if (first == null) first = packageDir; File target = new File(packageDir, PACKAGE_INFO_JAVA); if (target.isFile()) return target; target = new File(packageDir, PACKAGEINFO); if (target.isFile()) return target; } // // See if the package directory actually exists // if (first == null) return null; // // In the old times, the default was PACKAGEINFO // we now allow this to be controlled with the -versionannotation // String versionAnnotation = getVersionAnnotation(); if (versionAnnotation == null) return new File(first, PACKAGEINFO); else return new File(first, PACKAGE_INFO_JAVA); } /* * Get the version from the file using the pattern */ private Version getVersion(File source, Pattern pattern) throws IOException { if (!source.isFile()) return null; String content = IO.collect(source); Matcher m = pattern.matcher(content); if (!m.find()) return null; return new Version(m.group(1)); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy