omnibus.rb 10.3 KB
Newer Older
1
#
Seth Vargo's avatar
Seth Vargo committed
2
# Copyright 2012-2014 Chef Software, Inc.
3
4
5
6
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
Seth Chisamore's avatar
Seth Chisamore committed
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
Seth Chisamore's avatar
Seth Chisamore committed
9
#
10
11
12
13
14
15
16
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

17
require "omnibus/core_extensions"
Seth Vargo's avatar
Seth Vargo committed
18

19
20
require "cleanroom"
require "pathname"
Seth Vargo's avatar
Seth Vargo committed
21

22
require "omnibus/digestable"
23
require "omnibus/exceptions"
24
25
26
require "omnibus/sugarable"
require "omnibus/util"
require "omnibus/fetcher"
27
require "omnibus/version"
28
29

module Omnibus
Seth Vargo's avatar
Seth Vargo committed
30
31
32
33
34
  #
  # The path to the default configuration file.
  #
  # @return [String]
  #
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  DEFAULT_CONFIG = "omnibus.rb".freeze

  autoload :Builder,          "omnibus/builder"
  autoload :BuildVersion,     "omnibus/build_version"
  autoload :BuildVersionDSL,  "omnibus/build_version_dsl"
  autoload :Cleaner,          "omnibus/cleaner"
  autoload :Compressor,       "omnibus/compressor"
  autoload :Config,           "omnibus/config"
  autoload :Error,            "omnibus/exceptions"
  autoload :FileSyncer,       "omnibus/file_syncer"
  autoload :Generator,        "omnibus/generator"
  autoload :GitCache,         "omnibus/git_cache"
  autoload :HealthCheck,      "omnibus/health_check"
  autoload :Instrumentation,  "omnibus/instrumentation"
  autoload :Library,          "omnibus/library"
  autoload :Logger,           "omnibus/logger"
  autoload :Logging,          "omnibus/logging"
  autoload :Metadata,         "omnibus/metadata"
  autoload :NullArgumentable, "omnibus/null_argumentable"
  autoload :Ohai,             "omnibus/ohai"
  autoload :Package,          "omnibus/package"
  autoload :Packager,         "omnibus/packager"
  autoload :Project,          "omnibus/project"
  autoload :Publisher,        "omnibus/publisher"
  autoload :Reports,          "omnibus/reports"
  autoload :S3Cache,          "omnibus/s3_cache"
  autoload :Software,         "omnibus/software"
  autoload :Templating,       "omnibus/templating"
  autoload :ThreadPool,       "omnibus/thread_pool"
  autoload :Licensing,        "omnibus/licensing"

  autoload :GitFetcher,  "omnibus/fetchers/git_fetcher"
  autoload :NetFetcher,  "omnibus/fetchers/net_fetcher"
  autoload :NullFetcher, "omnibus/fetchers/null_fetcher"
  autoload :PathFetcher, "omnibus/fetchers/path_fetcher"
aklyachkin's avatar
aklyachkin committed
70
  autoload :FileFetcher, "omnibus/fetchers/file_fetcher"
71
72
73
74
75
76
77
78
79
80
81
82
83

  autoload :ArtifactoryPublisher, "omnibus/publishers/artifactory_publisher"
  autoload :NullPublisher,        "omnibus/publishers/null_publisher"
  autoload :S3Publisher,          "omnibus/publishers/s3_publisher"

  autoload :Manifest,      "omnibus/manifest"
  autoload :ManifestEntry, "omnibus/manifest_entry"
  autoload :ManifestDiff,  "omnibus/manifest_diff"

  autoload :ChangeLog, "omnibus/changelog"
  autoload :GitRepository, "omnibus/git_repository"

  autoload :SemanticVersion, "omnibus/semantic_version"
Steven Danna's avatar
Steven Danna committed
84

Seth Vargo's avatar
Seth Vargo committed
85
  module Command
86
87
88
89
    autoload :Base,    "omnibus/cli/base"
    autoload :Cache,   "omnibus/cli/cache"
    autoload :Publish, "omnibus/cli/publish"
    autoload :ChangeLog, "omnibus/cli/changelog"
Seth Vargo's avatar
Seth Vargo committed
90
  end
Seth Vargo's avatar
Seth Vargo committed
91

Seth Vargo's avatar
Seth Vargo committed
92
  class << self
