Package org.moxie.ant

Source Code of org.moxie.ant.MxVersion

/*
* Copyright 2013 James Moger
*
* 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.
*/
package org.moxie.ant;

import java.io.File;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.tools.ant.DefaultLogger;
import org.moxie.ArtifactVersion;
import org.moxie.ArtifactVersion.NumberField;
import org.moxie.Constants;
import org.moxie.MoxieException;
import org.moxie.Substitute;
import org.moxie.Toolkit;
import org.moxie.maxml.Maxml;
import org.moxie.maxml.MaxmlException;
import org.moxie.maxml.MaxmlMap;
import org.moxie.utils.FileUtils;
import org.moxie.utils.StringUtils;

/**
* MxVersion is used to build a release target where you want to publish a release
* or to reset for the next development cycle.  It is something like the Maven
* versions plugin.
*
* @author James Moger
*
*/
public class MxVersion extends MxTask {

  enum Stage {
    release, snapshot;
  }

  Stage stage;
  NumberField incrementNumber;
  File moxieFile;
  File releaseLog;
  boolean dryrun;

  public MxVersion() {
    super();
    setTaskName("mx:version");
  }
 
  public void setStage(String value) {
    for (Stage stage : Stage.values()) {
      if (value.equalsIgnoreCase(stage.name())) {
        this.stage = stage;
        break;
      }
    }
    if (stage ==  null) {
      throw new MoxieException(MessageFormat.format("Illegal stage {0}", value));
    }
  }
 
  public void setIncrementNumber(String value) {
    for (NumberField number : NumberField.values()) {
      if (value.equalsIgnoreCase(number.name())) {
        this.incrementNumber = number;
        break;
      }
    }
    if (stage ==  null) {
      throw new MoxieException(MessageFormat.format("Illegal stage {0}", value));
    }
  }
 
  public void setReleaselog(File file) {
    releaseLog = file;
  }
 
  public void setDryrun(boolean value) {
    this.dryrun = value;
  }

