Package org.atc.tools.ant

Source Code of org.atc.tools.ant.TODOTask

package org.atc.tools.ant;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.atc.tools.ant.format.*;
import org.atc.tools.ant.parsers.GenericItemParser;
import org.atc.tools.ant.parsers.ItemParser;
import org.atc.tools.ant.writers.CSVItemWriter;
import org.atc.tools.ant.writers.ItemWriter;
import org.atc.tools.ant.writers.PlainTextItemWriter;
import org.atc.tools.ant.writers.XMLItemWriter;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.lang.String.format;

/**
* A task that outputs TODOs to a file for all source files that contain them
*
* @author Alex Collins
*/
public class TODOTask extends MatchingTask {

  private PrintStream outStream;
  private boolean shouldWriteToProperty;

  /**
   * The delimited string containing the origin and content of TODOs/FIXMEs.
   * e.g. "My.java: do something,Another.java: code some more"
   */
  private StringBuffer optBuffer;
  private List<FormattedItem> itemsList;
  private ItemParser itemParser;
  private Map<Format, ItemFormatter> itemFormattersMap;
  private Map<Format, ItemWriter> itemWriterMap;

  public void init() {
    super.init();
  }

  public void execute() throws BuildException {
    super.execute();
    initRequiredFields();
    parseFiles();
    outputFindings();
  }

  /**
   * For all files in baseDir call processFile(f)
   */
  private void parseFiles() {
    File baseDir = Configuration.baseDir;
    for (String fName : getDirectoryScanner(baseDir).getIncludedFiles()) {
      File f = new File(format("%s/%s", baseDir.getAbsolutePath(), fName));
      processFile(f);
    }
  }

  private void outputFindings() {
    vlog(format("itemsList before output is %s", itemsList));

    if (shouldWriteToProperty) {
      getProject().setNewProperty(Configuration.property, optBuffer.toString());
    }

    ItemWriter itemWriter = itemWriterMap.get(Configuration.optFormat);
    vlog(format("Writing using itemWriter '%s'", itemWriter));

    if (itemWriter == null) {
      itemWriter = itemWriterMap.get(Format.DEFAULT);
      log(format("Warning: using DEFAULT output format because I couldn't find a writer for '%s'", Configuration.optFormat));
    }

    itemWriter.write(outStream, itemsList);
    outStream.flush();
    outStream.close();
  }

  /**
   * Scan the file and parse any and all TODO/FIXMEs into the <code>itemsList</code> field.
   *
   * @param f
   */
  private void processFile(File f) {
    try {
      vlog(format("Processing %s", f.getName()));
      final BufferedReader br = new BufferedReader(new FileReader(f));
      String line;
      int lineCounter = 0;
      while ((line = br.readLine()) != null) {
        line = line.trim();
        lineCounter++;
        if (itemParser.containsItem(line)) {
          Item item = newItem(f, line);
          item.setLineNumber(lineCounter);

          FormattedItem fmtItem = formatItem(item);

          vlog(format("Line number %s", lineCounter));

          if (Configuration.regex != null) {
            String replace = Configuration.replace == null ? "" : Configuration.replace;
            vlog(format("Running pattern %s with replace '%s' against '%s'",
                Configuration.regex, replace, fmtItem.getValue()));
            fmtItem.setValue(fmtItem.getValue().replaceAll(Configuration.regex, replace));
            vlog(format("Pattern produced '%s'", fmtItem.getValue()));
          }

          itemsList.add(fmtItem);
          vlog(format("Added item to itemsList: %s", fmtItem));

          //TODO: write only to the list; remove this to the output phase
          if (shouldWriteToProperty) {
            // buffer the val until later
            // Part of a two-stage refactor; output to file is done later; buffering for property is still done here. We'll merge the two concepts later.
            bufferValueForProperty(item);
            vlog("Item buffered");
          }
//          }
        }
      }

    } catch (IOException e) {
      log(format("Error! I couldn't write a TODO to the output file: %s", e.getMessage()));
    }

  }

