kozo 0.2.0 → 0.3.0

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/CHANGELOG.md +15 -3
  4. data/Gemfile +1 -3
  5. data/Gemfile.lock +44 -51
  6. data/README.md +2 -0
  7. data/kozo.gemspec +2 -2
  8. data/lib/core_ext/boolean.rb +8 -0
  9. data/lib/core_ext/date.rb +15 -0
  10. data/lib/core_ext/enumerable.rb +27 -0
  11. data/lib/core_ext/float.rb +15 -0
  12. data/lib/core_ext/hash.rb +23 -0
  13. data/lib/core_ext/integer.rb +15 -0
  14. data/lib/core_ext/nil_class.rb +8 -0
  15. data/lib/core_ext/string.rb +11 -0
  16. data/lib/core_ext/symbol.rb +11 -0
  17. data/lib/core_ext/time.rb +16 -0
  18. data/lib/kozo/backend.rb +2 -13
  19. data/lib/kozo/backends/git.rb +1 -1
  20. data/lib/kozo/backends/local.rb +12 -4
  21. data/lib/kozo/cli.rb +11 -3
  22. data/lib/kozo/command.rb +6 -15
  23. data/lib/kozo/commands/apply.rb +2 -2
  24. data/lib/kozo/commands/import.rb +4 -2
  25. data/lib/kozo/commands/plan.rb +16 -7
  26. data/lib/kozo/commands/state/delete.rb +39 -0
  27. data/lib/kozo/commands/state/list.rb +21 -0
  28. data/lib/kozo/commands/state/show.rb +30 -0
  29. data/lib/kozo/commands/state/upgrade.rb +45 -0
  30. data/lib/kozo/commands/state.rb +2 -38
  31. data/lib/kozo/concerns/attributes.rb +59 -32
  32. data/lib/kozo/concerns/read_write.rb +45 -0
  33. data/lib/kozo/configuration.rb +28 -17
  34. data/lib/kozo/dsl.rb +15 -0
  35. data/lib/kozo/error.rb +13 -2
  36. data/lib/kozo/inflector.rb +11 -0
  37. data/lib/kozo/logger.rb +13 -7
  38. data/lib/kozo/operation.rb +0 -25
  39. data/lib/kozo/operations/create.rb +12 -6
  40. data/lib/kozo/operations/destroy.rb +12 -6
  41. data/lib/kozo/operations/show.rb +17 -0
  42. data/lib/kozo/operations/update.rb +17 -0
  43. data/lib/kozo/options.rb +24 -0
  44. data/lib/kozo/providers/dummy/resources/dummy.rb +11 -0
  45. data/lib/kozo/providers/hcloud/provider.rb +1 -1
  46. data/lib/kozo/providers/hcloud/resource.rb +30 -7
  47. data/lib/kozo/providers/hcloud/resources/server.rb +16 -8
  48. data/lib/kozo/providers/hcloud/resources/ssh_key.rb +6 -1
  49. data/lib/kozo/reference.rb +58 -0
  50. data/lib/kozo/resource.rb +35 -7
  51. data/lib/kozo/state.rb +11 -5
  52. data/lib/kozo/type.rb +3 -3
  53. data/lib/kozo/types/boolean.rb +0 -4
  54. data/lib/kozo/types/date.rb +0 -4
  55. data/lib/kozo/types/float.rb +0 -4
  56. data/lib/kozo/types/hash.rb +0 -4
  57. data/lib/kozo/types/integer.rb +0 -4
  58. data/lib/kozo/types/reference.rb +17 -0
  59. data/lib/kozo/types/string.rb +0 -4
  60. data/lib/kozo/types/time.rb +0 -4
  61. data/lib/kozo/upgrade/1_initial.rb +9 -0
  62. data/lib/kozo/upgrade/2_remove_kozo_version.rb +11 -0
  63. data/lib/kozo/upgrade.rb +15 -0
  64. data/lib/kozo/version.rb +1 -1
  65. data/lib/kozo.rb +7 -1
  66. metadata +42 -19
  67. data/lib/kozo/concerns/mark.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6f328c53f7a4a3c079a6b01da46e6d669b7a5671b9d145dd28ac0bb9849a214
