diff --git a/src/main/java/hudson/scm/CVSChangeLogSet.java b/src/main/java/hudson/scm/CVSChangeLogSet.java
index 4125000..3b830b4 100644
--- a/src/main/java/hudson/scm/CVSChangeLogSet.java
+++ b/src/main/java/hudson/scm/CVSChangeLogSet.java
@@ -29,7 +29,10 @@
import hudson.util.Digester2;
import hudson.util.IOException2;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.PrintStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -683,4 +686,50 @@ public String toString() {
return buf.toString();
}
}
+
+ public void toFile(final java.io.File changelogFile) throws IOException {
+ PrintStream output = new PrintStream(new FileOutputStream(changelogFile));
+
+ DateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+
+ output.println("");
+ output.println("");
+
+ for (CVSChangeLog entry : this) {
+
+ output.println("\t");
+ output.println("\t\t" + format.format(entry.getChangeDate()) + "");
+ output.println("\t\t");
+
+ for (CVSChangeLogSet.File file : entry.getFiles()) {
+
+ output.println("\t\t");
+ output.println("\t\t\t");
+
+ if (file.getFullName() != null) {
+ output.println("\t\t\t");
+ }
+
+ output.println("\t\t\t" + file.getRevision() + "");
+
+ final String previousRevision = file.getPrevrevision();
+
+ if (previousRevision != null) {
+ output.println("\t\t\t" + previousRevision + "");
+ }
+
+ if (file.isDead()) {
+ output.println("\t\t\t");
+ }
+
+ output.println("\t\t");
+ }
+
+ output.println("\t\t");
+ output.println("\t");
+ }
+ output.println("");
+ output.flush();
+ output.close();
+ }
}
diff --git a/src/main/java/hudson/scm/CVSSCM.java b/src/main/java/hudson/scm/CVSSCM.java
index 3227c99..7011864 100644
--- a/src/main/java/hudson/scm/CVSSCM.java
+++ b/src/main/java/hudson/scm/CVSSCM.java
@@ -44,10 +44,13 @@
import hudson.scm.cvstagging.LegacyTagAction;
import hudson.util.Secret;
-import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
import java.io.File;
+import java.io.FileReader;
import java.io.IOException;
+import java.io.InputStreamReader;
import java.io.PrintStream;
+import java.io.Reader;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.text.DateFormat;
@@ -67,6 +70,7 @@
import net.sf.json.JSONObject;
+import org.apache.commons.io.output.DeferredFileOutputStream;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.export.Exported;
@@ -412,11 +416,11 @@ private List calculateChangeLog(final Date startTime, final Date e
for (final CvsRepositoryItem item : repository.getRepositoryItems()) {
for (final CvsModule module : item.getModules()) {
- String logContents = getRemoteLogForModule(repository, item, module, listener.getLogger(), startTime, endTime, envVars);
+ CvsLog logContents = getRemoteLogForModule(repository, item, module, listener.getLogger(), startTime, endTime, envVars);
// use the parser to build up a list of changes and add it to the
// list we've been creating
- changes.addAll(CvsChangeLogHelper.getInstance().mapCvsLog(logContents, repository, item, module, envVars).getChanges());
+ changes.addAll(logContents.mapCvsLog(repository, item, module, envVars).getChanges());
}
}
return changes;
@@ -458,11 +462,11 @@ private List calculateRepositoryState(final Date startTime, final Date
for (final CvsRepositoryItem item : repository.getRepositoryItems()) {
for (final CvsModule module : item.getModules()) {
- String logContents = getRemoteLogForModule(repository, item, module, listener.getLogger(), startTime, endTime, envVars);
+ CvsLog logContents = getRemoteLogForModule(repository, item, module, listener.getLogger(), startTime, endTime, envVars);
// use the parser to build up a list of changed files and add it to
// the list we've been creating
- files.addAll(CvsChangeLogHelper.getInstance().mapCvsLog(logContents, repository, item, module, envVars).getFiles());
+ files.addAll(logContents.mapCvsLog(repository, item, module, envVars).getFiles());
}
}
@@ -487,7 +491,7 @@ private List calculateRepositoryState(final Date startTime, final Date
* @throws IOException
* on underlying communication failure
*/
- private String getRemoteLogForModule(final CvsRepository repository, final CvsRepositoryItem item, final CvsModule module,
+ private CvsLog getRemoteLogForModule(final CvsRepository repository, final CvsRepositoryItem item, final CvsModule module,
final PrintStream errorStream, final Date startTime, final Date endTime, final EnvVars envVars) throws IOException {
final Client cvsClient = getCvsClient(repository, envVars);
@@ -509,7 +513,8 @@ private String getRemoteLogForModule(final CvsRepository repository, final CvsRe
// create an output stream to send the output from CVS command to - we
// can then parse it from here
- final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ final File tmpRlogSpill = File.createTempFile("cvs","rlog");
+ final DeferredFileOutputStream outputStream = new DeferredFileOutputStream(100*1024,tmpRlogSpill);
final PrintStream logStream = new PrintStream(outputStream);
// set a listener with our output stream that we parse the log from
@@ -539,11 +544,25 @@ private String getRemoteLogForModule(final CvsRepository repository, final CvsRe
}
// flush the output so we have it all available for parsing
- logStream.flush();
- outputStream.flush();
+ logStream.close();
// return the contents of the stream as the output of the command
- return outputStream.toString();
+ return new CvsLog() {
+ @Override
+ public Reader read() throws IOException {
+ // TODO: is it really correct that we read this in the platform encoding?
+ // note that master and slave can have different platform encoding
+ if (outputStream.isInMemory())
+ return new InputStreamReader(new ByteArrayInputStream(outputStream.getData()));
+ else
+ return new FileReader(outputStream.getFile());
+ }
+
+ @Override
+ public void dispose() {
+ tmpRlogSpill.delete();
+ }
+ };
}
/**
@@ -834,7 +853,7 @@ public boolean checkout(final AbstractBuild, ?> build, final Launcher launcher
changes.addAll(calculateChangeLog(lastCompleteBuild.getTime(), build.getTime(), location, launcher,
workspace, listener, build.getEnvironment(listener)));
}
- CvsChangeLogHelper.getInstance().toFile(changes, changelogFile);
+ new CVSChangeLogSet(build,changes).toFile(changelogFile);
}
// add the current workspace state as an action
diff --git a/src/main/java/hudson/scm/CvsChangeLogHelper.java b/src/main/java/hudson/scm/CvsLog.java
similarity index 66%
rename from src/main/java/hudson/scm/CvsChangeLogHelper.java
rename to src/main/java/hudson/scm/CvsLog.java
index 2c00bc7..e1bb58c 100644
--- a/src/main/java/hudson/scm/CvsChangeLogHelper.java
+++ b/src/main/java/hudson/scm/CvsLog.java
@@ -1,285 +1,287 @@
-/*
- * The MIT License
- *
- * Copyright (c) 2011-2012, Michael Clarke
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-package hudson.scm;
-
-import hudson.EnvVars;
-import hudson.scm.CVSChangeLogSet.CVSChangeLog;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public final class CvsChangeLogHelper {
-
- private static CvsChangeLogHelper instance;
- private static final String MAIN_REGEX = "[\\r|\\n]+RCS file:\\s(.+?),[a-z]+[\\r|\\n]+head:\\s+(.*?)"
- + "[\\r|\\n]+branch:(.*?)[\\r|\\n]+locks:.*?[\\r|\\n]+access list:.*?[\\r|\\n]+symbolic names:(.*?)"
- + "[\\r|\\n]+keyword substitution:.*?[\\r|\\n]+total revisions:.+?;\\s+selected revisions:\\s+[1-9]+[0-9]*\\s*[\\r|\\n]+"
- + "description:.*?";
- private static final String SECONDARY_REGEX = "\\s+(.+?)[\\r|\\n]+date:\\s+(.+?)\\;\\s+author:\\s+(.+?);\\s+state:\\s+(.+?);.*?[\\r|\\n]+(.*|\\r|\\n])[\\r|\\r\\n]";
-
- private static final DateFormat[] DATE_FORMATTER = new SimpleDateFormat[] {
- new SimpleDateFormat("yyyy/MM/dd HH:mm:ss Z"), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"),
- new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), };
-
- private CvsChangeLogHelper() {
- }
-
- public static CvsChangeLogHelper getInstance() {
- synchronized (CvsChangeLogHelper.class) {
- if (null == instance) {
- instance = new CvsChangeLogHelper();
- }
- }
-
- return instance;
- }
-
- public void toFile(final List repositoryState, final File changelogFile) throws IOException {
- PrintStream output = new PrintStream(new FileOutputStream(changelogFile));
-
- output.println("");
- output.println("");
-
- for (CVSChangeLog entry : repositoryState) {
-
- synchronized (DATE_FORMATTER) {
- output.println("\t");
- output.println("\t\t" + DATE_FORMATTER[3].format(entry.getChangeDate()) + "");
- output.println("\t\t");
- }
-
- for (CVSChangeLogSet.File file : entry.getFiles()) {
-
- output.println("\t\t");
- output.println("\t\t\t");
-
- if (file.getFullName() != null) {
- output.println("\t\t\t");
- }
-
- output.println("\t\t\t" + file.getRevision() + "");
-
- final String previousRevision = file.getPrevrevision();
-
- if (previousRevision != null) {
- output.println("\t\t\t" + previousRevision + "");
- }
-
- if (file.isDead()) {
- output.println("\t\t\t");
- }
-
- output.println("\t\t");
- }
-
- output.println("\t\t");
- output.println("\t");
- }
- output.println("");
- output.flush();
- output.close();
- }
-
- /**
- * Converts the output of the cvs log command into a java structure.
- *
- * @param logContents
- * output of 'cvs log -S' (with any date filters)
- * @return a list of CVS files with changes in the log
- * @throws IOException
- * on error parsing log
- */
- public CvsChangeSet mapCvsLog(final String logContents,final CvsRepository repository,
- final CvsRepositoryItem item, final CvsModule module, final EnvVars envVars) {
- final List changes = new ArrayList();
- final List files = new ArrayList();
-
- final Pattern mainPattern = Pattern.compile(MAIN_REGEX, Pattern.DOTALL | Pattern.MULTILINE);
- final Pattern innerPattern = Pattern.compile(SECONDARY_REGEX, Pattern.MULTILINE | Pattern.DOTALL);
- for (String section : logContents.split("=============================================================================")) {
- final Matcher mainMatcher = mainPattern.matcher(section);
-
- if (!mainMatcher.find()) {
- continue;
- }
-
- /*
- * this is a bit of a hack - we get the root of the module in the
- * remote repository by splitting the CVS URL on a forward slash
- * which should give us the folder path in the second position of
- * the array
- */
- final String rootName = envVars.expand(repository.getCvsRoot()).split("/", 2)[1];
- final String fullName = mainMatcher.group(1);
- final String tipVersion;
-
- if (CvsRepositoryLocationType.HEAD == item.getLocation().getLocationType()) {
- tipVersion = mainMatcher.group(2);
- } else {
- CvsRepositoryLocation repositoryLocation = item.getLocation();
- tipVersion = getCurrentFileVersion(
- repositoryLocation.getLocationName(),
- mainMatcher.group(4),
- mainMatcher.group(2),
- repositoryLocation.isUseHeadIfNotFound());
-
- if (null == tipVersion) {
- continue;
- }
- }
-
- final String[] cvsChanges = section.split(
- "[\\r|\\n]+----------------------------[\\r|\\n]+revision");
-
- for (final String cvsChange : cvsChanges) {
- final Matcher innerMatcher = innerPattern.matcher(cvsChange);
-
- CvsFile cvsFile = null;
- while (innerMatcher.find()) {
-
- Date changeDate = null;
-
- synchronized (DATE_FORMATTER) {
-
- final String inputDate = innerMatcher.group(2);
-
- for (DateFormat dateFormat : DATE_FORMATTER) {
- try {
- changeDate = dateFormat.parse(inputDate);
- } catch (final ParseException ex) {
- /*
- * we can ignore the exception (for now), if
- * date is null after exiting the loop then we
- * throw an exception then.
- */
- }
- }
-
- if (null == changeDate) {
- throw new RuntimeException("Date could not be parsed into any recognised format - "
- + inputDate);
- }
- }
-
- final String changeVersion = innerMatcher.group(1);
- final String changeAuthor = innerMatcher.group(3);
- final String changeDescription = innerMatcher.group(5);
- final boolean isDead = innerMatcher.group(4).equals("dead");
-
- if (!isChangeValidForFileVersion(changeVersion, tipVersion)) {
- continue;
- }
-
- final CVSChangeLog change = getCvsChangeLog(changes, changeDescription, changeDate, changeAuthor);
-
- final CVSChangeLogSet.File file = new CVSChangeLogSet.File();
- file.setFullName(fullName);
- file.setName(fullName.substring(rootName.length() + 2));
- file.setRevision(changeVersion);
- if (isDead) {
- file.setDead();
- }
-
- if (null == cvsFile) {
- cvsFile = new CvsFile(file.getFullName(), file.getRevision(), isDead);
- files.add(cvsFile);
- }
-
- change.addFile(file);
-
- }
-
- }
-
- }
-
- return new CvsChangeSet(files, changes);
- }
-
- private CVSChangeLog getCvsChangeLog(final List changes, final String changeDescription,
- final Date changeDate, final String changeAuthor) {
- final CVSChangeLog changeLogEntry = new CVSChangeLog();
- changeLogEntry.setChangeDate(changeDate);
- changeLogEntry.setMsg(changeDescription);
- changeLogEntry.setUser(changeAuthor);
- for (CVSChangeLog change : changes) {
- if (change.canBeMergedWith(changeLogEntry)) {
- return change;
- }
- }
-
- changes.add(changeLogEntry);
- return changeLogEntry;
- }
-
- private boolean isChangeValidForFileVersion(final String changeRevision, final String fileRevision) {
- String[] changeParts = changeRevision.split("\\.");
- String[] fileParts = fileRevision.split("\\.");
-
- if (fileParts.length != changeParts.length) {
- return false;
- }
-
- for (int i = 0; i < fileParts.length - 1; i++) {
- if (!changeParts[i].equals(fileParts[i])) {
- return false;
- }
- }
-
- return (Integer.parseInt(fileParts[fileParts.length - 1]) <= Integer
- .parseInt(changeParts[changeParts.length - 1]));
- }
-
- private String getCurrentFileVersion(final String tagName, final String versionAndTagList,
- final String headVersion, final boolean useHeadIfNotFound) {
- final Pattern pattern = Pattern.compile(tagName + ": (([0-9]+\\.)+)0\\.([0-9]+)", Pattern.MULTILINE | Pattern.DOTALL);
- final Matcher matcher = pattern.matcher(versionAndTagList);
- if (!matcher.find()) {
- final Pattern innerPattern = Pattern.compile(tagName + ": ([0-9]+(\\.[0-9]+)+)", Pattern.MULTILINE | Pattern.DOTALL);
- final Matcher innerMatcher = innerPattern.matcher(versionAndTagList);
- if (innerMatcher.find()) {
- return innerMatcher.group(1);
- } else {
- if (useHeadIfNotFound) {
- return headVersion;
- } else {
- return null;
- }
- }
- }
-
- return matcher.group(1) + matcher.group(3) + ".0";
- }
-
-}
+package hudson.scm;
+
+import hudson.EnvVars;
+import hudson.scm.CVSChangeLogSet.CVSChangeLog;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Represents raw data produced by "cvs log"/"cvs rlog" and the parse logic to convert it into {@link CVSChangeLogSet}
+ *
+ * @author Michael Clarke
+ * @author Kohsuke Kawaguchi
+ */
+public abstract class CvsLog {
+ /**
+ * Reads the "cvs log" output.
+ */
+ abstract Reader read() throws IOException;
+
+ /**
+ * Deletes any data stored by this object.
+ */
+ abstract void dispose();
+
+ /**
+ * Splits cvs log by "============================================================================="
+ * and return each "section" separated by it.
+ *
+ * If an {@link IOException} is encountered while reading data, iterator will throw {@link Error}.
+ */
+ public Iterable getSections() {
+ return new Iterable() {
+ @Override
+ public Iterator iterator() {
+ try {
+ return new Iterator() {
+ String next;
+ BufferedReader in = new BufferedReader(read());
+
+ @Override
+ public boolean hasNext() {
+ fetch();
+ return next!=null;
+ }
+
+ @Override
+ public String next() {
+ fetch();
+ String r = next;
+ next = null;
+ if (r==null)
+ throw new NoSuchElementException();
+ return r;
+ }
+
+ private void fetch() {
+ if (next!=null) return; // already have the data fetched
+ if (in==null) return; // nothing more to read
+
+ try {
+ StringBuilder buf = new StringBuilder();
+ while (true) {
+ String line = in.readLine();
+ if (line==null) {
+ in.close();
+ in = null;
+ break;
+ }
+ if (line.equals("============================================================================="))
+ break;
+ buf.append(line).append('\n');
+ }
+ next = buf.toString();
+ } catch (IOException e) {
+ throw new Error(e);
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ } catch (IOException e) {
+ throw new Error(e);
+ }
+ }
+ };
+ }
+
+
+ /**
+ * Parses this output and produces {@link CvsChangeSet}.
+ *
+ * @return a list of CVS files with changes in the log
+ * @throws IOException
+ * on error parsing log
+ */
+ public CvsChangeSet mapCvsLog(final CvsRepository repository,
+ final CvsRepositoryItem item, final CvsModule module, final EnvVars envVars) {
+
+ final List changes = new ArrayList();
+ final List files = new ArrayList();
+
+ final Pattern mainPattern = Pattern.compile(MAIN_REGEX, Pattern.DOTALL | Pattern.MULTILINE);
+ final Pattern innerPattern = Pattern.compile(SECONDARY_REGEX, Pattern.MULTILINE | Pattern.DOTALL);
+ for (String section : this.getSections()) {
+ final Matcher mainMatcher = mainPattern.matcher(section);
+
+ if (!mainMatcher.find()) {
+ continue;
+ }
+
+ /*
+ * this is a bit of a hack - we get the root of the module in the
+ * remote repository by splitting the CVS URL on a forward slash
+ * which should give us the folder path in the second position of
+ * the array
+ */
+ final String rootName = envVars.expand(repository.getCvsRoot()).split("/", 2)[1];
+ final String fullName = mainMatcher.group(1);
+ final String tipVersion;
+
+ if (CvsRepositoryLocationType.HEAD == item.getLocation().getLocationType()) {
+ tipVersion = mainMatcher.group(2);
+ } else {
+ CvsRepositoryLocation repositoryLocation = item.getLocation();
+ tipVersion = getCurrentFileVersion(
+ repositoryLocation.getLocationName(),
+ mainMatcher.group(4),
+ mainMatcher.group(2),
+ repositoryLocation.isUseHeadIfNotFound());
+
+ if (null == tipVersion) {
+ continue;
+ }
+ }
+
+ final String[] cvsChanges = section.split(
+ "----------------------------[\\r|\\n]+revision");
+
+ for (final String cvsChange : cvsChanges) {
+ final Matcher innerMatcher = innerPattern.matcher(cvsChange);
+
+ CvsFile cvsFile = null;
+ while (innerMatcher.find()) {
+
+ Date changeDate = null;
+
+ synchronized (DATE_FORMATTER) {
+
+ final String inputDate = innerMatcher.group(2);
+
+ for (DateFormat dateFormat : DATE_FORMATTER) {
+ try {
+ changeDate = dateFormat.parse(inputDate);
+ } catch (final ParseException ex) {
+ /*
+ * we can ignore the exception (for now), if
+ * date is null after exiting the loop then we
+ * throw an exception then.
+ */
+ }
+ }
+
+ if (null == changeDate) {
+ throw new RuntimeException("Date could not be parsed into any recognised format - "
+ + inputDate);
+ }
+ }
+
+ final String changeVersion = innerMatcher.group(1);
+ final String changeAuthor = innerMatcher.group(3);
+ final String changeDescription = innerMatcher.group(5);
+ final boolean isDead = innerMatcher.group(4).equals("dead");
+
+ if (!isChangeValidForFileVersion(changeVersion, tipVersion)) {
+ continue;
+ }
+
+ final CVSChangeLog change = getCvsChangeLog(changes, changeDescription, changeDate, changeAuthor);
+
+ final CVSChangeLogSet.File file = new CVSChangeLogSet.File();
+ file.setFullName(fullName);
+ file.setName(fullName.substring(rootName.length() + 2));
+ file.setRevision(changeVersion);
+ if (isDead) {
+ file.setDead();
+ }
+
+ if (null == cvsFile) {
+ cvsFile = new CvsFile(file.getFullName(), file.getRevision(), isDead);
+ files.add(cvsFile);
+ }
+
+ change.addFile(file);
+
+ }
+
+ }
+
+ }
+
+ return new CvsChangeSet(files, changes);
+ }
+
+ private CVSChangeLog getCvsChangeLog(final List changes, final String changeDescription,
+ final Date changeDate, final String changeAuthor) {
+ final CVSChangeLog changeLogEntry = new CVSChangeLog();
+ changeLogEntry.setChangeDate(changeDate);
+ changeLogEntry.setMsg(changeDescription);
+ changeLogEntry.setUser(changeAuthor);
+ for (CVSChangeLog change : changes) {
+ if (change.canBeMergedWith(changeLogEntry)) {
+ return change;
+ }
+ }
+
+ changes.add(changeLogEntry);
+ return changeLogEntry;
+ }
+
+ private boolean isChangeValidForFileVersion(final String changeRevision, final String fileRevision) {
+ String[] changeParts = changeRevision.split("\\.");
+ String[] fileParts = fileRevision.split("\\.");
+
+ if (fileParts.length != changeParts.length) {
+ return false;
+ }
+
+ for (int i = 0; i < fileParts.length - 1; i++) {
+ if (!changeParts[i].equals(fileParts[i])) {
+ return false;
+ }
+ }
+
+ return (Integer.parseInt(fileParts[fileParts.length - 1]) <= Integer
+ .parseInt(changeParts[changeParts.length - 1]));
+ }
+
+ private String getCurrentFileVersion(final String tagName, final String versionAndTagList,
+ final String headVersion, final boolean useHeadIfNotFound) {
+ final Pattern pattern = Pattern.compile(tagName + ": (([0-9]+\\.)+)0\\.([0-9]+)", Pattern.MULTILINE | Pattern.DOTALL);
+ final Matcher matcher = pattern.matcher(versionAndTagList);
+ if (!matcher.find()) {
+ final Pattern innerPattern = Pattern.compile(tagName + ": ([0-9]+(\\.[0-9]+)+)", Pattern.MULTILINE | Pattern.DOTALL);
+ final Matcher innerMatcher = innerPattern.matcher(versionAndTagList);
+ if (innerMatcher.find()) {
+ return innerMatcher.group(1);
+ } else {
+ if (useHeadIfNotFound) {
+ return headVersion;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ return matcher.group(1) + matcher.group(3) + ".0";
+ }
+
+ private static final String MAIN_REGEX = "[\\r|\\n]+RCS file:\\s(.+?),[a-z]+[\\r|\\n]+head:\\s+(.*?)"
+ + "[\\r|\\n]+branch:(.*?)[\\r|\\n]+locks:.*?[\\r|\\n]+access list:.*?[\\r|\\n]+symbolic names:(.*?)"
+ + "[\\r|\\n]+keyword substitution:.*?[\\r|\\n]+total revisions:.+?;\\s+selected revisions:\\s+[1-9]+[0-9]*\\s*[\\r|\\n]+"
+ + "description:.*?";
+ private static final String SECONDARY_REGEX = "\\s+(.+?)[\\r|\\n]+date:\\s+(.+?)\\;\\s+author:\\s+(.+?);\\s+state:\\s+(.+?);.*?[\\r|\\n]+(.*|\\r|\\n])[\\r|\\r\\n]";
+
+ private static final DateFormat[] DATE_FORMATTER = new SimpleDateFormat[] {
+ new SimpleDateFormat("yyyy/MM/dd HH:mm:ss Z"), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"),
+ new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), };
+
+}
diff --git a/src/test/java/hudson/scm/CvsChangeLogHelperTest.java b/src/test/java/hudson/scm/CvsChangeLogHelperTest.java
index bd61b82..4e47a6f 100644
--- a/src/test/java/hudson/scm/CvsChangeLogHelperTest.java
+++ b/src/test/java/hudson/scm/CvsChangeLogHelperTest.java
@@ -8,6 +8,8 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
@@ -15,7 +17,6 @@
public class CvsChangeLogHelperTest extends HudsonTestCase {
- @Test
public void testMapCvsLog() {
String logContents = "cvs rlog: Logging doc\n"
+ "\n"
@@ -40,12 +41,11 @@ public void testMapCvsLog() {
":local:/Users/Shared/cvs", false, null,
Arrays.asList(new CvsRepositoryItem[] {item}),
new ArrayList(), -1);
- assertEquals("adding in a test file", CvsChangeLogHelper.getInstance()
- .mapCvsLog(logContents, repository, item, module, new EnvVars())
+ assertEquals("adding in a test file", new StringCvsLog(logContents)
+ .mapCvsLog(repository, item, module, new EnvVars())
.getChanges().get(0).getMsg());
}
- @Test
public void testMapNonFilteredCvsLog() throws IOException, URISyntaxException {
File changeLogFile = new File(CvsChangeLogHelperTest.class.getResource("cvsRlogOutput_ISSUE-13227.txt").toURI());
int len = (int)changeLogFile.length();
@@ -55,10 +55,10 @@ public void testMapNonFilteredCvsLog() throws IOException, URISyntaxException {
CvsModule module = new CvsModule("portalInt", null);
CvsRepositoryItem item = new CvsRepositoryItem(new CvsRepositoryLocation.BranchRepositoryLocation("d-chg00017366_op_brc_prod-op-2012-04-19", false), new CvsModule[]{module});
CvsRepository repository = new CvsRepository(":pserver:user:password@host:port:/usr/local/cvs/repcvs/", false, null, Arrays.asList(new CvsRepositoryItem[]{item}), new ArrayList(), -1);
- assertEquals(4, CvsChangeLogHelper.getInstance().mapCvsLog(logContents, repository, item, module, new EnvVars()).getChanges().size());
+ CvsChangeSet cvsChangeSet = new StringCvsLog(logContents).mapCvsLog(repository, item, module, new EnvVars());
+ assertEquals(4, cvsChangeSet.getChanges().size());
}
- @Test
public void testMapNonFilteredCvsLog2() throws IOException, URISyntaxException {
File changeLogFile = new File(CvsChangeLogHelperTest.class.getResource("cvsRlogOutput2.txt").toURI());
int len = (int)changeLogFile.length();
@@ -68,7 +68,22 @@ public void testMapNonFilteredCvsLog2() throws IOException, URISyntaxException {
CvsModule module = new CvsModule("branch2", null);
CvsRepositoryItem item = new CvsRepositoryItem(new CvsRepositoryLocation.BranchRepositoryLocation(/*"d-chg00017366_op_brc_prod-op-2012-04-19"*/ "branch2", false), new CvsModule[]{module});
CvsRepository repository = new CvsRepository(":pserver:user:password@host:port:/homepages/25/d83630321/htdocs/cvs", false, null, Arrays.asList(new CvsRepositoryItem[]{item}), new ArrayList(), -1);
- assertEquals(3, CvsChangeLogHelper.getInstance().mapCvsLog(logContents, repository, item, module, new EnvVars()).getChanges().size());
+ CvsChangeSet set = new StringCvsLog(logContents).mapCvsLog(repository, item, module, new EnvVars());
+ assertEquals(3, set.getChanges().size());
}
+ public static class StringCvsLog extends CvsLog {
+ private final String text;
+
+ public StringCvsLog(String text) {
+ this.text = text;
+ }
+
+ Reader read() throws IOException {
+ return new StringReader(text);
+ }
+
+ void dispose() {
+ }
+ }
}