litestream 0.12.0-x86_64-darwin → 0.14.0-x86_64-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c13566bd8545074907f3a007a1136a12109a12e6b465074284ded9aa26e4d39f
4
- data.tar.gz: 0a79f21b7d5dd4892400d7904eee3fbce17c051258b37396d3886d7546e1af54
3
+ metadata.gz: 1bf4ecef5154a30f83749368b3120b9aa925cf3a75bee03e54086ddec25c27db
4
+ data.tar.gz: 436704c8aad09afa36147cef521c9882eadf6c4badb68d4635b695d69d4631a4
5
5
  SHA512:
6
- metadata.gz: a8449421a8b85b8d97357b3b9b6307061e48d4046b60b9de675ad9854b06887c3bc0dc196101a666c80c663442c39e5859b0101c3bb830f2ffa5ddd865045d7a
7
- data.tar.gz: 57a9c3ee1826dbc1cf9a33afda9baf5fbbf6f6938513bfa4af06719b863f784014b335224fea9a5ba36e4aabaa8790f0c5ccd96d1edacc463c00822991d98790
6
+ metadata.gz: 33c8b011eb9d012585d4c94cea5e560ab3da96c6dec4b07561f5390ef78e679ba338ec044429cac10cb08f0a3eb2961568cfdf04133858cce572617e4a69ec2b
7
+ data.tar.gz: d5c44ae0fcb94ac747522880eb6e4adbc102bde7b285bc90e79bfb92f1104224d5fff1c12c4a90fc13f248281a58f6631387b97d1352f4fce481220a0a642bff
data/README.md CHANGED
@@ -54,6 +54,7 @@ Supported platforms are:
54
54
 
55
55
  - arm64-darwin (macos-arm64)
56
56
  - x86_64-darwin (macos-x64)
57
+ - aarch64-linux (linux-aarch64)
57
58
  - arm64-linux (linux-arm64)
58
59
  - x86_64-linux (linux-x64)
59
60
 
@@ -79,22 +80,27 @@ LITESTREAM_INSTALL_DIR=.bin
79
80
 