93
94
95
96
97
    #
    # Reset the current Omnibus configuration. This is primary an internal API
    # used in testing, but it can also be useful when Omnibus is used as a
    # library.
    #
98
99
100
101
    # Note - this persists the +Logger+ object by default.
    #
    # @param [true, false] include_logger
    #   whether the logger object should be cleared as well
102
    #
103
104
    # @return [void]
    #
105
    def reset!(include_logger = false)
106
      instance_variables.each do |instance_variable|
107
108
109
110
        unless include_logger
          next if instance_variable == :@logger
        end

111
112
        remove_instance_variable(instance_variable)
      end
113

114
      Config.reset!
115
116
117
      # Clear caches on Project and Software
      Project.reset!
      Software.reset!
118
119
    end

120
121
122
123
    #
    # The logger for this Omnibus instance.
    #
    # @example
Seth Vargo's avatar
Seth Vargo committed
124
    #   Omnibus.logger.debug { 'This is a message!' }
125
126
127
    #
    # @return [Logger]
    #
Seth Vargo's avatar
Seth Vargo committed
128
129
130
    def logger
      @logger ||= Logger.new
    end
Seth Vargo's avatar
Seth Vargo committed
131

Seth Vargo's avatar
Seth Vargo committed
132
133
134
135
136
137
138
    #
    # @api private
    #
    # Programatically set the logger for Omnibus.
    #
    # @param [Logger] logger
    #
Seth Vargo's avatar
Seth Vargo committed
139
140
    def logger=(logger)
      @logger = logger
Seth Vargo's avatar
Seth Vargo committed
141
142
    end

Seth Vargo's avatar
Seth Vargo committed
143
144
145
146
147
    #
    # The UI class for Omnibus.
    #
    # @return [Thor::Shell]
    #
Seth Vargo's avatar
Seth Vargo committed
148
149
    def ui
      @ui ||= Thor::Base.shell.new
Seth Vargo's avatar
Seth Vargo committed
150
151
    end

152
    #
153
    # Load in an Omnibus configuration file.  Values will be merged with
154
    # and override the defaults defined in {Config}.
155
    #
Seth Vargo's avatar
Seth Vargo committed
156
    # @param [String] file path to a configuration file to load
157
158
    #
    # @return [void]
159
    #
Seth Vargo's avatar
Seth Vargo committed
160
    def load_configuration(file)
161
      Config.load(file)
162
    end
163
164
165
166
167
168
169
170
171
172

    #
    # Locate an executable in the current $PATH.
    #
    # @return [String, nil]
    #   the path to the executable, or +nil+ if not present
    #
    def which(executable)
      if File.file?(executable) && File.executable?(executable)
        executable
173
174
      elsif ENV["PATH"]
        path = ENV["PATH"].split(File::PATH_SEPARATOR).find do |path|
175
176
177
178
179
180
          File.executable?(File.join(path, executable))
        end

        path && File.expand_path(executable, path)
      end
    end
181

182
    #
183
184
185
186
    # All {Project} instances that have been loaded.
    #
    # @return [Array<:Project>]
    #
187
    def projects
Seth Vargo's avatar
Seth Vargo committed
188
189
190
      project_map.map do |name, _|
        Project.load(name)
      end
191
    end
192

193
    #
194
195
196
197
198
199
    # Load the {Project} instance with the given name.
    #
    # @param [String] name
    #   the name of the project to get
    #
    # @return [Project]
200
201
    #
    def project(name)
Seth Vargo's avatar
Seth Vargo committed
202
      Project.load(name)
203
    end
204

Seth Vargo's avatar
Seth Vargo committed
205
    #
206
207
208
    # The source root is the path to the root directory of the `omnibus` gem.
    #
    # @return [Pathname]
Seth Vargo's avatar
Seth Vargo committed
209
    #
210
    def source_root
211
      @source_root ||= Pathname.new(File.expand_path("../..", __FILE__))
212
    end
213

214
    #
215
216
217
218
219
220
    # The preferred filepath to a project with the given name on disk.
    #
    # @return [String, nil]
    #
    def project_path(name)
      project_map[name.to_s]
221
222
    end

223
    #
224
    # The preferred filepath to a software with the given name on disk.
225
    #
