Skip to content

Commit

Permalink
API for conventional archive and executable file names.
Browse files Browse the repository at this point in the history
Closes #33.
  • Loading branch information
pedrolamarao committed Oct 10, 2023
1 parent 2d0bdf6 commit 75ccac2
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public Provider<RegularFile> getOutput ()
{
return getOutputDirectory().map(out -> {
final var target = getTarget().get();
final var name = getProject().getName();
return out.file("%s/%s.lib".formatted(target,name));
final var file = getMetal().get().archiveFileName(target,getProject().getName());
return out.file("%s/%s".formatted(target,file));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
@NonNullApi
public abstract class MetalExtension implements ExtensionAware
{
// properties

/**
* Metal service.
*
Expand Down Expand Up @@ -46,7 +48,7 @@ public abstract class MetalExtension implements ExtensionAware
*/
public Provider<String> getHostTarget ()
{
return getMetalService().flatMap(MetalService::getHostTarget);
return getMetalService().map(MetalService::getHost);
}

/**
Expand All @@ -56,6 +58,30 @@ public Provider<String> getHostTarget ()
*/
public abstract ListProperty<String> getLinkOptions ();

// methods

/**
* Formats an archive file name according to the host conventions.
*
* @param name core name
* @return file name
*/
public Provider<String> archiveFileName (String name)
{
return getMetalService().map(it -> it.archiveFileName(name));
}

/**
* Formats an executable file name according to the host conventions.
*
* @param name core name
* @return file name
*/
public Provider<String> executableFileName (String name)
{
return getMetalService().map(it -> it.executableFileName(name));
}

/**
* Locate tool.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ public Provider<RegularFile> getOutput ()
{
return getOutputDirectory().map(out -> {
final var target = getTarget().get();
final var name = getProject().getName();
return out.file("%s/%s.exe".formatted(target,name));
final var file = getMetal().get().executableFileName(target,getProject().getName());
return out.file("%s/%s".formatted(target,file));
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,47 @@
package br.dev.pedrolamarao.gradle.metal.base;

import org.gradle.api.GradleException;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.api.services.BuildService;
import org.gradle.api.services.BuildServiceParameters;
import org.gradle.process.ExecOperations;

import javax.inject.Inject;
import java.io.File;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicReference;

/**
* Metal service.
*/
public abstract class MetalService implements BuildService<BuildServiceParameters.None>
{
private final Provider<String> hostTarget;
private final AtomicReference<String> hostTarget = new AtomicReference<>();

private final Provider<String> path;
private final String path;

/**
* Constructor.
*/
@Inject
public MetalService ()
{
hostTarget = getProviders().of(MetalHostTargetSource.class, it -> {});
path = getProviders().gradleProperty("metal.path")
.orElse(getProviders().environmentVariable("PATH"));
.orElse(getProviders().environmentVariable("PATH"))
.orElse("")
.get();
}

/**
* Exec operations service.
*
* @return service
*/
@Inject
protected abstract ExecOperations getExec ();

/**
* Provider factory service.
*
Expand All @@ -39,11 +53,117 @@ public MetalService ()
/**
* Host target.
*
* @return provider
* @return target name
*/
public String getHost ()
{
final var cached = hostTarget.get();
if (cached != null) return cached;

final var buffer = new ByteArrayOutputStream();
getExec().exec(exec -> {
exec.executable( Metal.toExecutableFile(path,"clang") );
exec.args("-v");
exec.setErrorOutput(buffer);
});

String value = null;
try (var reader = new BufferedReader( new StringReader( buffer.toString() ) ) )
{
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("Target")) {
final var split = line.split(":");
if (split.length != 2) continue;
value = split[1].trim();
break;
}
}
}
catch (IOException e) { throw new GradleException("failed parsing clang -v output", e); }

if (value != null) {
hostTarget.set(value);
return value;
}

throw new GradleException("failed to discover host target");
}

/**
* Formats an archive file name according to the host convention.
*
* @param name core name
* @return file name
*/
public String archiveFileName (String name)
{
return archiveFileName(getHost(),name);
}

/**
* Formats an archive file name according to the target convention.
*
* @param target target
* @param name core name
* @return file name
*/
public String archiveFileName (String target, String name)
{
final var prefix = archiveFilePrefix(target);
final var suffix = archiveFileSuffix(target);
return "%s%s%s".formatted(prefix,name,suffix);
}

String archiveFilePrefix (String target)
{
final var parts = target.split("-");
if (contains(parts,"msvc")) return "";
else return "lib";
}

String archiveFileSuffix (String target)
{
final var parts = target.split("-");
if (contains(parts,"msvc")) return ".lib";
else return ".a";
}

/**
* Formats an executable file name according to the host convention.
*
* @param name core name
* @return file name
*/
public Provider<String> getHostTarget ()
public String executableFileName (String name)
{
return hostTarget;
return executableFileName(getHost(),name);
}

/**
* Formats an executable file name according to the target convention.
*
* @param target target
* @param name core name
* @return file name
*/
public String executableFileName (String target, String name)
{
final var prefix = executableFilePrefix(target);
final var suffix = executableFileSuffix(target);
return "%s%s%s".formatted(prefix,name,suffix);
}

String executableFilePrefix (String target)
{
return "";
}

String executableFileSuffix (String target)
{
final var parts = target.split("-");
if (contains(parts,"windows")) return ".exe";
else return "";
}

/**
Expand All @@ -54,6 +174,24 @@ public Provider<String> getHostTarget ()
*/
public Provider<File> locateTool (String name)
{
return path.map(it -> Metal.toExecutableFile(it,name));
for (var item : path.split(File.pathSeparator))
{
final var directory = Paths.get(item);
if (! Files.isDirectory(directory)) continue;
final var file = directory.resolve(name);
if (Files.isExecutable(file)) return getProviders().provider(file::toFile);
final var file_exe = file.resolveSibling(name + ".exe");
if (Files.isExecutable(file_exe)) return getProviders().provider(file_exe::toFile);
}

throw new GradleException("executable file not found: " + name);
}

static <T> boolean contains (T[] array, T value)
{
for (T item : array)
if (item.equals(value))
return true;
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ public abstract class MetalSourceTask extends SourceTask
*/
protected MetalSourceTask ()
{
getTarget().convention( getProviders().gradleProperty("metal.target").orElse( getMetal().flatMap(MetalService::getHostTarget) ) );
getTarget().convention( getProviders().gradleProperty("metal.target").orElse( getMetal().map(MetalService::getHost) ) );
}
}

0 comments on commit 75ccac2

Please sign in to comment.