4
- data.tar.gz: 7ee031a2ed77304366d4f4d6d6cbfb9ef9525018b54fc89d0109c0da358f84c9
3
+ metadata.gz: 4aac9ed1535bda5369fd59e0b853cdad3c4c1415b9a386950bf6814fd7ad23aa
4
+ data.tar.gz: 4194c01bdd53178ed6efd4dc9d707a3e5e750c448b8e28c8093f1206969535d6
5
5
  SHA512:
6
- metadata.gz: 70a8837f4076eb87771371397f95ca43e73d07f7105b23095214f3f89f5ac85db234b8c4f2407e0f3d9671e2ed10d68fbb5f4cd9d27356248cfdf86fb0a693dd
7
- data.tar.gz: 1b8d14f8bceaae53776d94db21e7651b5b65fe88074e0297175067c04941e2dc57618640993795945eb82235d686fe93f31ef714adc1f0fd659ee82ec612db68
6
+ metadata.gz: 3c41bce3880883e545ae7550cdbabdfcdff122907980afd6be61c1e951ed38e43f7414ae785f64e4d418509a92d3d6481a101c744baa13d92e6091acc9265d98
7
+ data.tar.gz: b671195833c085efbf3386d9a94810bb0e2360d02228586ef6c7dd27002fde12820983d635c253105e669ba45220cfd18104462184c187da41426879a3fed497
data/.gitignore CHANGED
@@ -72,3 +72,5 @@ build-iPhoneSimulator/
72
72
  ### Kozo ###
73
73
  *.kz
74
74
  *.kzstate
75
+ *.kzbackup
76
+ cloud-init.yml
data/CHANGELOG.md CHANGED
@@ -1,10 +1,22 @@
1
1
  # Changelog
2
2
 
3
- ## Kozo v0.1.0
3
+ All notable changes to this project will be documented in this file.
4
4
 
5
- Initial release
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
7
 
7
- ## Kozo v0.2.0
8
+ ## [Unreleased]
9
+
10
+ ## [0.3.0] - 2022-02-13
11
+
12
+ - Add dependencies between resources
13
+ - Show old and new attribute values in execution plan
14
+
15
+ ## [0.2.0] - 2021-12-02
8
16
 
9
17
  - Add SSH Key and Server resource
10
18
  - Update only changed attributes
19
+
20
+ ## [0.1.0] - 2020-12-23
21
+
22
+ Initial release.
data/Gemfile CHANGED
@@ -4,8 +4,6 @@ source "https://rubygems.org"
4
4
 
5
5
  git_source(:github) { |repo| "https://github.com/#{repo}.git" }
6
6
 
7
- ruby "~> 3.0"
7
+ ruby "~> 3.1"
8
8
 
9
9
  gemspec
10
-
11
- gem "hcloud", github: "floriandejonckheere/hcloud"
data/Gemfile.lock CHANGED
@@ -1,36 +1,25 @@
1
- GIT
2
- remote: https://github.com/floriandejonckheere/hcloud.git
3
- revision: c2ef9116c0f696ded8a8e91aba15820481a74936
4
- specs:
5
- hcloud (1.0.0)
6
- activemodel
7
- activesupport
8
- http
9
- zeitwerk
10
-
11
1
  PATH
12
2
  remote: .
13
3
  specs:
14
- kozo (0.2.0)
15
- activemodel (~> 6.0)
16
- activesupport (~> 6.0)
4
+ kozo (0.3.0)
5
+ activesupport (>= 6.0, < 7.1)
17
6
  colorize (~> 0.8)
18
7
  dinja (~> 2.0)
19
8
  dotenv (~> 2.7)
20
9
  git (~> 1.9)
10
+ hetznercloud (~> 1.3)
21
11
  zeitwerk (~> 2.4)
22
12
 
23
13
  GEM
24
14
  remote: https://rubygems.org/
25
15
  specs:
