omnibus 3.1.1 → 3.2.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +71 -0
  3. data/Gemfile +0 -7
  4. data/README.md +108 -36
  5. data/Rakefile +1 -5
  6. data/docs/omnibus-build-cache.md +5 -5
  7. data/features/commands/_deprecated.feature +21 -3
  8. data/features/step_definitions/generator_steps.rb +7 -7
  9. data/lib/omnibus.rb +232 -171
  10. data/lib/omnibus/build_version.rb +2 -2
  11. data/lib/omnibus/builder.rb +38 -19
  12. data/lib/omnibus/cleaner.rb +5 -5
  13. data/lib/omnibus/cleanroom.rb +141 -0
  14. data/lib/omnibus/cli.rb +6 -9
  15. data/lib/omnibus/cli/base.rb +2 -1
  16. data/lib/omnibus/cli/cache.rb +15 -21
  17. data/lib/omnibus/cli/deprecated.rb +40 -4
  18. data/lib/omnibus/cli/publish.rb +61 -0
  19. data/lib/omnibus/config.rb +350 -189
  20. data/lib/omnibus/digestable.rb +131 -0
  21. data/lib/omnibus/exceptions.rb +163 -83
  22. data/lib/omnibus/fetcher.rb +1 -1
  23. data/lib/omnibus/fetchers/net_fetcher.rb +19 -13
  24. data/lib/omnibus/fetchers/path_fetcher.rb +8 -1
  25. data/lib/omnibus/fetchers/s3_cache_fetcher.rb +16 -7
  26. data/lib/omnibus/generator.rb +2 -2
  27. data/lib/omnibus/generator_files/Gemfile.erb +4 -1
  28. data/lib/omnibus/generator_files/README.md.erb +10 -0
  29. data/lib/omnibus/generator_files/{omnibus.rb.example.erb → omnibus.rb.erb} +20 -11
  30. data/lib/omnibus/generator_files/package_scripts/makeselfinst.erb +1 -1
  31. data/lib/omnibus/generator_files/project.rb.erb +2 -2
  32. data/lib/omnibus/generator_files/windows_msi/localization-en-us.wxl.erb +3 -3
  33. data/lib/omnibus/git_cache.rb +192 -0
  34. data/lib/omnibus/health_check.rb +171 -116
  35. data/lib/omnibus/library.rb +4 -2
  36. data/lib/omnibus/logger.rb +60 -1
  37. data/lib/omnibus/null_argumentable.rb +51 -0
  38. data/lib/omnibus/ohai.rb +29 -8
  39. data/lib/omnibus/package.rb +240 -0
  40. data/lib/omnibus/packagers/base.rb +21 -42
  41. data/lib/omnibus/packagers/mac_dmg.rb +5 -5
  42. data/lib/omnibus/packagers/mac_pkg.rb +20 -19
  43. data/lib/omnibus/packagers/windows_msi.rb +7 -7
  44. data/lib/omnibus/project.rb +969 -486
  45. data/lib/omnibus/publisher.rb +76 -0
  46. data/lib/omnibus/publishers/artifactory_publisher.rb +168 -0
  47. data/lib/omnibus/publishers/null_publisher.rb +23 -0
  48. data/lib/omnibus/publishers/s3_publisher.rb +99 -0
  49. data/lib/omnibus/s3_cache.rb +150 -63
  50. data/lib/omnibus/software.rb +749 -321
  51. data/lib/omnibus/{sugar.rb → sugarable.rb} +11 -6
  52. data/lib/omnibus/version.rb +1 -1
  53. data/omnibus.gemspec +8 -8
  54. data/spec/data/complicated/config/projects/angrychef.rb +1 -1
  55. data/spec/data/complicated/config/projects/chef-windows.rb +1 -1
  56. data/spec/data/complicated/config/projects/chef.rb +1 -1
  57. data/spec/data/complicated/config/projects/chefdk-windows.rb +1 -1
  58. data/spec/data/complicated/config/projects/chefdk.rb +1 -1
  59. data/spec/data/complicated/config/software/cacerts.rb +1 -1
  60. data/spec/data/complicated/config/software/chef-client-msi.rb +1 -1
  61. data/spec/data/complicated/config/software/libgcc.rb +1 -1
  62. data/spec/data/complicated/config/software/libiconv.rb +0 -11
  63. data/spec/data/complicated/config/software/libpng.rb +2 -2
  64. data/spec/data/complicated/config/software/openssl.rb +1 -1
  65. data/spec/data/complicated/config/software/ruby.rb +1 -1
  66. data/spec/data/complicated/config/software/runit.rb +4 -4
  67. data/spec/data/projects/chefdk.rb +1 -1
  68. data/spec/data/projects/sample.rb +1 -1
  69. data/spec/data/software/erchef.rb +3 -1
  70. data/spec/functional/packagers/mac_spec.rb +25 -24
  71. data/spec/functional/packagers/windows_spec.rb +21 -20
  72. data/spec/spec_helper.rb +43 -4
  73. data/spec/unit/build_version_spec.rb +14 -16
  74. data/spec/unit/cleanroom_spec.rb +63 -0
  75. data/spec/unit/config_spec.rb +36 -30
  76. data/spec/unit/digestable_spec.rb +38 -0
  77. data/spec/unit/fetchers/net_fetcher_spec.rb +98 -87
  78. data/spec/unit/{install_path_cache_spec.rb → git_cache_spec.rb} +67 -56
  79. data/spec/unit/health_check_spec.rb +73 -0
  80. data/spec/unit/library_spec.rb +166 -159
  81. data/spec/unit/ohai_spec.rb +19 -0
  82. data/spec/unit/omnibus_spec.rb +43 -41
  83. data/spec/unit/package_spec.rb +178 -0
  84. data/spec/unit/packagers/base_spec.rb +17 -47
  85. data/spec/unit/packagers/mac_pkg_spec.rb +104 -126
  86. data/spec/unit/project_spec.rb +176 -25
  87. data/spec/unit/publisher_spec.rb +49 -0
  88. data/spec/unit/publishers/artifactory_publisher_spec.rb +80 -0
  89. data/spec/unit/publishers/s3_publisher_spec.rb +120 -0
  90. data/spec/unit/s3_cacher_spec.rb +84 -19
  91. data/spec/unit/software_spec.rb +397 -170
  92. data/spec/unit/sugarable_spec.rb +43 -0
  93. metadata +62 -50
  94. data/Guardfile +0 -10
  95. data/lib/omnibus/artifact.rb +0 -165
  96. data/lib/omnibus/cli/release.rb +0 -40
  97. data/lib/omnibus/generator_files/Vagrantfile.erb +0 -75
  98. data/lib/omnibus/install_path_cache.rb +0 -105
  99. data/lib/omnibus/overrides.rb +0 -88
  100. data/lib/omnibus/package_release.rb +0 -154
  101. data/lib/omnibus/software_s3_urls.rb +0 -50
  102. data/spec/unit/artifact_spec.rb +0 -91
  103. data/spec/unit/overrides_spec.rb +0 -102
  104. data/spec/unit/package_release_spec.rb +0 -180
  105. data/spec/unit/sugar_spec.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 47494584e1a03e4d60e11d7e184ef6fdacfb3fcf
