Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2648 refactor bin mojo #2765

Merged
merged 7 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 11 additions & 182 deletions eo-maven-plugin/src/main/java/org/eolang/maven/BinarizeMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,34 +24,23 @@
package org.eolang.maven;

import com.jcabi.log.Logger;
import com.yegor256.Jaxec;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.SystemUtils;
import java.util.Collection;
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.cactoos.experimental.Threads;
import org.cactoos.iterable.Filtered;
import org.cactoos.iterable.Mapped;
import org.cactoos.number.SumOf;
import org.cactoos.text.TextOf;
import org.cactoos.text.UncheckedText;
import org.eolang.maven.rust.BuildFailureException;
import org.eolang.maven.rust.Buildable;
import org.eolang.maven.rust.Names;

/**
* Compile binaries.
*
* @checkstyle ClassDataAbstractionCouplingCheck (500 lines)
* @since 0.1
* @todo #2118:90min Make it more generic. Perhaps by compilation of
* RustNode instead of going and building throw directories. Maybe it
* is better to get from BinarizeParseMojo.
*/
@Mojo(
name = "binarize",
Expand All @@ -62,11 +51,6 @@
@SuppressWarnings("PMD.LongVariable")
public final class BinarizeMojo extends SafeMojo {

/**
* Name of executable file which is result of cargo building.
*/
public static final String LIB = BinarizeMojo.common();

/**
* The directory where to binarize to.
*/
Expand Down Expand Up @@ -108,170 +92,15 @@ public final class BinarizeMojo extends SafeMojo {
private File eoPortalDir;

@Override
public void exec() {
new Moja<>(BinarizeParseMojo.class).with(
"names", new Names(this.namesDir.toPath())
).copy(this).execute();
final int total = new SumOf(
new Threads<>(
Runtime.getRuntime().availableProcessors(),
new Mapped<>(
project -> () -> {
this.build(project);
return 1;
},
new Filtered<>(
BinarizeMojo::valid,
targetDir.toPath().resolve("Lib").toFile().listFiles()
)
)
)
).intValue();
Logger.info(this, "Built in total %d cargo projects", total);
}

/**
* Calculates name for Rust shared library depending on OS.
* @return Name.
*/
private static String common() {
final String result;
if (SystemUtils.IS_OS_WINDOWS) {
result = "common.dll";
} else if (SystemUtils.IS_OS_LINUX) {
result = "libcommon.so";
} else if (SystemUtils.IS_OS_MAC) {
result = "libcommon.dylib";
} else {
throw new IllegalArgumentException(
String.format(
"Rust inserts are not supported in %s os. Only windows, linux and macos are allowed.",
System.getProperty("os.name")
)
);
}
return result;
}

/**
* Is the project valid?
* @param project File to check.
* @return True if valid. Otherwise, false.
*/
private static boolean valid(final File project) {
return project.isDirectory()
&& project.toPath().resolve("Cargo.toml").toFile().exists();
}

/**
* Builds cargo project.
* @param project Path to the project.
* @throws IOException If any issues with IO.
*/
private void build(final File project) throws IOException {
final File cached = this.cache
.resolve("Lib")
.resolve(project.getName())
.resolve("target").toFile();
if (BinarizeMojo.sameProject(
project.toPath(),
this.cache
.resolve("Lib")
.resolve(project.getName())
)) {
Logger.info(
this,
"content of %s was not changed since the last launch",
project.getName()
);
final File executable = cached.toPath()
.resolve("debug")
.resolve(BinarizeMojo.LIB)
.toFile();
if (executable.exists()) {
FileUtils.copyFile(
executable,
project.toPath()
.resolve("target")
.resolve("debug")
.resolve(BinarizeMojo.LIB)
.toFile()
);
}
} else {
final File target = project.toPath().resolve("target").toFile();
if (cached.exists()) {
Logger.info(this, "Copying %s to %s", cached, target);
FileUtils.copyDirectory(cached, target);
}
Logger.info(this, "Building %s rust project..", project.getName());
try {
new Jaxec("cargo", "build").withHome(project).execUnsafe();
} catch (final IOException | IllegalArgumentException ex) {
throw new BuildFailureException(
String.format(
"Failed to build cargo project with dest = %s",
project
),
ex
);
}
Logger.info(
this,
"Cargo building succeeded, update cached %s with %s",
cached,
target
);
FileUtils.copyDirectory(target.getParentFile(), cached.getParentFile());
}
public void exec() throws IOException {
final Collection<Buildable> ffis = new BinarizeParse(
this.generatedDir,
this.eoPortalDir,
new Names(this.namesDir.toPath()),
this.targetDir
).exec(this.scopedTojos().withOptimized());
ffis.stream().parallel().forEach(ffi -> ffi.build(this.cache));
Logger.info(this, "Built in total %d cargo projects", ffis.size());
}

/**
* Check if the project was not changed.
* @param src Directory in current target.
* @param cached Directory in cache.
* @return True if the project is the same.
*/
private static boolean sameProject(final Path src, final Path cached) {
return BinarizeMojo.sameFile(
src.resolve("src/foo.rs"), cached.resolve("src/foo.rs")
) && BinarizeMojo.sameFile(
src.resolve("src/lib.rs"), cached.resolve("src/lib.rs")
) && BinarizeMojo.sameFile(
src.resolve("Cargo.toml"), cached.resolve("Cargo.toml")
);
}

/**
* Check if the source file is the same as in cache.
* @param src Source file.
* @param cached Cache file.
* @return True if the same.
*/
private static boolean sameFile(final Path src, final Path cached) {
return cached.toFile().exists() && BinarizeMojo.uncomment(
new UncheckedText(
new TextOf(src)
).asString()
).equals(
BinarizeMojo.uncomment(
new UncheckedText(
new TextOf(cached)
).asString()
)
);
}

/**
* Removed the first line from the string.
* We need it because generated files are disclaimed.
* @param content Content.
* @return String without the first line.
* @checkstyle StringLiteralsConcatenationCheck (8 lines)
*/
private static String uncomment(final String content) {
return content.substring(
1 + content.indexOf(System.getProperty("line.separator"))
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,8 @@
import java.util.Collection;
import java.util.Map;
import java.util.function.BiFunction;
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.cactoos.map.MapOf;
import org.eolang.maven.rust.Buildable;
import org.eolang.maven.rust.FFINode;
import org.eolang.maven.rust.Names;
import org.eolang.maven.rust.RustNode;
Expand All @@ -56,15 +53,8 @@
* @checkstyle ClassDataAbstractionCouplingCheck (500 lines)
* @since 0.1
*/
@Mojo(
name = "binarize_parse",
defaultPhase = LifecyclePhase.PROCESS_SOURCES,
threadSafe = true,
requiresDependencyResolution = ResolutionScope.COMPILE
)

@SuppressWarnings("PMD.LongVariable")
public final class BinarizeParseMojo extends SafeMojo {
public final class BinarizeParse {

/**
* The directory where to binarize to.
Expand All @@ -90,7 +80,7 @@ public final class BinarizeParseMojo extends SafeMojo {
* Map that matches ffi insert xpath to building of FFINode.
*/
private static final
Map<String, BiFunction<XML, BinarizeParseMojo, FFINode>> FACTORY = new MapOf<>(
Map<String, BiFunction<XML, BinarizeParse, FFINode>> FACTORY = new MapOf<>(
"/program/rusts/rust",
(node, mojo) -> new RustNode(
node,
Expand All @@ -105,39 +95,65 @@ public final class BinarizeParseMojo extends SafeMojo {
* Target directory.
* @checkstyle MemberNameCheck (7 lines)
*/
@Parameter(
required = true,
defaultValue = "${project.build.directory}/eo-binaries"
)
@SuppressWarnings("PMD.UnusedPrivateField")
private File generatedDir;
private final File generatedDir;

/**
* The directory with portal project.
* @checkstyle MemberNameCheck (8 lines)
*/
@Parameter(
property = "eo.portal",
required = true,
defaultValue = "${project.basedir}/src/main/rust/eo"
)
@SuppressWarnings("PMD.UnusedPrivateField")
private File eoPortalDir;
private final File eoPortalDir;

/**
* To uniquely name different ffi inerts.
*/
private Names names;
private final Names names;

@Override
public void exec() throws IOException {
/**
* To uniquely name different ffi inerts.
* @checkstyle MemberNameCheck (7 lines)
*/
private final File targetDir;

/**
* Ctor.
* @param generated Generated directory.
* @param portal Directory to portal dependency.
* @param names Names.
* @param target Target directory.
* @checkstyle ParameterNumberCheck (10 lines)
*/
public BinarizeParse(
final File generated,
final File portal,
final Names names,
final File target
) {
this.generatedDir = generated;
this.eoPortalDir = portal;
this.names = names;
this.targetDir = target;
}

/**
* Parse ffi nodes in tojos.
* @param tojos Tojos where to parse ffi node,
* @return Collection of {@link FFINode}s that will be then also compiled.
* @throws IOException if any issue with IO.
*/
public Collection<Buildable> exec(final Collection<ForeignTojo> tojos) throws IOException {
final Collection<Buildable> res = new ArrayList<>(0);
new File(this.targetDir.toPath().resolve("Lib/").toString()).mkdirs();
for (final ForeignTojo tojo : this.scopedTojos().withOptimized()) {
for (final ForeignTojo tojo : tojos) {
final Path file = tojo.verified();
this.getFFIs(new XMLDocument(file))
.forEach(FFINode::generateUnchecked);
for (final FFINode ffi: this.getFFIs(new XMLDocument(file))) {
ffi.generateUnchecked();
if (ffi instanceof Buildable) {
res.add((Buildable) ffi);
}
}
}
this.names.save();
return res;
}

/**
Expand All @@ -152,7 +168,7 @@ private XML addFFIs(
final String name = input.xpath("/program/@name").get(0);
final Place place = new Place(name);
final Train<Shift> trn = new SpyTrain(
BinarizeParseMojo.TRAIN,
BinarizeParse.TRAIN,
place.make(this.targetDir.toPath().resolve(BinarizeMojo.DIR), "")
);
return new Xsline(trn).pass(input);
Expand All @@ -167,7 +183,7 @@ private XML addFFIs(
private Collection<FFINode> getFFIs(final XML input) {
final Collection<FFINode> ret = new ArrayList<>(0);
final XML injected = this.addFFIs(input);
BinarizeParseMojo.FACTORY.forEach(
BinarizeParse.FACTORY.forEach(
(xpath, ctor) -> injected
.nodes(xpath)
.forEach(node -> ret.add(ctor.apply(node, this)))
Expand Down
Loading
Loading