26
- activemodel (6.1.4.1)
27
- activesupport (= 6.1.4.1)
28
- activesupport (6.1.4.1)
16
+ activemodel (7.0.2.2)
17
+ activesupport (= 7.0.2.2)
18
+ activesupport (7.0.2.2)
29
19
  concurrent-ruby (~> 1.0, >= 1.0.2)
30
20
  i18n (>= 1.6, < 2)
31
21
  minitest (>= 5.1)
32
22
  tzinfo (~> 2.0)
33
- zeitwerk (~> 2.3)
34
23
  addressable (2.8.0)
35
24
  public_suffix (>= 2.0.2, < 5.0)
36
25
  ast (2.4.2)
@@ -44,7 +33,7 @@ GEM
44
33
  concurrent-ruby (1.1.9)
45
34
  crack (0.4.5)
46
35
  rexml
47
- diff-lcs (1.4.4)
36
+ diff-lcs (1.5.0)
48
37
  dinja (2.0.0)
49
38
  zeitwerk
50
39
  docile (1.4.0)
@@ -57,16 +46,21 @@ GEM
57
46
  eventmachine (1.2.7)
58
47
  factory_bot (6.2.0)
59
48
  activesupport (>= 5.0.0)
60
- fakefs (1.4.0)
49
+ fakefs (1.4.1)
61
50
  ffaker (2.20.0)
62
- ffi (1.15.4)
51
+ ffi (1.15.5)
63
52
  ffi-compiler (1.0.1)
64
53
  ffi (>= 1.0.0)
65
54
  rake
66
55
  forwardable-extended (2.6.0)
67
- git (1.9.1)
56
+ git (1.10.2)
68
57
  rchardet (~> 1.8)
69
58
  hashdiff (1.0.1)
59
+ hetznercloud (1.3.1)
60
+ activemodel
61
+ activesupport
62
+ http
63
+ zeitwerk
70
64
  http (5.0.4)
71
65
  addressable (~> 2.8)
72
66
  http-cookie (~> 1.0)
@@ -76,7 +70,7 @@ GEM
76
70
  domain_name (~> 0.5)
77
71
  http-form_data (2.3.0)
78
72
  http_parser.rb (0.8.0)
79
- i18n (1.8.11)
73
+ i18n (1.9.1)
80
74
  concurrent-ruby (~> 1.0)
81
75
  iniparse (1.5.0)
82
76
  jekyll (4.2.1)
@@ -103,7 +97,7 @@ GEM
103
97
  kramdown-parser-gfm (1.1.0)
104
98
  kramdown (~> 2.0)
105
99
  liquid (4.0.3)
106
- listen (3.7.0)
100
+ listen (3.7.1)
107
101
  rb-fsevent (~> 0.10, >= 0.10.3)
108
102
  rb-inotify (~> 0.9, >= 0.9.10)
109
103
  llhttp-ffi (0.4.0)
@@ -111,14 +105,14 @@ GEM
111
105
  rake (~> 13.0)
112
106
  mercenary (0.4.0)
113
107
  method_source (1.0.0)
114
- minitest (5.14.4)
108
+ minitest (5.15.0)
115
109
  optimist (3.0.1)
116
110
  overcommit (0.58.0)
117
111
  childprocess (>= 0.6.3, < 5)
118
112
  iniparse (~> 1.4)
119
113
  rexml (~> 3.2)
120
114
  parallel (1.21.0)
121
- parser (3.0.3.0)
115
+ parser (3.1.0.0)
122
116
  ast (~> 2.4.1)
123
117
  pathutil (0.16.2)
124
118
  forwardable-extended (~> 2.6)
@@ -131,51 +125,51 @@ GEM
131
125
  byebug (~> 11.0)
132
126
  pry (~> 0.13.0)
133
127
  public_suffix (4.0.6)
134
- rainbow (3.0.0)
128
+ rainbow (3.1.1)
135
129
  rake (13.0.6)
136
- rb-fsevent (0.11.0)
130
+ rb-fsevent (0.11.1)
137
131
  rb-inotify (0.10.1)
138
132
  ffi (~> 1.0)
