litestream 0.5.3-arm64-darwin → 0.5.5-arm64-darwin
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.
- checksums.yaml +4 -4
- data/README.md +46 -5
- data/lib/litestream/commands.rb +41 -26
- data/lib/litestream/version.rb +1 -1
- data/lib/litestream.rb +1 -1
- data/lib/tasks/litestream_tasks.rake +16 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4a5c5ae7fdeb51f926aa3d7e75310dac1f3b8cc9d4fb462d37cbb0135e1ad05
|
4
|
+
data.tar.gz: e12caf009c5915e769b185638d4b3dae3a52ea7922711512f1203b984b1424fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d415cd48549eb62928c83fcfbb845fc4ef248fd5f23b2ed98afed2b0a84bfa61a8a3766146c4965b6188a06d197242c45dac370644a466927c961113a36b680d
|
7
|
+
data.tar.gz: 8f02d3d01c8cc5e703238dc2c8c8ba7a881b42daae13da13f540a21961ce0ecc45756981ee9739b8f12e2313bccc92559c6d5de31f9a3e84719fb52e54b80948
|
data/README.md
CHANGED
@@ -53,9 +53,11 @@ The gem streamlines the configuration process by providing a default configurati
|
|
53
53
|
|
54
54
|
```yaml
|
55
55
|
dbs:
|
56
|
-
- path:
|
56
|
+
- path: storage/production.sqlite3
|
57
57
|
replicas:
|
58
|
-
-
|
58
|
+
- type: s3
|
59
|
+
bucket: $LITESTREAM_REPLICA_BUCKET
|
60
|
+
path: storage/production.sqlite3
|
59
61
|
access-key-id: $LITESTREAM_ACCESS_KEY_ID
|
60
62
|
secret-access-key: $LITESTREAM_SECRET_ACCESS_KEY
|
61
63
|
```
|
@@ -65,7 +67,6 @@ The gem also provides a default initializer file at `config/initializers/litestr
|
|
65
67
|
```ruby
|
66
68
|
litestream_credentials = Rails.application.credentials.litestream
|
67
69
|
Litestream.configure do |config|
|
68
|
-
config.database_path = ActiveRecord::Base.connection_db_config.database
|
69
70
|
config.replica_bucket = litestream_credentials.replica_bucket
|
70
71
|
config.replica_key_id = litestream_credentials.replica_key_id
|
71
72
|
config.replica_access_key = litestream_credentials.replica_access_key
|
@@ -240,7 +241,48 @@ replica generation index size created
|
|
240
241
|
s3 a295b16a796689f3 1 4645465 2024-04-17T00:01:19Z
|
241
242
|
```
|
242
243
|
|
243
|
-
###
|
244
|
+
### Running commands from Ruby
|
245
|
+
|
246
|
+
In addition to the provided rake tasks, you can also run Litestream commands directly from Ruby. The gem provides a `Litestream::Commands` module that wraps the Litestream CLI commands. This is particularly useful for the introspection commands, as you can use the output in your Ruby code.
|
247
|
+
|
248
|
+
The `Litestream::Commands.databases` method returns an array of hashes with the "path" and "replicas" keys for each database:
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
Litestream::Commands.databases
|
252
|
+
# => [{"path"=>"/Users/you/Code/your-app/storage/production.sqlite3", "replicas"=>"s3"}]
|
253
|
+
```
|
254
|
+
|
255
|
+
The `Litestream::Commands.generations` method returns an array of hashes with the "name", "generation", "lag", "start", and "end" keys for each generation:
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
Litestream::Commands.generations('storage/production.sqlite3')
|
259
|
+
# => [{"name"=>"s3", "generation"=>"5f4341bc3d22d615", "lag"=>"3s", "start"=>"2024-04-17T19:48:09Z", "end"=>"2024-04-17T19:48:09Z"}]
|
260
|
+
```
|
261
|
+
|
262
|
+
The `Litestream::Commands.snapshots` method returns an array of hashes with the "replica", "generation", "index", "size", and "created" keys for each snapshot:
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
Litestream::Commands.snapshots('storage/production.sqlite3')
|
266
|
+
# => [{"replica"=>"s3", "generation"=>"5f4341bc3d22d615", "index"=>"0", "size"=>"4645465", "created"=>"2024-04-17T19:48:09Z"}]
|
267
|
+
```
|
268
|
+
|
269
|
+
You can also restore a database programatically using the `Litestream::Commands.restore` method, which returns the path to the restored database:
|
270
|
+
|
271
|
+
```ruby
|
272
|
+
Litestream::Commands.restore('storage/production.sqlite3')
|
273
|
+
# => "storage/production-20240418090048.sqlite3"
|
274
|
+
```
|
275
|
+
|
276
|
+
Finally, you can verify the integrity of a restored database using the `Litestream::Commands.verify` method, which returns a hash with the "size" and "tables" keys for the original and restored databases:
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
Litestream::Commands.verify('storage/production.sqlite3')
|
280
|
+
# => {"size"=>{"original"=>21688320, "restored"=>21688320}, "tables"=>{"original"=>9, "restored"=>9}}
|
281
|
+
```
|
282
|
+
|
283
|
+
You _can_ start the replication process using the `Litestream::Commands.replicate` method, but this is not recommended. The replication process should be managed by Litestream itself, and you should not need to manually start it.
|
284
|
+
|
285
|
+
### Running commands from CLI
|
244
286
|
|
245
287
|
The rake tasks are the recommended way to interact with the Litestream utility in your Rails application or Ruby project. But, you _can_ work directly with the Litestream CLI. Since the gem installs the native executable via Bundler, the `litestream` command will be available in your `PATH`.
|
246
288
|
|
@@ -272,7 +314,6 @@ Once you have a MinIO server running, you can create a bucket for Litestream to
|
|
272
314
|
|
273
315
|
```ruby
|
274
316
|
Litestream.configure do |config|
|
275
|
-
config.database_path = ActiveRecord::Base.connection_db_config.database
|
276
317
|
config.replica_bucket = "s3://mybkt.localhost:9000/"
|
277
318
|
config.replica_key_id = "minioadmin"
|
278
319
|
config.replica_access_key = "minioadmin"
|
data/lib/litestream/commands.rb
CHANGED
@@ -76,11 +76,11 @@ module Litestream
|
|
76
76
|
exe_file
|
77
77
|
end
|
78
78
|
|
79
|
-
def replicate(async:
|
80
|
-
execute("replicate", argv, async: async)
|
79
|
+
def replicate(async: false, **argv)
|
80
|
+
execute("replicate", argv, async: async, hashify: false)
|
81
81
|
end
|
82
82
|
|
83
|
-
def restore(database, async:
|
83
|
+
def restore(database, async: false, **argv)
|
84
84
|
raise DatabaseRequiredException, "database argument is required for restore command, e.g. litestream:restore -- --database=path/to/database.sqlite" if database.nil?
|
85
85
|
|
86
86
|
dir, file = File.split(database)
|
@@ -93,28 +93,12 @@ module Litestream
|
|
93
93
|
"-o" => backup
|
94
94
|
}.merge(argv)
|
95
95
|
|
96
|
-
execute("restore", args, database, async: async)
|
96
|
+
execute("restore", args, database, async: async, hashify: false)
|
97
97
|
|
98
98
|
backup
|
99
99
|
end
|
100
100
|
|
101
|
-
def
|
102
|
-
execute("databases", argv, async: async)
|
103
|
-
end
|
104
|
-
|
105
|
-
def generations(database, async: true, **argv)
|
106
|
-
raise DatabaseRequiredException, "database argument is required for generations command, e.g. litestream:generations -- --database=path/to/database.sqlite" if database.nil?
|
107
|
-
|
108
|
-
execute("generations", argv, database, async: async)
|
109
|
-
end
|
110
|
-
|
111
|
-
def snapshots(database, async: true, **argv)
|
112
|
-
raise DatabaseRequiredException, "database argument is required for snapshots command, e.g. litestream:snapshots -- --database=path/to/database.sqlite" if database.nil?
|
113
|
-
|
114
|
-
execute("snapshots", argv, database, async: async)
|
115
|
-
end
|
116
|
-
|
117
|
-
def verify(database, async: true, **argv)
|
101
|
+
def verify(database, async: false, **argv)
|
118
102
|
raise DatabaseRequiredException, "database argument is required for verify command, e.g. litestream:verify -- --database=path/to/database.sqlite" if database.nil? || !File.exist?(database)
|
119
103
|
|
120
104
|
backup = restore(database, async: false, **argv)
|
@@ -129,14 +113,35 @@ module Litestream
|
|
129
113
|
Dir.glob(backup + "*").each { |file| File.delete(file) }
|
130
114
|
|
131
115
|
{
|
132
|
-
size
|
133
|
-
tables
|
116
|
+
"size" => {"original" => original_size, "restored" => restored_size},
|
117
|
+
"tables" => {"original" => original_tables_count, "restored" => restored_tables_count}
|
134
118
|
}
|
135
119
|
end
|
136
120
|
|
121
|
+
def databases(async: false, **argv)
|
122
|
+
execute("databases", argv, async: async, hashify: true)
|
123
|
+
end
|
124
|
+
|
125
|
+
def generations(database, async: false, **argv)
|
126
|
+
raise DatabaseRequiredException, "database argument is required for generations command, e.g. litestream:generations -- --database=path/to/database.sqlite" if database.nil?
|
127
|
+
|
128
|
+
execute("generations", argv, database, async: async, hashify: true)
|
129
|
+
end
|
130
|
+
|
131
|
+
def snapshots(database, async: false, **argv)
|
132
|
+
raise DatabaseRequiredException, "database argument is required for snapshots command, e.g. litestream:snapshots -- --database=path/to/database.sqlite" if database.nil?
|
133
|
+
|
134
|
+
execute("snapshots", argv, database, async: async, hashify: true)
|
135
|
+
end
|
136
|
+
|
137
137
|
private
|
138
138
|
|
139
|
-
def execute(command, argv = {}, database = nil, async:
|
139
|
+
def execute(command, argv = {}, database = nil, async: false, hashify: false)
|
140
|
+
cmd = prepare(command, argv, database)
|
141
|
+
run(cmd, async: async, hashify: hashify)
|
142
|
+
end
|
143
|
+
|
144
|
+
def prepare(command, argv = {}, database = nil)
|
140
145
|
if Litestream.configuration
|
141
146
|
ENV["LITESTREAM_REPLICA_BUCKET"] ||= Litestream.configuration.replica_bucket
|
142
147
|
ENV["LITESTREAM_ACCESS_KEY_ID"] ||= Litestream.configuration.replica_key_id
|
@@ -145,18 +150,28 @@ module Litestream
|
|
145
150
|
|
146
151
|
args = {
|
147
152
|
"--config" => Rails.root.join("config", "litestream.yml").to_s
|
148
|
-
}.merge(argv).to_a.flatten.compact
|
153
|
+
}.merge(argv.stringify_keys).to_a.flatten.compact
|
149
154
|
cmd = [executable, command, *args, database].compact
|
150
155
|
puts cmd.inspect if ENV["DEBUG"]
|
151
156
|
|
157
|
+
cmd
|
158
|
+
end
|
159
|
+
|
160
|
+
def run(cmd, async: false, hashify: false)
|
152
161
|
if async
|
153
162
|
# To release the resources of the Ruby process, just fork and exit.
|
154
163
|
# The forked process executes litestream and replaces itself.
|
155
164
|
exec(*cmd) if fork.nil?
|
156
165
|
else
|
157
|
-
|
166
|
+
out = `#{cmd.join(" ")}`
|
167
|
+
text_table_to_hashes(out) if hashify
|
158
168
|
end
|
159
169
|
end
|
170
|
+
|
171
|
+
def text_table_to_hashes(string)
|
172
|
+
keys, *rows = string.split("\n").map { _1.split(/\s+/) }
|
173
|
+
rows.map { keys.zip(_1).to_h }
|
174
|
+
end
|
160
175
|
end
|
161
176
|
end
|
162
177
|
end
|
data/lib/litestream/version.rb
CHANGED
data/lib/litestream.rb
CHANGED
@@ -21,8 +21,9 @@ namespace :litestream do
|
|
21
21
|
.map { |pair| pair.split("=") }
|
22
22
|
.each { |opt| options[opt[0]] = opt[1] || nil }
|
23
23
|
end
|
24
|
+
options.symbolize_keys!
|
24
25
|
|
25
|
-
Litestream::Commands.replicate(**options)
|
26
|
+
Litestream::Commands.replicate(async: true, **options)
|
26
27
|
end
|
27
28
|
|
28
29
|
desc "Restore a SQLite database from a Litestream replica, e.g. rake litestream:restore -- -database=storage/production.sqlite3"
|
@@ -33,8 +34,10 @@ namespace :litestream do
|
|
33
34
|
.map { |pair| pair.split("=") }
|
34
35
|
.each { |opt| options[opt[0]] = opt[1] || nil }
|
35
36
|
end
|
37
|
+
database = options.delete("--database") || options.delete("-database")
|
38
|
+
options.symbolize_keys!
|
36
39
|
|
37
|
-
Litestream::Commands.restore(
|
40
|
+
Litestream::Commands.restore(database, async: true, **options)
|
38
41
|
end
|
39
42
|
|
40
43
|
desc "List all databases and associated replicas in the config file, e.g. rake litestream:databases -- -no-expand-env"
|
@@ -45,8 +48,9 @@ namespace :litestream do
|
|
45
48
|
.map { |pair| pair.split("=") }
|
46
49
|
.each { |opt| options[opt[0]] = opt[1] || nil }
|
47
50
|
end
|
51
|
+
options.symbolize_keys!
|
48
52
|
|
49
|
-
Litestream::Commands.databases(**options)
|
53
|
+
Litestream::Commands.databases(async: true, **options)
|
50
54
|
end
|
51
55
|
|
52
56
|
desc "List all generations for a database or replica, e.g. rake litestream:generations -- -database=storage/production.sqlite3"
|
@@ -57,8 +61,10 @@ namespace :litestream do
|
|
57
61
|
.map { |pair| pair.split("=") }
|
58
62
|
.each { |opt| options[opt[0]] = opt[1] || nil }
|
59
63
|
end
|
64
|
+
database = options.delete("--database") || options.delete("-database")
|
65
|
+
options.symbolize_keys!
|
60
66
|
|
61
|
-
Litestream::Commands.generations(
|
67
|
+
Litestream::Commands.generations(database, async: true, **options)
|
62
68
|
end
|
63
69
|
|
64
70
|
desc "List all snapshots for a database or replica, e.g. rake litestream:snapshots -- -database=storage/production.sqlite3"
|
@@ -69,8 +75,10 @@ namespace :litestream do
|
|
69
75
|
.map { |pair| pair.split("=") }
|
70
76
|
.each { |opt| options[opt[0]] = opt[1] || nil }
|
71
77
|
end
|
78
|
+
database = options.delete("--database") || options.delete("-database")
|
79
|
+
options.symbolize_keys!
|
72
80
|
|
73
|
-
Litestream::Commands.snapshots(
|
81
|
+
Litestream::Commands.snapshots(database, async: true, **options)
|
74
82
|
end
|
75
83
|
|
76
84
|
desc "verify backup of SQLite database from a Litestream replica, e.g. rake litestream:verify -- -database=storage/production.sqlite3"
|
@@ -81,8 +89,10 @@ namespace :litestream do
|
|
81
89
|
.map { |pair| pair.split("=") }
|
82
90
|
.each { |opt| options[opt[0]] = opt[1] || nil }
|
83
91
|
end
|
92
|
+
database = options.delete("--database") || options.delete("-database")
|
93
|
+
options.symbolize_keys!
|
84
94
|
|
85
|
-
result = Litestream::Commands.verify(
|
95
|
+
result = Litestream::Commands.verify(database, async: true, **options)
|
86
96
|
|
87
97
|
puts <<~TXT if result
|
88
98
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: litestream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.5
|
5
5
|
platform: arm64-darwin
|
6
6
|
authors:
|
7
7
|
- Stephen Margheim
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyzip
|