-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9ae778c
commit 21f2d34
Showing
16 changed files
with
469 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
/.gradle/ | ||
/.idea/ | ||
/build/ | ||
build/ | ||
/repo/ | ||
/.settings/ | ||
/bin/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
dependencies { | ||
testImplementation('org.junit.jupiter:junit-jupiter-api:5.8.2') | ||
testImplementation('org.junit.jupiter:junit-jupiter-engine:5.8.2') | ||
} | ||
|
||
test { | ||
useJUnitPlatform() | ||
} | ||
|
||
publishing { | ||
publications.register('mavenJava', MavenPublication) { | ||
from components.java | ||
pom { | ||
name = 'CLI Utils' | ||
description = "CLI Utilities for NeoForge's projects" | ||
} | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
cli-utils/src/main/java/net/neoforged/cliutils/progress/ProgressActionType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package net.neoforged.cliutils.progress; | ||
|
||
import java.util.Arrays; | ||
import java.util.Map; | ||
import java.util.function.BiConsumer; | ||
import java.util.function.Function; | ||
import java.util.stream.Collectors; | ||
|
||
public enum ProgressActionType { | ||
STEP('s', ProgressManager::setStep), | ||
PROGRESS('p', (progressManager, value) -> { | ||
if (value.endsWith("%")) { | ||
progressManager.setPercentageProgress(Double.parseDouble(value.substring(0, value.length() - 1))); | ||
} else { | ||
progressManager.setProgress(Integer.parseInt(value)); | ||
} | ||
}), | ||
MAX_PROGRESS('m', (progressManager, value) -> progressManager.setMaxProgress(Integer.parseInt(value))), | ||
INDETERMINATE('i', (progressManager, value) -> progressManager.setIndeterminate(Boolean.parseBoolean(value))); | ||
|
||
public static final Map<Character, ProgressActionType> TYPES = Arrays.stream(values()) | ||
.collect(Collectors.toMap(val -> val.identifier, Function.identity())); | ||
|
||
public final char identifier; | ||
public final BiConsumer<ProgressManager, String> acceptor; | ||
|
||
ProgressActionType(char identifier, BiConsumer<ProgressManager, String> acceptor) { | ||
this.identifier = identifier; | ||
this.acceptor = acceptor; | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
cli-utils/src/main/java/net/neoforged/cliutils/progress/ProgressInterceptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package net.neoforged.cliutils.progress; | ||
|
||
import java.io.FilterOutputStream; | ||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.Arrays; | ||
|
||
/** | ||
* Intercepts {@link ProgressActionType} progress manager actions and redirects them to the {@code manager}. | ||
*/ | ||
public class ProgressInterceptor extends FilterOutputStream { | ||
public static final String FULL_MODIFIER = "\033[" + ProgressReporter.MODIFIER_KEY + ";"; | ||
|
||
protected final ProgressManager manager; | ||
public ProgressInterceptor(OutputStream out, ProgressManager manager) { | ||
super(out); | ||
this.manager = manager; | ||
} | ||
|
||
private StringBuffer current; | ||
|
||
@Override | ||
public void write(int b) throws IOException { | ||
if (current != null) { | ||
if (b == '\n') { | ||
processCurrent(); | ||
} else if (b != '\r') // Ignore CR because Windows is bad | ||
current.append((char)b); | ||
} else { | ||
if (b == '\033') { | ||
current = new StringBuffer() | ||
.append((char)b); | ||
} else { | ||
out.write(b); | ||
} | ||
} | ||
} | ||
|
||
private void processCurrent() throws IOException { | ||
final String cur = current.toString(); | ||
if (cur.startsWith(FULL_MODIFIER)) { | ||
final String[] values = cur.substring(FULL_MODIFIER.length()).split(" ", 2); | ||
// If not 2, the value's empty, which isn't supported, so ignore | ||
if (values.length == 2) { | ||
final String first = values[0]; | ||
if (first.length() != 1) { | ||
System.err.println("Invalid progress modifier: " + values[0]); | ||
return; | ||
} | ||
|
||
final ProgressActionType action = ProgressActionType.TYPES.get(first.charAt(0)); | ||
if (action == null) { | ||
System.err.println("Unknown progress modifier: " + first.charAt(0)); | ||
return; | ||
} | ||
|
||
action.acceptor.accept(manager, values[1]); | ||
} | ||
} else { | ||
out.write(cur.getBytes(StandardCharsets.UTF_8)); | ||
out.write(System.lineSeparator().getBytes(StandardCharsets.UTF_8)); | ||
} | ||
|
||
current = null; | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
cli-utils/src/main/java/net/neoforged/cliutils/progress/ProgressManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package net.neoforged.cliutils.progress; | ||
|
||
/** | ||
* A manager that changes the progress of a progress bar, to indicate the current progress to users. | ||
*/ | ||
public interface ProgressManager { | ||
/** | ||
* Sets the max progress of the manager. | ||
*/ | ||
void setMaxProgress(int maxProgress); | ||
|
||
/** | ||
* Sets the current progress of the manager. | ||
*/ | ||
void setProgress(int progress); | ||
|
||
/** | ||
* Sets progress of the manager, based on a fractional value. <br> | ||
* Note: this also sets the {@link #setMaxProgress(int)} to {@literal 100}. | ||
*/ | ||
void setPercentageProgress(double progress); | ||
|
||
/** | ||
* Sets the current step to be shown to the user. | ||
*/ | ||
void setStep(String name); | ||
|
||
/** | ||
* Sets whether the max progress is known or not. If not, the loading bar will load 'forever'. | ||
*/ | ||
void setIndeterminate(boolean indeterminate); | ||
} |
114 changes: 114 additions & 0 deletions
114
cli-utils/src/main/java/net/neoforged/cliutils/progress/ProgressReporter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package net.neoforged.cliutils.progress; | ||
|
||
import java.io.FilterInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.PrintStream; | ||
import java.net.URLConnection; | ||
import java.text.DecimalFormat; | ||
|
||
/** | ||
* A {@link ProgressManager} that forwards all changes to a {@link ProgressReporter#output print stream} | ||
* that writes the changes with an ANSI modifier {@value #MODIFIER_KEY}. <br> | ||
* The ANSI modifier takes the form "\033[{@literal progressmanager};action value". <p> | ||
* The {@link #getDefault() default reporter} will only be enabled if the {@value #ENABLED_PROPERTY} system property is set to {@code true}, | ||
* and will output to {@link System#err}. | ||
* @see ProgressActionType for the actions | ||
*/ | ||
public class ProgressReporter implements ProgressManager { | ||
public static final String MODIFIER_KEY = "progressmanager"; | ||
public static final String ENABLED_PROPERTY = "net.neoforged.progressmanager.enabled"; | ||
private static final DecimalFormat TWO_DECIMALS = new DecimalFormat("#.00"); | ||
|
||
protected final boolean enabled; | ||
protected final PrintStream output; | ||
|
||
public ProgressReporter(boolean enabled, PrintStream output) { | ||
this.enabled = enabled; | ||
this.output = output; | ||
} | ||
|
||
public static ProgressReporter getDefault() { | ||
return new ProgressReporter(Boolean.getBoolean(ENABLED_PROPERTY), System.err); | ||
} | ||
|
||
@Override | ||
public void setMaxProgress(int maxProgress) { | ||
write(ProgressActionType.MAX_PROGRESS, String.valueOf(maxProgress)); | ||
} | ||
|
||
@Override | ||
public void setProgress(int progress) { | ||
write(ProgressActionType.PROGRESS, String.valueOf(progress)); | ||
} | ||
|
||
@Override | ||
public void setPercentageProgress(double progress) { | ||
write(ProgressActionType.PROGRESS, TWO_DECIMALS.format(progress) + "%"); | ||
} | ||
|
||
@Override | ||
public void setStep(String name) { | ||
write(ProgressActionType.STEP, name); | ||
} | ||
|
||
@Override | ||
public void setIndeterminate(boolean indeterminate) { | ||
write(ProgressActionType.INDETERMINATE, String.valueOf(indeterminate)); | ||
} | ||
|
||
protected void write(ProgressActionType type, String value) { | ||
if (!enabled) return; | ||
|
||
try { | ||
//noinspection RedundantStringFormatCall | ||
output.println(String.format("\033[%s;%s %s", MODIFIER_KEY, type.identifier, value)); | ||
} catch (Exception exception) { | ||
exception.printStackTrace(System.err); | ||
System.err.println("Failed to write progress: " + exception); | ||
} | ||
} | ||
|
||
public InputStream wrapDownload(URLConnection connection) throws IOException { | ||
connection.connect(); | ||
setMaxProgress(connection.getContentLength()); | ||
return wrapDownload(connection.getInputStream()); | ||
} | ||
|
||
public InputStream wrapDownload(InputStream in) { | ||
return new FilterInputStream(in) { | ||
private int nread = 0; | ||
|
||
@Override | ||
public int read() throws IOException { | ||
int c = in.read(); | ||
if (c >= 0) setProgress(++nread); | ||
return c; | ||
} | ||
|
||
|
||
@Override | ||
public int read(byte[] b) throws IOException { | ||
int nr = in.read(b); | ||
if (nr > 0) setProgress(nread += nr); | ||
return nr; | ||
} | ||
|
||
|
||
@Override | ||
public int read(byte[] b, int off, int len) throws IOException { | ||
int nr = in.read(b, off, len); | ||
if (nr > 0) setProgress(nread += nr); | ||
return nr; | ||
} | ||
|
||
|
||
@Override | ||
public long skip(long n) throws IOException { | ||
long nr = in.skip(n); | ||
if (nr > 0) setProgress(nread += nr); | ||
return nr; | ||
} | ||
}; | ||
} | ||
} |
Oops, something went wrong.