139
133
  rchardet (1.8.0)
140
- regexp_parser (2.1.1)
134
+ regexp_parser (2.2.1)
141
135
  rexml (3.2.5)
142
- rouge (3.26.1)
143
- rspec (3.10.0)
144
- rspec-core (~> 3.10.0)
145
- rspec-expectations (~> 3.10.0)
146
- rspec-mocks (~> 3.10.0)
147
- rspec-core (3.10.1)
148
- rspec-support (~> 3.10.0)
149
- rspec-expectations (3.10.1)
136
+ rouge (3.28.0)
137
+ rspec (3.11.0)
138
+ rspec-core (~> 3.11.0)
139
+ rspec-expectations (~> 3.11.0)
140
+ rspec-mocks (~> 3.11.0)
141
+ rspec-core (3.11.0)
142
+ rspec-support (~> 3.11.0)
143
+ rspec-expectations (3.11.0)
150
144
  diff-lcs (>= 1.2.0, < 2.0)
151
- rspec-support (~> 3.10.0)
152
- rspec-mocks (3.10.2)
145
+ rspec-support (~> 3.11.0)
146
+ rspec-mocks (3.11.0)
153
147
  diff-lcs (>= 1.2.0, < 2.0)
154
- rspec-support (~> 3.10.0)
155
- rspec-support (3.10.3)
156
- rubocop (1.23.0)
148
+ rspec-support (~> 3.11.0)
149
+ rspec-support (3.11.0)
150
+ rubocop (1.25.1)
157
151
  parallel (~> 1.10)
158
- parser (>= 3.0.0.0)
152
+ parser (>= 3.1.0.0)
159
153
  rainbow (>= 2.2.2, < 4.0)
160
154
  regexp_parser (>= 1.8, < 3.0)
161
155
  rexml
162
- rubocop-ast (>= 1.12.0, < 2.0)
156
+ rubocop-ast (>= 1.15.1, < 2.0)
163
157
  ruby-progressbar (~> 1.7)
164
158
  unicode-display_width (>= 1.4.0, < 3.0)
165
- rubocop-ast (1.13.0)
159
+ rubocop-ast (1.15.2)
166
160
  parser (>= 3.0.1.1)
167
- rubocop-performance (1.12.0)
161
+ rubocop-performance (1.13.2)
168
162
  rubocop (>= 1.7.0, < 2.0)
169
163
  rubocop-ast (>= 0.4.0)
170
164
  rubocop-rake (0.6.0)
171
165
  rubocop (~> 1.0)
172
- rubocop-rspec (2.6.0)
166
+ rubocop-rspec (2.8.0)
173
167
  rubocop (~> 1.19)
174
168
  ruby-progressbar (1.11.0)
175
169
  safe_yaml (1.0.5)
176
170
  sassc (2.4.0)
177
171
  ffi (~> 1.9)
178
- shoulda-matchers (5.0.0)
172
+ shoulda-matchers (5.1.0)
179
173
  activesupport (>= 5.2.0)
180
174
  simplecov (0.21.2)
181
175
  docile (~> 1.1)
@@ -200,7 +194,7 @@ GEM
200
194
  addressable (>= 2.8.0)
201
195
  crack (>= 0.3.2)
202
196
  hashdiff (>= 0.4.0, < 2.0.0)
203
- zeitwerk (2.5.1)
197
+ zeitwerk (2.5.4)
204
198
 
205
199
  PLATFORMS
206
200
  ruby
@@ -210,7 +204,6 @@ DEPENDENCIES
210
204
  factory_bot
211
205
  fakefs
212
206
  ffaker
213
- hcloud!
214
207
  jekyll
215
208
  kozo!
216
209
  overcommit
@@ -228,7 +221,7 @@ DEPENDENCIES
228
221
  webmock
229
222
 
230
223
  RUBY VERSION
231
- ruby 3.0.0p0
224
+ ruby 3.1.0p0
232
225
 
233
226
  BUNDLED WITH