  private FormattedItem formatItem(Item item) {
    //FIXME: do we risk a null pointer if the optFormat isn't recognisable?
    return itemFormattersMap.get(Configuration.optFormat).format(Configuration.optFormat, item);
  }

  private Item newItem(File f, String line) {
    Item item = itemParser.parse(line);
    item.setOrigin(f.getName());
    return item;
  }

  private void bufferValueForProperty(Item item) {
    String todoStr = item.toString();
    optBuffer.append(todoStr).append(Configuration.delim);
    vlog(format("Buffered %s to property %s with delim %s",
        todoStr, Configuration.property, Configuration.delim));
  }

  /**
   * Check if we should be writing to a property instead of an output file.
   *
   * @return true if the property field is set
   */
  private boolean shouldWriteToProperty() {
    return Configuration.property != null && !"".equals(Configuration.property);
  }

  private void initRequiredFields() throws BuildException {
    if (Configuration.baseDir == null) {
      log("You didn't specify a directory to recurse, so I'll use the current directory by default. This might not be what you want...");
      Configuration.baseDir = new File(System.getProperty("user.dir"));
    }

    if (Configuration.outFile == null) {
      outStream = System.out;
      log("No output file specified; writing to stdout");
    } else {
      try {
        outStream = new PrintStream(Configuration.outFile);
        log(format("Using file '%s'", Configuration.outFile.getAbsoluteFile()));
      } catch (FileNotFoundException e) {
        log("Error! Couldn't find output file!");
        throw new BuildException(e);
      }
    }

    if (Configuration.regex != null) {
      if (Configuration.replace == null) {
        log("No replace provided for regex; replacing all occurrences with nothing");
      }
    }

    shouldWriteToProperty = shouldWriteToProperty();
    optBuffer = new StringBuffer();
    itemsList = new ArrayList<FormattedItem>();
    itemParser = new GenericItemParser();

    itemFormattersMap = new HashMap<Format, ItemFormatter>();
    //TODO only add those we're generating? Or leave and add support for multiple formats?
    itemFormattersMap.put(Format.DEFAULT, new PlainTextItemFormatter());
    itemFormattersMap.put(Format.CSV, new CSVItemFormatter());
    itemFormattersMap.put(Format.XML, new XMLItemFormatter());

    //TODO move this to a register pattern and code for subclassing?
    itemWriterMap = new HashMap<Format, ItemWriter>();
    itemWriterMap.put(Format.DEFAULT, new PlainTextItemWriter());
    itemWriterMap.put(Format.CSV, new CSVItemWriter());
    itemWriterMap.put(Format.XML, new XMLItemWriter());
  }

  /**
   * Log <code>msg</code> if this.verbose is true
   */
  protected final void vlog(String msg) {
    if (Configuration.verbose) log(msg);
  }

  /**
   * Set the base directory for the source files
   * Required!
   */
  public void setDir(File dir) {
    Configuration.baseDir = dir;
  }

  /**
   * The file to write the TODOs to, or stdout otherwise
   */
  public void setOutFile(File file) {
    Configuration.outFile = file;
  }

  public void setVerbose(boolean verbose) {
    Configuration.verbose = verbose;
  }

  /**
   * What format to write the TODOs as. One of CSV, XML or the default (blank):
   * SourceFilename:TODO_CONTENT
   */
  public void setFormat(String format) {
    Configuration.optFormat = Format.fromString(format);
  }

  /**
   * Store the TODOs found in the property identified by <code>property</code>.
   *
   * @param property
   */
  public void setProperty(String property) {
    Configuration.property = property;
  }

  /**
   * Use the given String as the delimiter for each TODO item.
   * By default this is set to the system's line separator.
   */
  public void setDelim(String delim) {
    Configuration.delim = delim;
  }

  public void setPattern(String regex) {
    Configuration.regex = regex;
  }

  public void setReplace(String replace) {
    Configuration.replace = replace;
  }
}
TOP

Related Classes of org.atc.tools.ant.TODOTask

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.