embulk 0.6.2 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/bin/embulk +2 -2
  4. data/build.gradle +11 -2
  5. data/embulk-cli/src/main/java/org/embulk/cli/Main.java +0 -2
  6. data/embulk-core/build.gradle +1 -1
  7. data/embulk-core/src/main/java/org/embulk/command/Runner.java +10 -0
  8. data/embulk-core/src/main/java/org/embulk/exec/GuessExecutor.java +3 -2
  9. data/embulk-core/src/main/java/org/embulk/exec/PreviewExecutor.java +1 -1
  10. data/embulk-core/src/main/java/org/embulk/jruby/JRubyScriptingModule.java +18 -6
  11. data/embulk-core/src/main/java/org/embulk/plugin/PluginManager.java +14 -11
  12. data/embulk-core/src/main/java/org/embulk/spi/Column.java +5 -5
  13. data/embulk-core/src/main/java/org/embulk/spi/ColumnConfig.java +4 -4
  14. data/embulk-core/src/main/java/org/embulk/spi/Exec.java +6 -0
  15. data/embulk-core/src/main/java/org/embulk/spi/FileInputRunner.java +1 -1
  16. data/embulk-core/src/main/java/org/embulk/spi/Schema.java +2 -2
  17. data/embulk-core/src/main/java/org/embulk/spi/SchemaConfig.java +2 -2
  18. data/embulk-core/src/main/java/org/embulk/spi/unit/ByteSize.java +148 -0
  19. data/embulk-core/src/test/java/org/embulk/spi/unit/TestByteSize.java +79 -0
  20. data/embulk-docs/build.gradle +5 -1
  21. data/embulk-docs/src/customization.rst +184 -0
  22. data/embulk-docs/src/index.rst +10 -1
  23. data/embulk-docs/src/release.rst +1 -0
  24. data/embulk-docs/src/release/release-0.6.3.rst +23 -0
  25. data/lib/embulk/command/embulk_run.rb +41 -3
  26. data/lib/embulk/data/new/gitignore.erb +1 -0
  27. data/lib/embulk/data/new/java/build.gradle.erb +20 -4
  28. data/lib/embulk/java/bootstrap.rb +2 -2
  29. data/lib/embulk/plugin.rb +1 -1
  30. data/lib/embulk/version.rb +1 -1
  31. data/test/helper.rb +7 -0
  32. metadata +8 -6
  33. data/embulk-docs/plugins/index.html.erb +0 -73
  34. data/embulk-docs/plugins/plugins.css +0 -148
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 148c75f1b85e1d85859d0be3293d85e5fc3f1bab
4
- data.tar.gz: c07d2801fc7cc4b0caa60d2ff692553b29827cfe
3
+ metadata.gz: b37c9dd1d3a700e0057040d27f0a29e917e21b13
4
+ data.tar.gz: 3372de3c3f382dc6f83bea6936d84af3b815194c
5
5
  SHA512:
6
- metadata.gz: 6f499389219a19663e1e3789b68bf1eea7f650df7921347ec5d0641395a1a1b11a5087f571a9e0ac3536cc1156592cb15b1f5b4283e069f68d456449c90d4c69
7
- data.tar.gz: 78eeb275c30689f63947961fd1d2f0b01d96abfef0c16b1e68370fdca0570c809f1e4cb38924e67c10f11e86759c88e706dcb32c45f55eaf10876055bdedf8ea
6
+ metadata.gz: 7d0c416b6c063508b95d23941c5cf97149bcf6fd11134392f79d0d7540f106df019e502fc7296ba47a94a945a64c8b34a4d4aaf682227d390300592d598c0f1a
7
+ data.tar.gz: b370deb8322442973cc3109ca2a0b8eb3931d11840f55e7d230f56c10de45c93a71d39cb892dad491ef67870c9e77932fabee4d82cf99ea601ba3417ea3e7cc8
@@ -8,7 +8,7 @@ sudo: false
8
8
  install:
9
9
  - pip install --user sphinx
10
10
  script:
11
- - ./gradlew check
11
+ - ./gradlew check rubyTest
12
12
  after_success:
13
13
  - PATH="$HOME/.local/bin:$PATH" ./embulk-docs/push-gh-pages.sh
14
14
  env:
data/bin/embulk CHANGED
@@ -69,9 +69,9 @@ unless jruby_complete
69
69
  end
70
70
 
71
71
  if overwrite_optimize == true || (default_optimize == true && overwrite_optimize != false)
