package mandelbrot.ocamljava_maven_plugin; import java.io.File; import java.io.FileOutputStream; import java.util.Collection; import java.util.List; import java.util.Properties; import mandelbrot.dependency.data.DependencyGraph; import mandelbrot.ocamljava_maven_plugin.io.UncheckedOutputStream; import mandelbrot.ocamljava_maven_plugin.util.FileMappings; import ocaml.tools.ocamldep.ocamljavaMain; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.shared.invoker.InvocationOutputHandler; import org.codehaus.plexus.util.StringUtils; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; /** * <p> * This is a goal which anaylzes OCaml sources during the maven process sources * phase to determine the build dependency order. It is the same as executing * something like * </p> * <p> * <code>ocamldep -I com/foobar foo.ml bar.ml ...</code> * </p> * from the command line but instead uses maven properties to infer the source * locations and class path. All parameters can be overridden. See the * configuration section of the documentation for more information.</p> * * @since 1.0 */ @Mojo(requiresProject = true, defaultPhase = LifecyclePhase.PROCESS_SOURCES, name = "dep", executionStrategy = "once-per-session", requiresDependencyResolution = ResolutionScope.RUNTIME, threadSafe = true) public class OcamlJavaDependencyMojo extends OcamlJavaAbstractMojo { private static final String GOAL_NAME = OcamlJavaConstants.dependencyGoal(); public static String fullyQualifiedGoal() { return GOAL_NAME; } @Override public void execute() throws MojoExecutionException, MojoFailureException { final Properties properties = System.getProperties(); final Object object = properties.get(FORK_PROPERTY_NAME); if (Boolean.parseBoolean(Optional.fromNullable(object).or(Boolean.TRUE) .toString())) { getLog().info("[ocamldep] forking process"); final File path = this.rawDependencyTargetFullPath(); path.getParentFile().mkdirs(); try { path.createNewFile(); } catch (final Exception e) { throw new MojoExecutionException("couldn't create target file", e); } final UncheckedOutputStream<FileOutputStream> fileOutputStream = UncheckedOutputStream.fromFile(path); final boolean forkAgain = false; final File prefixToTruncate = chooseOcamlSourcesDirectory(); final InvocationOutputHandler handler = new InvocationOutputHandler() { @Override public void consumeLine(final String line) { if (StringUtils.isBlank(line)) return; if (line.startsWith("[")) return; if (!line.contains(prefixToTruncate.getAbsolutePath())) { return; } fileOutputStream.write((line + System.getProperty("line.separator")).getBytes()); } }; invokePlugin(fullyQualifiedGoal(), forkAgain, handler); fileOutputStream.close(); final DependencyGraph dependencyGraph = DependencyGraph .fromOcamlDep(rawDependencyTargetFullPath(), prefixToTruncate); getLog().info( "output directory to truncate with: " + project.getFile().getParent()); dependencyGraph.write(chooseDependencyGraphTargetFullPath(), project.getFile().getParentFile()); } else { getLog().info("[ocamldep] running in process"); generateDependencyGraph(); } } @Override protected File chooseOcamlSourcesDirectory() { return ocamlSourceDirectory; } @Override protected String chooseOcamlCompiledSourcesTarget() { return ocamlCompiledSourcesTarget; } private List<String> generateCommandLineArguments( final Collection<String> includePaths, final Collection<String> ocamlSourceFiles) throws MojoExecutionException { final ImmutableList.Builder<String> builder = ImmutableList .<String> builder(); if (javaOnly) builder.add(OcamlJavaConstants.JAVA_ONLY_OPTION); if (sort) builder.add(OcamlJavaConstants.SORT_OPTION); if (all) builder.add((OcamlJavaConstants.ALL_OPTION)); addIncludePaths(includePaths, builder); builder.addAll(ocamlSourceFiles); return builder.build(); } /*** * Whether to sort the list of modules in dependency order. */ @Parameter(readonly = true, defaultValue = "true") protected boolean sort = true; /*** * Only compile binaries for the java virtual machine (no *.cmo files). */ @Parameter(defaultValue = "true") protected boolean javaOnly = true; /*** * Generate dependency information on all files. */ @Parameter(defaultValue = "true", readonly = true) protected boolean all = true; protected void generateDependencyGraph() throws MojoExecutionException { final Collection<String> ocamlSourceFiles = gatherOcamlSourceFiles( chooseOcamlSourcesDirectory()).values(); final Collection<String> includePaths = FileMappings.buildPathMap( ocamlSourceFiles).keySet(); final File dependencyGraphTargetFullPath = rawDependencyTargetFullPath(); final boolean madeDirs = dependencyGraphTargetFullPath.getParentFile() .mkdirs(); if (getLog().isDebugEnabled()) getLog().debug("made dirs? " + madeDirs); //final UncheckedOutputStream<FileOutputStream> fileOutputStream = UncheckedOutputStream // .fromFile(dependencyGraphTargetFullPath); // final PrintStream printStream = new PrintStream(fileOutputStream); final List<String> commandLineArguments = generateCommandLineArguments(includePaths, ocamlSourceFiles); if (getLog().isDebugEnabled()) getLog().debug( "about to generate dependency graph: " + commandLineArguments); ocamljavaMain.main(commandLineArguments.toArray(new String[]{})); // final ocamljavaMain ocamljavaMain = mainWithReturn("ocamldep.jar", // commandLineArguments.toArray(new String[] {}), printStream, // ocamljavaMain.class), // new Function<ocamljavaMain, ocamljavaMain>() { // // @Override // public ocamljavaMain apply(final ocamljavaMain ocamljavaMain) { // // getLog().info("inside apply, initializing stuff!"); // ocamljavaMain.setConstant(Pervasives.class, // Pervasives.createConstants()); // ocamljavaMain.setConstant(Array.class, // ocaml.stdlib.Array.createConstants()); // ocamljavaMain.setConstant(List.class, // ocaml.stdlib.List.createConstants()); // ocamljavaMain.setConstant(Char.class, // Char.createConstants()); // ocamljavaMain.setConstant(ocaml.stdlib.String.class, // ocaml.stdlib.String.createConstants()); // ocamljavaMain.setConstant(Sys.class, // Sys.createConstants()); // ocamljavaMain.setConstant(Marshal.class, // Marshal.createConstants()); // ocamljavaMain.setConstant(Obj.class, // Obj.createConstants()); // ocamljavaMain.setConstant(Int32.class, // Int32.createConstants()); // ocamljavaMain.setConstant(Int64.class, // Int64.createConstants()); // ocamljavaMain.setConstant(Nativeint.class, // Nativeint.createConstants()); // ocamljavaMain.setConstant(Lexing.class, // Lexing.createConstants()); // ocamljavaMain.setConstant(Parsing.class, // Parsing.createConstants()); // ocamljavaMain.setConstant(Set.class, // Set.createConstants()); // ocamljavaMain.setConstant(ocaml.stdlib.Map.class, // ocaml.stdlib.Map.createConstants()); // ocamljavaMain.setConstant(CamlinternalLazy.class, // CamlinternalLazy.createConstants()); // ocamljavaMain.setConstant(Buffer.class, // Buffer.createConstants()); // ocamljavaMain.setConstant(Printf.class, // Printf.createConstants()); // ocamljavaMain.setConstant(Arg.class, // Arg.createConstants()); // ocamljavaMain.setConstant(Digest.class, // Digest.createConstants()); // ocamljavaMain.setConstant(Random.class, // Random.createConstants()); // ocamljavaMain.setConstant(Hashtbl.class, // Hashtbl.createConstants()); // ocamljavaMain.setConstant(Format.class, // Format.createConstants()); // ocamljavaMain.setConstant(Filename.class, // Filename.createConstants()); // ocamljavaMain.setConstant(Misc.class, // Misc.createConstants()); // ocamljavaMain.setConstant(Config.class, // Config.createConstants()); // ocamljavaMain.setConstant(Clflags.class, // Clflags.createConstants()); // ocamljavaMain.setConstant(Terminfo.class, // Terminfo.createConstants()); // ocamljavaMain.setConstant(Warnings.class, // Warnings.createConstants()); // ocamljavaMain.setConstant(Location.class, // Location.createConstants()); // ocamljavaMain.setConstant(Longident.class, // Longident.createConstants()); // ocamljavaMain.setConstant(Syntaxerr.class, // Syntaxerr.createConstants()); // ocamljavaMain.setConstant(Parser.class, // Parser.createConstants()); // ocamljavaMain.setConstant(Lexer.class, // Lexer.createConstants()); // ocamljavaMain.setConstant(Parse.class, // Parse.createConstants()); // ocamljavaMain.setConstant(Ccomp.class, // Ccomp.createConstants()); // ocamljavaMain.setConstant(Pparse.class, // Pparse.createConstants()); // ocamljavaMain.setConstant(Compenv.class, // Compenv.createConstants()); // ocamljavaMain.setConstant(Depend.class, // Depend.createConstants()); // ocamljavaMain.setConstant(Ocamldep.class, // Ocamldep.createConstants()); // getLog().info("inside apply, done initializing stuff!"); // // return ocamljavaMain; // } // }); } private File rawDependencyTargetFullPath() { return new File(chooseDependencyGraphTargetFullPath().getPath() + ".raw"); } };