Skip to content

Commit a438e2d

Browse files
authored
tart {list,get}: display humanized byte units (#1301)
1 parent 160b7cd commit a438e2d

4 files changed

Lines changed: 63 additions & 9 deletions

File tree

‎Sources/tart/Commands/Get.swift‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ fileprivate struct VMInfo: Encodable {
55
let OS: OS
66
let CPU: Int
77
let Memory: UInt64
8-
let Disk: Int
8+
let Disk: HumanReadableByteCount
99
let DiskFormat: String
10-
let Size: String
10+
let Size: HumanReadableByteCount
1111
let Display: String
1212
let Running: Bool
1313
let State: String
@@ -27,7 +27,20 @@ struct Get: AsyncParsableCommand {
2727
let vmConfig = try VMConfig(fromURL: vmDir.configURL)
2828
let memorySizeInMb = vmConfig.memorySize / 1024 / 1024
2929

30-
let info = VMInfo(OS: vmConfig.os, CPU: vmConfig.cpuCount, Memory: memorySizeInMb, Disk: try vmDir.sizeGB(), DiskFormat: vmConfig.diskFormat.rawValue, Size: String(format: "%.3f", Float(try vmDir.allocatedSizeBytes()) / 1000 / 1000 / 1000), Display: vmConfig.display.description, Running: try vmDir.running(), State: try vmDir.state().rawValue)
30+
let info = VMInfo(
31+
OS: vmConfig.os,
32+
CPU: vmConfig.cpuCount,
33+
Memory: memorySizeInMb,
34+
Disk: HumanReadableByteCount(try vmDir.sizeBytes()) { $0 / 1000 / 1000 / 1000 },
35+
DiskFormat: vmConfig.diskFormat.rawValue,
36+
Size: HumanReadableByteCount(try vmDir.allocatedSizeBytes()) {
37+
String(format: "%.3f", Float($0) / 1000 / 1000 / 1000)
38+
},
39+
Display: vmConfig.display.description,
40+
Running: try vmDir.running(),
41+
State: try vmDir.state().rawValue
42+
)
43+
3144
print(format.renderSingle(info))
3245
}
3346
}

‎Sources/tart/Commands/List.swift‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import SwiftUI
55
fileprivate struct VMInfo: Encodable {
66
let Source: String
77
let Name: String
8-
let Disk: Int
9-
let Size: Int
8+
let Disk: HumanReadableByteCount
9+
let Size: HumanReadableByteCount
1010
let Accessed: String
1111
let Running: Bool
1212
let State: String
@@ -42,8 +42,8 @@ struct List: AsyncParsableCommand {
4242
try VMInfo(
4343
Source: "local",
4444
Name: name,
45-
Disk: vmDir.sizeGB(),
46-
Size: vmDir.allocatedSizeGB(),
45+
Disk: HumanReadableByteCount(try vmDir.sizeBytes()) { $0 / 1000 / 1000 / 1000 },
46+
Size: HumanReadableByteCount(try vmDir.allocatedSizeBytes()) { $0 / 1000 / 1000 / 1000 },
4747
Accessed: formatAccessDate(try vmDir.accessDate()),
4848
Running: vmDir.running(),
4949
State: vmDir.state().rawValue
@@ -56,8 +56,8 @@ struct List: AsyncParsableCommand {
5656
try VMInfo(
5757
Source: "OCI",
5858
Name: name,
59-
Disk: vmDir.sizeGB(),
60-
Size: vmDir.allocatedSizeGB(),
59+
Disk: HumanReadableByteCount(try vmDir.sizeBytes()) { $0 / 1000 / 1000 / 1000 },
60+
Size: HumanReadableByteCount(try vmDir.allocatedSizeBytes()) { $0 / 1000 / 1000 / 1000 },
6161
Accessed: formatAccessDate(try vmDir.accessDate()),
6262
Running: vmDir.running(),
6363
State: vmDir.state().rawValue
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import Foundation
2+
3+
struct HumanReadableByteCount: Encodable, CustomStringConvertible {
4+
private let byteCount: Int
5+
private let jsonValue: any Encodable
6+
7+
init<JSONValue: Encodable>(_ byteCount: Int, encodedAs: (Int) -> JSONValue) {
8+
self.byteCount = byteCount
9+
self.jsonValue = encodedAs(byteCount)
10+
}
11+
12+
var description: String {
13+
let formatter = MeasurementFormatter()
14+
formatter.unitOptions = .naturalScale
15+
formatter.unitStyle = .medium
16+
formatter.numberFormatter.maximumFractionDigits = 0
17+
18+
return formatter.string(
19+
from: Measurement(value: Double(byteCount), unit: UnitInformationStorage.bytes)
20+
)
21+
}
22+
23+
func encode(to encoder: Encoder) throws {
24+
try jsonValue.encode(to: encoder)
25+
}
26+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import Foundation
2+
import XCTest
3+
@testable import tart
4+
5+
final class HumanReadableByteCountTests: XCTestCase {
6+
func testTextAndJSONRepresentations() throws {
7+
let integer = HumanReadableByteCount(51_400_000_000) { _ in 51 }
8+
let string = HumanReadableByteCount(17_234_000_000) { _ in "17.234" }
9+
let encoder = JSONEncoder()
10+
11+
XCTAssertEqual(string.description.compactMap(\.wholeNumberValue), [1, 7])
12+
XCTAssertEqual(try JSONDecoder().decode(Int.self, from: encoder.encode(integer)), 51)
13+
XCTAssertEqual(try JSONDecoder().decode(String.self, from: encoder.encode(string)), "17.234")
14+
}
15+
}

0 commit comments

Comments
 (0)