72
- java_args = %w[-XX:+AggressiveOpts -XX:+UseConcMarkSweepGC] + java_args
72
+ java_args = %w[-XX:+AggressiveOpts -XX:+UseConcMarkSweepGC] + java_args
73
73
  else
74
- java_args = %w[-XX:+AggressiveOpts -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Xverify:none] + java_args
74
+ java_args = %w[-XX:+AggressiveOpts -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Xverify:none] + java_args
75
75
  end
76
76
 
77
77
  # java ... -jar ruby-complete.jar $EMBULK_HOME/lib/embulk/command/embulk.rb "$@"
@@ -5,14 +5,17 @@ plugins {
5
5
  id 'com.github.jruby-gradle.base' version '0.1.5'
6
6
  id 'com.github.johnrengelman.shadow' version '1.2.0'
7
7
  }
8
- import com.github.jrubygradle.JRubyExec
9
8
 
10
9
  def java_projects = [project(":embulk-core"), project(":embulk-standards"), project(":embulk-cli")]
11
10
  def release_projects = [project(":embulk-core"), project(":embulk-standards")]
12
11
 
13
12
  allprojects {
14
13
  group = 'org.embulk'
15
- version = '0.6.2'
14
+ version = '0.6.3'
15
+
16
+ ext {
17
+ jrubyVersion = '1.7.19'
18
+ }
16
19
 
17
20
  apply plugin: 'java'
18
21
  apply plugin: 'maven-publish'
@@ -137,6 +140,11 @@ subprojects {
137
140
  }
138
141
  }
139
142
 
143
+ import com.github.jrubygradle.JRubyExec
144
+ jruby {
145
+ execVersion = project.jrubyVersion
146
+ }
147
+
140
148
  dependencies {
141
149
  jrubyExec 'rubygems:test-unit:3.0.+'
142
150
  }
@@ -187,6 +195,7 @@ task rubyTest(type: JRubyExec) {
187
195
  jrubyArgs '-Ilib', '-Itest', '-rtest/unit', '-eTest::Unit::AutoRunner.run(true, *ARGV)'
188
196
  script 'test'
189
197
  }
198
+ rubyTest.dependsOn('classpath')
190
199
 
191
200
  //
192
201
  // gem task
@@ -4,8 +4,6 @@ public class Main
4
4
  {
5
5
  public static void main(String[] args)
6
6
  {
7
- // TODO set GEM_HOME to point the internal gem repository created by gem-maven-plugin?
8
-
9
7
  // $ java -jar jruby-complete.jar classpath:embulk/command/embulk.rb "$@"
10
8
  String[] jrubyArgs = new String[args.length + 1];
11
9
  jrubyArgs[0] = "classpath:embulk/command/embulk.rb";
@@ -27,7 +27,7 @@ dependencies {
27
27
  compile 'log4j:log4j:1.2.17'
28
28
  compile 'org.slf4j:slf4j-api:1.7.10'
29
29
  compile 'org.slf4j:slf4j-log4j12:1.7.10'
30
- compile 'org.jruby:jruby-complete:1.7.19'
30
+ compile 'org.jruby:jruby-complete:' + project.jrubyVersion
31
31
  compile 'com.google.code.findbugs:annotations:3.0.0'
32
32
  compile 'org.yaml:snakeyaml:1.14'
33
33
  compile 'javax.validation:validation-api:1.1.0.Final'
@@ -50,6 +50,9 @@ public class Runner
50
50
 
51
51
  private List<PluginType> guessPlugins;
52
52
  public List<PluginType> getGuessPlugins() { return guessPlugins; }
53
+
54
+ private boolean useGlobalRubyRuntime;
55
+ public boolean getUseGlobalRubyRuntime() { return useGlobalRubyRuntime; }
53
56
  }
54
57
 
55
58
  private final Options options;
@@ -72,16 +75,23 @@ public class Runner
72
75
  {
73
76
  String logLevel = options.getLogLevel();
74
77
  if (logLevel != null) {
78
+ // used by LoggerProvider
75
79
  systemConfig.set("log_level", logLevel);
76
80
  }
77
81
 
78
82
  List<PluginType> guessPlugins = options.getGuessPlugins();
79
83
  if (guessPlugins != null && !guessPlugins.isEmpty()) {
84
+ // used by GuessExecutor
80
85
  List<PluginType> list = new ArrayList<PluginType>() { };
81
86
  list = systemConfig.get((Class<List<PluginType>>) list.getClass(), "guess_plugins", list);
82
87
  list.addAll(guessPlugins);
83
88
  systemConfig.set("guess_plugins", list);
84
89
  }
90
+
91
+ if (options.getUseGlobalRubyRuntime()) {
92
+ // used by JRubyScriptingModule
93
+ systemConfig.set("use_global_ruby_runtime", true);
94
+ }
85
95
  }
86
96
 
87
97
  public void main(String command, String[] args)
@@ -3,6 +3,7 @@ package org.embulk.exec;
3
3
  import java.util.List;
4
4
  import java.util.Set;
5
5
  import java.util.ArrayList;
6
+ import java.util.concurrent.ExecutionException;
6
7
  import com.google.common.collect.ImmutableList;
7
8
  import com.google.common.base.Throwables;
8
9
  import com.google.inject.Inject;
@@ -87,8 +88,8 @@ public class GuessExecutor
87
88
  }
88
89
  }
