/** * */ package de.saumya.mojo.gem; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.maven.model.Contributor; import org.apache.maven.model.Developer; import org.apache.maven.model.License; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.FileUtils; class GemspecWriter { final MavenProject project; final Writer writer; final String excludes = ".*~$|^[.][a-zA-Z].*"; final List<File> dirs = new ArrayList<File>(); final List<File> files = new ArrayList<File>(); final List<URL> licenses = new ArrayList<URL>(); final Map<String, File> jarFiles = new HashMap<String, File>(); long latestModified = 0; final File gemspec; private boolean firstAuthor = true; private boolean firstFile = true; private boolean platformAppended = false; private boolean firstTestFile; // private List<String> executables = new ArrayList<String>(); GemspecWriter(final File gemspec, final MavenProject project, final GemArtifact artifact) throws IOException { this.latestModified = project.getFile() == null ? 0 : project.getFile() .lastModified(); this.gemspec = gemspec; this.gemspec.getParentFile().mkdirs(); this.writer = new FileWriter(gemspec); this.project = project; append("# create by maven - leave it as is"); append("Gem::Specification.new do |s|"); append("name", artifact.getGemName()); appendRaw("version", "'" + GemArtifact.getGemVersion(project.getVersion()) + "'"); append(); append("summary", project.getName()); append("description", project.getDescription()); append("homepage", project.getUrl()); append(); for (final Developer developer : project.getDevelopers()) { appendAuthor(developer.getName(), developer.getEmail()); } for (final Contributor contributor : project.getContributors()) { appendAuthor(contributor.getName(), contributor.getEmail()); } if (project.getDevelopers().isEmpty() && project.getContributors().isEmpty()){ appendList("authors", "dummy"); } append(); for (final License license : project.getLicenses()) { appendLicense(license.getUrl(), license.getName()); } } boolean isUptodate() { return this.gemspec.lastModified() > this.latestModified; } private String gemVersion(String version) { version = version.replaceAll("-SNAPSHOT", "").replace("-", "."); if (version.matches("^[\\[\\(].*[\\]\\)]$")) { final int comma = version.indexOf(","); final String first = version.substring(1, comma); final String second = version.substring(comma + 1, version.length() - 1); if (version.matches("\\[.*99999.99999\\)$")) { // out of '[1.2.0, 1.99999.99999]' make '1.2' final String prefix = second.replaceFirst("99999.99999$", ""); return "'~> " + prefix + first.substring(prefix.length()) .replaceFirst("[.].*", "") + "'"; } else if (version.matches("\\[.*,\\)$")) { final StringBuilder buf = new StringBuilder("'>"); buf.append(version.charAt(0) == '[' ? "=" : ""); buf.append(first).append("'"); return buf.toString(); } else { final StringBuilder buf = new StringBuilder("['>"); buf.append(version.charAt(0) == '[' ? "=" : ""); buf.append(first).append("','<"); buf.append(version.charAt(version.length() - 1) == '[' ? "=" : ""); buf.append(second); buf.append("']"); return buf.toString(); } } else { return "'" + version + "'"; } } private void append() throws IOException { this.writer.append("\n"); } private void append(final String line) throws IOException { this.writer.append(line).append("\n"); } private void appendAuthor(final String name, final String email) throws IOException { if (name != null && email != null) { if (this.firstAuthor) { this.writer.append(" s.authors = ['") .append(name) .append("']\n"); this.writer.append(" s.email = ['") .append(email) .append("']\n"); this.firstAuthor = false; } else { this.writer.append(" s.authors << '") .append(name) .append("'\n"); this.writer.append(" s.email << '") .append(email) .append("'\n"); } } } void append(final String key, final String value) throws IOException { if (value != null) { this.writer.append(" s.") .append(key) .append(" = '") .append(value.replaceAll("'", "\"")) .append("'\n"); } } private void appendRaw(final String key, final String value) throws IOException { if (value != null) { this.writer.append(" s.") .append(key) .append(" = ") .append(value) .append("\n"); } } void appendDependency(final String name, final String version) throws IOException { this.writer.append(" s.add_dependency '") .append(name) .append("', ") .append(gemVersion(version)) .append("\n"); } void appendDevelopmentDependency(final String name, final String version) throws IOException { this.writer.append(" s.add_development_dependency '") .append(name) .append("', ") .append(gemVersion(version)) .append("\n"); } void appendPath(final String path) throws IOException { if (this.firstFile) { this.writer.append(" s.files = Dir['") .append(path) .append("/**/*']\n"); this.firstFile = false; } else { this.writer.append(" s.files += Dir['") .append(path) .append("/**/*']\n"); } final File file = new File(this.project.getBasedir(), path); if (file.lastModified() > this.latestModified) { this.latestModified = file.lastModified(); } this.dirs.add(new File(path)); } void appendTestPath(final String path) throws IOException { if (this.firstTestFile) { this.writer.append(" s.test_files = Dir['") .append(path) .append("/**/*_" + path + ".rb']\n"); this.firstTestFile = false; } else { this.writer.append(" s.test_files += Dir['") .append(path) .append("/**/*_" + path + ".rb']\n"); } final File file = new File(this.project.getBasedir(), path); if (file.lastModified() > this.latestModified) { this.latestModified = file.lastModified(); } this.dirs.add(new File(path)); } void appendPlatform(final String platform) throws IOException { if (!this.platformAppended && platform != null) { append("platform", platform); this.platformAppended = true; } } void appendJarfile(final File jar, final String jarfileName) throws IOException { final File f = new File("lib", jarfileName); this.jarFiles.put(f.toString(), jar); appendFile(f); } void appendFile(final File file) throws IOException { if (this.firstFile) { this.writer.append(" s.files = Dir['") .append(file.toString()) .append("']\n"); this.firstFile = false; } else { this.writer.append(" s.files += Dir['") .append(file.toString()) .append("']\n"); } if (file.lastModified() > this.latestModified) { this.latestModified = file.lastModified(); } } void appendFile(final String file) throws IOException { final File f = new File(file); appendFile(f); this.files.add(f); } void appendExecutable(final String executable) throws IOException { this.writer.append(" s.executables << '" + executable + "'\n"); } private void appendLicense(final String url, final String name) throws IOException { URL u; try { u = new URL(url); } catch (final MalformedURLException e) { u = new URL("file:." + url); } this.licenses.add(u); final URLConnection con = u.openConnection(); if (this.latestModified < con.getLastModified()) { this.latestModified = con.getLastModified(); } // omit the first slash final File license = new File(u.getFile() .substring(1) .replaceFirst("^./", "")); appendFile(license); if ("file".equals(u.getProtocol())) { // make a nice File without unix style prefix "./" this.files.add(new File(license.getPath().replaceFirst("^./", ""))); } if (name != null) { append(" s.licenses << '" + name.replaceFirst("^./", "") + "'"); } } void copy(final File target) throws IOException { target.mkdirs(); copyJarFiles(target); copyFiles(target); copyLicenses(target); } private void copyLicenses(final File target) throws IOException { OutputStream writer = null; InputStream reader = null; for (final URL url : this.licenses) { try { try { reader = new BufferedInputStream(url.openStream()); } catch (final IOException e) { // TODO log it but otherwise ignore break; } final File licenseFile = new File(target, url.getFile()); licenseFile.getParentFile().mkdirs(); writer = new BufferedOutputStream(new FileOutputStream(licenseFile)); int b = reader.read(); while (b != -1) { writer.write(b); b = reader.read(); } } finally { if (reader != null) { try { reader.close(); } catch (final IOException ignore) { } } if (writer != null) { try { writer.close(); } catch (final IOException ignore) { } } } } } private void copyJarFiles(final File target) throws IOException { new File(target, "lib").mkdirs(); for (final Map.Entry<String, File> entry : this.jarFiles.entrySet()) { FileUtils.copyFile(entry.getValue(), new File(target, entry.getKey())); } } private void copyFiles(final File target) throws IOException { for (final File file : this.files) { if (file.exists()) { FileUtils.copyFile(file, new File(target, file.getPath())); } } for (final File dir : this.dirs) { copyDir(target, dir); } } private void copyDir(final File target, final File dir) throws IOException { final File realDir = new File(this.project.getBasedir(), dir.getPath()); if (realDir.isDirectory()) { for (final String file : realDir.list()) { copyDir(target, new File(dir, file)); } } else { if (realDir.exists() && !realDir.getName().matches(this.excludes)) { final File targetFile = new File(target, dir.getPath()); FileUtils.copyFile(realDir, targetFile); } } } void close() throws IOException { try { this.writer.append("end"); } finally { this.writer.close(); } } void appendList(final String name, final String list) throws IOException { if (list != null) { final StringBuilder buf = new StringBuilder("["); boolean first = true; for (final String part : list.split(",")) { if (first) { first = false; } else { buf.append(","); } final char quoteChar = part.contains("'") ? '"' : '\''; buf.append(quoteChar).append(part.trim()).append(quoteChar); } buf.append("]"); appendRaw(name, buf.toString()); } } void appendRdocFiles(final String extraRdocFiles) throws IOException { if (extraRdocFiles != null) { for (final String f : extraRdocFiles.split(",")) { appendFile(f.trim()); } appendList("extra_rdoc_files", extraRdocFiles); } } void appendFiles(final String files) throws IOException { if (files != null) { for (final String f : files.split(",")) { appendFile(f.trim()); } } } }