4
- data.tar.gz: 6afbd1c06cb80f127ed9d1ef153e6cc66e41a41f
3
+ metadata.gz: 4812c396c2ec933378d32542df7c8245700ecf52
4
+ data.tar.gz: 51791434059dcada2197bf2bb8693e6c080669f2
5
5
  SHA512:
6
- metadata.gz: 909e063a81130bc42ddcda0ec238276768b40a12089b26e9ef98ae422ab1ec19cc2b9a888964ef22930d7ce77293dfd2696d4dd8b8d9a2a8ec617d8c88e38f1f
7
- data.tar.gz: 627dbb3379bf4642618770455455a977cdf7256c6d97c0e88d50ec999defc77ad532616cb782fe41295fc227613ee672df82718e1b530b837623ac6b5f33e19b
6
+ metadata.gz: 805e85738934c39e9d849fa6dd93d0877b17c60aab484e788616e1e143bd72df59971a8fce9c02cc15f2c3402717a565883425058a6fba20c0e3231c4508a6c8
7
+ data.tar.gz: 9351cf29fb353525d4e705bd0fdde1884ccaac3d393c3c78b96ed88f6963467a92ed32b40f5aad9e8ef7ccda0e460df0a8ed0954b39818e2d0a715d96261aca6
@@ -1,6 +1,77 @@
1
1
  Omnibus Ruby CHANGELOG
2
2
  ======================
3
3
 
4
+ v3.2.0.rc.1 (July 14, 2014)
5
+ -----------==--------------
6
+ - Make build commands output during `log.info` instead of `log.debug`
7
+ - Refactor Chef Sugar into an includable module, permitting DSL methods in both Software and Project definitions
8
+ - Refactor `omnibus release` into a non-S3-specific backend "publisher"
9
+ - Add support for specifying a dir glob to the `publish` command to upload multiple packages
10
+ - "Package" is now a public API
11
+ - Generate a real omnibus configuration file (no more `omnibus.rb.example`)
12
+ - Add a releaser for Artifactory
13
+ - Add additional information to package metdata (such as shasums)
14
+ - Remove uses of Omnibus.config and use the Config object directly
15
+ - Add the ability to define multiple `software_gems` in the config
16
+ - Add the ability to define `local_software_paths` in the config
17
+ - Add the ability to disable git caching in the config
18
+ - Omnibus.load_configuration now requires a file path
19
+ - Add new API for loading a project - `Project.load`
20
+ - Add new API for loading a software - `Software.load`
21
+ - Add publish APIs for dirtying the git cache
22
+ - Add test coverage for the "public" API
23
+ - Add validation to `source` in software DSL
24
+ - Update generator templates to use the new APIs
25
+ - Upgrade to Ohai 7.2
26
+ - Improve YARDoc
27
+
28
+ ### Deprecations
29
+ - Remove deprecated `Omnibus.configure` method
30
+ - Deprecate `Omnibus.config.value` in favor of `Config.value` instead
31
+ - Deprecate `Omnibus.project_root` in favor of `Config.project_root`
32
+ - Deprecate [DSL] `platform` in favor of `Ohai['platform']`
33
+ - Deprecate [DSL] `platform_family` in favor of `Ohai['platform_family']`
34
+ - Deprecate [DSL] `platform_version` in favor of `Ohai['platform_version']`
35
+ - Deprecate [DSL] `build_dir` in favor of `Config.build_dir`
36
+ - Deprecate [DSL] `cache_dir` in favor of `Config.cache_dir`
37
+ - Deprecate [DSL] `source_dir` in favor of `Config.source_dir`
38
+ - Deprecate [DSL] `config` in favor of `Config` (capitalized)
39
+ - Deprecate `Ohai.value` in favor of `Ohai['value']`
40
+ - Deprecate `Project#install_path` in favor of `Project.install_dir`
41
+ - Deprecate [DSL] `install_path` in favor of `install_dir`
42
+ - Rename `Config.install_path_cache_dir` to `git_cache_dir`
43
+
44
+ ### DSL Changes
45
+ - Add `with_embedded_path` to software
46
+ - Add `with_standard_compiler_flags` to software
47
+ - Add `package_scripts_path` to project
48
+
49
+ ### Bug fixes
50
+ - Fix a small typo in the project generator (come -> some)
51
+ - Update sample software definition for libpng to 1.5.18
52
+ - Improved logging output
53
+ - Include Chef Sugar in both software and project DSLs
54
+ - Documentation updates and typographical fixes
55
+ - Change the generated omnibus.rb to use a default homepage that includes the protocol
56
+ - Ensure that software fetched via the PathFetcher are cached correctly
57
+ - Downgrade FPM to ~> 0.4 - FPM 1.0.0+ uses FFI to attach to some libc functions. This fails on RHEL 5 & 6. As we don’t need a bleeding edge FPM the easiest fix is to just downgrade to the most recent pre-1.0.0 version.
58
+ - Always print backtraces when errors occur
59
+ - Do not sent ldd/otool to the same file - first steps in allowing parallel builds
60
+ - Only rescue `Omnibus::Error` when invoked through the CLI - this will allow other bugs to actually raise at the Ruby level
61
+ - Refactor the algorithm for git caching to take into account overrides and missing versions
62
+ - Remove nested git directories before incremental caching occurs
63
+ - Intelligently parse the project's homepage because Ruby's native URI implementation is buggy
64
+ - Fetch all software at the start of the build - this fixes a bug where a build would fail halfway through because of a tiny typo of GitHub outage. Now, all required software is downloaded **before** the build starts, lowering the feedback time for a failure due to networking issues
65
+ - Use the fetcher's `version_for_cache` method directly, falling back to `0.0.0` (and a warining) if no version is given
66
+
67
+ ### Potentially breaking changes
68
+ - Merged `Package` and `Artifact` into the same class and updated API - this was considered an **internal** API so it is not a violation of semver
69
+ - Use a common class for Omnibus exceptions - if you were rescuing Omnibus::Error, you might be rescuing all exceptions now
70
+ - Use a cleanroom object when evaluating the DSL - prior to this release, Omnibus did not declare a public API. Project and software definitions had unrestricted access to the entire project.rb and software.rb methods respectively. This poses two problems - first, it makes it impossible to guarantee a public DSL API over a public (code) API. Second, it permits a developer to change the behavior of project.rb or software.rb accidentially, simply by defining a new method. The introducing of a cleanroom fixes both these bugs, however, it was impossible to know what was formerly considered a public API. Thus, it is possible that a previously-relied-on method is now unavaiable using the cleanroom. Please open an issue if you encounter such a case.
71
+ - Remove mixlib-config - if you were relying on mixlib-config as a transitive dependency, it is no longer available
72
+ - Remove the ability to use an overrides file - this was for internal use only and was never exposed as a public API. However, if you dug into the code and found it, it has now been removed. For BC purposes, the value still exists in the configuration object, but is essentially a no-op
73
+
74
+
4
75
  v3.1.1 (May 20, 2014)
