dotenvx 4.0.3 → 4.0.5

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: dbc11188493670e456723d7d984cb3118d3c9e3abaaba8652a5650f9b99c7d14
4
- data.tar.gz: eaa5409b065a89f9105109f3b955f0ae68c43e137c7a35cd99103fe290572240
3
+ metadata.gz: 8b598e9f335c0ce4bcec51dd215f72e75c9735dc389b167139e29a60595aa696
4
+ data.tar.gz: d0d03d0e33828498a6ee322689a51856ded35b99cf2dfa68c7dcd5efd87e2230
5
5
  SHA512:
6
- metadata.gz: 31b8875875fa83cdb13ff2ec5a3660ce9cf637c5eed17aa1cfa7ea3d66ab0ca451f5d8a9c1d31f6c7b0f739e0767b3e361e77b6e1b814660e4591886e931011c
7
- data.tar.gz: 720420e1e1f2018215c47d9b1064449ca6699b277bcc3cdfc6f4506f69b45d2255dc433b4182118a398ecf5578d8b3c6fd68e93c0faaf426b4533bb95c38f7dd
6
+ metadata.gz: af0097282ab2fa863d4fc334ec92def248282b700dcfa679c0e8c7340c4a8c31655efd7be3c48b6675d0d6c8e317b5e55df84a70e7aea7693e4a1b44ee71eeb8
7
+ data.tar.gz: 11f12169e0788357b768ec967699eb14dce3fb78726b208a4d9ab58613fb61f63f45828e0776b49c15fed93f255df223cc1570ebf0a53708357abaf727ff24c1
data/CHANGELOG.md CHANGED
@@ -2,7 +2,16 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
- ## [Unreleased](https://github.com/dotenvx/dotenvx-ruby/compare/v4.0.0...main)
5
+ ## [Unreleased](https://github.com/dotenvx/dotenvx-ruby/compare/v4.0.5...main)
6
+
7
+ ## [4.0.5](https://github.com/dotenvx/dotenvx-ruby/compare/v4.0.4...v4.0.5)
8
+
9
+ - Continue after parse and decryption errors by default, with strict and
10
+ error-code ignore options for callers that need them.
11
+
12
+ ## [4.0.4](https://github.com/dotenvx/dotenvx-ruby/compare/v4.0.3...v4.0.4)
13
+
14
+ - Report the unique variables injected from readable dotenv files.
6
15
 
7
16
  ## [4.0.0](https://github.com/dotenvx/dotenvx-ruby/compare/v0.0.2...v4.0.0)
8
17
 
