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() { + } + } }