5
76
  ---------------------
6
77
  - Update project generators to use new APIs. The old project generators created a project that issued deprecation warnings!
data/Gemfile CHANGED
@@ -6,10 +6,3 @@ group :docs do
6
6
  gem 'redcarpet', '~> 2.2.2'
7
7
  gem 'github-markup', '~> 0.7'
8
8
  end
9
-
10
- group :local do
11
- gem 'guard'
12
- gem 'guard-rspec'
13
- gem 'guard-rubocop'
14
- gem 'ruby_gntp'
15
- end
data/README.md CHANGED
@@ -47,7 +47,9 @@ $ bundle install --binstubs
47
47
  $ bin/omnibus build $MY_PROJECT_NAME
48
48
  ```
49
49
 
50
- More details can be found in the generated project README file.
50
+ More details can be found in the generated project's README file.
51
+
52
+ Omnibus determines the platform for which to build an installer based on **the platform it is currently running on**. That is, you can only generate a `.deb` file on a Debian-based system. To alleviate this caveat, the generated project includes a [Test Kitchen](http://kitchen.ci) setup suitable for generating a series of Omnibus projects.
51
53
 
52
54
 
53
55
  More documentation
@@ -56,18 +58,79 @@ If you are creating OSX packages, please see the [OSX-specific documentation](do
56
58
 
57
59
 
58
60
  Configuration DSL
59
- ------------------
60
- Though the template project will build, it won't do anything exciting. For that, you'll need to use the Omnibus DSL to define the specifics of your own application.
61
+ -----------------
62
+ Though the template project will build, it will not do anything exciting. For that, you need to use the Omnibus DSL to define the specifics of your application.
63
+
64
+ ### Config
65
+ If present, Omnibus will use a top-level configuration file named `omnibus.rb` at the root of your repository. This file is loaded at runtime and includes a number of configuration tunables. Here is an example:
66
+
67
+ ```ruby
68
+ # Build locally (instead of /var)
69
+ # -------------------------------
70
+ base_dir './local'
71
+
72
+ # Disable git caching
73
+ # ------------------------------
74
+ use_git_caching false
75
+
76
+ # Enable S3 asset caching
77
+ # ------------------------------
78
+ use_s3_caching true
79
+ s3_access_key ENV['S3_ACCESS_KEY']
80
+ s3_secret_key ENV['S3_SECRET_KEY']
81
+ s3_bucket ENV['S3_BUCKET']
82
+ ```
83
+
84
+ For more information, please see the [`Config` documentation](http://rubydoc.info/github/opscode/omnibus-ruby/Omnibus/Config).
85
+
86
+ You can tell Omnibus to load a difference configuration file by passing the `--config` option to any command:
87
+
88
+ ```shell
89
+ $ bin/omnibus --config /path/to/config.rb
90
+ ```
91
+
92
+ Finally, you can override a specific configuration option at the command line using the `--override` flag. This takes ultimate precedence over any configuration file values:
93
+
94
+ ```shell
95
+ $ bin/omnibus --override use_git_caching:false
96
+ ```
97
+
98
+ ### Projects
99
+ A Project DSL file defines your actual application; this is the thing you are creating a full-stack installer for in the first place. It provides a means to define the dependencies of the project (again, as specified in Software DSL definition files), as well as ways to set installer package metadata.
100
+
101
+ All project definitions must be in the `config/projects` directory of your Omnibus repository.
102
+
103
+ ```ruby
104
+ name 'chef-full'
105
+ maintainer 'YOUR NAME'
106
+ homepage 'http://yoursite.com'
107
+
108
+ install_dir '/opt/chef'
109
+ build_version '0.10.8'
110
+ build_iteration 4
111
+
112
+ dependency 'chef'
113
+ ```
114
+
115
+ Some DSL methods available include:
116
+
117
+ | DSL Method | Description |
118
+ | :---------------: | --------------------------------------------|
119
+ | `name` | The name of the project |
120
+ | `install_dir` | The desired install location of the package |
121
+ | `build_version` | The package version |
122
+ | `build_iteration` | The package iteration number |
123
+ | `dependency` | An Omnibus software-defined component to include in this package |
124
+
125
+ For more information, please see the [`Project` documentation](http://rubydoc.info/github/opscode/omnibus-ruby/Omnibus/Project).
126
+
61
127
 
62
128
  ### Software
63
129
  Omnibus "software" files define individual software components that go into making your overall package. They are the building blocks of your application. The Software DSL provides a way to define where to retrieve the software sources, how to build them, and what dependencies they have. These dependencies are also defined in their own Software DSL files, thus forming the basis for a dependency-aware build ordering.
64
130
 
65
131
  All Software definitions should go in the `config/software` directory of your Omnibus project repository.
66
132
 
67
- CHEF has created software definitions for a number of commonly-needed components, available in the [omnibus-software](https://github.com/opscode/omnibus-software.git)
68
- repository. When you create a new project skeleton using Omnibus, this is automatically added to the project's Gemfile, making all these software definitions available to you. (If you prefer, however, you can write your own versions of these same definitions in your project repository; local copies in `config/software` have precedence over anything from the `omnibus-software` repository.)
69
-
70
- An example:
133
+ Here is an example:
71
134
 
72
135
  ```ruby