80
81
  You configure the Litestream executable through the [`config/litestream.yml` file](https://litestream.io/reference/config/), which is a standard Litestream configuration file as if Litestream was running in a traditional installation.
81
82
 
82
- The gem streamlines the configuration process by providing a default configuration file for you. This configuration file will backup all SQLite databases defined in your `config/database.yml` file to one replication bucket. In order to ensure that no secrets are stored in plain-text in your repository, this configuration file leverages Litestream's support for environment variables. The default configuration file looks like this if you only have one SQLite database:
83
+ The gem streamlines the configuration process by providing a default configuration file for you. This configuration file will backup all SQLite databases defined in your `config/database.yml` file to one replication bucket. In order to ensure that no secrets are stored in plain-text in your repository, this configuration file leverages Litestream's support for environment variables. Inspect which environment variables are available by running the `bin/rails litestream:env` command.
84
+
85
+ The default configuration file looks like this if you only have one SQLite database:
83
86
 
84
87
  ```yaml
85
88
  dbs:
86
89
  - path: storage/production.sqlite3
87
90
  replicas:
88
91
  - type: s3
89
- bucket: $LITESTREAM_REPLICA_BUCKET
90
92
  path: storage/production.sqlite3
93
+ bucket: $LITESTREAM_REPLICA_BUCKET
91
94
  access-key-id: $LITESTREAM_ACCESS_KEY_ID
92
95
  secret-access-key: $LITESTREAM_SECRET_ACCESS_KEY
93
96
  ```
94
97
 
95
- The gem also provides a default initializer file at `config/initializers/litestream.rb` that allows you to configure these four environment variables referenced in the configuration file in Ruby. By providing a Ruby interface to these environment variables, you can use any method of storing secrets that you prefer. For example, the default generated file uses Rails' encrypted credentials to store your secrets:
98
+ This is the default for Amazon S3. The full range of possible replica types (e.g. other S3-compatible object storage servers) are covered in Litestream's [replica guides](https://litestream.io/guides/#replica-guides).
99
+
100
+ The gem also provides a default initializer file at `config/initializers/litestream.rb` that allows you to configure various variables referenced in the configuration file in Ruby. By providing a Ruby interface to these environment variables, you can use your preferred method of storing secrets. For example, the default generated file uses Rails' encrypted credentials to store your secrets.
96
101
 
97
102
  ```ruby
103
+ # config/initializers/litestream.rb
98
104
  Rails.application.configure do
99
105
  litestream_credentials = Rails.application.credentials.litestream
100
106
 
@@ -104,20 +110,33 @@ Rails.application.configure do
104
110
  end
105
111
  ```
106
112
 
107
- However, if you need manual control over the Litestream configuration, you can manually edit the `config/litestream.yml` file. The full range of possible configurations are covered in Litestream's [configuration reference](https://litestream.io/reference/config/).
113
+ Outside of configuring Litestream's replication, you may also configure various other aspects of `litestream-ruby` itself.
114
+
115
+ ```ruby
116
+ # config/initializers/litestream.rb
117
+ Rails.application.configure do
118
+ # ...
119
+
120
+ # Base controller used for Litestream dashboard
121
+ config.litestream.base_controller_class = "MyApplicationController"
122
+ # Set the location of the Litestream config
123
+ config.litestream.config_path = "config/litestream.yml"
124
+ end
125
+ ```
126
+
127
+ However, if you need manual control over the Litestream configuration, you can edit the `config/litestream.yml` file. The full range of possible configurations are covered in Litestream's [configuration reference](https://litestream.io/reference/config/).
108
128
 
109
129
  ### Replication
110
130
 
111
131
  In order to stream changes to your configured replicas, you need to start the Litestream replication process.
112
132
 
113
- The simplest way to run the Litestream replication process is use the Puma plugin provided by the gem. This allows you to run the Litestream replication process together with Puma and have Puma monitor and manage it. You just need to add
133
+ The simplest way to run the Litestream replication process is use the Puma plugin provided by the gem. This allows you to run the Litestream replication process together with Puma and have Puma monitor and manage it. You just need to add the following to your `puma.rb` configuration:
114
134
 
115
135
  ```ruby
116
- plugin :litestream
136
+ # Run litestream only in production.
137
+ plugin :litestream if ENV.fetch("RAILS_ENV", "production") == "production"
117
138
  ```
118
139
 
119
- to your `puma.rb` configuration.
120
-
121
140
  If you would prefer to run the Litestream replication process separately from Puma, you can use the provided `litestream:replicate` rake task. This rake task will automatically load the configuration file and set the environment variables before starting the Litestream process.
122
141
 
123
142
  The simplest way to spin up a Litestream process separately from your Rails application is to use a `Procfile`:
@@ -155,20 +174,32 @@ The Litestream `replicate` command supports the following options, which can be
155
174
 
156
175
  ### Restoration
157
176
 
158
- You can restore any replicated database at any point using the gem's provided `litestream:restore` rake task. This rake task requires that you specify which specific database you want to restore. As with the `litestream:replicate` task, you pass arguments to the rake task via argument forwarding. For example, to restore the production database, you would run:
177
+ You can restore any replicated database at any point using the gem's provided `litestream:restore` rake task. This rake task requires that you specify which specific database you want to restore. As with the `litestream:replicate` task, you pass arguments to the rake task via argument forwarding. For example, to restore the production database, you would do the following:
159
178
 
160
- ```shell
161
- bin/rails litestream:restore -- --database=storage/production.sqlite3
162
- # or
163
- bundle exec rake litestream:restore -- --database=storage/production.sqlite3
164
- ```
179
+ > [!NOTE]
180
+ > During the restoration process, you need to prevent any interaction with ActiveRecord/SQLite, such as from a running `rails server` or `rails console` instance. If there is any interaction, Rails might regenerate the production database and prevent restoration via litestream. If this happens, you might get a "cannot restore, output path already exists" error.
181
+
182
+ 1. Rename the production (`production.sqlite3`, `production.sqlite3-shm`, and `production.sqlite3-wal`) databases (**recommended**) or alternatively delete. To delete the production databases locally, you can run the following at your own risk:
183
+ ```shell
184
+ # DANGEROUS OPERATION, consider renaming database files instead
185
+ bin/rails db:drop DISABLE_DATABASE_ENVIRONMENT_CHECK=1
186
+ ```
187
+
188
+ 2. Run restore command:
189
+ ```shell
190
+ bin/rails litestream:restore -- --database=storage/production.sqlite3
191
+ # or
192
+ bundle exec rake litestream:restore -- --database=storage/production.sqlite3
193
+ ```
194
+
195
+ 3. Restart your Rails application or Docker container if applicable.
165
196
 
166
197
  You can restore any of the databases specified in your `config/litestream.yml` file. The `--database` argument should be the path to the database file you want to restore and must match the value for the `path` key of one of your configured databases. The `litestream:restore` rake task will automatically load the configuration file and set the environment variables before calling the Litestream executable.
167
198
 
168
199
  If you need to pass arguments through the rake task to the underlying `litestream` command, that can be done with additional forwarded arguments:
169
200
 
170
201
  ```shell
171
- bin/rails litestream:replicate -- --database=storage/production.sqlite3 --if-db-not-exists
202
+ bin/rails litestream:restore -- --database=storage/production.sqlite3 --if-db-not-exists
172
203
  ```
173
204
 
174
205
  You can forward arguments in whatever order you like, you simply need to ensure that the `--database` argument is present. You can also use either a single-dash `-database` or double-dash `--database` argument format. The Litestream `restore` command supports the following options, which can be passed through the rake task:
@@ -218,9 +249,10 @@ You can verify the integrity of your backed-up databases using the gem's provide
218
249
 
219
250
  ```ruby
220
251
  Litestream.verify! "storage/production.sqlite3"
252
+ Litestream.verify!(replication_sleep: 10) "storage/production.sqlite3"
221
253
  ```
222
254
 
223
- In order to verify that the backup for that database is both restorable and fresh, the method will add a new row to that database under the `_litestream_verification` table, which it will create if needed. It will then wait 10 seconds to give the Litestream utility time to replicate that change to whatever storage providers you have configured. After that, it will download the latest backup from that storage provider and ensure that this verification row is present in the backup. If the verification row is _not_ present, the method will raise a `Litestream::VerificationFailure` exception. This check ensures that the restored database file
255
+ In order to verify that the backup for that database is both restorable and fresh, the method will add a new row to that database under the `_litestream_verification` table, which it will create if needed. It will then wait `replication_sleep` seconds (defaults to 10) to give the Litestream utility time to replicate that change to whatever storage providers you have configured. After that, it will download the latest backup from that storage provider and ensure that this verification row is present in the backup. If the verification row is _not_ present, the method will raise a `Litestream::VerificationFailure` exception. This check ensures that the restored database file:
224
256
 
225
257
  1. exists,
226
258
  2. can be opened by SQLite, and
@@ -228,6 +260,9 @@ In order to verify that the backup for that database is both restorable and fres
228
260
 
229
261
  After restoring the backup, the `Litestream.verify!` method will delete the restored database file. If you need the restored database file, use the `litestream:restore` rake task or `Litestream::Commands.restore` method instead.
230
262
 
263
+ > [!NOTE]
264
+ > If you configure Litestream's [`sync-interval`](https://litestream.io/reference/config/#replica-settings) to be longer than the default `replication_sleep` value of 10 seconds, you will need to adjust `replication_sleep` to a value larger than `sync-interval`; otherwise, `Litestream.verify!` may appear to fail where it actually simply didn't wait long enough for replication.
265
+
231
266
  ### Dashboard
232
267
 
233
268
  The gem provides a web dashboard for monitoring the status of your Litestream replication. To mount the dashboard in your Rails application, add the following to your `config/routes.rb` file:
@@ -256,8 +291,8 @@ Second, you can configure the access credentials via the Rails configuration obj
256
291
 
257
292
  ```ruby
258
293
  # Set authentication credentials for Litestream
259
- config.litestream.username = Rails.application.credentials.litestream.username
260
- config.litestream.password = Rails.application.credentials.litestream.password
294
+ config.litestream.username = Rails.application.credentials.dig(:litestream, :username)
295
+ config.litestream.password = Rails.application.credentials.dig(:litestream, :password)
261
296
  ```
262
297
 
263
298
  Either way, if you have set a username and password, Litestream will use basic HTTP authentication.
@@ -269,7 +304,7 @@ If you use Devise for authentication in your app, you can also restrict access t
269
304
 
270
305
  ```ruby
271
306
  authenticate :user, -> (user) { user.admin? } do
272
- mount LitestreamRails::Engine, at: "/litestream"
307
+ mount Litestream::Engine, at: "/litestream"
273
308
  end
274
309
  ```
275
310
 
@@ -294,7 +329,7 @@ config.middleware.use ActionDispatch::Flash
294
329
 
295
330
  ### Overwriting the views
296
331
 
297
- You can find the views in [`app/views`](https://github.com/fractaledmind/litestream/tree/main/app/views).
332
+ You can find the views in [`app/views`](https://github.com/fractaledmind/litestream-ruby/tree/main/app/views).
298
333
 
299
334
  ```bash
300
335
  app/views/
@@ -362,7 +397,7 @@ You can also list the generations of a specific database:
362
397
  bin/rails litestream:generations -- --database=storage/production.sqlite3
363
398
  ```
364
399
 
365
- This will list all generations for the specified database, including stats about their lag behind the primary database and the time range they cover.
400
+ This will list all generations for the specified database, including stats about their lag behind the primary database and the time range they cover:
366
401
 
367
402
  ```
368
403
  name generation lag start end
@@ -434,13 +469,6 @@ Litestream::Commands.restore('storage/production.sqlite3')
434
469
  # => "storage/production-20240418090048.sqlite3"
435
470
  ```
436
471
 
437
- 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:
438
-
439
- ```ruby
440
- Litestream::Commands.verify('storage/production.sqlite3')
441
- # => {"size"=>{"original"=>21688320, "restored"=>21688320}, "tables"=>{"original"=>9, "restored"=>9}}
442
- ```
443
-
444
472
  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.
445
473
 
446
474
  ### Running commands from CLI
@@ -461,7 +489,13 @@ litestream wal [arguments] DB_PATH|REPLICA_URL
461
489
 
462
490
  ### Using in development
463
491
 
464
- By default, installing the gem does not update your `Procfile.dev` file, and so Litestream will not be started in development. If you would like to test that your configuration is properly setup, you can manually add the `litestream:replicate` rake task to your `Procfile.dev` file. Just copy the `litestream` definition from the production `Procfile`. Then, in order to have a replication bucket for Litestream to point to, you can use a Docker instance of [MinIO](https://min.io/). MinIO is an S3-compatible object storage server that can be run locally. You can run a MinIO server with the following command:
492
+ By default, if you install the gem and configure via `puma.rb` or `Procfile`, Litestream will not start in development.
493
+
494
+ If you setup via `puma.rb`, then remove the conditional statement.
495
+
496
+ If you setup via `Procfile`, you will need to update your `Procfile.dev` file. If you would like to test that your configuration is properly setup, you can manually add the `litestream:replicate` rake task to your `Procfile.dev` file. Just copy the `litestream` definition from the production `Procfile`.
497
+
498
+ In order to have a replication bucket for Litestream to point to, you can use a Docker instance of [MinIO](https://min.io/). MinIO is an S3-compatible object storage server that can be run locally. You can run a MinIO server with the following command:
465
499
 
466
500
  ```sh
467
501
  docker run -p 9000:9000 -p 9001:9001 minio/minio server /data --console-address ":9001"
@@ -493,7 +527,7 @@ time=YYYY-MM-DDTHH:MM:SS level=INFO msg="replicating to" name=s3 type=s3 sync-in
493
527
 
494
528
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
495
529
 
496
- To install this gem onto your local machine, run `bundle exec rake install`.
530
+ To install this gem onto your local machine, run `bundle exec rake install`. To download the Litestream binaries run `bundle exec rake download`.
497
531
 
498
532
  For maintainers, to release a new version, run `bin/release $VERSION`, which will create a git tag for the version, push git commits and tags, and push all of the platform-specific `.gem` files to [rubygems.org](https://rubygems.org).
499
533
 
@@ -1,7 +1,6 @@
1
1
  module Litestream
2
- class ApplicationController < ActionController::Base
2
+ class ApplicationController < Litestream.base_controller_class.constantize
3
3
  protect_from_forgery with: :exception
4
- around_action :force_english_locale!
5
4
 
6
5
  if Litestream.password
7
6
  http_basic_authenticate_with(
@@ -9,11 +8,5 @@ module Litestream
9
8
  password: Litestream.password
10
9
  )
11
10
  end
12
-
13
- private
14
-
15
- def force_english_locale!(&action)
16
- I18n.with_locale(:en, &action)
17
- end
18
11
  end
19
12
  end
@@ -9,7 +9,7 @@ module Litestream
9
9
  now = Time.now.utc.strftime("%Y%m%d%H%M%S")
10
10
  backup = File.join(dir, "#{base}-#{now}#{ext}")
11
11
 
12
- Litestream::Commands.restore(database, async: false, **{"-o" => backup})
12
+ Litestream::Commands.restore(database, **{"-o" => backup})
13
13
 
14
14
  redirect_to root_path, notice: "Restored to <code>#{backup}</code>."
15
15
  end
@@ -801,4 +801,42 @@
801
801
  .hover\:underline:hover {
802
802
  text-decoration-line: underline;
803
803
  }
804
+ @media (prefers-color-scheme: dark) {
805
+ .dark\:border-gray-800 {
806
+ --tw-border-opacity: 1;
807
+ border-color: rgb(31 41 55 / var(--tw-border-opacity));
808
+ }
809
+ .dark\:bg-gray-900 {
810
+ --tw-bg-opacity: 1;
811
+ background-color: rgb(17 24 39 / var(--tw-bg-opacity));
812
+ }
813
+ .dark\:bg-green-900 {
814
+ --tw-bg-opacity: 1;
815
+ background-color: rgb(20 83 45 / var(--tw-bg-opacity));
816
+ }
817
+ .dark\:bg-red-900 {
818
+ --tw-bg-opacity: 1;
819
+ background-color: rgb(127 29 29 / var(--tw-bg-opacity));
820
+ }
821
+ .dark\:text-gray-100 {
822
+ --tw-text-opacity: 1;
823
+ color: rgb(243 244 246 / var(--tw-text-opacity));
824
+ }
825
+ .dark\:text-white {
826
+ --tw-text-opacity: 1;
827
+ color: rgb(255 255 255 / var(--tw-text-opacity));
828
+ }
829
+ .dark\:even\:bg-gray-800:nth-child(even) {
830
+ --tw-bg-opacity: 1;
831
+ background-color: rgb(31 41 55 / var(--tw-bg-opacity));
832
+ }
833
+ .dark\:hover\:bg-gray-900:hover {
834
+ --tw-bg-opacity: 1;
835
+ background-color: rgb(17 24 39 / var(--tw-bg-opacity));
836
+ }
837
+ .dark\:hover\:bg-gray-800:hover {
838
+ --tw-bg-opacity: 1;
839
+ background-color: rgb(31 41 55 / var(--tw-bg-opacity));
840
+ }
841
+ }
804
842
  </style>
@@ -7,22 +7,22 @@
7
7
 
8
8
  <%= render "layouts/litestream/style" %>
9
9
  </head>
10
- <body class="h-full flex flex-col">
10
+ <body class="h-full flex flex-col dark:bg-gray-900 dark:text-white">
11
11
  <main class="container mx-auto max-w-4xl mt-4 px-2 grow">
12
12
  <%= content_for?(:content) ? yield(:content) : yield %>
13
13
  </main>
14
14
 
15
- <footer class="container mx-auto mt-24 flex items-center justify-between border-t px-2 py-4 text-base">
15
+ <footer class="container mx-auto mt-24 flex items-center justify-between border-t dark:border-gray-800 px-2 py-4 text-base">
16
16
  <p>
17
17
  <code><strong>Litestream</strong></code>&nbsp;&nbsp;|&nbsp;
18
- Made by <a href="https://twitter.com/fractaledmind" class="text-blue-500 hover:underline decoration-blue-500">@fractaledmind</a> and <a href="https://github.com/fractaledmind/litestream/graphs/contributors" class="text-blue-500 hover:underline decoration-blue-500">friends</a>! Want to help? It's <a href="https://github.com/fractaledmind/litestream" class="text-blue-500 hover:underline decoration-blue-500">open source</a>!
18
+ Made by <a href="https://twitter.com/fractaledmind" class="text-blue-500 hover:underline decoration-blue-500">@fractaledmind</a> and <a href="https://github.com/fractaledmind/litestream-ruby/graphs/contributors" class="text-blue-500 hover:underline decoration-blue-500">friends</a>! Want to help? It's <a href="https://github.com/fractaledmind/litestream-ruby" class="text-blue-500 hover:underline decoration-blue-500">open source</a>!
19
19
  </p>
20
20
  </footer>
21
21
 
22
22
  <div class="fixed top-0 left-0 right-0 text-center py-2">
23
23
  <% if notice.present? %>
24
24
  <p id="notice"
25
- class="py-2 px-3 bg-green-50 text-green-500 font-medium rounded-lg inline-block"
25
+ class="py-2 px-3 bg-green-50 dark:bg-green-900 text-green-500 font-medium rounded-lg inline-block"
26
26
  data-controller="fade">
27
27
  <%= notice.html_safe %>
28
28
  </p>
@@ -30,7 +30,7 @@
30
30
 
31
31
  <% if alert.present? %>
32
32
  <p id="alert"
33
- class="py-2 px-3 bg-red-50 text-red-500 font-medium rounded-lg inline-block"
33
+ class="py-2 px-3 bg-red-50 dark:bg-red-900 text-red-500 font-medium rounded-lg inline-block"
34
34
  data-controller="fade">
35
35
  <%= alert.html_safe %>
36
36
  </p>
@@ -40,7 +40,7 @@
40
40
  <br>
41
41
 
42
42
  <section id="databases" class="">
43
- <div class="mb-3 flex items-center justify-between border-b">
43
+ <div class="mb-3 flex items-center justify-between border-b dark:border-gray-800">
44
44
  <h2 class="text-2xl font-bold">Databases</h2>
45
45
  <p class="text-right">Total: <strong><%= @databases.size %></strong></p>
46
46
  </div>
@@ -59,7 +59,7 @@
59
59
  <section id="generations" class="ml-6">
60
60
  <% database['generations'].each do |generation| %>
61
61
  <details id="<%= generation['generation'] %>" open="open">
62
- <summary class="cursor-pointer rounded p-2 hover:bg-gray-50">
62
+ <summary class="cursor-pointer rounded p-2 hover:bg-gray-50 dark:hover:bg-gray-800">
63
63
  <code><%= generation['generation'] %></code>
64
64
  (<em><%= generation['lag'] %> lag</em>)
65
65
  </summary>
@@ -85,24 +85,24 @@
85
85
  <table class="min-w-full divide-y divide-gray-300">
86
86
  <thead>
87
87
  <tr>
88
- <th scope="col" class="whitespace-nowrap px-2 py-2 text-left text-sm font-semibold text-gray-900">Created at</th>
89
- <th scope="col" class="whitespace-nowrap px-2 py-2 text-right text-sm font-semibold text-gray-900">Index</th>
90
- <th scope="col" class="whitespace-nowrap px-2 py-2 text-right text-sm font-semibold text-gray-900">Size</th>
88
+ <th scope="col" class="whitespace-nowrap px-2 py-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100">Created at</th>
89
+ <th scope="col" class="whitespace-nowrap px-2 py-2 text-right text-sm font-semibold text-gray-900 dark:text-gray-100">Index</th>
90
+ <th scope="col" class="whitespace-nowrap px-2 py-2 text-right text-sm font-semibold text-gray-900 dark:text-gray-100">Size</th>
91
91
  </tr>
92
92
  </thead>
93
93
 
94
- <tbody class="bg-white">
94
+ <tbody class="bg-white dark:bg-gray-900">
95
95
  <% generation['snapshots'].each do |snapshot| %>
96
- <tr class="align-top even:bg-gray-50">
97
- <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900">
96
+ <tr class="align-top even:bg-gray-50 dark:even:bg-gray-800">
97
+ <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100">
98
98
  <abbr title="<%= snapshot['created'] %>" class="underline decoration-dashed decoration-gray-500 cursor-help">
99
99
  <time datetime="<%= snapshot['created'] %>"><%= DateTime.parse(snapshot['created']).to_formatted_s(:db) %></time>
100
100
  </abbr>
101
101
  </td>
102
- <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 text-right">
102
+ <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100 text-right">
103
103
  <%= snapshot['index'] %>
104
104
  </td>
105
- <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 text-right">
105
+ <td scope="col" class="whitespace-nowrap px-2 py-2 text-sm text-gray-900 dark:text-gray-100 text-right">
106
106
  <%= number_to_human_size snapshot['size'] %>
107
107
  </td>
108
108
  </tr>
@@ -1,5 +1,4 @@
1
1
  require_relative "upstream"
2
- require "logfmt"
3
2
 
4
3
  module Litestream
5
4
  module Commands
@@ -21,6 +20,24 @@ module Litestream
21
20
  # raised when a litestream command fails
22
21
  CommandFailedException = Class.new(StandardError)
23
22
 
23
+ module Output
24
+ class << self
25
+ def format(data)
26
+ return "" if data.nil? || data.empty?
27
+
28
+ headers = data.first.keys.map(&:to_s)
29
+ widths = headers.map.with_index { |h, i|
30
+ [h.length, data.map { |r| r[data.first.keys[i]].to_s.length }.max].max
31
+ }
32
+
33
+ format_str = widths.map { |w| "%-#{w}s" }.join(" ")
34
+ ([headers] + data.map(&:values)).map { |row|
35
+ sprintf(format_str, *row.map(&:to_s))
36
+ }.join("\n")
37
+ end
38
+ end
39
+ end
40
+
24
41
  class << self
25
42
  def platform
26
43
  [:cpu, :os].map { |m| Gem::Platform.local.send(m) }.join("-")
@@ -77,44 +94,49 @@ module Litestream
77
94
  exe_file
78
95
  end
79
96
 
97
+ # Replicate can be run either as a fork or in the same process, depending on the context.
98
+ # Puma will start replication as a forked process, while running replication from a rake
99
+ # tasks won't.
80
100
  def replicate(async: false, **argv)
81
- execute("replicate", argv, async: async, tabled_output: false)
101
+ cmd = prepare("replicate", argv)
102
+ run_replicate(cmd, async: async)
103
+ rescue
104
+ raise CommandFailedException, "Failed to execute `#{cmd.join(" ")}`"
82
105
  end
83
106
 
84
- def restore(database, async: false, **argv)
107
+ def restore(database, **argv)
85
108
  raise DatabaseRequiredException, "database argument is required for restore command, e.g. litestream:restore -- --database=path/to/database.sqlite" if database.nil?
86
- argv.stringify_keys!
87
109
 
88
- execute("restore", argv, database, async: async, tabled_output: false)
110
+ execute("restore", argv, database, tabled_output: false)
89
111
  end
90
112
 
91
- def databases(async: false, **argv)
92
- execute("databases", argv, async: async, tabled_output: true)
113
+ def databases(**argv)
114
+ execute("databases", argv)
93
115
  end
94
116
 
95
- def generations(database, async: false, **argv)
117
+ def generations(database, **argv)
96
118
  raise DatabaseRequiredException, "database argument is required for generations command, e.g. litestream:generations -- --database=path/to/database.sqlite" if database.nil?
97
119
 
98
- execute("generations", argv, database, async: async, tabled_output: true)
120
+ execute("generations", argv, database)
99
121
  end
100
122
 
101
- def snapshots(database, async: false, **argv)
123
+ def snapshots(database, **argv)
102
124
  raise DatabaseRequiredException, "database argument is required for snapshots command, e.g. litestream:snapshots -- --database=path/to/database.sqlite" if database.nil?
103
125
 
104
- execute("snapshots", argv, database, async: async, tabled_output: true)
126
+ execute("snapshots", argv, database)
105
127
  end
106
128
 
107
- def wal(database, async: false, **argv)
129
+ def wal(database, **argv)
108
130
  raise DatabaseRequiredException, "database argument is required for wal command, e.g. litestream:wal -- --database=path/to/database.sqlite" if database.nil?
109
131
 
110
- execute("wal", argv, database, async: async, tabled_output: true)
132
+ execute("wal", argv, database)
111
133
  end
112
134
 
113
135
  private
114
136
 
115
- def execute(command, argv = {}, database = nil, async: false, tabled_output: false)
137
+ def execute(command, argv = {}, database = nil, tabled_output: true)
116
138
  cmd = prepare(command, argv, database)
117
- results = run(cmd, async: async, tabled_output: tabled_output)
139
+ results = run(cmd, tabled_output: tabled_output)
118
140
 
119
141
  if Array === results && results.one? && results[0]["level"] == "ERROR"
120
142
  raise CommandFailedException, "Failed to execute `#{cmd.join(" ")}`; Reason: #{results[0]["error"]}"
@@ -125,11 +147,13 @@ module Litestream
125
147
 
126
148
  def prepare(command, argv = {}, database = nil)
127
149
  ENV["LITESTREAM_REPLICA_BUCKET"] ||= Litestream.replica_bucket
150
+ ENV["LITESTREAM_REPLICA_REGION"] ||= Litestream.replica_region
151
+ ENV["LITESTREAM_REPLICA_ENDPOINT"] ||= Litestream.replica_endpoint
128
152
  ENV["LITESTREAM_ACCESS_KEY_ID"] ||= Litestream.replica_key_id
129
153
  ENV["LITESTREAM_SECRET_ACCESS_KEY"] ||= Litestream.replica_access_key
130
154
 
131
155
  args = {
132
- "--config" => Rails.root.join("config", "litestream.yml").to_s
156
+ "--config" => Litestream.config_path.to_s
133
157
  }.merge(argv.stringify_keys).to_a.flatten.compact
134
158
  cmd = [executable, command, *args, database].compact
135
159
  puts cmd.inspect if ENV["DEBUG"]
@@ -137,21 +161,24 @@ module Litestream
137
161
  cmd
138
162
  end
139
163
 
140
- def run(cmd, async: false, tabled_output: false)
164
+ def run(cmd, tabled_output:)
165
+ stdout = `#{cmd.join(" ")}`.chomp
166
+ return stdout unless tabled_output
167
+
168
+ keys, *rows = stdout.split("\n").map { _1.split(/\s+/) }
169
+ rows.map { keys.zip(_1).to_h }
170
+ end
171
+
172
+ def run_replicate(cmd, async:)
141
173
  if async
142
- # To release the resources of the Ruby process, just fork and exit.
143
- # The forked process executes litestream and replaces itself.
144
174
  exec(*cmd) if fork.nil?
145
175
  else
146
- stdout = `#{cmd.join(" ")}`.chomp
147
- tabled_output ? text_table_to_hashes(stdout) : stdout.split("\n").map { Logfmt.parse(_1) }
176
+ # When running in-process, we capture output continuously and write to stdout.
177
+ IO.popen(cmd, err: [:child, :out]) do |io|
178
+ io.each_line { |line| puts line }
179
+ end
148
180
  end
149
181
  end
150
-
151
- def text_table_to_hashes(string)
152
- keys, *rows = string.split("\n").map { _1.split(/\s+/) }
153
- rows.map { keys.zip(_1).to_h }
154
- end
155
182
  end
156
183
  end
157
184
  end
@@ -2,32 +2,44 @@
2
2
  # All configuration options will be available as environment variables, e.g.
3
3
  # config.replica_bucket becomes LITESTREAM_REPLICA_BUCKET
4
4
  # This allows you to configure Litestream using Rails encrypted credentials,
5
- # or some other mechanism where the values are only avaialble at runtime.
5
+ # or some other mechanism where the values are only available at runtime.
6
6
 
7
7
  Rails.application.configure do
8
- # An example of using Rails encrypted credentials to configure Litestream.
8
+ # Configure Litestream through environment variables. Use Rails encrypted credentials for secrets.
9
9
  # litestream_credentials = Rails.application.credentials.litestream
10
10
 
11
- # Replica-specific bucket location.
12
- # This will be your bucket's URL without the `https://` prefix.
11
+ # Replica-specific bucket location. This will be your bucket's URL without the `https://` prefix.
13
12
  # For example, if you used DigitalOcean Spaces, your bucket URL could look like:
13
+ #
14
14
  # https://myapp.fra1.digitaloceanspaces.com
15
+ #
15
16
  # And so you should set your `replica_bucket` to:
17
+ #
16
18
  # myapp.fra1.digitaloceanspaces.com
17
- # Litestream supports Azure Blog Storage, Backblaze B2, DigitalOcean Spaces,
18
- # Scaleway Object Storage, Google Cloud Storage, Linode Object Storage, and
19
- # any SFTP server.
20
- # In this example, we are using Rails encrypted credentials to store the URL to
21
- # our storage provider bucket.
19
+ #
22
20
  # config.litestream.replica_bucket = litestream_credentials&.replica_bucket
23
-
24
- # Replica-specific authentication key.
25
- # Litestream needs authentication credentials to access your storage provider bucket.
26
- # In this example, we are using Rails encrypted credentials to store the access key ID.
21
+ #
22
+ # Replica-specific authentication key. Litestream needs authentication credentials to access your storage provider bucket.
27
23
  # config.litestream.replica_key_id = litestream_credentials&.replica_key_id
28
-
29
- # Replica-specific secret key.
30
- # Litestream needs authentication credentials to access your storage provider bucket.
31
- # In this example, we are using Rails encrypted credentials to store the secret access key.
24
+ #
25
+ # Replica-specific secret key. Litestream needs authentication credentials to access your storage provider bucket.
32
26
  # config.litestream.replica_access_key = litestream_credentials&.replica_access_key
27
+ #
28
+ # Replica-specific region. Set the bucket’s region. Only used for AWS S3 & Backblaze B2.
29
+ # config.litestream.replica_region = "us-east-1"
30
+ #
31
+ # Replica-specific endpoint. Set the endpoint URL of the S3-compatible service. Only required for non-AWS services.
32
+ # config.litestream.replica_endpoint = "endpoint.your-objectstorage.com"
33
+
34
+ # Configure the default Litestream config path
35
+ # config.config_path = Rails.root.join("config", "litestream.yml")
36
+
37
+ # Configure the Litestream dashboard
38
+ #
39
+ # Set the default base controller class
40
+ # config.litestream.base_controller_class = "MyApplicationController"
41
+ #
42
+ # Set authentication credentials for Litestream dashboard
43
+ # config.litestream.username = litestream_credentials&.username
44
+ # config.litestream.password = litestream_credentials&.password
33
45
  end
@@ -4,6 +4,7 @@ module Litestream
4
4
 
5
5
  # rubygems platform name => upstream release filename
6
6
  NATIVE_PLATFORMS = {
7
+ "aarch64-linux" => "litestream-#{VERSION}-linux-arm64.tar.gz",
7
8
  "arm64-darwin" => "litestream-#{VERSION}-darwin-arm64.zip",
8
9
  "arm64-linux" => "litestream-#{VERSION}-linux-arm64.tar.gz",
9
10
  "x86_64-darwin" => "litestream-#{VERSION}-darwin-amd64.zip",
@@ -1,3 +1,3 @@
1
1
  module Litestream
2
- VERSION = "0.12.0"
2
+ VERSION = "0.14.0"
3
3
  end
data/lib/litestream.rb CHANGED
@@ -33,16 +33,17 @@ module Litestream
33
33
  end
34
34
  end
35
35
 
36
- mattr_writer :username, :password, :queue, :replica_bucket, :replica_key_id, :replica_access_key, :systemctl_command
36
+ mattr_writer :username, :password, :queue, :replica_bucket, :replica_region, :replica_endpoint, :replica_key_id, :replica_access_key, :systemctl_command, :config_path
37
+ mattr_accessor :base_controller_class, default: "::ApplicationController"
37
38
 
38
39
  class << self
39
- def verify!(database_path)
40
+ def verify!(database_path, replication_sleep: 10)
40
41
  database = SQLite3::Database.new(database_path)
41
42
  database.execute("CREATE TABLE IF NOT EXISTS _litestream_verification (id INTEGER PRIMARY KEY, uuid BLOB)")
42
43
  sentinel = SecureRandom.uuid
43
44
  database.execute("INSERT INTO _litestream_verification (uuid) VALUES (?)", [sentinel])
44
45
  # give the Litestream replication process time to replicate the sentinel value
45
- sleep 10
46
+ sleep replication_sleep
46
47
 
47
48
  backup_path = "tmp/#{Time.now.utc.strftime("%Y%m%d%H%M%S")}_#{sentinel}.sqlite3"
48
49
  Litestream::Commands.restore(database_path, **{"-o" => backup_path})
@@ -77,6 +78,14 @@ module Litestream
77
78
  @@replica_bucket || configuration.replica_bucket
78
79
  end
79
80
 
81
+ def replica_region
82
+ @@replica_region
83
+ end
84
+
85
+ def replica_endpoint
86
+ @@replica_endpoint
87
+ end
88
+
80
89
  def replica_key_id
81
90
  @@replica_key_id || configuration.replica_key_id
82
91
  end
@@ -89,55 +98,12 @@ module Litestream
89
98
  @@systemctl_command || "systemctl status litestream"
90
99
  end
91
100
 
101
+ def config_path
102
+ @@config_path || Rails.root.join("config", "litestream.yml")
103
+ end
104
+
92
105
  def replicate_process
93
- info = {}
94
- if !`which systemctl`.empty?
95
- systemctl_status = `#{Litestream.systemctl_command}`.chomp
96
- # ["● litestream.service - Litestream",
97
- # " Loaded: loaded (/lib/systemd/system/litestream.service; enabled; vendor preset: enabled)",
98
- # " Active: active (running) since Tue 2023-07-25 13:49:43 UTC; 8 months 24 days ago",
99
- # " Main PID: 1179656 (litestream)",
100
- # " Tasks: 9 (limit: 1115)",
101
- # " Memory: 22.9M",
102
- # " CPU: 10h 49.843s",
103
- # " CGroup: /system.slice/litestream.service",
104
- # " └─1179656 /usr/bin/litestream replicate",
105
- # "",
106
- # "Warning: some journal files were not opened due to insufficient permissions."]
107
- systemctl_status.split("\n").each do |line|
108
- line.strip!
109
- if line.start_with?("Main PID:")
110
- _key, value = line.split(":")
111
- pid, _name = value.strip.split(" ")
112
- info[:pid] = pid
113
- elsif line.start_with?("Active:")
114
- value, _ago = line.split(";")
115
- status, timestamp = value.split(" since ")
116
- info[:started] = DateTime.strptime(timestamp.strip, "%a %Y-%m-%d %H:%M:%S %Z")
117
- status_match = status.match(%r{\((?<status>.*)\)})
118
- info[:status] = status_match ? status_match[:status] : nil
119
- end
120
- end
121
- else
122
- litestream_replicate_ps = `ps -ax | grep litestream | grep replicate`.chomp
123
- litestream_replicate_ps.split("\n").each do |line|
124
- next unless line.include?("litestream replicate")
125
- pid, * = line.split(" ")
126
- info[:pid] = pid
127
- state, _, lstart = `ps -o "state,lstart" #{pid}`.chomp.split("\n").last.partition(/\s+/)
128
-
129
- info[:status] = case state[0]
130
- when "I" then "idle"
131
- when "R" then "running"
132
- when "S" then "sleeping"
133
- when "T" then "stopped"
134
- when "U" then "uninterruptible"
135
- when "Z" then "zombie"
136
- end
137
- info[:started] = DateTime.strptime(lstart.strip, "%a %b %d %H:%M:%S %Y")
138
- end
139
- end
140
- info
106
+ systemctl_info || process_info || {}
141
107
  end
142
108
 
143
109
  def databases
@@ -157,6 +123,71 @@ module Litestream
157
123
  end
158
124
  end
159
125
  end
126
+
127
+ private
128
+
129
+ def systemctl_info
130
+ return if `which systemctl`.empty?
131
+
132
+ systemctl_output = `#{Litestream.systemctl_command}`
133
+ systemctl_exit_code = $?.exitstatus
134
+ return unless systemctl_exit_code.zero?
135
+
136
+ # ["● litestream.service - Litestream",
137
+ # " Loaded: loaded (/lib/systemd/system/litestream.service; enabled; vendor preset: enabled)",
138
+ # " Active: active (running) since Tue 2023-07-25 13:49:43 UTC; 8 months 24 days ago",
139
+ # " Main PID: 1179656 (litestream)",
140
+ # " Tasks: 9 (limit: 1115)",
141
+ # " Memory: 22.9M",
142
+ # " CPU: 10h 49.843s",
143
+ # " CGroup: /system.slice/litestream.service",
144
+ # " └─1179656 /usr/bin/litestream replicate",
145
+ # "",
146
+ # "Warning: some journal files were not opened due to insufficient permissions."]
147
+
148
+ info = {}
149
+ systemctl_output.chomp.split("\n").each do |line|
150
+ line.strip!
151
+ if line.start_with?("Main PID:")
152
+ _key, value = line.split(":")
153
+ pid, _name = value.strip.split(" ")
154
+ info[:pid] = pid
155
+ elsif line.start_with?("Active:")
156
+ value, _ago = line.split(";")
157
+ status, timestamp = value.split(" since ")
158
+ info[:started] = DateTime.strptime(timestamp.strip, "%a %Y-%m-%d %H:%M:%S %Z")
159
+ status_match = status.match(%r{\((?<status>.*)\)})
160
+ info[:status] = status_match ? status_match[:status] : nil
161
+ end
162
+ end
163
+ info
164
+ end
165
+
166
+ def process_info
167
+ litestream_replicate_ps = `ps -ax | grep litestream | grep replicate`
168
+ exit_code = $?.exitstatus
169
+ return unless exit_code.zero?
170
+
171
+ info = {}
172
+ litestream_replicate_ps.chomp.split("\n").each do |line|
173
+ next unless line.include?("litestream replicate")
174
+
175
+ pid, * = line.split(" ")
176
+ info[:pid] = pid
177
+ state, _, lstart = `ps -o "state,lstart" #{pid}`.chomp.split("\n").last.partition(/\s+/)
178
+
179
+ info[:status] = case state[0]
180
+ when "I" then "idle"
181
+ when "R" then "running"
182
+ when "S" then "sleeping"
183
+ when "T" then "stopped"
184
+ when "U" then "uninterruptible"
185
+ when "Z" then "zombie"
186
+ end
187
+ info[:started] = DateTime.strptime(lstart.strip, "%a %b %d %H:%M:%S %Y")
188
+ end
189
+ info
190
+ end
160
191
  end
161
192
  end
162
193
 
@@ -2,6 +2,8 @@ namespace :litestream do
2
2
  desc "Print the ENV variables needed for the Litestream config file"
3
3
  task env: :environment do
4
4
  puts "LITESTREAM_REPLICA_BUCKET=#{Litestream.replica_bucket}"
5
+ puts "LITESTREAM_REPLICA_REGION=#{Litestream.replica_region}"
6
+ puts "LITESTREAM_REPLICA_ENDPOINT=#{Litestream.replica_endpoint}"
5
7
  puts "LITESTREAM_ACCESS_KEY_ID=#{Litestream.replica_key_id}"
6
8
  puts "LITESTREAM_SECRET_ACCESS_KEY=#{Litestream.replica_access_key}"
7
9
 
@@ -10,83 +12,61 @@ namespace :litestream do
10
12
 
11
13
  desc 'Monitor and continuously replicate SQLite databases defined in your config file, for example `rake litestream:replicate -- -exec "foreman start"`'
12
14
  task replicate: :environment do
13
- options = {}
14
- if (separator_index = ARGV.index("--"))
15
- ARGV.slice(separator_index + 1, ARGV.length)
16
- .map { |pair| pair.split("=") }
17
- .each { |opt| options[opt[0]] = opt[1] || nil }
18
- end
19
- options.symbolize_keys!
15
+ options = parse_argv_options
20
16
 
21
- Litestream::Commands.replicate(async: true, **options)
17
+ Litestream::Commands.replicate(**options)
22
18
  end
23
19
 
24
20
  desc "Restore a SQLite database from a Litestream replica, for example `rake litestream:restore -- -database=storage/production.sqlite3`"
25
21
  task restore: :environment do
26
- options = {}
27
- if (separator_index = ARGV.index("--"))
28
- ARGV.slice(separator_index + 1, ARGV.length)
29
- .map { |pair| pair.split("=") }
30
- .each { |opt| options[opt[0]] = opt[1] || nil }
31
- end
32
- database = options.delete("--database") || options.delete("-database")
33
- options.symbolize_keys!
22
+ options = parse_argv_options
23
+ database = options.delete(:"--database") || options.delete(:"-database")
34
24
 
35
- Litestream::Commands.restore(database, async: true, **options)
25
+ puts Litestream::Commands.restore(database, **options)
36
26
  end
37
27
 
38
28
  desc "List all databases and associated replicas in the config file, for example `rake litestream:databases -- -no-expand-env`"
39
29
  task databases: :environment do
40
- options = {}
41
- if (separator_index = ARGV.index("--"))
42
- ARGV.slice(separator_index + 1, ARGV.length)
43
- .map { |pair| pair.split("=") }
44
- .each { |opt| options[opt[0]] = opt[1] || nil }
45
- end
46
- options.symbolize_keys!
30
+ options = parse_argv_options
47
31
 
48
- Litestream::Commands.databases(async: true, **options)
32
+ puts Litestream::Commands::Output.format(Litestream::Commands.databases(**options))
49
33
  end
50
34
 
51
35
  desc "List all generations for a database or replica, for example `rake litestream:generations -- -database=storage/production.sqlite3`"
52
36
  task generations: :environment do
53
- options = {}
54
- if (separator_index = ARGV.index("--"))
55
- ARGV.slice(separator_index + 1, ARGV.length)
56
- .map { |pair| pair.split("=") }
57
- .each { |opt| options[opt[0]] = opt[1] || nil }
58
- end
59
- database = options.delete("--database") || options.delete("-database")
60
- options.symbolize_keys!
37
+ options = parse_argv_options
38
+ database = options.delete(:"--database") || options.delete(:"-database")
61
39
 
62
- Litestream::Commands.generations(database, async: true, **options)
40
+ puts Litestream::Commands::Output.format(Litestream::Commands.generations(database, **options))
63
41
  end
64
42
 
65
43
  desc "List all snapshots for a database or replica, for example `rake litestream:snapshots -- -database=storage/production.sqlite3`"
66
44
  task snapshots: :environment do
67
- options = {}
68
- if (separator_index = ARGV.index("--"))
69
- ARGV.slice(separator_index + 1, ARGV.length)
70
- .map { |pair| pair.split("=") }
71
- .each { |opt| options[opt[0]] = opt[1] || nil }
72
- end
73
- database = options.delete("--database") || options.delete("-database")
74
- options.symbolize_keys!
45
+ options = parse_argv_options
46
+ database = options.delete(:"--database") || options.delete(:"-database")
75
47
 
76
- Litestream::Commands.snapshots(database, async: true, **options)
48
+ puts Litestream::Commands::Output.format(Litestream::Commands.snapshots(database, **options))
77
49
  end
78
50
 
79
51
  desc "List all wal files for a database or replica, for example `rake litestream:wal -- -database=storage/production.sqlite3`"
80
52
  task wal: :environment do
53
+ options = parse_argv_options
54
+ database = options.delete(:"--database") || options.delete(:"-database")
55
+
56
+ puts Litestream::Commands::Output.format(
57
+ Litestream::Commands.wal(database, **options)
58
+ )
59
+ end
60
+
61
+ private
62
+
63
+ def parse_argv_options
81
64
  options = {}
82
65
  if (separator_index = ARGV.index("--"))
83
66
  ARGV.slice(separator_index + 1, ARGV.length)
84
67
  .map { |pair| pair.split("=") }
85
68
  .each { |opt| options[opt[0]] = opt[1] || nil }
86
69
  end
87
- database = options.delete("--database") || options.delete("-database")
88
70
  options.symbolize_keys!
89
-
90
- Litestream::Commands.wal(database, async: true, **options)
91
71
  end
92
72
  end
metadata CHANGED
@@ -1,29 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: litestream
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.14.0
5
5
  platform: x86_64-darwin
6
6
  authors:
7
7
  - Stephen Margheim
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-10-22 00:00:00.000000000 Z
10
+ date: 2025-06-13 00:00:00.000000000 Z
12
11
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: logfmt
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 0.0.10
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: 0.0.10
27
12
  - !ruby/object:Gem::Dependency
28
13
  name: sqlite3
29
14
  requirement: !ruby/object:Gem::Requirement
@@ -67,7 +52,7 @@ dependencies:
67
52
  - !ruby/object:Gem::Version
68
53
  version: '7.0'
69
54
  - !ruby/object:Gem::Dependency
70
- name: activesupport
55
+ name: activejob
71
56
  requirement: !ruby/object:Gem::Requirement
72
57
  requirements:
73
58
  - - ">="
@@ -81,7 +66,7 @@ dependencies:
81
66
  - !ruby/object:Gem::Version
82
67
  version: '7.0'
83
68
  - !ruby/object:Gem::Dependency
84
- name: activejob
69
+ name: activesupport
85
70
  requirement: !ruby/object:Gem::Requirement
86
71
  requirements:
87
72
  - - ">="
@@ -108,20 +93,6 @@ dependencies:
108
93
  - - ">="
109
94
  - !ruby/object:Gem::Version
110
95
  version: '7.0'
111
- - !ruby/object:Gem::Dependency
112
- name: rubyzip
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
96
  - !ruby/object:Gem::Dependency
126
97
  name: rails
127
98
  requirement: !ruby/object:Gem::Requirement
@@ -137,7 +108,7 @@ dependencies:
137
108
  - !ruby/object:Gem::Version
138
109
  version: '0'
139
110
  - !ruby/object:Gem::Dependency
140
- name: sqlite3
111
+ name: rubyzip
141
112
  requirement: !ruby/object:Gem::Requirement
142
113
  requirements:
143
114
  - - ">="
@@ -150,7 +121,6 @@ dependencies:
150
121
  - - ">="
151
122
  - !ruby/object:Gem::Version
152
123
  version: '0'
153
- description:
154
124
  email:
155
125
  - stephen.margheim@gmail.com
156
126
  executables:
@@ -190,7 +160,6 @@ metadata:
190
160
  rubygems_mfa_required: 'true'
191
161
  source_code_uri: https://github.com/fractaledmind/litestream-ruby
192
162
  changelog_uri: https://github.com/fractaledmind/litestream-ruby/CHANGELOG.md
193
- post_install_message:
194
163
  rdoc_options: []
195
164
  require_paths:
196
165
  - lib
@@ -205,8 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
205
174
  - !ruby/object:Gem::Version
206
175
  version: '0'
207
176
  requirements: []
208
- rubygems_version: 3.5.21
209
- signing_key:
177
+ rubygems_version: 3.6.3
210
178
  specification_version: 4
211
179
  summary: Integrate Litestream with the RubyGems infrastructure.
212
180
  test_files: []