data/Cargo.lock CHANGED
@@ -222,7 +222,7 @@ dependencies = [
222
222
 
223
223
  [[package]]
224
224
  name = "dotenvx_native"
225
- version = "4.0.3"
225
+ version = "4.0.5"
226
226
  dependencies = [
227
227
  "dotenvx-primitives",
228
228
  "magnus",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "dotenvx_native"
3
- version = "4.0.3"
3
+ version = "4.0.5"
4
4
  edition = "2021"
5
5
  rust-version = "1.83"
6
6
  publish = false
@@ -5,6 +5,7 @@ use std::collections::HashMap;
5
5
  use std::path::PathBuf;
6
6
 
7
7
  type StringPairs = Vec<(String, String)>;
8
+ type ErrorPairs = Vec<(String, String)>;
8
9
 
9
10
  fn runtime_error(message: impl Into<String>) -> Error {
10
11
  let ruby = Ruby::get().expect("Ruby VM is not available");
@@ -21,18 +22,17 @@ fn scalar_values(values: HashMap<String, Value>) -> StringPairs {
21
22
  .collect()
22
23
  }
23
24
 
24
- fn parse_result(result: ParseResult) -> Result<(StringPairs, StringPairs), Error> {
25
- if !result.errors.is_empty() {
26
- let message = result
27
- .errors
28
- .iter()
29
- .map(ToString::to_string)
30
- .collect::<Vec<_>>()
31
- .join("\n");
32
- return Err(runtime_error(message));
33
- }
34
-
35
- Ok((scalar_values(result.parsed), scalar_values(result.injected)))
25
+ fn parse_result(result: ParseResult) -> (StringPairs, StringPairs, ErrorPairs) {
26
+ let errors = result
27
+ .errors
28
+ .iter()
29
+ .map(|error| (error.code().to_owned(), error.to_string()))
30
+ .collect();
31
+ (
32
+ scalar_values(result.parsed),
33
+ scalar_values(result.injected),
34
+ errors,
35
+ )
36
36
  }
37
37
 
38
38
  #[derive(Deserialize)]
@@ -43,7 +43,7 @@ struct ParseInput {
43
43
  key_files: Vec<String>,
44
44
  }
45
45
 
46
- fn parse_dotenv(input_json: String) -> Result<(StringPairs, StringPairs), Error> {
46
+ fn parse_dotenv(input_json: String) -> Result<(StringPairs, StringPairs, ErrorPairs), Error> {
47
47
  let input = serde_json::from_str::<ParseInput>(&input_json)
48
48
  .map_err(|error| runtime_error(error.to_string()))?;
49
49
  let process_env = input.process_env;
@@ -54,7 +54,7 @@ fn parse_dotenv(input_json: String) -> Result<(StringPairs, StringPairs), Error>
54
54
  })
55
55
  .map_err(|error| runtime_error(error.to_string()))?;
56
56
 
57
- parse_result(parse(
57
+ Ok(parse_result(parse(
58
58
  &input.source,
59
59
  &ParseOptions {
60
60
  process_env,
@@ -62,7 +62,7 @@ fn parse_dotenv(input_json: String) -> Result<(StringPairs, StringPairs), Error>
62
62
  ring,
63
63
  ..Default::default()
64
64
  },
65
- ))
65
+ )))
66
66
  }
67
67
 
68
68
  #[magnus::init]
data/lib/dotenvx/rails.rb CHANGED
@@ -37,7 +37,10 @@ module Dotenvx
37
37
  config.before_configuration { Dotenvx::Railtie.instance.load }
38
38
 
39
39
  def load
40
+ return if @loaded
41
+
40
42
  Dotenvx.load(*dotenvx_files)
43
+ @loaded = true
41
44
  end
42
45
 
43
46
  private
@@ -1,3 +1,3 @@
1
1
  module Dotenvx
2
- VERSION = "4.0.3"
2
+ VERSION = "4.0.5"
3
3
  end
data/lib/dotenvx.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "dotenvx/version"
2
2
  require "dotenvx/dotenvx_native"
3
3
  require "json"
4
+ require "pathname"
4
5
 
5
6
  module Dotenvx
6
7
  class MissingKeys < RuntimeError
@@ -12,16 +13,32 @@ module Dotenvx
12
13
  end
13
14
  end
14
15
 
16
+ class ParseError < RuntimeError
17
+ attr_reader :code
18
+
19
+ def initialize(code, message)
20
+ @code = code
21
+ super(message)
22
+ end
23
+ end
24
+
15
25
  class << self
16
26
  attr_accessor :instrumenter
17
27
 
18
- def load(*filenames, overwrite: false, ignore: true)
19
- env = parse(*filenames, overwrite: overwrite, ignore: ignore)
20
- update(env, overwrite: overwrite)
28
+ def load(*filenames, overwrite: false, ignore: true, strict: false)
29
+ env, injected_keys, loaded_paths = parse_files(
30
+ *filenames,
31
+ overwrite: overwrite,
32
+ ignore: ignore,
33
+ strict: strict
34
+ )
35
+ changed = update(env, overwrite: overwrite)
36
+ log_injected(injected_keys, loaded_paths)
37
+ changed
21
38
  end
22
39
 
23
40
  def load!(*filenames)
24
- load(*filenames, ignore: false)
41
+ load(*filenames, ignore: false, strict: true)
25
42
  end
26
43
 
27
44
  def overwrite(*filenames)
@@ -30,36 +47,17 @@ module Dotenvx
30
47
  alias overload overwrite
31
48
 
32
49
  def overwrite!(*filenames)
33
- load(*filenames, overwrite: true, ignore: false)
50
+ load(*filenames, overwrite: true, ignore: false, strict: true)
34
51
  end
35
52
  alias overload! overwrite!
36
53
 
37
- def parse(*filenames, overwrite: false, ignore: true)
38
- filenames = [".env"] if filenames.empty?
39
- filenames = filenames.flatten.reverse if overwrite
40
-
41
- process_env = ENV.to_h
42
- filenames.reduce({}) do |values, filename|
43
- path = File.expand_path(filename)
44
- begin
45
- source = File.binread(path).sub(/\A\xEF\xBB\xBF/, "").force_encoding(Encoding::UTF_8)
46
- rescue Errno::ENOENT, Errno::EISDIR
47
- raise unless ignore
48
- next values
49
- end
50
-
51
- parsed, = Native.parse_dotenv(JSON.generate(
52
- source: source,
53
- process_env: process_env,
54
- overwrite: overwrite == true,
55
- key_files: key_files(path)
56
- ))
57
- parsed = parsed.to_h
58
- process_env.merge!(parsed)
59
- values.merge!(parsed)
60
- yield Environment.new(path, parsed) if block_given?
61
- values
62
- end
54
+ def parse(*filenames, overwrite: false, ignore: true, strict: false)
55
+ parse_files(
56
+ *filenames,
57
+ overwrite: overwrite,
58
+ ignore: ignore,
59
+ strict: strict
60
+ ).first
63
61
  end
64
62
 
65
63
  def update(env = {}, overwrite: false)
@@ -89,6 +87,72 @@ module Dotenvx
89
87
 
90
88
  private
91
89
 
90
+ def parse_files(*filenames, overwrite: false, ignore: true, strict: false)
91
+ filenames = [".env"] if filenames.empty?
92
+ filenames = filenames.flatten.reverse if overwrite
93
+
94
+ process_env = ENV.to_h
95
+ injected_keys = {}
96
+ loaded_paths = []
97
+ values = filenames.reduce({}) do |accumulator, filename|
98
+ path = File.expand_path(filename)
99
+ begin
100
+ source = File.binread(path).sub(/\A\xEF\xBB\xBF/, "").force_encoding(Encoding::UTF_8)
101
+ rescue Errno::ENOENT, Errno::EISDIR
102
+ raise unless ignore_missing?(ignore)
103
+ next accumulator
104
+ end
105
+
106
+ parsed, injected, errors = Native.parse_dotenv(JSON.generate(
107
+ source: source,
108
+ process_env: process_env,
109
+ overwrite: overwrite == true,
110
+ key_files: key_files(path)
111
+ ))
112
+ handle_errors(errors, ignore: ignore, strict: strict)
113
+ parsed = parsed.to_h
114
+ injected.each { |key, _value| injected_keys[key] = true }
115
+ loaded_paths << path
116
+ process_env.merge!(parsed)
117
+ accumulator.merge!(parsed)
118
+ yield Environment.new(path, parsed) if block_given?
119
+ accumulator
120
+ end
121
+ [values, injected_keys.keys, loaded_paths]
122
+ end
123
+
124
+ def handle_errors(errors, ignore:, strict:)
125
+ ignored_codes = Array(ignore).grep(String)
126
+ errors.each do |code, message|
127
+ next if ignored_codes.include?(code)
128
+
129
+ raise ParseError.new(code, message) if strict
130
+
131
+ warn "☠ #{message}"
132
+ end
133
+ end
134
+
135
+ def ignore_missing?(ignore)
136
+ ignore == true || Array(ignore).map(&:to_s).include?("MISSING_ENV_FILE")
137
+ end
138
+
139
+ def log_injected(injected_keys, loaded_paths)
140
+ message = "⟐ injected env (#{injected_keys.length})"
141
+ unless loaded_paths.empty?
142
+ paths = loaded_paths.map { |path| readable_path(path) }
143
+ message = "#{message} from #{paths.join(", ")}"
144
+ end
145
+ warn message
146
+ end
147
+
148
+ def readable_path(path)
149
+ pathname = Pathname.new(path)
150
+ relative = pathname.relative_path_from(Pathname.pwd).to_s
151
+ relative.start_with?("../") ? pathname.to_s : relative
152
+ rescue ArgumentError
153
+ pathname.to_s
154
+ end
155
+
92
156
  def key_files(path)
93
157
  candidates = ["#{path}.keys", File.join(File.dirname(path), ".env.keys")]
94
158
  candidates.select { |candidate| File.file?(candidate) }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dotenvx
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.3
4
+ version: 4.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - motdotla