73
136
  name 'ruby'
@@ -118,48 +181,48 @@ version '2.1.1' do
118
181
  end
119
182
  ```
120
183
 
121
- Since the software definitions are simply ruby code, you can conditionally execute anything by wrapping it with pure ruby that tests for the version number.
184
+ Since the software definitions are simply ruby code, you can conditionally execute anything by wrapping it with pure Ruby that tests for the version number.
122
185
 
123
- For more DSL methods, please consult the documentation.
186
+ For more DSL methods, please consult the [`Software` documentation](http://rubydoc.info/github/opscode/omnibus-ruby/Omnibus/Software).
124
187
 
125
- ### Projects
126
- A Project DSL file defines your actual application; this is the thing you are creating a full-stack installer for in the first place. It provides a means to define the dependencies of the project (again, as specified in Software DSL definition files), as well as ways to set installer package metadata.
188
+ #### Sharing software definitions
189
+ The easiest way to share organization-wide software is via bundler and Rubygems. For an example software repository, look at Chef's [omnibus-software](https://github.com/opscode/omnibus-software). For more information, please see the [Rubygems documentation](http://guides.rubygems.org/publishing/).
127
190
 
128
- All Project definitions (yes, you can have more than one) should go in the `config/projects` directory of your Omnibus project repository.
191
+ It is recommended you use bundler to pull down these gems (as bundler also permits pulling softare directly from GitHub):
129
192
 
130
193
  ```ruby
131
- name 'chef-full'
132
- maintainer 'YOUR NAME'
133
- homepage 'http://yoursite.com'
194
+ gem 'my-company-omnibus-software'
195
+ gem 'omnibus-software', github: 'my-company/omnibus-software'
196
+ ```
134
197
 
135
- install_path '/opt/chef'
136
- build_version '0.10.8'
137
- build_iteration 4
198
+ Then add the name of the software to the list of `software_gems` in your Omnibus config:
138
199
 
139
- dependency 'chef'
200
+ ```ruby
201
+ software_gems %w(my-company-omnibus-software omnibus-software)
140
202
  ```
141
203
 
142
- Some DSL methods available include:
204
+ You may also specify local paths on disk (but be warned this may make sharing the project among teams difficult):
143
205
 
144
- | DSL Method | Description |
145
- | :---------------: | --------------------------------------------|
146
- | `name` | The name of the project |
147
- | `install_path` | The desired install location of the package |
148
- | `build_version` | The package version |
149
- | `build_iteration` | The package iteration number |
150
- | `dependency` | An Omnibus software-defined component to include in this package |
206
+ ```ruby
207
+ local_software_dirs %w(/path/to/software /other/path/to/software)
208
+ ```
151
209
 
152
- For more information, please see the documentation.
210
+ For all of these paths, **order matters**, so it is possible to depend on local software version while still retaining a remote software repo. Given the above example, Omnibus will search for a software definition named `foo` in this order:
153
211
 
154
212
 
155
- Caveats
156
- -------
157
- ### A note on builds
158
- As stated above, the generated project skeleton can run "as-is". However, Omnibus determines the platform for which to build an installer based on *the platform it is currently running on*. That is, you can only generate a `.deb` file for Ubuntu if you're actually running Omnibus *on Ubuntu*.
213
+ ```text
214
+ $PWD/config/software/foo.rb
215
+ /path/to/software/config/software/foo.rb
216
+ /other/path/to/software/config/software/foo.rb
217
+ /Users/sethvargo/.gems/.../my-comany-omnibus-software/config/software/foo.rb
218
+ /Users/sethvargo/.gems/.../omnibus-software/config/software/foo.rb
219
+ ```
159
220
 
160
- This is currently achieved using [Test Kitchen](http://kitchen.ci), which is included with any newly generated Omnibus project.
221
+ The first instance of `foo.rb` that is encountered will be used. Please note that **local** (vendored) softare definitions take precedence!
161
222
 
162
223
 
224
+ Caveats
225
+ -------
163
226
  ### Overrides
164
227
  The project definitions can override specific software dependencies by passing in `override` to use the correct version:
165
228
 
@@ -173,12 +236,21 @@ override :chef, version: '2.1.1'
173
236
  dependency 'chef'
174
237
  ```
175
238
 
176
- There is no checking that the version override that you supply has been provided in a version override block in the software definition.
239
+ **The overridden version must be defined in the associated software!**
240
+
241
+ ### Debugging
242
+ By default, Omnibus will log at the `warn` level. You can override this by passing the `--log-level` flag to your Omnibus call:
243
+
244
+ ```shell
245
+ $ bin/omnibus build <project> --log-level info // or 'debug'
246
+ ```
177
247
 
178
248
  ### Git caching
179
- As of Omnibus 3.0.0, projects are no longer built using rake. Instead, we have rewritten the software dependencies to leverage git caching. This means we cache compiled software definitions, so future Omnibus project builds are much faster.
249
+ by default, Omnibus caches compiled software definitions, so n+1 Omnibus project builds are much faster. This functionality can be disabled by adding the following to your `omnibus.rb`:
180
250
 
181
- For more information on potential breaking changes, please see the CHANGELOG entry for Omnibus 3.0.0.
251
+ ```ruby
252
+ use_git_caching false
253
+ ```
182
254
 
183
255
 
184
256
  License
data/Rakefile CHANGED
@@ -20,13 +20,9 @@ Cucumber::Rake::Task.new(:acceptance) do |t|
20
20
  end.join(' ')
21
21
  end
22
22
 
23
- require 'rubocop/rake_task'
24
- desc 'Run Ruby style checks'
25
- Rubocop::RakeTask.new(:style)
26
-
27
23
  namespace :travis do
28
24
  desc 'Run tests on Travis'
29
- task ci: %w(unit acceptance style)
25
+ task ci: %w(unit acceptance)
30
26
  end
31
27
 
32
28
  task default: %w(travis:ci)
@@ -5,7 +5,7 @@ reduces the time it takes to rebuild a project when only a few
5
5
  components need to be rebuilt.