  @Override
  public void execute() {
    if (stage == null) {
      stage = Stage.release;
    }
   
    if (moxieFile == null) {
      moxieFile = new File(getProject().getBaseDir(), "build.moxie");
    }
   
    if (releaseLog == null) {
      releaseLog = new File(getProject().getBaseDir(), "releases.moxie");
    }
   
    MaxmlMap map = null;
    try {
      map = Maxml.parse(moxieFile);
    } catch (MaxmlException e) {
      throw new MoxieException(e);
    }

    String groupId = map.getString(Toolkit.Key.groupId.name(), "");
    String artifactId = map.getString(Toolkit.Key.artifactId.name(), "");
    String projectName = map.getString(Toolkit.Key.name.name(), null);
    if (StringUtils.isEmpty(projectName)) {
      projectName = groupId + ":" + artifactId;
    }

    String version;
    String releaseVersion = map.getString(Toolkit.Key.releaseVersion.name(), "");
   
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    Date releaseDate = map.getDate(Toolkit.Key.releaseDate.name(), null);
    String releaseDateStr = releaseDate == null ? null : df.format(releaseDate);
    Date buildDate = new Date();
    String buildDateStr = buildDate == null ? null : df.format(buildDate);
   
    ArtifactVersion artifactVersion = new ArtifactVersion(
        map.getString(Constants.Key.version.name(), "0.0.0-SNAPSHOT"));
   
    Map<String, String> properties = new HashMap<String, String>();
    List<Substitute> replacements = new ArrayList<Substitute>();
    switch (stage) {
    case release:
      if (artifactVersion.isSnapshot()) {
        // update development snapshot info to release info
        releaseVersion = artifactVersion.setSnapshot(false).toString();
      } else {
        // preserve major.minor.incremental, increment build number
        releaseVersion = artifactVersion.incrementBuildNumber().toString();
      }
      title("Preparing RELEASE", releaseVersion);
      version = releaseVersion;
      releaseDate = buildDate;
      releaseDateStr = buildDateStr;
      replacements.add(new Substitute(Toolkit.Key.version.name(), releaseVersion));
      replacements.add(new Substitute(Toolkit.Key.releaseVersion.name(), releaseVersion));
      replacements.add(new Substitute(Toolkit.Key.releaseDate.name(), releaseDateStr));
      updateDescriptor(replacements);
     
      // update release log
      properties.put(Toolkit.Key.name.projectId(), projectName);
      properties.put(Toolkit.Key.version.projectId(), releaseVersion);
      properties.put(Toolkit.Key.buildDate.projectId(), releaseDateStr);
      properties.put(Toolkit.Key.releaseVersion.projectId(), releaseVersion);
      properties.put(Toolkit.Key.releaseDate.projectId(), releaseDateStr);
      updateReleaseLog(stage, releaseLog, properties);
      break;
    case snapshot:
      // start a new minor version SNAPSHOT development cycle
      if (artifactVersion.isSnapshot()) {
        throw new MoxieException("The current version {0} is already a SNAPSHOT!", artifactVersion.toString());
      }
      artifactVersion.setSnapshot(true);
      if (incrementNumber == null) {
        // increment minor version, if unspecified
        incrementNumber = NumberField.minor;
      }
      switch (incrementNumber) {
      case major:
        artifactVersion.incrementMajorVersion();
        break;
      case minor:
        artifactVersion.incrementMinorVersion();
        break;
      case incremental:
        artifactVersion.incrementIncrementalVersion();
        break;
      default:
        artifactVersion.incrementMinorVersion();
        break;
      }
     
      version = artifactVersion.toString();
      title("Preparing SNAPSHOT", version);
      replacements.add(new Substitute(Toolkit.Key.version.name(), version));
      updateDescriptor(replacements);

      // update release log
      updateReleaseLog(stage, releaseLog, properties);
      break;
    default:
      throw new MoxieException("Unknown stage \"{0}\"", stage);
    }
   
    // update Ant project properties
    getProject().setProperty(Toolkit.Key.name.projectId(), projectName);
    getProject().setProperty(Toolkit.Key.groupId.projectId(), groupId);
    getProject().setProperty(Toolkit.Key.artifactId.projectId(), artifactId);
    getProject().setProperty(Toolkit.Key.version.projectId(), version);
    getProject().setProperty(Toolkit.Key.releaseVersion.projectId(), releaseVersion);
    getProject().setProperty(Toolkit.Key.releaseDate.projectId(), releaseDateStr);
    getProject().setProperty(Toolkit.Key.buildDate.projectId(), buildDateStr);
   
    if (isShowTitle()) {
      // 3 is for "[] "
      setConsoleOffset(getTaskName().length() + 3 - DefaultLogger.LEFT_COLUMN_SIZE);
    }
   
    // share these paths for consumption by another task (e.g. mx:Commit)
    if (releaseLog.exists()) {
      sharePaths(moxieFile.getAbsolutePath(), releaseLog.getAbsolutePath());
    } else {
      sharePaths(moxieFile.getAbsolutePath());
    }
  }
 
 
  /**
   * Updates the Moxie descriptor with the specified key:value pairs.
   *
   * @param replacements
   */
  protected void updateDescriptor(List<Substitute> replacements) {
    String content = FileUtils.readContent(moxieFile, "\n");
    StringBuilder sb = new StringBuilder();
    String [] lines = content.split("\n");
    for (String line : lines) {
      String trimmed = line.trim();
      for (Substitute replacement : replacements) {       
        if (trimmed.startsWith(replacement.token)) {
          int start = line.indexOf(replacement.token) + replacement.token.length();
          int colon = line.indexOf(':', start) + 1;
          line = line.substring(0, colon) + " " + replacement.value;
        }
      }
      sb.append(line).append('\n');
    }
   
    if (dryrun) {
      System.out.println(sb.toString());
    } else {
      FileUtils.writeContent(moxieFile, sb.toString());
    }
  }
 
