detect mixed svn revisions at build time and add a warning to the version string if mixed revisions are detected

This commit is contained in:
myk
2013-02-22 21:11:54 +00:00
parent 8cd49f24bb
commit 8733773c2a
10 changed files with 109 additions and 491 deletions

1
.gitattributes vendored
View File

@@ -14504,5 +14504,4 @@ src/test/java/forge/deck/generate/Generate5ColorDeckTest.java svneol=native#text
src/test/java/forge/gui/ListChooserTest.java svneol=native#text/plain
src/test/java/forge/gui/game/CardDetailPanelTest.java svneol=native#text/plain
src/test/java/forge/item/DeckHintsTest.java -text
src/test/java/forge/model/BuildInfoTest.java -text
src/test/java/forge/model/FModelTest.java -text

104
pom.xml
View File

@@ -171,25 +171,49 @@
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.1</version>
<groupId>com.google.code.maven-svn-revision-number-plugin</groupId>
<artifactId>svn-revision-number-maven-plugin</artifactId>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<revisionOnScmFailure>0000</revisionOnScmFailure>
<providerImplementations>
</providerImplementations>
<failOnError>false</failOnError>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-nodeps</artifactId>
<version>1.8.1</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>build-version-string</id>
<phase>process-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<exportAntProperties>true</exportAntProperties>
<target>
<condition property="fullversionstring" value="${project.version}-r${forge.revision}${forge.specialStatus}" else="${project.version}-r${forge.revision}${forge.specialStatus} (mixed revisions detected; please update from the root directory)">
<contains string="${forge.mixedRevisions}" substring="false"/>
</condition>
</target>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -202,7 +226,7 @@
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<Implementation-Version>${project.version}-r${buildNumber}</Implementation-Version>
<Implementation-Version>${fullversionstring}</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
@@ -265,7 +289,7 @@
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
<manifestEntries>
<Implementation-Version>${project.version}-r${buildNumber}</Implementation-Version>
<Implementation-Version>${fullversionstring}</Implementation-Version>
</manifestEntries>
</archive>
</configuration>
@@ -379,6 +403,12 @@
<pluginManagement>
<plugins>
<plugin>
<groupId>com.google.code.maven-svn-revision-number-plugin</groupId>
<artifactId>svn-revision-number-maven-plugin</artifactId>
<version>1.13</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
@@ -423,46 +453,43 @@
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.codehaus.mojo
</groupId>
<artifactId>
build-helper-maven-plugin
</artifactId>
<versionRange>
[1.7,)
</versionRange>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<versionRange>[1.7,)</versionRange>
<goals>
<goal>
released-version
</goal>
<goal>
parse-version
</goal>
<goal>released-version</goal>
<goal>parse-version</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore />
<ignore/>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.apache.maven.plugins
</groupId>
<artifactId>
maven-compiler-plugin
</artifactId>
<versionRange>
[2.5.1,)
</versionRange>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<versionRange>[2.5.1,)</versionRange>
<goals>
<goal>testCompile</goal>
<goal>compile</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute />
<execute/>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>com.google.code.maven-svn-revision-number-plugin</groupId>
<artifactId>svn-revision-number-maven-plugin</artifactId>
<versionRange>[1.0.0,)</versionRange>
<goals>
<goal>revision</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute/>
</action>
</pluginExecution>
</pluginExecutions>
@@ -471,8 +498,8 @@
</plugin>
</plugins>
</pluginManagement>
</build>
<reporting>
<plugins>
<!-- Configure Built-In Dependency Reports NOT to scan Repos, Saves a
@@ -750,6 +777,7 @@
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>arcane-maven-repo</id>

View File

@@ -28,7 +28,6 @@ import forge.CardCharacteristicName;
import forge.CardColor;
import forge.CardUtil;
import forge.Color;
import forge.Singletons;
import forge.card.CardRules;
import forge.card.CardSplitType;
import forge.card.ICardFace;

View File