6
6
 
7
7
  The cache uses git to snapshot the project tree after each software
8
- component build. The entire contents of the project's `install_path`
8
+ component build. The entire contents of the project's `install_dir`
9
9
  is included in the snaphot.
10
10
 
11
11
  When rebuilding, omnibus walks the linearized component list and
@@ -18,11 +18,11 @@ config/software/$COMPONENT).
18
18
 
19
19
  The default location of the cache (which is just a bare git
20
20
  repository) is
21
- `/var/cache/omnibus/cache/install_path/$INSTALL_PATH`. You can
21
+ `/var/cache/omnibus/cache/git_cache/$INSTALL_DIR`. You can
22
22
  customize the location of the cache in the `omnibus.rb` config file
23
- using the key `install_path_cache_dir`. For example:
23
+ using the key `git_cache_dir`. For example:
24
24
 
25
- install_path_cache_dir "/opt/ominbus-caches"
25
+ git_cache_dir "/opt/ominbus-caches"
26
26
 
27
27
  ## How It Works ##
28
28
 
@@ -44,7 +44,7 @@ component list, you want to have your most frequently changed
44
44
  components last to minimize rebuild churn.
45
45
 
46
46
  Lightweight git tags are used as cache keys. After building a
47
- component, a tag name is computed in `install_path_cache.rb#tag`. The
47
+ component, a tag name is computed in `GitCache#tag`. The
48
48
  tag name has the format `#{name}-#{version}-#{digest}` where name and
49
49
  version map to the component that was just built and digest is a
50
50
  SHA256 value. The digest is computed by string-ifying the name/version
@@ -1,7 +1,4 @@
1
1
  Feature: Backwards-compatible deprecated commands
2
- Background:
3
- * I have an omnibus project named "hamlet"
4
-
5
2
  Scenario: When "build project" is given
6
3
  * I run `omnibus build project hamlet`
7
4
  * the output should contain:
@@ -64,3 +61,24 @@ Feature: Backwards-compatible deprecated commands
64
61
  """
65
62
  The environment variable 'OMNIBUS_APPEND_TIMESTAMP' is deprecated. Please use '--override append_timestamp:false' instead.
66
63
  """
64
+
65
+ Scenario: When "release package" is given
66
+ * I run `omnibus release package /path/to/package`
67
+ * the output should contain:
68
+ """
69
+ The interface for releasing a project has changed. Please use 'omnibus publish BACKEND [COMAMND]' instead.
70
+ """
71
+
72
+ Scenario: When "release package --public" is given
73
+ * I run `omnibus release package /path/to/package --public`
74
+ * the output should contain:
75
+ """
76
+ The '--public' option has been deprecated! Please use '--acl public' instead.
77
+ """
78
+
79
+ Scenario: When "release package --no-public" is given
80
+ * I run `omnibus release package /path/to/package --no-public`
81
+ * the output should contain:
82
+ """
83
+ The '--no-public' option has been deprecated! Please use '--acl private' instead.
84
+ """
@@ -8,7 +8,7 @@ Given(/^I have an omnibus project named "(.+)"$/) do |name|
8
8
  name '#{name}'
9
9
  maintainer 'Mrs. Maintainer'
10
10
  homepage 'https://example.com'
11
- install_path './local/build/#{name}'
11
+ install_dir './local/build/#{name}'
12
12
 
13
13
  build_version '1.0.0'
14
14
 
@@ -18,11 +18,11 @@ Given(/^I have an omnibus project named "(.+)"$/) do |name|
18
18
 
19
19
  write_file('omnibus.rb', <<-EOH.gsub(/^ {4}/, ''))
20
20
  # Build configuration
21
- cache_dir './local/omnibus/cache'
22
- install_path_cache_dir './local/omnibus/cache/install_path'
23
- source_dir './local/omnibus/src'
24
- build_dir './local/omnibus/build'
25
- package_dir './local/omnibus/pkg'
26
- package_tmp './local/omnibus/pkg-tmp'
21
+ cache_dir './local/omnibus/cache'
22
+ git_cache_dir './local/omnibus/cache/git_cache'
23
+ source_dir './local/omnibus/src'
24
+ build_dir './local/omnibus/build'
25
+ package_dir './local/omnibus/pkg'
26
+ package_tmp './local/omnibus/pkg-tmp'
27
27
  EOH
28
28
  end
@@ -15,6 +15,7 @@
15
15
  #
16
16
 
17
17
  require 'pathname'
18
+ require 'json'
18
19
 
19
20
  require 'omnibus/exceptions'
20
21
  require 'omnibus/version'
@@ -25,46 +26,51 @@ module Omnibus
25
26
  #
26
27
  # @return [String]
27
28
  #
28
- DEFAULT_CONFIG = 'omnibus.rb'
29
+ DEFAULT_CONFIG = 'omnibus.rb'.freeze
29
30
 
30
- autoload :Artifact, 'omnibus/artifact'
31
31
  autoload :Builder, 'omnibus/builder'
32
32
  autoload :BuildVersion, 'omnibus/build_version'
33
33
  autoload :BuildVersionDSL, 'omnibus/build_version_dsl'
34
34
  autoload :Cleaner, 'omnibus/cleaner'
35
+ autoload :Cleanroom, 'omnibus/cleanroom'
35
36
  autoload :Config, 'omnibus/config'
37
+ autoload :Digestable, 'omnibus/digestable'
36
38
  autoload :Error, 'omnibus/exceptions'
37
39
  autoload :Fetcher, 'omnibus/fetcher'
38
40
  autoload :Generator, 'omnibus/generator'
41
+ autoload :GitCache, 'omnibus/git_cache'
39
42
  autoload :HealthCheck, 'omnibus/health_check'
40
- autoload :InstallPathCache, 'omnibus/install_path_cache'
41
43
  autoload :Library, 'omnibus/library'
42
44
  autoload :Logger, 'omnibus/logger'
43
45
  autoload :Logging, 'omnibus/logging'
46
+ autoload :NullArgumentable, 'omnibus/null_argumentable'
44
47
  autoload :NullBuilder, 'omnibus/null_builder'
45
48
  autoload :Ohai, 'omnibus/ohai'
46
- autoload :Overrides, 'omnibus/overrides'
47
- autoload :PackageRelease, 'omnibus/package_release'
49
+ autoload :Package, 'omnibus/package'
48
50
  autoload :Project, 'omnibus/project'