226
227
228
229
230
231
232
233
234
235
236
237
    # @return [String, nil]
    #
    def software_path(name)
      software_map[name.to_s]
    end

    #
    # The list of directories to search for the given +path+. These paths are
    # returned **in order** of specificity.
    #
    # @param [String] path
    #   the subpath to search for
238
    #
239
    # @return [Array<String>]
240
    #
241
242
    def possible_paths_for(path)
      possible_paths[path] ||= [
243
244
245
        paths_from_project_root,
        paths_from_local_software_dirs,
        paths_from_software_gems,
246
247
      ].flatten.inject([]) do |array, directory|
        destination = File.join(directory, path)
248

249
250
        if File.directory?(destination)
          array << destination
251
        end
252

253
        array
254
255
      end
    end
256

257
258
    private

259
    #
260
    # The list of possible paths, cached as a hash for quick lookup.
261
    #
262
    # @see {Omnibus.possible_paths_for}
263
    #
264
    # @return [Hash]
265
    #
266
267
268
    def possible_paths
      @possible_paths ||= {}
    end
269

270
271
272
273
274
275
276
277
278
279
280
281
    #
    # Map the given file paths to the basename of their file, with the +.rb+
    # extension removed.
    #
    # @example
    #   { 'foo' => '/path/to/foo' }
    #
    # @return [Hash<String, String>]
    #
    def basename_map(paths)
      paths.inject({}) do |hash, directory|
        Dir.glob("#{directory}/*.rb").each do |path|
282
          name = File.basename(path, ".rb")
283
          hash[name] ||= path
284
        end
285

286
        hash
287
288
      end
    end
289

290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
    #
    # A hash of all softwares (by name) and their respective path on disk. These
    # files are **in order**, meaning the software path is the **first**
    # occurrence of the software in the list. If the same software is
    # encountered a second time, it will be skipped.
    #
    # @example
    #   { 'preparation' => '/home/omnibus/project/config/software/preparation.rb' }
    #
    # @return [Hash<String, String>]
    #
    def software_map
      @software_map ||= basename_map(possible_paths_for(Config.software_dir))
    end

    #
    # A hash of all projects (by name) and their respective path on disk. These
    # files are **in order**, meaning the project path is the **first**
    # occurrence of the project in the list. If the same project is
    # encountered a second time, it will be skipped.
    #
    # @example
    #   { 'chefdk' => '/home/omnibus/project/config/projects/chefdk.rb' }
    #
    # @return [Hash<String, String>]
    #
    def project_map
      @project_map ||= basename_map(possible_paths_for(Config.project_dir))
    end

320
    #
321
322
323
324
325
326
327
    # The list of all software paths to software from the project root. This is
    # always a single value, but an array is returned for consistency with the
    # other +software_paths_*+ methods.
    #
    # @see (Config#project_root)
    # @see (Config#software_dir)
    #
328
    # @return [Array<String>]
329
    #
330
    def paths_from_project_root
331
332
      @paths_from_project_root ||=
        [Config.project_root]
333
    end
334

335
    #
336
337
338
339
340
341
342
    # The list of all software paths on disk to software files. If relative
    # paths are given, they are expanded relative to {Config#project_root}.
    #
    # @see (Config#local_software_dirs)
    #
    # @return [Array<String>]
    #
343
    def paths_from_local_software_dirs
344
345
346
347
348
349
      @paths_from_local_software_dirs ||=
        Array(Config.local_software_dirs).inject([]) do |array, path|
          fullpath = File.expand_path(path, Config.project_root)

          if File.directory?(fullpath)
            array << fullpath
350
351
          end

352
353
          array
        end
354
355
    end

356
    #
357
358
359
360
361
362
    # The list of software paths from within the list of gems. These gems paths
    # are loaded from disk using +Gem::Specification+. The latest version of
    # the gem on disk is loaded. For this reason, it is recommended that you
    # add these gems to your bundle and be nice to your co-workers.
    #
    # @see (Config#software_gems)
363
364
    #
    # @return [Array<String>]
365
    #
366
    def paths_from_software_gems
367
368
369
370
      @paths_from_software_gems ||=
        Array(Config.software_gems).inject([]) do |array, name|
          if (spec = Gem::Specification.find_all_by_name(name).first)
            array << File.expand_path(spec.gem_dir)
371
372
          end

373
          array
374
        end
375
    end
376
  end
377
end