89
90
  });
90
- } catch (Exception ex) {
91
- throw Throwables.propagate(ex);
91
+ } catch (ExecutionException ex) {
92
+ throw Throwables.propagate(ex.getCause());
92
93
  }
93
94
  }
94
95
 
@@ -69,7 +69,7 @@ public class PreviewExecutor
69
69
  }
70
70
  });
71
71
  } catch (Exception ex) {
72
- throw Throwables.propagate(ex);
72
+ throw Throwables.propagate(ex.getCause());
73
73
  }
74
74
  }
75
75
 
@@ -16,10 +16,12 @@ import com.google.inject.Key;
16
16
  import com.google.inject.spi.Dependency;
17
17
  import com.google.inject.spi.ProviderWithDependencies;
18
18
  import org.jruby.CompatVersion;
19
+ import org.jruby.embed.LocalContextScope;
19
20
  import org.jruby.embed.ScriptingContainer;
20
21
  import org.embulk.plugin.PluginSource;
21
22
  import org.embulk.config.ConfigSource;
22
23
  import org.embulk.config.ModelManager;
24
+ import org.embulk.exec.ForSystemConfig;
23
25
  import org.embulk.spi.BufferAllocator;
24
26
 
25
27
  public class JRubyScriptingModule
@@ -27,15 +29,12 @@ public class JRubyScriptingModule
27
29
  {
28
30
  public JRubyScriptingModule(ConfigSource systemConfig)
29
31
  {
30
- // TODO get jruby-home from systemConfig to call jruby.container.setHomeDirectory
31
- // TODO get jruby-load-paths from systemConfig to call jruby.container.setLoadPaths
32
32
  }
33
33
 
34
34
  @Override
35
35
  public void configure(Binder binder)
36
36
  {
37
37
  binder.bind(ScriptingContainer.class).toProvider(ScriptingContainerProvider.class).in(Scopes.SINGLETON);
38
- //binder.bind(JRubyModule.class).in(Scopes.SINGLETON);
39
38
 
40
39
  Multibinder<PluginSource> multibinder = Multibinder.newSetBinder(binder, PluginSource.class);
41
40
  multibinder.addBinding().to(JRubyPluginSource.class);
@@ -45,16 +44,25 @@ public class JRubyScriptingModule
45
44
  implements ProviderWithDependencies<ScriptingContainer>
46
45
  {
47
46
  private final Injector injector;
47
+ private final boolean useGlobalRubyRuntime;
48
48
 
49
49
  @Inject
50
- public ScriptingContainerProvider(Injector injector)
50
+ public ScriptingContainerProvider(Injector injector, @ForSystemConfig ConfigSource systemConfig)
51
51
  {
52
52
  this.injector = injector;
53
+
54
+ // use_global_ruby_runtime is valid only when it's guaranteed that just one Injector is
55
+ // instantiated in this JVM.
56
+ this.useGlobalRubyRuntime = systemConfig.get(boolean.class, "use_global_ruby_runtime", false);
57
+
58
+ // TODO get jruby-home from systemConfig to call jruby.container.setHomeDirectory
59
+ // TODO get jruby-load-paths from systemConfig to call jruby.container.setLoadPaths
53
60
  }
54
61
 
55
62
  public ScriptingContainer get()
56
63
  {
57
- ScriptingContainer jruby = new ScriptingContainer();
64
+ LocalContextScope scope = (useGlobalRubyRuntime ? LocalContextScope.SINGLETON : LocalContextScope.SINGLETHREAD);
65
+ ScriptingContainer jruby = new ScriptingContainer(scope);
58
66
  jruby.setCompatVersion(CompatVersion.RUBY1_9);
59
67
 
60
68
  // Search embulk/java/bootstrap.rb from a $LOAD_PATH.
@@ -72,9 +80,13 @@ public class JRubyScriptingModule
72
80
  // jruby searches embulk/java/bootstrap.rb from the beginning of $LOAD_PATH.
73
81
  jruby.runScriptlet("require 'embulk/java/bootstrap'");
74
82
 
83
+ // TODO validate Embulk::Java::Injected::Injector doesn't exist? If it already exists,
84
+ // Injector is created more than once in this JVM although use_global_ruby_runtime
85
+ // is set to true.
86
+
75
87
  // set some constants
76
88
  jruby.callMethod(
77
- jruby.runScriptlet("Embulk::Java"),
89
+ jruby.runScriptlet("Embulk::Java::Injected"),
78
90
  "const_set", "Injector", injector);
79
91
  jruby.callMethod(
80
92
  jruby.runScriptlet("Embulk::Java::Injected"),
@@ -13,7 +13,7 @@ public class PluginManager
13
13
  private final List<PluginSource> sources;
14
14
  private final Injector injector;
15
15
 
16
- // Set<PluginSource> is injected BuiltinPluginSourceModule or extensions
16
+ // Set<PluginSource> is injected by BuiltinPluginSourceModule or extensions
17
17
  // using Multibinder<PluginSource>.
18
18
  @Inject
19
19
  public PluginManager(Set<PluginSource> pluginSources, Injector injector)
@@ -32,31 +32,34 @@ public class PluginManager
32
32
  throw new ConfigException(String.format("%s type is not set (if you intend to use NullOutputPlugin, you should enclose null in quotes such as {type: \"null\"}.", iface.getSimpleName()));
33
33
  }
34
34
 
35
- List<Throwable> causes = new ArrayList<Throwable>();
35
+ List<PluginSourceNotMatchException> exceptions = new ArrayList<>();
36
36
  for (PluginSource source : sources) {
37
37
  try {
38
38
  return source.newPlugin(iface, type);
39
39
  } catch (PluginSourceNotMatchException e) {
40
- if (e.getCause() != null) {
41
- causes.add(e.getCause());
42
- } else {
43
- causes.add(e);
44
- }
40
+ exceptions.add(e);
45
41
  }
46
42
  }
47
43
 
44
+ throw buildPluginNotFoundException(iface, type, exceptions);
45
+ }
46
+
47
+ private static ConfigException buildPluginNotFoundException(Class<?> iface, PluginType type,
48
+ List<PluginSourceNotMatchException> exceptions)
49
+ {
48
50
  StringBuilder message = new StringBuilder();
49
51
  message.append(String.format("%s '%s' is not found.", iface.getSimpleName(), type.getName()));
50
- for (Throwable cause : causes) {
52
+ for (PluginSourceNotMatchException exception : exceptions) {
53
+ Throwable cause = (exception.getCause() == null ? exception : exception.getCause());
51
54
  if (cause.getMessage() != null) {
52
55
  message.append(String.format("%n"));
53
56
  message.append(cause.getMessage());
54
57
  }
55
58
  }
56
59
  ConfigException e = new ConfigException(message.toString());
57
- for (Throwable cause : causes) {
58
- e.addSuppressed(cause);
60
+ for (PluginSourceNotMatchException exception : exceptions) {
61
+ e.addSuppressed(exception);
59
62
  }
60
- throw e;
63
+ return e;
61
64
  }
62
65
  }
@@ -1,6 +1,6 @@
1
1
  package org.embulk.spi;
2
2
 
3
- import com.google.common.base.Objects;
3
+ import java.util.Objects;
4
4
  import com.fasterxml.jackson.annotation.JsonCreator;
5
5
  import com.fasterxml.jackson.annotation.JsonProperty;
6
6
  import org.embulk.spi.type.Type;
@@ -72,15 +72,15 @@ public class Column
72
72
  return false;
73
73
  }
74
74
  Column other = (Column) obj;
75
- return Objects.equal(index, other.index) &&
76
- Objects.equal(name, other.name) &&
77
- Objects.equal(type, other.type);
75
+ return Objects.equals(index, other.index) &&
76
+ Objects.equals(name, other.name) &&
77
+ Objects.equals(type, other.type);
78
78
  }
79
79
 
80
80
  @Override
81
81
  public int hashCode()
82
82
  {
83
- return Objects.hashCode(index, name, type);
83
+ return Objects.hash(index, name, type);
84
84
  }
85
85
 
86
86
  @Override
@@ -1,6 +1,6 @@
1
1
  package org.embulk.spi;
2
2
 
3
- import com.google.common.base.Objects;
3
+ import java.util.Objects;
4
4
  import com.fasterxml.jackson.annotation.JsonCreator;
5
5
  import com.fasterxml.jackson.annotation.JsonProperty;
6
6
  import org.embulk.spi.type.Type;
@@ -60,14 +60,14 @@ public class ColumnConfig
60
60
  return false;
61
61
  }
62
62
  ColumnConfig other = (ColumnConfig) obj;
63
- return Objects.equal(this.name, other.name) &&
64
- Objects.equal(type, other.type);
63
+ return Objects.equals(this.name, other.name) &&
64
+ Objects.equals(type, other.type);
65
65
  }