51
+ autoload :Publisher, 'omnibus/publisher'
49
52
  autoload :Reports, 'omnibus/reports'
50
53
  autoload :S3Cache, 'omnibus/s3_cache'
51
54
  autoload :Software, 'omnibus/software'
52
- autoload :SoftwareS3URLs, 'omnibus/software_s3_urls'
55
+ autoload :Sugarable, 'omnibus/sugarable'
53
56
  autoload :Util, 'omnibus/util'
54
57
 
55
58
  # @todo Remove this in the next major release
56
59
  autoload :OHAI, 'omnibus/ohai'
57
60
 
58
- # @todo Refactor these under a +Fetcher module
59
61
  autoload :GitFetcher, 'omnibus/fetchers/git_fetcher'
60
62
  autoload :NetFetcher, 'omnibus/fetchers/net_fetcher'
61
63
  autoload :PathFetcher, 'omnibus/fetchers/path_fetcher'
62
64
  autoload :S3CacheFetcher, 'omnibus/fetchers/s3_cache_fetcher'
63
65
 
66
+ autoload :ArtifactoryPublisher, 'omnibus/publishers/artifactory_publisher'
67
+ autoload :NullPublisher, 'omnibus/publishers/null_publisher'
68
+ autoload :S3Publisher, 'omnibus/publishers/s3_publisher'
69
+
64
70
  module Command
65
71
  autoload :Base, 'omnibus/cli/base'
66
72
  autoload :Cache, 'omnibus/cli/cache'
67
- autoload :Release, 'omnibus/cli/release'
73
+ autoload :Publish, 'omnibus/cli/publish'
68
74
  end
69
75
 
70
76
  module Packager
@@ -111,48 +117,48 @@ module Omnibus
111
117
  @logger ||= Logger.new
112
118
  end
113
119
 
120
+ #
121
+ # @api private
122
+ #
123
+ # Programatically set the logger for Omnibus.
124
+ #
125
+ # @param [Logger] logger
126
+ #
114
127
  def logger=(logger)
115
128
  @logger = logger
116
129
  end
117
130
 
118
- def ui
119
- @ui ||= Thor::Base.shell.new
120
- end
121
-
122
- # Configure Omnibus.
123
131
  #
124
- # After this has been called, the {Omnibus::Config} object is
125
- # available as `Omnibus.config`.
132
+ # The UI class for Omnibus.
126
133
  #
127
- # @return [void]
134
+ # @return [Thor::Shell]
128
135
  #
129
- # @deprecated Use {#load_configuration} if you need to process a
130
- # config file, followed by {#process_configuration} to act upon it.
131
- def configure
132
- load_configuration
133
- process_configuration
136
+ def ui
137
+ @ui ||= Thor::Base.shell.new
134
138
  end
135
139
 
136
- # Convenience method for access to the Omnibus::Config object.
140
+ # Convenience method for access to the {Config} object.
137
141
  # Provided for backward compatibility.
138
142
  #
139
- # @ return [Omnibus::Config]
143
+ # @return [Config]
140
144
  #
141
- # @deprecated Just refer to {Omnibus::Config} directly.
145
+ # @deprecated Just refer to {Config} directly.
142
146
  def config
147
+ Omnibus.logger.deprecated('Omnibus') do
148
+ 'Omnibus.config. Please use Config.(thing) instead.'
149
+ end
150
+
143
151
  Config
144
152
  end
145
153
 
146
154
  # Load in an Omnibus configuration file. Values will be merged with
147
- # and override the defaults defined in {Omnibus::Config}.
155
+ # and override the defaults defined in {Config}.
148
156
  #
149
- # @param file [String] path to a configuration file to load
157
+ # @param [String] file path to a configuration file to load
150
158
  #
151
159
  # @return [void]
152
- def load_configuration(file = nil)
153
- if file
154
- Config.from_file(file)
155
- end
160
+ def load_configuration(file)
161
+ Config.load(file)
156
162
  end
157
163
 
158
164
  # Processes the configuration to construct the dependency tree of
@@ -160,227 +166,282 @@ module Omnibus
160
166
  #
161
167
  # @return [void]
162
168
  def process_configuration
163
- Config.validate
164
169
  process_dsl_files
165
170
  end
166
171
 
167
- # All {Omnibus::Project} instances that have been created.
168
172
  #
169
- # @return [Array<Omnibus::Project>]
173
+ # All {Project} instances that have been loaded.
174
+ #
175
+ # @return [Array<:Project>]
176
+ #
170
177
  def projects
171
- @projects ||= []
178
+ _projects.values
172
179
  end
173
180
 
174
- # Names of all the {Omnibus::Project} instances that have been created.
175
181
  #
176
- # @return [Array<String>]
177
- def project_names
178
- projects.map { |p| p.name }
179
- end
180
-
181
- # Load the {Omnibus::Project} instance with the given name.
182
+ # Load the {Project} instance with the given name.
183
+ #
184
+ # @param [String] name
185
+ # the name of the project to get
186
+ #
187
+ # @return [Project]
182
188
  #
183
- # @param name [String]
184
- # @return {Omnibus::Project}
185
189
  def project(name)
186
- projects.find { |p| p.name == name }
190
+ _projects[name.to_s]
187
191
  end
188
192
 
189
- # The absolute path to the Omnibus project/repository directory.
193
+ #
194
+ # The absolute path to the Omnibus project/reository directory.
195
+ #
196
+ # @deprecated Use {Config.project_root} instead.
190
197
  #
191
198
  # @return [String]
199
+ #
192
200
  def project_root
201
+ Omnibus.logger.deprecated('Omnibus') do
202
+ 'Omnibus.project_root. Please use Config.project_root instead.'
203
+ end
204
+
205
+ Config.project_root
206
+ end
207
+
208
+ #
209
+ # Backward compat alias.
210
+ #
211
+ # @deprecated Use {Config.project_root} instead.
212
+ #
213
+ # @see (Omnibus.project_root)
214
+ #
215
+ def root
216
+ Omnibus.logger.deprecated('Omnibus') do
217
+ 'Omnibus.root. Please use Omnibus.project_root instead.'
218
+ end
219
+
193
220
  Config.project_root
194
221
  end
195
222
 
223
+ #
196
224
  # The source root is the path to the root directory of the `omnibus` gem.
