Skip to content

Commit

Permalink
Merge pull request #127 from Roche-CSI/LoggingRunner
Browse files Browse the repository at this point in the history
LoggingRunner & CommnadLogger simplify debug/trace logging of commands being run
  • Loading branch information
gdgib committed Apr 13, 2024
2 parents 5cd465f + 4961a5b commit 5eaf009
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.g2forge.alexandria.annotations.note.NoteType;
import com.g2forge.alexandria.command.invocation.CommandInvocation;
import com.g2forge.alexandria.command.invocation.environment.SystemEnvironment;
import com.g2forge.alexandria.command.invocation.environment.modified.IEnvironmentModifier;
import com.g2forge.alexandria.command.invocation.environment.modified.ModifiedEnvironment;
import com.g2forge.alexandria.command.invocation.format.ICommandFormat;
import com.g2forge.alexandria.command.stdio.StandardIO;
Expand Down Expand Up @@ -48,6 +49,7 @@

import lombok.Builder;
import lombok.Data;
import lombok.RequiredArgsConstructor;

public class DumbCommandConverter implements ICommandConverterR_, ISingleton {
@Data
Expand All @@ -62,6 +64,31 @@ protected static class ArgumentContext {

protected static final DumbCommandConverter instance = new DumbCommandConverter();

@Data
@Builder(toBuilder = true)
@RequiredArgsConstructor
protected static class EnvPathModifier implements IEnvironmentModifier {
protected final EnvPath.Usage usage;

protected final Path value;

@Override
public String modify(String parent) {
final String pathSeparator = HPlatform.getPlatform().getPathSpec().getPathSeparator();
switch (getUsage()) {
case AddFirst:
return getValue().toString() + pathSeparator + parent;
case Replace:
return getValue().toString();
case AddLast:
return parent + pathSeparator + getValue().toString();
default:
throw new EnumException(EnvPath.Usage.class, getUsage());
}
}

}

protected static final IConsumer2<ArgumentContext, Object> ARGUMENT_BUILDER = new TypeSwitch2.ConsumerBuilder<ArgumentContext, Object>().with(builder -> {
builder.add(ArgumentContext.class, String[].class, (c, v) -> {
final ISubject metadata = c.getArgument().getMetadata();
Expand All @@ -84,25 +111,13 @@ protected static class ArgumentContext {

final Working working = c.getArgument().getMetadata().get(Working.class);
if (working != null) {
c.getCommand().working(v);
if (v != null) c.getCommand().working(v);
isNormal = false;
}

final EnvPath envPath = c.getArgument().getMetadata().get(EnvPath.class);
if (envPath != null) {
c.getEnvironment().modifier(HPlatform.PATH, parent -> {
final String pathSeparator = HPlatform.getPlatform().getPathSpec().getPathSeparator();
switch (envPath.usage()) {
case AddFirst:
return v.toString() + pathSeparator + parent;
case Replace:
return v.toString();
case AddLast:
return parent + pathSeparator + v.toString();
default:
throw new EnumException(EnvPath.Usage.class, envPath.usage());
}
});
c.getEnvironment().modifier(HPlatform.PATH, new EnvPathModifier(envPath.usage(), v));
isNormal = false;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.g2forge.gearbox.command.log;

import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;

import com.g2forge.alexandria.java.close.ICloseable;
import com.g2forge.alexandria.java.function.IConsumer1;
import com.g2forge.alexandria.java.io.RuntimeIOException;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class CommandLogger implements ICloseable, IConsumer1<String> {
protected final Path logFile;

protected final IConsumer1<String> tee;

protected PrintStream stream = null;

@Override
public void accept(String t) {
if (stream == null) try {
Files.createDirectories(logFile.getParent());
stream = new PrintStream(Files.newOutputStream(logFile));
} catch (IOException e) {
throw new RuntimeIOException(e);
}
stream.println(t);
if (tee != null) tee.accept(t);
}

@Override
public void close() {
if (stream == null) {
try {
Files.deleteIfExists(logFile);
} catch (IOException e) {
throw new RuntimeIOException(e);
}
} else stream.close();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.g2forge.gearbox.command.log;

import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import com.g2forge.alexandria.command.invocation.CommandInvocation;
import com.g2forge.alexandria.command.invocation.environment.IEnvironment;
import com.g2forge.alexandria.command.invocation.environment.MapEnvironment;
import com.g2forge.alexandria.command.invocation.environment.SystemEnvironment;
import com.g2forge.alexandria.command.invocation.environment.modified.IEnvironmentModifier;
import com.g2forge.alexandria.command.invocation.environment.modified.ModifiedEnvironment;
import com.g2forge.alexandria.java.core.error.NotYetImplementedError;
import com.g2forge.alexandria.java.core.helpers.HCollection;
import com.g2forge.alexandria.java.function.IConsumer1;
import com.g2forge.gearbox.command.process.IProcess;
import com.g2forge.gearbox.command.process.IRunner;
import com.g2forge.gearbox.command.process.redirect.IRedirect;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter(AccessLevel.PROTECTED)
@RequiredArgsConstructor
public class LoggingRunner implements IRunner {
protected static String toString(IEnvironment environment, String prefix) {
final StringBuilder retVal = new StringBuilder();
if (environment instanceof MapEnvironment) {
for (Map.Entry<String, String> entry : ((MapEnvironment) environment).getVariables().entrySet()) {
retVal.append(prefix).append(entry.getKey()).append('=').append(entry.getValue()).append("\n");
}
} else if (environment instanceof ModifiedEnvironment) {
final ModifiedEnvironment modified = ((ModifiedEnvironment) environment);

final String base = toString(modified.getBase(), prefix + "\t");
final boolean multiLineBase = base.contains("\n");
final int modifierCount = modified.getModifiers().size();

if (multiLineBase || modifierCount > 1) {
retVal.append(prefix).append("modified:").append(multiLineBase ? '\n' : ' ').append(multiLineBase ? base : base.strip()).append('\n');
retVal.append(prefix).append("modifiers:\n");
for (Map.Entry<String, IEnvironmentModifier> entry : modified.getModifiers().entrySet()) {
retVal.append(prefix).append('\t').append(entry.getKey()).append(" <- ").append(entry.getValue()).append('\n');
}
} else if (modifierCount < 1) retVal.append(base.strip());
else {
final Entry<String, IEnvironmentModifier> entry = HCollection.getOne(modified.getModifiers().entrySet());
retVal.append(prefix).append("modified ").append(base.strip()).append(" with ").append(entry.getKey()).append(" <- ").append(entry.getValue());
}
} else if (environment instanceof SystemEnvironment) {
retVal.append(prefix).append("system environment\n");
} else throw new NotYetImplementedError("Environments of type " + environment.getClass() + " are not yet supported!");

return retVal.toString().stripTrailing();
}

protected final IConsumer1<String> log;

protected final IRunner runner;

@Override
public IProcess apply(CommandInvocation<IRedirect, IRedirect> commandInvocation) {
final IConsumer1<String> log = getLog();
log.accept("Running: " + commandInvocation.getArguments().stream().collect(Collectors.joining(" ")));
if (commandInvocation.getWorking() != null) log.accept("\tin " + commandInvocation.getWorking());
final IEnvironment environment = commandInvocation.getEnvironment();
if ((environment != null) && !(commandInvocation.getEnvironment() instanceof SystemEnvironment)) {
final String string = toString(environment, "\t\t");
if (string.contains("\n")) {
log.accept("\tenvironment:");
for (String line : string.split("\n")) {
log.accept(line);
}
} else log.accept("\tenvironment: " + string.substring(2 /* Remove the tabs */));
}
return runner.apply(commandInvocation);
}
}

0 comments on commit 5eaf009

Please sign in to comment.