embulk 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
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
+ }