234
- 2.2.22
227
+ 2.3.6
data/README.md CHANGED
@@ -6,6 +6,8 @@
6
6
  _Kōzō_ (構造) is an open-source tool to manage your cloud resources based on the [infrastructure as code](https://en.wikipedia.org/wiki/Infrastructure_as_code) principle.
7
7
  It leverages the power of [Ruby](https://www.ruby-lang.org/en/) to allow you to declare your infrastructure in your favourite language.
8
8
 
9
+ Read more about the project on [kozo.dev](https://kozo.dev).
10
+
9
11
  ## Installation
10
12
 
11
13
  Install the gem using your operating system's package manager, or using RubyGems:
data/kozo.gemspec CHANGED
@@ -29,12 +29,12 @@ Gem::Specification.new do |spec|
29
29
  "rubygems_mfa_required" => "true",
30
30
  }
31
31
 
32
- spec.add_runtime_dependency "activemodel", "~> 6.0"
33
- spec.add_runtime_dependency "activesupport", "~> 6.0"
32
+ spec.add_runtime_dependency "activesupport", ">= 6.0", "< 7.1"
34
33
  spec.add_runtime_dependency "colorize", "~> 0.8"
35
34
  spec.add_runtime_dependency "dinja", "~> 2.0"
36
35
  spec.add_runtime_dependency "dotenv", "~> 2.7"
37
36
  spec.add_runtime_dependency "git", "~> 1.9"
37
+ spec.add_runtime_dependency "hetznercloud", "~> 1.3"
38
38
  spec.add_runtime_dependency "zeitwerk", "~> 2.4"
39
39
 
40
40
  spec.add_development_dependency "rubocop"
@@ -5,6 +5,14 @@ module CoreExt
5
5
  def to_b
6
6
  self
7
7
  end
8
+
9
+ def as_h
10
+ self
11
+ end
12
+
13
+ def as_s
14
+ to_s
15
+ end
8
16
  end
9
17
  end
10
18
 
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoreExt
4
+ module Date
5
+ def as_h
6
+ iso8601
7
+ end
8
+
9
+ def as_s
10
+ iso8601
11
+ end
12
+ end
13
+ end
14
+
15
+ Date.prepend CoreExt::Date
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoreExt
4
+ module Enumerable
5
+ def intersperse(value)
6
+ flat_map { |h| [h, value] }.tap(&:pop)
7
+ end
8
+
9
+ def as_h
10
+ map(&:as_h)
11
+ end
12
+
13
+ def as_s
14
+ return "[]" if empty?
15
+
16
+ map { |k| " #{k.as_s}" }
17
+ .intersperse(",")
18
+ .each_slice(2)
19
+ .map(&:join)
20
+ .prepend("[")
21
+ .append("]")
22
+ .join("\n")
23
+ end
24
+ end
25
+ end
26
+
27
+ Enumerable.prepend CoreExt::Enumerable
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoreExt
4
+ module Float
5
+ def as_h
6
+ self
7
+ end
8
+
9
+ def as_s
10
+ to_s
11
+ end
12
+ end
13
+ end
14
+
15
+ Float.prepend CoreExt::Float
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoreExt
4
+ module Hash
5
+ def as_h
6
+ transform_values(&:as_h)
7
+ end
8
+
9
+ def as_s
10
+ return "{}" if empty?
11
+
12
+ map { |k, v| " #{k} = #{v.as_s}" }
13
+ .intersperse(",")
14
+ .each_slice(2)
15
+ .map(&:join)
16
+ .prepend("{")
17
+ .append("}")
18
+ .join("\n")
19
+ end
20
+ end
21
+ end
22
+
23
+ Hash.prepend CoreExt::Hash
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoreExt
4
+ module Integer
5
+ def as_h
6
+ self
7
+ end
8
+
9
+ def as_s
10
+ to_s
11
+ end
12
+ end
13
+ end
14
+
15
+ Integer.prepend CoreExt::Integer
@@ -5,6 +5,14 @@ module CoreExt
5
5
  def to_b
6
6
  self
7
7
  end
8
+
9
+ def as_h
10
+ self
11
+ end
12
+
13
+ def as_s
14
+ "nil"
15
+ end
8
16
  end
9
17
  end
10
18
 
@@ -16,9 +16,20 @@ module CoreExt
16
16
  ].freeze
17
17
  # rubocop:enable Lint/BooleanSymbol
18
18
 
19
+ # Maximum number of characters displayed
20
+ LENGTH = 75
21
+
19
22
  def to_b
20
23
  self == "" ? nil : FALSE_VALUES.exclude?(self)
21
24
  end
25
+
26
+ def as_h
27
+ self
28
+ end
29
+
30
+ def as_s
31
+ "\"#{chomp.tr("\n", ' ').truncate(LENGTH)}\""
32
+ end
22
33
  end
23
34
  end
24
35
 
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoreExt
4
+ module Symbol
5
+ delegate :as_h,
6
+ :as_s,
7
+ to: :to_s
8
+ end
9
+ end
10
+
11
+ Symbol.prepend CoreExt::Symbol
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CoreExt
4
+ module Time
5
+ def as_h
6
+ iso8601
7
+ end
8
+
9
+ def as_s
10
+ iso8601
11
+ end
12
+ end
13
+ end
14
+
15
+ Time.prepend CoreExt::Time
16
+ ActiveSupport::TimeWithZone.prepend CoreExt::Time
data/lib/kozo/backend.rb CHANGED
@@ -9,9 +9,9 @@ module Kozo
9
9
  @directory = directory
10
10
  end
11
11
 
12
- def state
12
+ def state(verify: true)
13
13
  @state ||= State
14
- .new(resources)
14
+ .new(resources, data[:version], verify: verify)
15
15
  end
16
16
 
17
17
  def state=(value)
@@ -20,17 +20,6 @@ module Kozo
20
20
  self.data = value.to_h
21
21
  end
22
22
 
23
- def validate!
24
- state_version = data.fetch(:version)
25
- kozo_version = data.fetch(:kozo_version)
26
-
27
- raise StateError, "invalid version in state: got #{state_version}, expected #{State::VERSION}" unless state_version == State::VERSION
28
-
29
- return if kozo_version == Kozo::VERSION
30
-
31
- raise StateError, "invalid kozo version in state: got #{kozo_version}, expected #{Kozo::VERSION}"
32
- end
33
-
34
23
  ##
35
24
  # Create necessary backend files/structures if they do not exist
36
25
  #
@@ -21,7 +21,7 @@ module Kozo
21
21
  end
22
22
 
23
23
  def data=(value)
24
- super
24
+ return unless super
25
25
 
26
26
  git.add(file)
27
27
  git.commit("Update Kozo resource state")
@@ -8,6 +8,7 @@ module Kozo
8
8
  class Local < Kozo::Backend
9
9
  attr_writer :file
10
10
  attr_accessor :backups
11
+ attr_reader :fingerprint
11
12
 
12
13
  def initialize(configuration, directory)
13
14
  super
@@ -28,7 +29,7 @@ module Kozo
28
29
  Kozo.logger.debug "Reading local state in #{path}"
29
30
 
30
31
  YAML
31
- .safe_load(File.read(path), [Time, Date])
32
+ .safe_load(File.read(path), permitted_classes: [Time, Date])
32
33
  .deep_symbolize_keys
33
34
  rescue Errno::ENOENT, Errno::ENOTDIR
34
35
  raise StateError, "local state at #{path} not initialized"
@@ -39,13 +40,20 @@ module Kozo
39
40
  def data=(value)
40
41
  Kozo.logger.debug "Writing local state in #{path}"
41
42
 
43
+ return if @data.hash == value.hash
44
+
42
45
  @data = value
43
46
 
47
+ return if Kozo.options.dry_run?
48
+
49
+ # Write local state to temporary file
50
+ File.write("#{path}.tmp", value.deep_stringify_keys.to_yaml)
51
+
44
52
  # Write backup state file
45
- FileUtils.mv(path, "#{path}.#{DateTime.current.to_i}.kzbackup") if backups
53
+ FileUtils.mv(path, "#{path}.#{DateTime.current.to_i}.kzbackup") if backups && File.exist?(path)
46
54
 
47
- # Write local state file
48
- File.write(path, value.deep_stringify_keys.to_yaml)
55
+ # Move temporary file to local state file
56
+ FileUtils.mv("#{path}.tmp", path)
49
57
  end
50
58
 
51
59
  def file
data/lib/kozo/cli.rb CHANGED
@@ -12,6 +12,8 @@ module Kozo
12
12
  o.on("Global options:")
13
13
  o.on("-d", "--directory=DIRECTORY", "Set working directory")
14
14
  o.on("-v", "--verbose", "Turn on verbose logging")
15
+ o.on("-D", "--debug", "Turn on debug logging")
16
+ o.on("-n", "--dry_run", "Dry run all operations")
15
17
  o.on("-h", "--help", "Display this message") { usage }
16
18
  o.separator("\n")
17
19
  o.on("Commands:")
@@ -51,8 +53,14 @@ module Kozo
51
53
 
52
54
  raise UsageError, "unknown command: #{command}" unless klass
53
55
 
56
+ configuration = Parser
57
+ .new(Kozo.options.directory)
58
+ .call
59
+
60
+ Kozo.logger.info "Dry running all operations" if Kozo.options.dry_run?
61
+
54
62
  klass
55
- .new(*command_args)
63
+ .new(configuration, *command_args)
56
64
  .start
57
65
  rescue UsageError => e
58
66
  # Don't print tail if no message was passed
@@ -73,11 +81,11 @@ module Kozo
73
81
  end
74
82
 
75
83
  def commands
76
- Command.subclasses.sort_by(&:name).map do |k|
84
+ Command.descendants.select { |d| d.module_parent == Commands }.sort_by(&:name).map do |k|
77
85
  [
78
86
  k.name.demodulize.underscore,
79
87
  k.description,
80
- k.descendants.sort_by(&:name).map { |s| [s.name.demodulize.underscore, s.description] },
88
+ k.constants.sort_by(&:name).map { |s| [s.to_s.underscore, k.const_get(s).description] },
81
89
  ]
82
90
  end
83
91
  end
data/lib/kozo/command.rb CHANGED
@@ -5,9 +5,10 @@ module Kozo
5
5
  class_attribute :description
6
6
 
7
7
  attr_reader :args
8
- attr_writer :state, :configuration
8
+ attr_accessor :configuration
9
9
 
10
- def initialize(*args)
10
+ def initialize(configuration, *args)
11
+ @configuration = configuration
11
12
  @args = args
12
13
  end
13
14
 
@@ -15,18 +16,8 @@ module Kozo
15
16
  raise NotImplementedError
16
17
  end
17
18
 
18
- protected
19
-
20
- def configuration
21
- @configuration ||= Parser
22
- .new(Kozo.options.directory)
23
- .call
24
- end
25
-
26
- def state
27
- @state ||= configuration
28
- .backend
29
- .state
30
- end
19
+ delegate :state,
20
+ :changes,
21
+ to: :configuration
31
22
  end
32
23
  end
@@ -7,8 +7,8 @@ module Kozo
7
7
 
8
8
  attr_reader :parser, :options
9
9
 
10
- def initialize(*args)
11
- super()
10
+ def initialize(configuration, *args)
11
+ super(configuration)
12
12
 
13
13
  @options = {
14
14
  yes: false,
@@ -7,7 +7,9 @@ module Kozo
7
7
 
8
8
  attr_reader :address, :id
9
9
 
10
- def initialize(*args)
10
+ def initialize(configuration, *args)
11
+ super(configuration)
12
+
11
13
  address = args.shift
12
14
 
13
15
  raise UsageError, "address not specified" unless address
@@ -30,7 +32,7 @@ module Kozo
30
32
 
31
33
  # Set ID and fetch attributes
32
34
  resource
33
- .tap { |r| r.id = id }
35
+ .tap { |r| r.send(:id=, id) }
34
36
  .refresh!
35
37
 
36
38
  # Add or replace resource to in-memory state