-
Notifications
You must be signed in to change notification settings - Fork 30
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
#130: Add default content length to progress bar #286
Changes from 25 commits
a6799be
be68571
82a521f
72b90ef
7c81d4a
2651706
301b5bb
483311d
c4e6d0a
a95ac8d
1729d2e
0ad0b7b
356f7ec
9886857
368f3a1
2526187
d931dff
7ac7fa4
f7205aa
1ecce2b
fc4b554
50d38c4
8dccee1
acf8e96
ba27c39
f3ccb0a
df01ffe
5a146b1
c13439d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package com.devonfw.tools.ide.io; | ||
|
||
/** | ||
* Abstract implementation of {@link IdeProgressBar}. | ||
*/ | ||
public abstract class AbstractIdeProgressBar implements IdeProgressBar { | ||
|
||
/** The default value for missing content length */ | ||
public static final long DEFAULT_CONTENT_LENGTH = 10000000L; | ||
|
||
private long currentProgress; | ||
private final long maxLength; | ||
|
||
/** | ||
* @param maxLength the maximum length of the progress bar. | ||
*/ | ||
public AbstractIdeProgressBar(long maxLength) { | ||
|
||
this.maxLength = maxLength; | ||
} | ||
|
||
/** | ||
* Increases the progress bar by given step size. | ||
* | ||
* @param stepSize size to step by. | ||
* @param currentProgress | ||
*/ | ||
protected abstract void doStepBy(long stepSize, long currentProgress); | ||
|
||
/** | ||
* Increases the progress bar by given step size. | ||
* | ||
* @param stepSize size to step by. | ||
*/ | ||
protected abstract void doStepBy(long stepSize); | ||
|
||
/** | ||
* Sets the progress bar to given step position. | ||
* | ||
* @param stepPosition position to set to. | ||
*/ | ||
protected abstract void doStepTo(long stepPosition); | ||
|
||
@Override | ||
public void stepBy(long stepSize) { | ||
|
||
this.currentProgress += stepSize; | ||
if (this.maxLength > 0) { | ||
// check if maximum overflow | ||
if (this.currentProgress > this.maxLength) { | ||
this.currentProgress = this.maxLength; | ||
doStepTo(this.maxLength); | ||
return; | ||
} | ||
} | ||
|
||
doStepBy(stepSize, this.currentProgress); | ||
} | ||
|
||
@Override | ||
public void close() { | ||
if (this.currentProgress < this.maxLength) { | ||
// TODO: Check if doStepTo should be used instead. | ||
doStepBy(this.maxLength - this.currentProgress, this.currentProgress); | ||
jan-vcapgemini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,8 +24,9 @@ public interface FileAccess { | |
* @param url the location of the binary file to download. May also be a local or remote path to copy from. | ||
* @param targetFile the {@link Path} to the target file to download to. Should not already exists. Missing parent directories will be created | ||
* automatically. | ||
* @param test boolean indicating if this is used in a test or not. | ||
*/ | ||
void download(String url, Path targetFile); | ||
void download(String url, Path targetFile, boolean test); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we need this parameter? This seems odd to have in a regular API. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a left over from the first draft and should be removed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed now. |
||
|
||
/** | ||
* Creates the entire {@link Path} as directories if not already existing. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -89,7 +89,7 @@ private HttpClient createHttpClient(String url) { | |
} | ||
|
||
@Override | ||
public void download(String url, Path target) { | ||
public void download(String url, Path target, boolean test) { | ||
|
||
this.context.info("Trying to download {} from {}", target.getFileName(), url); | ||
mkdirs(target.getParent()); | ||
|
@@ -109,7 +109,7 @@ public void download(String url, Path target) { | |
Path source = Path.of(url); | ||
if (isFile(source)) { | ||
// network drive | ||
copyFileWithProgressBar(source, target); | ||
copyFileWithProgressBar(source, target, test); | ||
} else { | ||
throw new IllegalArgumentException("Download path does not point to a downloadable file: " + url); | ||
} | ||
|
@@ -126,13 +126,10 @@ public void download(String url, Path target) { | |
* @param target Path of the target directory. | ||
* @param response the {@link HttpResponse} to use. | ||
*/ | ||
private void downloadFileWithProgressBar(String url, Path target, HttpResponse<InputStream> response) throws IOException { | ||
private void downloadFileWithProgressBar(String url, Path target, HttpResponse<InputStream> response) { | ||
|
||
long contentLength = response.headers().firstValueAsLong("content-length").orElse(0); | ||
if (contentLength == 0) { | ||
this.context.warning("Content-Length was not provided by download source : {} using fallback for the progress bar which will be inaccurate.", url); | ||
contentLength = 10000000; | ||
} | ||
informAboutSettingDefaultContentLength(contentLength, url, null); | ||
|
||
byte[] data = new byte[1024]; | ||
boolean fileComplete = false; | ||
|
@@ -151,6 +148,7 @@ private void downloadFileWithProgressBar(String url, Path target, HttpResponse<I | |
pb.stepBy(count); | ||
} | ||
} | ||
|
||
} catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
|
@@ -161,26 +159,49 @@ private void downloadFileWithProgressBar(String url, Path target, HttpResponse<I | |
* | ||
* @param source Path of file to copy | ||
* @param target Path of target directory | ||
* @param test the flag about calling this method from test classes. | ||
*/ | ||
private void copyFileWithProgressBar(Path source, Path target) throws IOException { | ||
private void copyFileWithProgressBar(Path source, Path target, boolean test) throws IOException { | ||
ndemirca marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
try (InputStream in = new FileInputStream(source.toFile()); OutputStream out = new FileOutputStream(target.toFile())) { | ||
long size; | ||
if (test) { | ||
size = 0L; | ||
} else { | ||
size = source.toFile().length(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if you need to test this somehow, extract to protected method There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've implemented this as you've suggested, thanks. |
||
|
||
long size = source.toFile().length(); | ||
informAboutSettingDefaultContentLength(size, null, source); | ||
byte[] buf = new byte[1024]; | ||
int readBytes; | ||
|
||
try (IdeProgressBar pb = this.context.prepareProgressBar("Copying", size)) { | ||
while ((readBytes = in.read(buf)) > 0) { | ||
out.write(buf, 0, readBytes); | ||
pb.stepByOne(); | ||
if (size > 0) { | ||
pb.stepBy(readBytes); | ||
} | ||
} | ||
} catch (Exception e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} | ||
|
||
private void informAboutSettingDefaultContentLength(long contentLength, String url, Path path) { | ||
|
||
String source; | ||
if (contentLength == 0) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why are you using Files can be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've set the default for undefined to -1 now. |
||
if (path != null) { | ||
source = path.toString(); | ||
} else { | ||
source = url; | ||
} | ||
this.context.warning("Content-Length was not provided by download/copy source: {}.", | ||
source); | ||
} | ||
} | ||
|
||
@Override | ||
public void mkdirs(Path directory) { | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,88 @@ | ||
package com.devonfw.tools.ide.io; | ||
|
||
import com.devonfw.tools.ide.os.SystemInfo; | ||
|
||
import me.tongfei.progressbar.ProgressBar; | ||
import me.tongfei.progressbar.ProgressBarBuilder; | ||
import me.tongfei.progressbar.ProgressBarStyle; | ||
|
||
/** | ||
* Implementation of {@link IdeProgressBar}. | ||
*/ | ||
public class IdeProgressBarConsole implements IdeProgressBar { | ||
public class IdeProgressBarConsole extends AbstractIdeProgressBar { | ||
|
||
private final ProgressBar progressBar; | ||
private final SystemInfo systemInfo; | ||
|
||
/** | ||
* The constructor. | ||
* | ||
* @param progressBar the {@link ProgressBar} to initialize. | ||
* @param systemInfo the {@link SystemInfo}. | ||
* @param taskName the {@link ProgressBar} to initialize. | ||
* @param maxSize the maximum size of the progress bar. | ||
*/ | ||
public IdeProgressBarConsole(SystemInfo systemInfo, String taskName, long maxSize) { | ||
|
||
super(maxSize); | ||
|
||
this.systemInfo = systemInfo; | ||
this.progressBar = createProgressBar(taskName, maxSize); | ||
} | ||
|
||
/** | ||
* Creates the {@link ProgressBar} initializes task name and maximum size as well as the behaviour and style. | ||
* | ||
* @param taskName name of the task. | ||
* @param size of the content. | ||
* @return {@link ProgressBar} to use. | ||
*/ | ||
public IdeProgressBarConsole(ProgressBar progressBar) { | ||
protected ProgressBar createProgressBar(String taskName, long size) { | ||
|
||
this.progressBar = progressBar; | ||
ProgressBarBuilder pbb = new ProgressBarBuilder(); | ||
// default (COLORFUL_UNICODE_BLOCK) | ||
pbb.setStyle(ProgressBarStyle.builder().refreshPrompt("\r").leftBracket("\u001b[33m│").delimitingSequence("") | ||
.rightBracket("│\u001b[0m").block('█').space(' ').fractionSymbols(" ▏▎▍▌▋▊▉").rightSideFractionSymbol(' ') | ||
.build()); | ||
// set different style for Windows systems (ASCII) | ||
if (this.systemInfo.isWindows()) { | ||
pbb.setStyle(ProgressBarStyle.builder().refreshPrompt("\r").leftBracket("[").delimitingSequence("") | ||
.rightBracket("]").block('=').space(' ').fractionSymbols(">").rightSideFractionSymbol(' ').build()); | ||
} | ||
jan-vcapgemini marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
pbb.setUnit("MiB", 1048576); | ||
if (size == 0) { | ||
pbb.setTaskName(taskName + " (unknown size)"); | ||
pbb.setInitialMax(-1); | ||
pbb.hideEta(); | ||
} else { | ||
pbb.setTaskName(taskName); | ||
pbb.showSpeed(); | ||
pbb.setInitialMax(size); | ||
} | ||
pbb.continuousUpdate(); | ||
pbb.setUpdateIntervalMillis(1); | ||
|
||
return pbb.build(); | ||
} | ||
|
||
@Override | ||
public void stepBy(long stepSize) { | ||
protected void doStepBy(long stepSize, long currentProgress) { | ||
doStepBy(stepSize); | ||
} | ||
|
||
@Override | ||
protected void doStepBy(long stepSize) { | ||
this.progressBar.stepBy(stepSize); | ||
} | ||
|
||
@Override | ||
public void close() { | ||
protected void doStepTo(long stepPosition) { | ||
this.progressBar.stepTo(stepPosition); | ||
} | ||
|
||
@Override | ||
public void close() { | ||
super.close(); | ||
this.progressBar.close(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
handle
maxLength < 0
(-1) caseThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added a check for
maxLength < 0
which will simply return and not change the progress bar anymore.