001    /*
002     * Copyright (C) 2008 Adam Cornett This program is free software; you can
003     * redistribute it and/or modify it under the terms of the GNU General Public
004     * License as published by the Free Software Foundation; either version 3 of the
005     * License, or (at your option) any later version. This program is distributed
006     * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
007     * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
008     * See the GNU General Public License for more details. You should have received
009     * a copy of the GNU General Public License along with this program; if not, see
010     * <http://www.gnu.org/licenses>.
011     */
012    
013    package net.codescore.exe;
014    
015    import java.io.IOException;
016    
017    import org.apache.commons.logging.Log;
018    import org.apache.commons.logging.LogFactory;
019    
020    import net.codescore.dbo.Submission;
021    import net.codescore.dbo.TeamSubmission;
022    
023    /**
024     * Executes a diff comparison on the standard output of a submission. This class
025     * expects that the diff executable is on the path.
026     * 
027     * @author Adam Cornett
028     */
029    public class DiffExecutor {
030            private Log log = LogFactory.getLog(Grader.class);
031            private ProcessBuilder pb;
032            private boolean sideBySide = false;
033            private final Submission sub;
034    
035            public DiffExecutor(final Submission s) {
036                    sub = s;
037            }
038    
039            /**
040             * Get the output of diff.</br> Makes this call: </br><code>
041             * diff {@link TeamSubmission#getExpectedStdOutFile()} {@link TeamSubmission#getExecuteStdOutFile()}
042             * </code>
043             * 
044             * @return
045             * @throws InterruptedException
046             * @throws IOException
047             */
048            public String getDiff() throws InterruptedException, IOException {
049                    initPB();
050                    final StringBuffer diff = new StringBuffer();
051                    final Process dExe = pb.start();
052                    int b = dExe.getInputStream().read();
053                    for (; b != -1; b = dExe.getInputStream().read())
054                            diff.append((char) b);
055                    /* Clean up streams */
056                    dExe.getErrorStream().close();
057                    dExe.getInputStream().close();
058                    dExe.getOutputStream().close();
059                    final int rv = dExe.waitFor();
060                    if (rv > 1) {
061                            log.error("diff did not exit normally(" + rv + ") for "
062                                    + sub.getObjectId());
063                            return null;
064                    }
065                    return diff.toString();
066            }
067    
068            public boolean isSideBySide() {
069                    return sideBySide;
070            }
071    
072            /**
073             * Generate a Side-By-Side diff, this is used for judging, the same as
074             * adding a '-y' option to the diff command.
075             * 
076             * @param sideBySide
077             */
078            public void setSideBySide(final boolean sideBySide) {
079                    this.sideBySide = sideBySide;
080            }
081    
082            private void initPB() {
083                    pb = new ProcessBuilder();
084                    pb.directory(sub.getTempDir());
085                    String executeStdOut, expectedStdOut;
086                    executeStdOut = sub.getExpectedStdOutFile().getName();
087                    expectedStdOut = sub.getExecuteStdOutFile().getName();
088                    if (sideBySide)
089                            pb.command("diff", "-y", "--strip-trailing-cr", expectedStdOut,
090                                    executeStdOut);
091                    else
092                            pb.command("diff", "--strip-trailing-cr", expectedStdOut,
093                                    executeStdOut);
094                    StringBuilder sb = new StringBuilder();
095                    for (String s : pb.command())
096                            sb.append(s + " ");
097            }
098    }