66
66
 
67
67
  @Override
68
68
  public int hashCode()
69
69
  {
70
- return Objects.hashCode(name, type);
70
+ return Objects.hash(name, type);
71
71
  }
72
72
 
73
73
  @Override
@@ -2,6 +2,7 @@ package org.embulk.spi;
2
2
 
3
3
  import java.util.concurrent.ExecutionException;
4
4
  import org.slf4j.Logger;
5
+ import com.google.inject.Injector;
5
6
  import org.embulk.config.Task;
6
7
  import org.embulk.config.ModelManager;
7
8
  import org.embulk.config.CommitReport;
@@ -38,6 +39,11 @@ public class Exec
38
39
  return session;
39
40
  }
40
41
 
42
+ public static Injector getInjector()
43
+ {
44
+ return session().getInjector();
45
+ }
46
+
41
47
  public static Logger getLogger(String name)
42
48
  {
43
49
  return session().getLogger(name);
@@ -80,7 +80,7 @@ public class FileInputRunner
80
80
  throw new NoSampleException("Can't get sample data because the first input file is empty");
81
81
  }
82
82
 
83
- GuessExecutor guessExecutor = Exec.session().getInjector().getInstance(GuessExecutor.class);
83
+ GuessExecutor guessExecutor = Exec.getInjector().getInstance(GuessExecutor.class);
84
84
  return guessExecutor.guessParserConfig(sample, config, Exec.session().getExecConfig());