197
225
  #
198
226
  # @return [Pathname]
227
+ #
199
228
  def source_root
200
229
  @source_root ||= Pathname.new(File.expand_path('../..', __FILE__))
201
230
  end
202
231
 
203
- # The source root is the path to the root directory of the `omnibus-software`
204
- # gem.
232
+ # Processes all configured {Omnibus::Project} and
233
+ # {Omnibus::Software} DSL files.
205
234
  #
206
- # @return [Pathname]
207
- def omnibus_software_root
208
- @omnibus_software_root ||= begin
209
- if (spec = Gem::Specification.find_all_by_name(Config.software_gem).first)
210
- Pathname.new(spec.gem_dir)
211
- else
212
- nil
213
- end
214
- end
235
+ # @return [void]
236
+ def process_dsl_files
237
+ expand_software
215
238
  end
216
239
 
217
- # Return paths to all configured {Omnibus::Project} DSL files.
218
240
  #
219
- # @return [Array<String>]
220
- def project_files
221
- ruby_files(File.join(project_root, Config.project_dir))
222
- end
223
-
224
- # Return paths to all configured {Omnibus::Software} DSL files.
241
+ # The list of directories to search for {Software} files. These paths are
242
+ # returned **in order** of specifity.
225
243
  #
226
- # @return [Array<String>]
227
- def software_files
228
- ruby_files(File.join(project_root, Config.software_dir))
229
- end
230
-
231
- # Return directories to search for {Omnibus::Software} DSL files.
244
+ # @see (Config#project_root)
245
+ # @see (Config#software_dir)
246
+ # @see (Config#software_gems)
247
+ # @see (Config#local_software_dirs)
232
248
  #
233
249
  # @return [Array<String>]
250
+ #
234
251
  def software_dirs
235
- @software_dirs ||= begin
236
- software_dirs = [File.join(project_root, Config.software_dir)]
237
- software_dirs << File.join(omnibus_software_root, 'config', 'software') if omnibus_software_root
238
- software_dirs
252
+ directories = [
253
+ paths_from_project_root,
254
+ paths_from_local_software_dirs,
255
+ paths_from_software_gems,
256
+ ].flatten
257
+
258
+ directories.inject([]) do |array, directory|
259
+ softwares_path = File.join(directory, Config.software_dir)
260
+
261
+ if File.directory?(softwares_path)
262
+ array << softwares_path
263
+ else
264
+ Omnibus.logger.warn('Omnibus') do
265
+ "`#{directory}' does not contain a valid directory structure. " \
266
+ "Does it contain a folder at `#{Config.software_dir}'?"
267
+ end
268
+ end
269
+
270
+ array
239
271
  end
240
272
  end
241
273
 
242
- # Backward compat alias
243
274
  #
244
- # @todo Remve this in the next major release (4.0)
275
+ # A hash of all softwares (by name) and their respective path on disk. These
276
+ # files are **in order**, meaning the software path is the **first**
277
+ # occurrence of the software in the list. If the same software is
278
+ # encountered a second time, it will be skipped.
245
279
  #
246
- # @see (Omnibus.project_root)
247
- def root
248
- Omnibus.logger.deprecated('Omnibus') do
249
- 'Omnibus.root. Please use Omnibus.project_root instead.'
250
- end
251
-
252
- project_root
253
- end
254
-
255
- # Processes all configured {Omnibus::Project} and
256
- # {Omnibus::Software} DSL files.
280
+ # @example
281
+ # { 'preparation' => '/home/omnibus/project/config/software/preparation.rb' }
257
282
  #
258
- # @return [void]
259
- def process_dsl_files
260
- # Do projects first
261
- expand_projects
262
-
263
- # Then do software
264
- final_software_map = prefer_local_software(omnibus_software_files, software_files)
265
-
266
- overrides = Config.override_file ? Omnibus::Overrides.overrides : {}
283
+ # @return [Hash<String, String>]
284
+ #
285
+ def software_map
286
+ software_dirs.inject({}) do |hash, directory|
287
+ Dir.glob("#{directory}/*.rb").each do |path|
288
+ name = File.basename(path, '.rb')
289
+
290
+ if hash[name].nil?
291
+ Omnibus.logger.info('Omnibus#software_map') do
292
+ "Using software `#{name}' from `#{path}'."
293
+ end
294
+
295
+ hash[name] = path
296
+ else
297
+ Omnibus.logger.debug('Omnibus#software_map') do
298
+ "Skipping software `#{name}' because it was loaded from an " \
299
+ "earlier path."
300
+ end
301
+ end
302
+ end
267
303
 
268
- expand_software(overrides, final_software_map)
304
+ hash
305
+ end
269
306
  end
270
307
 
271
308
  private
272
309
 
273
- # Generates {Omnibus::Project}s for each project DSL file in
274
- # `project_specs`. All projects are then accessible at
275
- # {Omnibus#projects}
276
310
  #
277
- # @return [void]
311
+ # @api private
278
312
  #
279
- # @see Omnibus::Project
280
- def expand_projects
281
- project_files.each do |spec|
282
- Omnibus.projects << Omnibus::Project.load(spec)
283
- end
284
- end
285
-
286
- # Generate {Omnibus::Software} objects for all software DSL files in
287
- # `software_specs`.
313
+ # The list of omnibus projects. This is an internal API that maps a
314
+ # project's name to the actual project object.
288
315
  #
289
- # @param overrides [Hash] a hash of version override information.
290
- # @param software_files [Array<String>]
291
- # @return [void]
316
+ # @return [Hash<String, Project>]
292
317
  #
293
- # @see Omnibus::Overrides#overrides
294
- def expand_software(overrides, software_map)
295
- unless overrides.is_a? Hash
296
- raise ArgumentError, "Overrides argument must be a hash! You passed #{overrides.inspect}."
297
- end
318
+ def _projects
319
+ return @_projects if @_projects
298
320
 
299
- Omnibus.projects.each do |project|
300
- project.dependencies.each do |dependency|
301
- recursively_load_dependency(dependency, project, overrides, software_map)
321
+ path = File.expand_path(Config.project_dir, Config.project_root)
322
+ @_projects = Dir.glob("#{path}/*.rb").inject({}) do |hash, path|
323
+ name = File.basename(path, '.rb')
324
+
325
+ if hash[name].nil?
326
+ Omnibus.logger.info('Omnibus#projects') do
327
+ "Using project `#{name}' from `#{path}'."
328
+ end
329
+
330
+ hash[name] = Project.load(path)
331
+ else
332
+ Omnibus.logger.debug('Omnibus#projects') do
333
+ "Skipping project `#{name}' because it was already loaded."
334
+ end
302
335
  end