@@ -46,10 +46,10 @@ import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import net.miginfocom.swing.MigLayout;
import org.apache.commons.lang3.StringUtils;
import net.miginfocom.swing.MigLayout;
import forge.Singletons;
import forge.gui.WrapLayout;
import forge.gui.toolbox.FHyperlink;
import forge.gui.toolbox.FLabel;
@@ -165,7 +165,7 @@ public class BugReporter {
private static StringBuilder _buildSpoilerHeader(StringBuilder sb, String reportTitle) {
sb.append("[spoiler=").append(reportTitle).append("][code]");
sb.append("\nForge Version: ").append(Singletons.getModel().getBuildInfo().toPrettyString());
sb.append("\nForge Version: ").append(BuildInfo.getVersionString());
sb.append("\nOperating System: ").append(System.getProperty("os.name"))
.append(" ").append(System.getProperty("os.version"))
.append(" ").append(System.getProperty("os.arch"));
@@ -204,8 +204,7 @@ public class BugReporter {
p.add(new JScrollPane(area), "w 100%, h 100%, gaptop 5");
// determine proper forum URL
BuildInfo bi = Singletons.getModel().getBuildInfo();
String forgeVersion = bi.getVersion();
String forgeVersion = BuildInfo.getVersionString();
final String url;
if (StringUtils.containsIgnoreCase(forgeVersion, "svn")
|| StringUtils.containsIgnoreCase(forgeVersion, "snapshot")) {

View File

@@ -15,239 +15,28 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.model;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import org.apache.commons.lang3.StringUtils;
/**
* Provides access to information about the current version and build ID.
*/
public class BuildInfo {
/** Exception-free means of getting the ASCII Charset. */
public static final Charset US_ASCII_CHARSET = Charset.forName("US-ASCII");
/** Convenience for file.separator. */
/*
* private static final String FILE_SEP =
* System.getProperty("file.separator");
*/
/** Convenience for path.separator. */
/*
* private static final String PATH_SEP =
* System.getProperty("path.separator");
*/
/*
* private static final Pattern FORGE_JAR_REGEX_2G = // NOPMD by Braids on
* 8/12/11 10:18 AM Pattern.compile("^(.*" + Pattern.quote(FILE_SEP) + ")?"
* + Pattern.quote("forge-") + "([^" + Pattern.quote(FILE_SEP) +
* Pattern.quote(PATH_SEP) + "]*)" + Pattern.quote("-with-dependencies.jar")
* + "$", Pattern.CASE_INSENSITIVE);
*/
private transient String pathToForgeJar;
/**
* Construct a standard BuildInfo object.
*
* Package access is intentional for unit testing.
*
* @see forge.model.FModel#getBuildInfo()
*/
BuildInfo() {
// empty
}
/**
* Unit-testable constructor which allows a specific jar file to be set.
*
* Dependency injection! Relax, this won't hurt a bit.
*
* @param pathToMockJarFile
* where to find the mock Forge jar
*/
public BuildInfo(final String pathToMockJarFile) {
this.pathToForgeJar = pathToMockJarFile;
}
/**
* Get the current build ID for Forge.
*
* @return a String representing the build identifier, or null if we could
* not determine the value.
*/
public final String getBuildID() {
String manifestResult = "0000";
String[] manifestResultArray;
String result = "0000";
final String version = this.getVersion();
manifestResultArray = version.split("r");
manifestResult = manifestResultArray[manifestResultArray.length - 1];
if (manifestResult == null) {
result = "0000";
} else {
result = manifestResult;
}
return result;
}
// disable instantiation
private BuildInfo() { }
/**
* Get the current version of Forge.
*
* @return a String representing the version specifier, or "SVN" if unknown.
*/
public final String getVersion() {
String manifestResult;
String result;
manifestResult = BuildInfo.class.getPackage().getImplementationVersion();
if (manifestResult == null) {
result = "SVN";
} else {
result = manifestResult;
public static final String getVersionString() {
String version = BuildInfo.class.getPackage().getImplementationVersion();
if (StringUtils.isEmpty(version)) {
return "SVN";
}
// The code above will always return the SVN rev as "r15897" even with builds
// that are using a later revision for some unknown reason. This happens on
// Chris' dev system but not on Dave's dev system. We should note that many
// users are refering to the snapshot build by only using the SVS rev number
// and the code below may convince them to instead use the date of the archive.
// Note that the number appears to change at some point, now removing:
// r16084, 18445, 18685, 18891
if (result.endsWith("-r18891")) {
result = result.replace("-r18891", "");
return version;
}
return result;
}
/**
* Fetch an attribute from the Forge main jar's manifest.
*
* @param manifestAttrName
* the name of the attribute you want from the manifest
* @return the attribute's value, which may be empty or null
* @throws IOException
* if a (unique) Forge jar could not be found
*/
protected final String getManifestAttribute(final String manifestAttrName) throws IOException {
String result = null;
JarFile jar = null;
InputStream manifestStream = null;
try {
if (this.pathToForgeJar == null) {
// We're definitely not unit testing. Try to load from the
// currently running jar.
manifestStream = ClassLoader.getSystemResourceAsStream("META-INF/MANIFEST.MF");
final Manifest manifest = new Manifest(manifestStream);
result = this.getMainManifestAttribute(manifest, manifestAttrName);
}
/*
* if (result == null && pathToForgeJar == null) {
*
* // Try to find a unique Forge jar in the class path.
*
* final String classPath = System.getProperty("java.class.path");
* final String[] paths = classPath.split(PATH_SEP);
*
* for (String path : paths) { final Matcher matcher =
* FORGE_JAR_REGEX_2G.matcher(path);
*
* if (matcher.matches()) { if (pathToForgeJar == null) {
* pathToForgeJar = path; } else { // Error: we found more than one.
* pathToForgeJar = null; // NOPMD by Braids on 8/12/11 10:21 AM
*
* throw new MultipleForgeJarsFoundError( "Classpath = " +
* System.getProperty("java.class.path")); } } } }
*/
if ((result == null) && (this.pathToForgeJar == null)) {
throw new FileNotFoundException(
"There is nothing matching forge-*-with-dependencies.jar in the class path.");
}
if (result == null) {
jar = new JarFile(this.pathToForgeJar);
final Manifest manifest = jar.getManifest();
if (manifest == null) {
throw new IOException("Forge jar at <<" + this.pathToForgeJar + ">> has no manifest.");
}
result = this.getMainManifestAttribute(manifest, manifestAttrName);
}
} finally {
try {
manifestStream.close();
} catch (final Throwable ignored) {
// 10:21 AM
// ignored
}
try {
jar.close();
} catch (final Throwable ignored) {
// 10:21 AM
// ignored
}
}
return result;
}
/**
* Convience method for fetching an attribute from the main section of a
* jar's manifest.
*
* @param manifest
* the manifest that provides attributes
* @param manifestAttrName
* the name of the attribute to fetch
* @return the value of the attribute, or null if not set
*/
protected final String getMainManifestAttribute(final Manifest manifest, final String manifestAttrName) {
final Attributes atts = manifest.getMainAttributes();
return atts.getValue(manifestAttrName);
}
/**
* Generate a user-friendly string describing the version and build ID.
*
* This replaces the old system property program/version.
*
* @return a user-friendly string describing the version and build ID
*/
public final String toPrettyString() {
final String rawVersion = this.getVersion();
// final String rawBuildID = getBuildID();
String version;
if (rawVersion == null) {
version = "Unknown";
} else {
version = rawVersion;
}
/*
* String buildID; if (rawBuildID == null) { buildID = "Unknown"; } else
* { buildID = rawBuildID; }
*/
return "Forge version " + version; // ", build ID " + buildID;
}
}

View File

@@ -71,7 +71,6 @@ public enum FModel {
private final PrintStream oldSystemOut;
private final PrintStream oldSystemErr;
private BuildInfo buildInfo;
private OutputStream logFileStream;
@@ -152,7 +151,6 @@ public enum FModel {
testNetworkConnection();
this.setBuildInfo(new BuildInfo());
this.loadDynamicGamedata();
// Loads all cards (using progress bar).
@@ -286,25 +284,6 @@ public enum FModel {
*/
}
/**
* Gets the builds the info.
*
* @return {@link forge.model.BuildInfo}
*/
public final BuildInfo getBuildInfo() {
return this.buildInfo;
}
/**
* Sets the builds the info.
*
* @param bi0
* &emsp; {@link forge.model.BuildInfo}
*/
protected final void setBuildInfo(final BuildInfo bi0) {
this.buildInfo = bi0;
}
/**
* Gets the preferences.
*

View File

@@ -29,6 +29,7 @@ import forge.gui.match.VMatchUI;
import forge.gui.toolbox.FOverlay;
import forge.gui.toolbox.FPanel;
import forge.gui.toolbox.FSkin;
import forge.model.BuildInfo;
/** */
public enum FView {
@@ -73,7 +74,7 @@ public enum FView {
frmDocument.setExtendedState(frmDocument.getExtendedState() | Frame.MAXIMIZED_BOTH);
frmDocument.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frmDocument.setIconImage(FSkin.getIcon(FSkin.InterfaceIcons.ICO_FAVICON).getImage());
frmDocument.setTitle("Forge: " + Singletons.getModel().getBuildInfo().getVersion());
frmDocument.setTitle("Forge: " + BuildInfo.getVersionString());
// Frame components
frmDocument.setContentPane(lpnDocument);

View File

@@ -22,7 +22,6 @@ import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;

View File

@@ -1,157 +0,0 @@
package forge.model;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* Test the BuildInfo class.
*/
public class BuildInfoTest {
/** System property name for the class path. */
private static final String JAVA_CLASS_PATH = "java.class.path";
/** Manifest attribute name for the Build ID. */
private static final String MF_ATTR_NAME_BUILD = "Implementation-Build";
// by
// Braids
// on
// 8/12/11
// 10:29
// AM
/** Manifest attribute name for the version string. */
private static final String MF_ATTR_NAME_VERSION = "Implementation-Version";
// by
// Braids
// on
// 8/12/11
// 10:29
// AM
/**
* Test BuildInfo using a mock jar file.
*
* @throws IOException
* rarely
*/
@Test(enabled = false)
public final void test_BuildInfo_mockJar() throws IOException {
// Braids on
// 8/12/11
// 10:26 AM
File jarAsFile = null;
try {
jarAsFile = this.makeTmpJarWithManifest("BuildInfoTest-", ".jar", new String[] {
BuildInfoTest.MF_ATTR_NAME_VERSION, "1.2.42", BuildInfoTest.MF_ATTR_NAME_BUILD, "4200" });
final BuildInfo info = new BuildInfo(jarAsFile.getAbsolutePath());
final String actualVersion = info.getVersion();
Assert.assertEquals(actualVersion, "1.2.42", "versions match");
final String actualBuildID = info.getBuildID();
Assert.assertEquals(actualBuildID, "4200", "build IDs match");
} finally {
Assert.assertTrue(jarAsFile.delete(), "attempting to delete temporary jar file");
}
}
/**
* Test BuildInfo with one mock forge jar placed in the class path.
*
* @throws IOException
* indirectly
*/
@Test(enabled = false)
public final void test_BuildInfo_oneJarInCP() throws IOException {
// by
// Braids
// on
// 8/12/11
// 10:26
// AM
final String origClassPath = System.getProperty(BuildInfoTest.JAVA_CLASS_PATH);
File jarAsFile = null;
try {
jarAsFile = this.makeTmpJarWithManifest("forge-BuildInfoTest-", "-with-dependencies.jar", new String[] {
BuildInfoTest.MF_ATTR_NAME_VERSION, "1.2.43", BuildInfoTest.MF_ATTR_NAME_BUILD, "4201" });
System.setProperty(BuildInfoTest.JAVA_CLASS_PATH,
jarAsFile.getAbsolutePath() + System.getProperty("path.separator") + origClassPath);
final BuildInfo info = new BuildInfo();
final String actualVersion = info.getVersion();
Assert.assertEquals(actualVersion, "1.2.43", "versions match");
final String actualBuildID = info.getBuildID();
Assert.assertEquals(actualBuildID, "4201", "build IDs match");
} finally {
Assert.assertTrue(jarAsFile.delete(), "attempting to delete temporary jar file");
System.setProperty(BuildInfoTest.JAVA_CLASS_PATH, origClassPath);
}
}
/**
* Helper method to create jar files at specific locations with specific
* name-value pairs in their manifests.
*
* @param jarLocation
* where to create the jar file
* @param nameValuePairs
* has the form {"name1", "value1", "name2", "value2", ...}
*/
private File makeTmpJarWithManifest(final String fileNamePrefix, final String fileNameSuffix,
final String[] nameValuePairs) throws IOException {
if ((nameValuePairs.length % 2) != 0) {
throw new IllegalArgumentException("nameValuePairs must contain an even number of elements.");
}
File result = null;
FileOutputStream fileOut = null;
ZipOutputStream zipOut = null;
try {
result = File.createTempFile(fileNamePrefix, fileNameSuffix);
fileOut = new FileOutputStream(result);
zipOut = new ZipOutputStream(fileOut);
final ZipEntry zipEntry = new ZipEntry("META-INF/MANIFEST.MF");
zipOut.putNextEntry(zipEntry);
zipOut.write(this.toASCII("Manifest-Version: 1.3\n"));
for (int ix = 0; ix < nameValuePairs.length; ix += 2) {
zipOut.write(this.toASCII(nameValuePairs[ix]));
zipOut.write(this.toASCII(": "));
zipOut.write(this.toASCII(nameValuePairs[ix + 1]));
zipOut.write(this.toASCII("\n"));
}
zipOut.write(this.toASCII("\n"));
zipOut.closeEntry();
} finally {
if (zipOut != null) {
zipOut.close();
}
if (fileOut != null) {
fileOut.close();
}
}
return result;
}
private byte[] toASCII(final String str) {
return str.getBytes(BuildInfo.US_ASCII_CHARSET);
}
}

View File

@@ -76,29 +76,11 @@ public class FModelTest {
*/
@Test(enabled = false)
public final void test_getVersion() throws FileNotFoundException {
final String version = this.model.getBuildInfo().getVersion();
final String version = BuildInfo.getVersionString();
Assert.assertEquals(version, "SVN", "version is default");
}
/**
* Test getBuildID.
*
* @throws FileNotFoundException
* if something is really wrong
*/
@Test(enabled = false)
public final void test_getBuildID() throws FileNotFoundException {
// by
// Braids
// on
// 8/12/11
// 10:36
// AM
// Just test for an unexpected exception.
this.model.getBuildInfo().getBuildID();
}
/**
* Test getPreferences.
*