85
85
  }
86
86
 
@@ -1,7 +1,7 @@
1
1
  package org.embulk.spi;
2
2
 
3
3
  import java.util.List;
4
- import com.google.common.base.Objects;
4
+ import java.util.Objects;
5
5
  import com.fasterxml.jackson.annotation.JsonCreator;
6
6
  import com.fasterxml.jackson.annotation.JsonValue;
7
7
  import org.embulk.spi.type.Type;
@@ -78,7 +78,7 @@ public class Schema
78
78
  return false;
79
79
  }
80
80
  Schema other = (Schema) obj;
81
- return Objects.equal(columns, other.columns);
81
+ return Objects.equals(columns, other.columns);
82
82
  }
83
83
 
84
84
  @Override
@@ -1,7 +1,7 @@
1
1
  package org.embulk.spi;
2
2
 
3
3
  import java.util.List;
4
- import com.google.common.base.Objects;
4
+ import java.util.Objects;
5
5
  import com.google.common.collect.ImmutableList;
6
6
  import com.fasterxml.jackson.annotation.JsonCreator;
7
7
  import com.fasterxml.jackson.annotation.JsonValue;
@@ -41,7 +41,7 @@ public class SchemaConfig
41
41
  return false;
42
42
  }
43
43
  SchemaConfig other = (SchemaConfig) obj;
44
- return Objects.equal(columns, other.columns);
44
+ return Objects.equals(columns, other.columns);
45
45
  }
46
46
 
47
47
  @Override