  /**
   * Updates the release log.
   *
   * @param replacements
   */
  protected void updateReleaseLog(Stage stage, File file, Map<String, String> properties) {
    if (!file.exists()) {
      return;
    }
   
    int currentRelease = 0;
    String releaseBase = "r";
   
    // identify the releaseBase, current release, and conditionally resolve properties
    StringBuilder sb = new StringBuilder();
    String content = FileUtils.readContent(file, "\n");
    for (String line : content.split("\n")) {
     
      if (Stage.release.equals(stage)) {
        // resolve properties for a release
        line = resolveProperties(line, properties);
      }

      // identify the current release and the releaseBase
      if (currentRelease == 0 && line.matches(getFieldRegex("release"))) {
        Pattern p = Pattern.compile(getObjectRegex("release"));
        Matcher m = p.matcher(line);
        if (m.find()) {
          releaseBase = m.group(1);
          currentRelease = Integer.parseInt(m.group(2));
        }
      }
      sb.append(line).append('\n');
    }
   
    content = sb.toString();
    sb.setLength(0);

    // update snapshot and releases
    // we do this in a separate loop in case the order of the keys is different
    if (Stage.release.equals(stage)) {
      // RELEASE
      int newRelease = currentRelease + 1;
      boolean updatedRelease = false;
      boolean updatedSnapshot = false;
      boolean updatedReleases = false;
      for (String line : content.split("\n")) {
        // update
        if (line.matches(getFieldRegex("release"))) {
          // advance release number
          int idx = line.indexOf(':') + 1;
          String newline = line.substring(0, idx);
          line = newline + " &" + releaseBase + newRelease;
          updatedRelease = true;
        } else if (line.matches(getFieldRegex("snapshot"))) {
          // set snapshot to null
          int idx = line.indexOf(':') + 1;
          String newline = line.substring(0, idx);
          line = newline + " ~";
          updatedSnapshot = true;
        } else if (line.matches(getFieldRegex("releases"))) {
          // update releases array
          int idx = line.indexOf(':') + 1;
          String newline = line.substring(0, idx);
          line = newline + " &" + releaseBase + "[1.." + newRelease + "]";
          updatedReleases = true;
        }
        sb.append(line).append('\n');
      }
      if (!updatedRelease) {
        // insert release field
        sb.append("release: &" + releaseBase + newRelease).append('\n');
      }
      if (!updatedSnapshot) {
        // insert snapshot field
        sb.append("snapshot: ~\n");
      }
      if (!updatedReleases) {
        // insert releases field
        sb.append("releases:  &" + releaseBase + "[1.." + newRelease + "]").append('\n');
      }     
    } else if (Stage.snapshot.equals(stage)) {
      // RESET for development
      int snapshotRelease = currentRelease + 1;
      // insert log template for next release
      String indent = "    ";
      sb.append("#\n# ${project.version} release\n#\n");
      sb.append(releaseBase + snapshotRelease + ": {\n");
      sb.append(indent).append("title").append(": ${project.name} ${project.version} released\n");
      sb.append(indent).append("id").append(": ${project.version}\n");
      sb.append(indent).append("date").append(": ${project.buildDate}\n");
      sb.append(indent).append("note").append(": ~\n");
      sb.append(indent).append("html").append(": ~\n");
      sb.append(indent).append("text").append(": ~\n");
      sb.append(indent).append("security").append(": ~\n");
      sb.append(indent).append("fixes").append(": ~\n");
      sb.append(indent).append("changes").append(": ~\n");
      sb.append(indent).append("additions").append(": ~\n");
      sb.append(indent).append("dependencyChanges").append(": ~\n");
      sb.append(indent).append("contributors").append(": ~\n");
      sb.append("}\n\n");
     
      // update the snapshot field to point to the inserted template
      boolean updatedSnapshot = false;
      for (String line : content.split("\n")) {
        if (line.matches(getFieldRegex("snapshot"))) {
          int idx = line.indexOf(':') + 1;
          String newline = line.substring(0, idx);
          line = newline + " &" + releaseBase + snapshotRelease;
          updatedSnapshot= true;
        }
        sb.append(line).append('\n');
      }
     
      if (!updatedSnapshot) {
        // insert snapshot field
        sb.append("snapshot: &" + releaseBase + snapshotRelease).append('\n');
      }
    }
   
    if (dryrun) {
      System.out.println(sb.toString());
    } else {
      FileUtils.writeContent(file, sb.toString());
    }
  }
 
  protected String getFieldRegex(String name) {
    return "^\\s*(?:'|\")?" + name + "(?:'|\")?\\s*:.*";
  }
 
  protected String getObjectRegex(String name) {
    return "^\\s*(?:'|\")?" + name + "(?:'|\")?\\s*:\\s*&([a-zA-Z]+)(\\d+)";
  }
 
  protected String resolveProperties(String string, Map<String, String> properties) {
    if (string == null) {
      return null;
    }
    Pattern p = Pattern.compile("\\$\\{[a-zA-Z0-9-_\\.]+\\}");     
    StringBuilder sb = new StringBuilder(string);
    int start = 0;
    while (true) {
      Matcher m = p.matcher(sb.toString());
      if (m.find(start)) {
        String prop = m.group();
        prop = prop.substring(2, prop.length() - 1);
        String value = getProperty(prop, properties);
        if (value.equals(prop)) {
          // leave property intact, it will stand out
          start = m.end();
          continue;
        }
        sb.replace(m.start(), m.end(), value);
        start = m.start() + value.length();
      } else {
        return sb.toString();
      }
    }   
  }
 
  protected String getProperty(String key, Map<String, String> properties) {
    String value = key;
    if (properties.containsKey(key)) {
      value = properties.get(key);
    }
    return value;
  }
}
TOP

Related Classes of org.moxie.ant.MxVersion

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.