336
+
337
+ hash
303
338
  end
339
+
340
+ @_projects
304
341
  end
305
342
 
306
- # Return a list of all the Ruby files (i.e., those with an "rb"
307
- # extension) in the given directory
308
343
  #
309
- # @param dir [String]
344
+ # The list of all software paths to software from the project root. This is
345
+ # always a single value, but an array is returned for consistency with the
346
+ # other +software_paths_*+ methods.
347
+ #
348
+ # @see (Config#project_root)
349
+ # @see (Config#software_dir)
350
+ #
310
351
  # @return [Array<String>]
311
- def ruby_files(dir)
312
- Dir.glob("#{dir}/*.rb")
352
+ #
353
+ def paths_from_project_root
354
+ [Config.project_root]
313
355
  end
314
356
 
315
- # Retrieve the fully-qualified paths to every software definition
316
- # file bundled in the {https://github.com/opscode/omnibus-software omnibus-software} gem.
317
357
  #
318
- # @return [Array<String>] the list of paths. Will be empty if the
319
- # `omnibus-software` gem is not in the gem path.
320
- def omnibus_software_files
321
- if omnibus_software_root
322
- Dir.glob(File.join(omnibus_software_root, 'config', 'software', '*.rb'))
323
- else
324
- []
358
+ # The list of all software paths on disk to software files. If relative
359
+ # paths are given, they are expanded relative to {Config#project_root}.
360
+ #
361
+ # @see (Config#local_software_dirs)
362
+ #
363
+ # @return [Array<String>]
364
+ #
365
+ def paths_from_local_software_dirs
366
+ Array(Config.local_software_dirs).inject([]) do |array, path|
367
+ fullpath = File.expand_path(path, Config.project_root)
368
+
369
+ if File.directory?(fullpath)
370
+ array << fullpath
371
+ else
372
+ Omnibus.logger.warn('Omnibus') do
373
+ "Could not load softwares from path `#{fullpath}'. Does it exist?"
374
+ end
375
+ end
376
+
377
+ array
325
378
  end
326
379
  end
327
380
 
328
- # Given a list of software definitions from `omnibus-software` itself, and a
329
- # list of software files local to the current project, create a
330
- # single list of software definitions. If the software was defined
331
- # in both sets, the locally-defined one ends up in the final list.
332
381
  #
333
- # The base name of the software file determines what software it
334
- # defines.
382
+ # The list of software paths from within the list of gems. These gems paths
383
+ # are loaded from disk using +Gem::Specification+. The latest version of
384
+ # the gem on disk is loaded. For this reason, it is recommended that you
385
+ # add these gems to your bundle and be nice to your co-workers.
386
+ #
387
+ # @see (Config#software_gems)
335
388
  #
336
- # @param omnibus_files [Array<String>]
337
- # @param local_files [Array<String>]
338
389
  # @return [Array<String>]
339
- def prefer_local_software(omnibus_files, local_files)
340
- base = software_map(omnibus_files)
341
- local = software_map(local_files)
342
- base.merge(local)
390
+ #
391
+ def paths_from_software_gems
392
+ Array(Config.software_gems).inject([]) do |array, name|
393
+ if (spec = Gem::Specification.find_all_by_name(name).first)
394
+ array << File.expand_path(spec.gem_dir)
395
+ else
396
+ Omnibus.logger.warn('Omnibus') do
397
+ "Could not load softwares from gem `#{name}'. Is it installed?"
398
+ end
399
+ end
400
+
401
+ array
402
+ end
343
403
  end
344
404
 
345
- # Given a list of file paths, create a map of the basename (without
346
- # extension) to the complete path.
347
405
  #
348
- # @param files [Array<String>]
349
- # @return [Hash<String, String>]
350
- def software_map(files)
351
- files.each_with_object({}) do |file, collection|
352
- software_name = File.basename(file, '.*')
353
- collection[software_name] = file
406
+ # Generate {Software} objects for all software DSL files in
407
+ # +software_specs+.
408
+ #
409
+ # @return [void]
410
+ #
411
+ def expand_software
412
+ Omnibus.projects.each do |project|
413
+ project.dependencies.each do |dependency|
414
+ recursively_load_dependency(dependency, project)
415
+ end
354
416
  end
355
417
  end
356
418
 
357
- # Loads a project's dependency recursively, ensuring all transitive dependencies
358
- # are also loaded.
359
419
  #
360
- # @param dependency_name [String]
361
- # @param project [Omnibus::Project]
362
- # @param overrides [Hash] a hash of version override information.
363
- # @param software_map [Hash<String, String>]
420
+ # Loads a project's dependencies recursively, ensuring all transitive
421
+ # dependencies are also loaded in the correct order.
422
+ #
423
+ # @param [String] dependency
424
+ # the name of the dependency
425
+ # @param [Project] project
426
+ # the project that loaded the software
364
427
  #
365
428
  # @return [void]
366
- def recursively_load_dependency(dependency_name, project, overrides, software_map)
367
- dep_file = software_map[dependency_name]
429
+ #
430
+ def recursively_load_dependency(dependency, project)
431
+ filepath = software_map[dependency]
368
432
 
369
- unless dep_file
370
- raise MissingProjectDependency.new(dependency_name, software_dirs)
433
+ if filepath.nil?
434
+ raise MissingProjectDependency.new(dependency, software_dirs)
371
435
  end
372
436
 
373
- dep_software = Omnibus::Software.load(dep_file, project, overrides)
437
+ software = Software.load(project, filepath)
374
438
 
375
439
  # load any transitive deps for the component into the library also
376
- dep_software.dependencies.each do |dep|
377
- recursively_load_dependency(dep, project, overrides, software_map)
440
+ software.dependencies.each do |transitive_dependency|
441
+ recursively_load_dependency(transitive_dependency, project)
378
442
  end
379
443
 
380
- project.library.component_added(dep_software)
444
+ project.library.component_added(software)
381
445
  end
382
446
  end
383
447
  end
384
-
385
- # Sugars must be loaded after everything else has been registered
386
- require 'omnibus/sugar'