@@ -0,0 +1,148 @@
1
+ package org.embulk.spi.unit;
2
+
3
+ import java.util.Objects;
4
+ import java.util.Locale;
5
+ import java.util.regex.Matcher;
6
+ import java.util.regex.Pattern;
7
+ import com.google.common.base.Preconditions;
8
+ import com.fasterxml.jackson.annotation.JsonCreator;
9
+ import com.fasterxml.jackson.annotation.JsonValue;
10
+
11
+ public class ByteSize
12
+ implements Comparable<ByteSize>
13
+ {
14
+ private static final Pattern PATTERN = Pattern.compile("\\A(\\d+(?:\\.\\d+)?)\\s?([a-zA-Z]*)\\z");
15
+
16
+ private final long bytes;
17
+ private final Unit displayUnit;
18
+
19
+ public ByteSize(double size, Unit unit)
20
+ {
21
+ Preconditions.checkArgument(!Double.isInfinite(size), "size is infinite");
22
+ Preconditions.checkArgument(!Double.isNaN(size), "size is not a number");
23
+ Preconditions.checkArgument(size >= 0, "size is negative");
24
+ Preconditions.checkNotNull(unit, "unit is null");
25
+ Preconditions.checkArgument(size * unit.getFactor() <= (double) Long.MAX_VALUE, "size is large than (2^63)-1 in bytes");
26
+ this.bytes = (long) (size * unit.getFactor());
27
+ this.displayUnit = unit;
28
+ }
29
+
30
+ @JsonCreator
31
+ public ByteSize(long bytes)
32
+ {
33
+ Preconditions.checkArgument(bytes >= 0, "size is negative");
34
+ this.bytes = bytes;
35
+ this.displayUnit = Unit.BYTES;
36
+ }
37
+
38
+ public long getBytes()
39
+ {
40
+ return bytes;
41
+ }
42
+
43
+ public long roundTo(Unit unit)
44
+ {
45
+ return (long) Math.floor(getValue(unit) + 0.5);
46
+ }
47
+
48
+ public double getValue(Unit unit)
49
+ {
50
+ return bytes / (double) unit.getFactor();
51
+ }
52
+
53
+ @JsonCreator
54
+ public static ByteSize parseByteSize(String size)
55
+ {
56
+ Preconditions.checkNotNull(size, "size is null");
57
+ Preconditions.checkArgument(!size.isEmpty(), "size is empty");
58
+
59
+ Matcher matcher = PATTERN.matcher(size);
60
+ if (!matcher.matches()) {
61
+ throw new IllegalArgumentException("Invalid byte size string '" + size + "'");
62
+ }
63
+
64
+ double value = Double.parseDouble(matcher.group(1)); // NumberFormatException extends IllegalArgumentException.
65
+
66
+ String unitString = matcher.group(2);
67
+ if (unitString.isEmpty()) {
68
+ return new ByteSize(value, Unit.BYTES);
69
+ } else {
70
+ String upperUnitString = unitString.toUpperCase(Locale.ENGLISH);
71
+ for (Unit unit : Unit.values()) {
72
+ if (unit.getUnitString().toUpperCase(Locale.ENGLISH).equals(upperUnitString)) {
73
+ return new ByteSize(value, unit);
74
+ }
75
+ }
76
+ }
77
+
78
+ throw new IllegalArgumentException("Unknown unit '" + unitString + "'");
79
+ }
80
+
81
+ @JsonValue
82
+ @Override
83
+ public String toString()
84
+ {
85
+ double value = getValue(displayUnit);
86
+ String integer = String.format(Locale.ENGLISH, "%d", (long) value);
87
+ String decimal = String.format(Locale.ENGLISH, "%.2f", value);
88
+ if (decimal.equals(integer + ".00")) {
89
+ return integer + displayUnit.getUnitString();
90
+ } else {
91
+ return decimal + displayUnit.getUnitString();
92
+ }
93
+ }
94
+
95
+ @Override
96
+ public int compareTo(ByteSize o)
97
+ {
98
+ return Long.compare(bytes, o.bytes);
99
+ }
100
+
101
+ @Override
102
+ public boolean equals(Object obj)
103
+ {
104
+ if (this == obj) {
105
+ return true;
106
+ }
107
+ if (!(obj instanceof ByteSize)) {
108
+ return false;
109
+ }
110
+ ByteSize o = (ByteSize) obj;
111
+ return this.bytes == o.bytes;
112
+ }
113
+
114
+ @Override
115
+ public int hashCode()
116
+ {
117
+ return Objects.hashCode(bytes);
118
+ }
119
+
120
+ public enum Unit
121
+ {
122
+ BYTES(1L, "B"),
123
+ KB(1L << 10, "KB"),
124
+ MB(1L << 20, "MB"),
125
+ GB(1L << 30, "GB"),
126
+ TB(1L << 40, "TB"),
127
+ PT(1L << 50, "PB");
128
+
129
+ private final long factor;
130
+ private final String unitString;
131
+
132
+ Unit(long factor, String unitString)
133
+ {
134
+ this.factor = factor;
135
+ this.unitString = unitString;
136
+ }
137
+
138
+ long getFactor()
139
+ {
140
+ return factor;
141
+ }
142
+
143
+ String getUnitString()
144
+ {
145
+ return unitString;
146
+ }
147
+ }
148
+ }