test/tools/javac/lib/ToolBox.java

Thu, 14 Mar 2013 08:30:16 +0000

author
vromero
date
Thu, 14 Mar 2013 08:30:16 +0000
changeset 1637
2e21ecd7a5ad
parent 1591
dc8b7aa7cef3
child 2525
2eb010b6cb22
permissions
-rw-r--r--

8008582: jtreg failures after conversion of shell tests to Java
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  */
    24 import java.io.BufferedReader;
    25 import java.io.File;
    26 import java.io.FileNotFoundException;
    27 import java.io.FileWriter;
    28 import java.io.IOException;
    29 import java.io.InputStreamReader;
    30 import java.io.PrintWriter;
    31 import java.io.StringWriter;
    32 import java.net.URI;
    33 import java.nio.charset.Charset;
    34 import java.nio.file.Files;
    35 import java.nio.file.Path;
    36 import java.nio.file.Paths;
    37 import java.nio.file.StandardOpenOption;
    38 import java.util.ArrayList;
    39 import java.util.Arrays;
    40 import java.util.Collection;
    41 import java.util.Collections;
    42 import java.util.EnumSet;
    43 import java.util.List;
    44 import java.util.Map;
    45 import java.util.Set;
    46 import java.util.regex.Matcher;
    47 import java.util.regex.Pattern;
    49 import javax.tools.JavaCompiler;
    50 import javax.tools.JavaFileObject;
    51 import javax.tools.SimpleJavaFileObject;
    52 import javax.tools.ToolProvider;
    54 import com.sun.source.util.JavacTask;
    55 import com.sun.tools.javac.api.JavacTaskImpl;
    57 import sun.tools.jar.Main;
    59 import static java.nio.file.StandardCopyOption.*;
    61 /**
    62  * Toolbox for jtreg tests.
    63  */
    65 public class ToolBox {
    67     public static final String lineSeparator = System.getProperty("line.separator");
    68     public static final String jdkUnderTest = System.getProperty("test.jdk");
    69     public static final Path javaBinary = Paths.get(jdkUnderTest, "bin", "java");
    70     public static final Path javacBinary = Paths.get(jdkUnderTest, "bin", "javac");
    72     public static final List<String> testToolVMOpts;
    73     public static final List<String> testVMOpts;
    75     private static final Charset defaultCharset = Charset.defaultCharset();
    77     static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
    79     static {
    80         String sysProp = System.getProperty("test.tool.vm.opts");
    81         if (sysProp != null && sysProp.length() > 0) {
    82             testToolVMOpts = Arrays.asList(sysProp.split("\\s+"));
    83         } else {
    84             testToolVMOpts = Collections.<String>emptyList();
    85         }
    87         sysProp = System.getProperty("test.vm.opts");
    88         if (sysProp != null && sysProp.length() > 0) {
    89             testVMOpts = Arrays.asList(sysProp.split("\\s+"));
    90         } else {
    91             testVMOpts = Collections.<String>emptyList();
    92         }
    93     }
    95     /**
    96      * The expected result of command-like method execution.
    97      */
    98     public enum Expect {SUCCESS, FAIL}
   100     enum AcceptedParams {
   101         EXPECT,
   102         SOURCES,
   103         OPTIONS,
   104         STD_OUTPUT,
   105         ERR_OUTPUT,
   106         EXTRA_ENV,
   107     }
   109     enum OutputKind {STD, ERR}
   111     /**
   112      * Helper class to abstract the processing of command's output.
   113      */
   114     static abstract class WriterHelper {
   115         OutputKind kind;
   116         public abstract void pipeOutput(ProcessBuilder pb);
   117         public abstract void readFromStream(Process p) throws IOException;
   118         public abstract void addAll(Collection<? extends String> c) throws IOException;
   119     }
   121     /**
   122      * Helper class for redirecting command's output to a file.
   123      */
   124     static class FileWriterHelper extends WriterHelper {
   125         File file;
   127         FileWriterHelper(File file, OutputKind kind) {
   128             this.file = file;
   129             this.kind = kind;
   130         }
   132         @Override
   133         public void pipeOutput(ProcessBuilder pb) {
   134             if (file != null) {
   135                 switch (kind) {
   136                     case STD:
   137                         pb.redirectInput(file);
   138                         break;
   139                     case ERR:
   140                         pb.redirectError(file);
   141                         break;
   142                 }
   143             }
   144         }
   146         @Override
   147         public void readFromStream(Process p) throws IOException {}
   149         @Override
   150         public void addAll(Collection<? extends String> c) throws IOException {
   151             if (file.exists())
   152                 Files.write(file.toPath(), c, defaultCharset,
   153                         StandardOpenOption.WRITE, StandardOpenOption.APPEND);
   154             else
   155                 Files.write(file.toPath(), c, defaultCharset);
   156         }
   157     }
   159     /**
   160      * Helper class for redirecting command's output to a String list.
   161      */
   162     static class ListWriterHelper extends WriterHelper {
   163         List<String> list;
   165         public ListWriterHelper(List<String> list, OutputKind kind) {
   166             this.kind = kind;
   167             this.list = list;
   168         }
   170         @Override
   171         public void pipeOutput(ProcessBuilder pb) {}
   173         @Override
   174         public void readFromStream(Process p) throws IOException {
   175             BufferedReader br = null;
   176             switch (kind) {
   177                 case STD:
   178                     br = new BufferedReader(new InputStreamReader(p.getInputStream()));
   179                     break;
   180                 case ERR:
   181                     br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
   182                     break;
   183             }
   184             String line;
   185             while ((line = br.readLine()) != null) {
   186                 list.add(line);
   187             }
   188         }
   190         public void addAll(Collection<? extends String> c) {
   191             list.addAll(c);
   192         }
   193     }
   195     /**
   196      * Simple factory class for creating a WriterHelper instance.
   197      */
   198     static class WriterHelperFactory {
   199         static WriterHelper make(File file, OutputKind kind) {
   200             return new FileWriterHelper(file, kind);
   201         }
   203         static WriterHelper make(List<String> list, OutputKind kind) {
   204             return new ListWriterHelper(list, kind);
   205         }
   206     }
   208     /**
   209      * A generic class for holding command's arguments.
   210      */
   211     public static abstract class GenericArgs <T extends GenericArgs> {
   212         protected static List<Set<AcceptedParams>> minAcceptedParams;
   214         protected Set<AcceptedParams> currentParams =
   215                 EnumSet.<AcceptedParams>noneOf(AcceptedParams.class);
   217         protected Expect whatToExpect;
   218         protected WriterHelper stdOutput;
   219         protected WriterHelper errOutput;
   220         protected List<String> args = new ArrayList<>();
   221         protected String[] argsArr;
   223         protected GenericArgs() {
   224             set(Expect.SUCCESS);
   225         }
   227         public T set(Expect whatToExpt) {
   228             currentParams.add(AcceptedParams.EXPECT);
   229             this.whatToExpect = whatToExpt;
   230             return (T)this;
   231         }
   233         public T setStdOutput(List<String> stdOutput) {
   234             currentParams.add(AcceptedParams.STD_OUTPUT);
   235             this.stdOutput = WriterHelperFactory.make(stdOutput, OutputKind.STD);
   236             return (T)this;
   237         }
   239         public T setStdOutput(File output) {
   240             currentParams.add(AcceptedParams.STD_OUTPUT);
   241             this.stdOutput = WriterHelperFactory.make(output, OutputKind.STD);
   242             return (T)this;
   243         }
   245         public T setErrOutput(List<String> errOutput) {
   246             currentParams.add(AcceptedParams.ERR_OUTPUT);
   247             this.errOutput = WriterHelperFactory.make(errOutput, OutputKind.ERR);
   248             return (T)this;
   249         }
   251         public T setErrOutput(File errOutput) {
   252             currentParams.add(AcceptedParams.ERR_OUTPUT);
   253             this.errOutput = WriterHelperFactory.make(errOutput, OutputKind.ERR);
   254             return (T)this;
   255         }
   257         public T setAllArgs(String... args) {
   258             currentParams.add(AcceptedParams.OPTIONS);
   259             this.argsArr = args;
   260             return (T) this;
   261         }
   264         public T appendArgs(String... args) {
   265             appendArgs(Arrays.asList(args));
   266             return (T)this;
   267         }
   269         public T appendArgs(Path... args) {
   270             if (args != null) {
   271                 List<String> list = new ArrayList<>();
   272                 for (int i = 0; i < args.length; i++) {
   273                     if (args[i] != null) {
   274                         list.add(args[i].toString());
   275                     }
   276                 }
   277                 appendArgs(list);
   278             }
   279             return (T)this;
   280         }
   282         public T appendArgs(List<String> args) {
   283             if (args != null && args.size() > 0) {
   284                 currentParams.add(AcceptedParams.OPTIONS);
   285                 for (int i = 0; i < args.size(); i++) {
   286                     if (args.get(i) != null) {
   287                         this.args.add(args.get(i));
   288                     }
   289                 }
   290             }
   291             return (T)this;
   292         }
   294         public T setOptions(List<String> options) {
   295             currentParams.add(AcceptedParams.OPTIONS);
   296             this.args = options;
   297             return (T)this;
   298         }
   300         public T setOptions(String... options) {
   301             currentParams.add(AcceptedParams.OPTIONS);
   302             this.args = Arrays.asList(options);
   303             return (T)this;
   304         }
   306         public boolean hasMinParams() {
   307             for (Set<AcceptedParams> minSet : minAcceptedParams) {
   308                 if (currentParams.containsAll(minSet)) {
   309                     return true;
   310                 }
   311             }
   312             return false;
   313         }
   314     }
   316     /**
   317      * A more specific class for holding javac-like command's arguments.
   318      */
   319     public static class JavaToolArgs extends GenericArgs<JavaToolArgs> {
   321         static {
   322             minAcceptedParams = new ArrayList<>();
   323             minAcceptedParams.add(EnumSet.<AcceptedParams>of(
   324                     AcceptedParams.EXPECT, AcceptedParams.OPTIONS));
   325             minAcceptedParams.add(EnumSet.<AcceptedParams>of(
   326                     AcceptedParams.EXPECT, AcceptedParams.SOURCES));
   327         }
   329         protected List<? extends JavaFileObject> sources;
   331         public JavaToolArgs() {
   332             super();
   333         }
   335         public JavaToolArgs(Expect whatToExpt) {
   336             super.set(whatToExpt);
   337         }
   339         public JavaToolArgs setSources(List<? extends JavaFileObject> sources) {
   340             currentParams.add(AcceptedParams.SOURCES);
   341             this.sources = sources;
   342             return this;
   343         }
   345         public JavaToolArgs setSources(JavaSource... sources) {
   346             return setSources(Arrays.asList(sources));
   347         }
   349         public JavaToolArgs setSources(String... sources) {
   350             List<JavaSource> javaSrcs = new ArrayList<>();
   351             for (String source : sources) {
   352                 javaSrcs.add(new JavaSource(source));
   353             }
   354             return setSources(javaSrcs);
   355         }
   356     }
   358     /**
   359      * A more specific class for holding any command's arguments.
   360      */
   361     public static class AnyToolArgs extends GenericArgs<AnyToolArgs> {
   363         static {
   364             minAcceptedParams = new ArrayList<>();
   365             minAcceptedParams.add(EnumSet.<AcceptedParams>of(
   366                     AcceptedParams.EXPECT, AcceptedParams.OPTIONS));
   367         }
   369         Map<String, String> extraEnv;
   371         public AnyToolArgs() {
   372             super();
   373         }
   375         public AnyToolArgs(Expect whatToExpt) {
   376             set(whatToExpt);
   377         }
   379         public AnyToolArgs set(Map<String, String> extraEnv) {
   380             currentParams.add(AcceptedParams.EXTRA_ENV);
   381             this.extraEnv = extraEnv;
   382             return this;
   383         }
   384     }
   386     /**
   387      * Custom exception for bad command execution.
   388      */
   389     public static class CommandExecutionException extends Exception {
   390         CommandExecutionException(List<String> command, Expect whatToExpt) {
   391             super(createMessage(command, whatToExpt));
   392         }
   394         CommandExecutionException(Expect whatToExpt, String... command) {
   395             this(Arrays.asList(command), whatToExpt);
   396         }
   398         private static String createMessage(List<String> command, Expect whatToExpt) {
   399             StringBuilder sb = new StringBuilder().append("Command : ");
   400             sb.append(command.toString()).append(lineSeparator);
   401             switch (whatToExpt) {
   402                 case SUCCESS:
   403                     sb.append("    has unexpectedly failed");
   404                     break;
   405                 case FAIL:
   406                     sb.append("    has been unexpectedly successful");
   407                     break;
   408             }
   409             return sb.toString();
   410         }
   411     }
   413     /**
   414      * Custom exception for not equal resources.
   415      */
   416     public static class ResourcesNotEqualException extends Exception {
   417         public ResourcesNotEqualException(List<String> res1, List<String> res2) {
   418             super(createMessage(res1, res2));
   419         }
   421         public ResourcesNotEqualException(String line1, String line2) {
   422             super(createMessage(line1, line2));
   423         }
   425         public ResourcesNotEqualException(Path path1, Path path2) {
   426             super(createMessage(path1, path2));
   427         }
   429         private static String createMessage(Path path1, Path path2) {
   430             return new StringBuilder()
   431                     .append("The resources provided for comparison in paths \n")
   432                     .append(path1.toString()).append(" and \n")
   433                     .append(path2.toString()).append("are different").toString();
   434         }
   436         private static String createMessage(String line1, String line2) {
   437             return new StringBuilder()
   438                     .append("The resources provided for comparison are different at lines: \n")
   439                     .append(line1).append(" and \n")
   440                     .append(line2).toString();
   441         }
   443         private static String createMessage(List<String> res1, List<String> res2) {
   444             return new StringBuilder()
   445                     .append("The resources provided for comparison are different: \n")
   446                     .append("Resource 1 is: ").append(res1).append("\n and \n")
   447                     .append("Resource 2 is: ").append(res2).append("\n").toString();
   448         }
   449     }
   451     /**
   452      * A javac compiler caller method.
   453      */
   454     public static int javac(JavaToolArgs params)
   455             throws CommandExecutionException, IOException {
   456         if (params.hasMinParams()) {
   457             if (params.argsArr != null) {
   458                 return genericJavaCMD(JavaCMD.JAVAC, params);
   459             } else {
   460                 return genericJavaCMD(JavaCMD.JAVAC_API, params);
   461             }
   462         }
   463         throw new AssertionError("javac command has been invoked with less parameters than needed");
   464     }
   466     /**
   467      * A javap calling method.
   468      */
   469     public static String javap(JavaToolArgs params)
   470             throws CommandExecutionException, IOException {
   471         if (params.hasMinParams()) {
   472             List<String> list = new ArrayList<>();
   473             params.setErrOutput(list);
   474             genericJavaCMD(JavaCMD.JAVAP, params);
   475             return listToString(list);
   476         }
   477         throw new AssertionError("javap command has been invoked with less parameters than needed");
   478     }
   480     /**
   481      * A javah calling method.
   482      */
   483     public static int javah(JavaToolArgs params)
   484             throws CommandExecutionException, IOException {
   485         if (params.hasMinParams()) {
   486             return genericJavaCMD(JavaCMD.JAVAH, params);
   487         }
   488         throw new AssertionError("javah command has been invoked with less parameters than needed");
   489     }
   491     /**
   492      * A enum class for langtools commands.
   493      */
   494     enum JavaCMD {
   495         JAVAC {
   496             @Override
   497             int run(JavaToolArgs params, PrintWriter pw) {
   498                 return com.sun.tools.javac.Main.compile(params.argsArr, pw);
   499             }
   500         },
   501         JAVAC_API {
   502             @Override
   503             int run(JavaToolArgs params, PrintWriter pw) {
   504                 JavacTask ct = (JavacTask)comp.getTask(pw, null, null,
   505                         params.args, null, params.sources);
   506                 return ((JavacTaskImpl)ct).doCall().exitCode;
   507             }
   509             @Override
   510             String getName() {
   511                 return "javac";
   512             }
   514             @Override
   515             List<String> getExceptionMsgContent(JavaToolArgs params) {
   516                 List<String> result = super.getExceptionMsgContent(params);
   517                 for (JavaFileObject source : params.sources) {
   518                     if (source instanceof JavaSource) {
   519                         result.add(((JavaSource)source).name);
   520                     }
   521                 }
   522                 return result;
   523             }
   524         },
   525         JAVAH {
   526             @Override
   527             int run(JavaToolArgs params, PrintWriter pw) {
   528                 return com.sun.tools.javah.Main.run(params.argsArr, pw);
   529             }
   530         },
   531         JAVAP {
   532             @Override
   533             int run(JavaToolArgs params, PrintWriter pw) {
   534                 return com.sun.tools.javap.Main.run(params.argsArr, pw);
   535             }
   536         };
   538         abstract int run(JavaToolArgs params, PrintWriter pw);
   540         String getName() {
   541             return this.name().toLowerCase();
   542         }
   544         List<String> getExceptionMsgContent(JavaToolArgs params) {
   545             List<String> result = new ArrayList<>();
   546             result.add(getName());
   547             result.addAll(params.argsArr != null ?
   548                     Arrays.asList(params.argsArr) :
   549                     params.args);
   550             return result;
   551         }
   552     }
   554     /**
   555      * A helper method for executing langtools commands.
   556      */
   557     private static int genericJavaCMD(
   558             JavaCMD cmd,
   559             JavaToolArgs params)
   560             throws CommandExecutionException, IOException {
   561         int rc = 0;
   562         StringWriter sw = null;
   563         try (PrintWriter pw = (params.errOutput == null) ?
   564                 null : new PrintWriter(sw = new StringWriter())) {
   565             rc = cmd.run(params, pw);
   566         }
   567         String out = (sw == null) ? null : sw.toString();
   569         if (params.errOutput != null && (out != null) && !out.isEmpty()) {
   570             params.errOutput.addAll(splitLines(out, lineSeparator));
   571         }
   573         if ( (rc == 0 && params.whatToExpect == Expect.SUCCESS) ||
   574              (rc != 0 && params.whatToExpect == Expect.FAIL) ) {
   575             return rc;
   576         }
   578         throw new CommandExecutionException(cmd.getExceptionMsgContent(params),
   579                 params.whatToExpect);
   580     }
   582     /**
   583      * A jar calling method.
   584      */
   585     public static boolean jar(String... params) throws CommandExecutionException {
   586         Main jarGenerator = new Main(System.out, System.err, "jar");
   587         boolean result = jarGenerator.run(params);
   588         if (!result) {
   589             List<String> command = new ArrayList<>();
   590             command.add("jar");
   591             command.addAll(Arrays.asList(params));
   592             throw new CommandExecutionException(command, Expect.SUCCESS);
   593         }
   594         return result;
   595     }
   597     /**
   598      * A general command calling method.
   599      */
   600     public static int executeCommand(AnyToolArgs params)
   601             throws CommandExecutionException, IOException, InterruptedException {
   602         if (params.hasMinParams()) {
   603             List<String> cmd = (params.args != null) ?
   604                     params.args :
   605                     Arrays.asList(params.argsArr);
   606             return executeCommand(cmd, params.extraEnv, params.stdOutput,
   607                     params.errOutput, params.whatToExpect);
   608         }
   609         throw new AssertionError("command has been invoked with less parameters than needed");
   610     }
   612     /**
   613      * A helper method for calling a general command.
   614      */
   615     private static int executeCommand(
   616             List<String> command,
   617             Map<String, String> extraEnv,
   618             WriterHelper stdOutput,
   619             WriterHelper errOutput,
   620             Expect whatToExpt)
   621             throws IOException, InterruptedException, CommandExecutionException {
   622         ProcessBuilder pb = new ProcessBuilder(command);
   624         if (stdOutput != null) stdOutput.pipeOutput(pb);
   625         if (errOutput != null) errOutput.pipeOutput(pb);
   627         if (extraEnv != null) {
   628             pb.environment().putAll(extraEnv);
   629         }
   631         Process p = pb.start();
   633         if (stdOutput != null) stdOutput.readFromStream(p);
   634         if (errOutput != null) errOutput.readFromStream(p);
   636         int result = p.waitFor();
   637         if ( (result == 0 && whatToExpt == Expect.SUCCESS) ||
   638              (result != 0 && whatToExpt == Expect.FAIL) ) {
   639             return result;
   640         }
   642         throw new CommandExecutionException(command, whatToExpt);
   643     }
   645     /**
   646      * This set of methods can be used instead of diff when the only needed
   647      * result is the equality or inequality of the two given resources.
   648      *
   649      * A resource can be a file or a String list.
   650      */
   651     public static void compareLines(Path aPath, Path otherPath, String encoding)
   652             throws FileNotFoundException, IOException, ResourcesNotEqualException {
   653         compareLines(aPath, otherPath, encoding, false);
   654     }
   656     public static void compareLines(
   657             Path aPath, Path otherPath, String encoding, boolean trim)
   658             throws FileNotFoundException, IOException, ResourcesNotEqualException {
   659         Charset charset = encoding != null ?
   660                 Charset.forName(encoding) :
   661                 defaultCharset;
   662         List<String> list1 = Files.readAllLines(aPath, charset);
   663         List<String> list2 = Files.readAllLines(otherPath, charset);
   664         compareLines(list1, list2, trim);
   665     }
   667     public static void compareLines(Path path, List<String> strings, String encoding)
   668             throws FileNotFoundException, IOException, ResourcesNotEqualException {
   669         compareLines(path, strings, encoding, false);
   670     }
   672     public static void compareLines(Path path, List<String> strings,
   673             String encoding, boolean trim)
   674             throws FileNotFoundException, IOException, ResourcesNotEqualException {
   675         Charset charset = encoding != null ?
   676                 Charset.forName(encoding) :
   677                 defaultCharset;
   678         List<String> list = Files.readAllLines(path, charset);
   679         compareLines(list, strings, trim);
   680     }
   682     public static void compareLines(List<String> list1, List<String> list2)
   683             throws ResourcesNotEqualException {
   684         compareLines(list1, list2, false);
   685     }
   687     public static void compareLines(List<String> list1,
   688             List<String> list2, boolean trim) throws ResourcesNotEqualException {
   689         if ((list1 == list2) || (list1 == null && list2 == null)) return;
   690         if (list1.size() != list2.size())
   691             throw new ResourcesNotEqualException(list1, list2);
   692         int i = 0;
   693         int j = 0;
   694         while (i < list1.size() &&
   695                j < list2.size() &&
   696                equals(list1.get(i), list2.get(j), trim)) {
   697             i++; j++;
   698         }
   699         if (!(i == list1.size() && j == list2.size()))
   700             throw new ResourcesNotEqualException(list1, list2);
   701     }
   703     private static boolean equals(String s1, String s2, boolean trim) {
   704         return (trim ? s1.trim().equals(s2.trim()) : s1.equals(s2));
   705     }
   707     /**
   708      * A set of simple grep-like methods, looks for regExpr in text.
   709      * The content of text is split using the new line character as a pattern
   710      * and later the regExpr is seek in every split line. If a match is found,
   711      * the whole line is added to the result.
   712      */
   713     public static List<String> grep(String regExpr, String text, String sep) {
   714         return grep(regExpr, splitLines(text, sep));
   715     }
   717     public static List<String> grep(String regExpr, List<String> text) {
   718         List<String> result = new ArrayList<>();
   719         Pattern pattern = Pattern.compile(regExpr);
   720         for (String s : text) {
   721             if (pattern.matcher(s).find()) {
   722                 result.add(s);
   723             }
   724         }
   725         return result;
   726     }
   728     public static List<String> grep(String regExpr, File f)
   729             throws IOException {
   730         List<String> lines = Files.readAllLines(f.toPath(), defaultCharset);
   731         return grep(regExpr, lines);
   732     }
   734     /**
   735      * A touch-like method.
   736      */
   737     public static boolean touch(String fileName) {
   738         File file = new File(fileName);
   739         return touch(file);
   740     }
   742     public static boolean touch(File file) {
   743         if (file.exists()) {
   744             file.setLastModified(System.currentTimeMillis());
   745             return true;
   746         }
   747         return false;
   748     }
   750     public static void createJavaFile(File outFile) throws IOException {
   751         createJavaFile(outFile, null);
   752     }
   754     /**
   755      * A method for creating a valid but very simple java file.
   756      */
   757     public static void createJavaFile(File outFile, File superClass)
   758             throws IOException {
   759         String srcStr = "public class " + getSimpleName(outFile) + " ";
   760         if (superClass != null) {
   761             srcStr = srcStr.concat("extends " + getSimpleName(superClass) + " ");
   762         }
   763         srcStr = srcStr.concat("{}");
   764         try (PrintWriter ps = new PrintWriter(new FileWriter(outFile))) {
   765             ps.println(srcStr);
   766         }
   767     }
   769     /**
   770      * Creates a java file name given its source.
   771      * The file is created in the working directory, creating a directory
   772      * tree if there is a package declaration.
   773      */
   774     public static void createJavaFileFromSource(String source) throws IOException {
   775         createJavaFileFromSource(null, source);
   776     }
   778     /**
   779      * Creates a java file name given its source.
   780      * The file is created in the working directory, creating a directory
   781      * tree if there is a package declaration or the argument initialPath
   782      * has a valid path.
   783      *
   784      * e.i. if initialPath is foo/ and the source is:
   785      * package bar;
   786      *
   787      * public class bazz {}
   788      *
   789      * this method will create the file foo/bar/bazz.java in the working
   790      * directory.
   791      */
   792     public static void createJavaFileFromSource(Path initialPath,
   793             String source) throws IOException {
   794         String fileName = getJavaFileNameFromSource(source);
   795         String dirTree = getDirTreeFromSource(source);
   796         Path path = (dirTree != null) ?
   797                 Paths.get(dirTree, fileName) :
   798                 Paths.get(fileName);
   799         path = (initialPath != null) ?
   800                 initialPath.resolve(path):
   801                 path;
   802         writeFile(path, source);
   803     }
   805     static Pattern publicClassPattern =
   806             Pattern.compile("public\\s+(?:class|enum|interface){1}\\s+(\\w+)");
   807     static Pattern packageClassPattern =
   808             Pattern.compile("(?:class|enum|interface){1}\\s+(\\w+)");
   810     /**
   811      * Extracts the java file name from the class declaration.
   812      * This method is intended for simple files and uses regular expressions,
   813      * so comments matching the pattern can make the method fail.
   814      */
   815     private static String getJavaFileNameFromSource(String source) {
   816         String className = null;
   817         Matcher matcher = publicClassPattern.matcher(source);
   818         if (matcher.find()) {
   819             className = matcher.group(1) + ".java";
   820         } else {
   821             matcher = packageClassPattern.matcher(source);
   822             if (matcher.find()) {
   823                 className = matcher.group(1) + ".java";
   824             } else {
   825                 throw new AssertionError("Could not extract the java class " +
   826                         "name from the provided source");
   827             }
   828         }
   829         return className;
   830     }
   832     static Pattern packagePattern =
   833             Pattern.compile("package\\s+(((?:\\w+\\.)*)(?:\\w+))");
   835     /**
   836      * Extracts the path from the package declaration if present.
   837      * This method is intended for simple files and uses regular expressions,
   838      * so comments matching the pattern can make the method fail.
   839      */
   840     private static String getDirTreeFromSource(String source) {
   841         Matcher matcher = packagePattern.matcher(source);
   842         return matcher.find() ?
   843             matcher.group(1).replace(".", File.separator) :
   844             null;
   845     }
   847     /**
   848      * A method for creating a jar's manifest file with supplied data.
   849      */
   850     public static void mkManifestWithClassPath(String mainClass,
   851             String... classes) throws IOException {
   852         List <String> lines = new ArrayList<>();
   854         StringBuilder sb = new StringBuilder("Class-Path: ".length() +
   855                 classes[0].length()).append("Class-Path: ").append(classes[0]);
   856         for (int i = 1; i < classes.length; i++) {
   857             sb.append(" ").append(classes[i]);
   858         }
   859         lines.add(sb.toString());
   860         if (mainClass != null) {
   861             lines.add(new StringBuilder("Main-Class: ".length() +
   862                       mainClass.length())
   863                       .append("Main-Class: ")
   864                       .append(mainClass).toString());
   865         }
   866         Files.write(Paths.get("MANIFEST.MF"), lines, null);
   867     }
   869     /**
   870      * A utility method to obtain the file name.
   871      */
   872     static String getSimpleName(File inFile) {
   873         return inFile.toPath().getFileName().toString();
   874     }
   876     /**
   877      * A method to write to a file, the directory tree is created if needed.
   878      */
   879     public static File writeFile(Path path, String body) throws IOException {
   880         File result;
   881         if (path.getParent() != null) {
   882             Files.createDirectories(path.getParent());
   883         }
   884         try (FileWriter out = new FileWriter(result = path.toAbsolutePath().toFile())) {
   885             out.write(body);
   886         }
   887         return result;
   888     }
   890     public static File writeFile(String path, String body) throws IOException {
   891         return writeFile(Paths.get(path), body);
   892     }
   894     /**
   895      * A rm-like method, the file is deleted only if it exists.
   896      */
   897     public static void rm(Path path) throws Exception {
   898         Files.deleteIfExists(path);
   899     }
   901     public static void rm(String filename) throws Exception {
   902         rm(Paths.get(filename));
   903     }
   905     public static void rm(File f) throws Exception {
   906         rm(f.toPath());
   907     }
   909     /**
   910      * Copy source file to destination file.
   911      */
   912     public static void copyFile(File destfile, File srcfile)
   913         throws IOException {
   914         copyFile(destfile.toPath(), srcfile.toPath());
   915     }
   917     public static void copyFile(Path destPath, Path srcPath)
   918         throws IOException {
   919         Files.createDirectories(destPath);
   920         Files.copy(srcPath, destPath, REPLACE_EXISTING);
   921     }
   923     /**
   924      * Splits a String using the System's line separator character as splitting point.
   925      */
   926     public static List<String> splitLines(String lines, String sep) {
   927         return Arrays.asList(lines.split(sep));
   928     }
   930     /**
   931      * Converts a String list into one String by appending the System's line separator
   932      * character after each component.
   933      */
   934     private static String listToString(List<String> lines) {
   935         StringBuilder sb = new StringBuilder();
   936         for (String s : lines) {
   937             sb.append(s).append(lineSeparator);
   938         }
   939         return sb.toString();
   940     }
   942     /**
   943      * Returns true if the OS is a Windows version.
   944      */
   945     public static boolean isWindows() {
   946         String osName = System.getProperty("os.name");
   947         return osName.toUpperCase().startsWith("WINDOWS");
   948     }
   950     /**
   951      * Class representing an in-memory java source file. It is able to extract
   952      * the file name from simple source codes using regular expressions.
   953      */
   954     public static class JavaSource extends SimpleJavaFileObject {
   955         String source;
   956         String name;
   958         public JavaSource(String className, String source) {
   959             super(URI.create(className),
   960                     JavaFileObject.Kind.SOURCE);
   961             this.name = className;
   962             this.source = source;
   963         }
   965         public JavaSource(String source) {
   966             super(URI.create(getJavaFileNameFromSource(source)),
   967                     JavaFileObject.Kind.SOURCE);
   968             this.name = getJavaFileNameFromSource(source);
   969             this.source = source;
   970         }
   972         @Override
   973         public CharSequence getCharContent(boolean ignoreEncodingErrors) {
   974             return source;
   975         }
   976     }
   977 }

mercurial