├── .expeditor ├── config.yml ├── run_linux_tests.sh ├── update_version.sh └── verify.pipeline.yml ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── dependabot.yml ├── .gitignore ├── .rspec ├── .rubocop.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Gemfile ├── LICENSE ├── MAINTAINERS.md ├── README.md ├── RELEASE_NOTES.md ├── Rakefile ├── VERSION ├── bin └── omnibus ├── docs ├── Build Cache.md ├── Building on Debian.md ├── Building on OSX.md ├── Building on RHEL.md ├── Building on Windows.md ├── Overview.md └── Sequence Diagram - Omnibus Build.pdf ├── features ├── commands │ ├── build.feature │ ├── clean.feature │ ├── list.feature │ ├── manifest.feature │ ├── new.feature │ ├── publish.feature │ └── version.feature ├── step_definitions │ └── generator_steps.rb └── support │ └── env.rb ├── lib ├── omnibus.rb └── omnibus │ ├── assets │ ├── README-logo.png │ └── logo.psd │ ├── build_system_metadata.rb │ ├── build_system_metadata │ └── buildkite.rb │ ├── build_version.rb │ ├── build_version_dsl.rb │ ├── builder.rb │ ├── changelog.rb │ ├── changelog_printer.rb │ ├── cleaner.rb │ ├── cli.rb │ ├── cli │ ├── base.rb │ ├── cache.rb │ ├── changelog.rb │ └── publish.rb │ ├── compressor.rb │ ├── compressors │ ├── base.rb │ ├── dmg.rb │ ├── null.rb │ └── tgz.rb │ ├── config.rb │ ├── core_extensions.rb │ ├── core_extensions │ └── open_uri.rb │ ├── digestable.rb │ ├── download_helpers.rb │ ├── exceptions.rb │ ├── fetcher.rb │ ├── fetchers │ ├── file_fetcher.rb │ ├── git_fetcher.rb │ ├── net_fetcher.rb │ ├── null_fetcher.rb │ └── path_fetcher.rb │ ├── file_syncer.rb │ ├── generator.rb │ ├── generator_files │ ├── .kitchen.local.yml.erb │ ├── .kitchen.yml.erb │ ├── Berksfile.erb │ ├── Gemfile.erb │ ├── README.md.erb │ ├── config │ │ ├── projects │ │ │ └── project.rb.erb │ │ └── software │ │ │ ├── preparation.rb.erb │ │ │ └── zlib.rb.erb │ ├── gitignore.erb │ ├── omnibus.rb.erb │ └── package_scripts │ │ ├── postinst.erb │ │ ├── postrm.erb │ │ ├── preinst.erb │ │ └── prerm.erb │ ├── git_cache.rb │ ├── git_repository.rb │ ├── health_check.rb │ ├── instrumentation.rb │ ├── library.rb │ ├── licensing.rb │ ├── logger.rb │ ├── logging.rb │ ├── manifest.rb │ ├── manifest_diff.rb │ ├── manifest_entry.rb │ ├── metadata.rb │ ├── null_argumentable.rb │ ├── ohai.rb │ ├── package.rb │ ├── packager.rb │ ├── packagers │ ├── appx.rb │ ├── base.rb │ ├── bff.rb │ ├── deb.rb │ ├── ips.rb │ ├── makeself.rb │ ├── msi.rb │ ├── pkg.rb │ ├── pkgsrc.rb │ ├── rpm.rb │ ├── solaris.rb │ └── windows_base.rb │ ├── project.rb │ ├── publisher.rb │ ├── publishers │ ├── artifactory_publisher.rb │ ├── null_publisher.rb │ └── s3_publisher.rb │ ├── reports.rb │ ├── s3_cache.rb │ ├── s3_helpers.rb │ ├── semantic_version.rb │ ├── software.rb │ ├── sugarable.rb │ ├── templating.rb │ ├── thread_pool.rb │ ├── util.rb │ ├── version.rb │ └── whitelist.rb ├── omnibus.gemspec ├── resources ├── appx │ ├── AppxManifest.xml.erb │ └── assets │ │ └── clear.png ├── bff │ ├── config.erb │ └── gen.template.erb ├── deb │ ├── conffiles.erb │ ├── control.erb │ └── md5sums.erb ├── dmg │ ├── background.png │ ├── create_dmg.osascript.erb │ └── icon.png ├── ips │ ├── doc-transform.erb │ └── gen.manifestfile.erb ├── makeself │ ├── makeself-header.sh │ ├── makeself.sh │ └── makeselfinst.erb ├── msi │ ├── CustomActionFastMsi.CA.dll │ ├── assets │ │ ├── LICENSE.rtf │ │ ├── banner_background.bmp │ │ ├── dialog_background.bmp │ │ ├── project.ico │ │ ├── project_16x16.ico │ │ └── project_32x32.ico │ ├── bundle.wxs.erb │ ├── localization-en-us.wxl.erb │ ├── parameters.wxi.erb │ └── source.wxs.erb ├── pkg │ ├── background.png │ ├── distribution.xml.erb │ ├── license.html.erb │ └── welcome.html.erb └── rpm │ ├── filesystem_list │ ├── rpmmacros.erb │ ├── signing.erb │ └── spec.erb └── spec ├── fixtures ├── licensing │ └── license_scout │ │ ├── snoopy │ │ ├── ruby_bundler-bundler-audit-0.5.0-COPYING.txt │ │ ├── ruby_bundler-inifile-3.0.0-README.md │ │ └── snoopy-dependency-licenses.json │ │ └── zlib │ │ ├── ruby_bundler-inifile-3.0.0-README.md │ │ ├── ruby_bundler-mime-types-3.1-Licence.rdoc │ │ ├── ruby_bundler-mini_portile2-2.1.0-LICENSE.txt │ │ └── zlib-dependency-licenses.json └── sample │ └── package-scripts │ └── sample │ └── postinstall ├── functional ├── builder_spec.rb ├── fetchers │ ├── file_fetcher_spec.rb │ ├── git_fetcher_spec.rb │ ├── net_fetcher_spec.rb │ └── path_fetcher_spec.rb ├── file_syncer_spec.rb ├── licensing_spec.rb └── templating_spec.rb ├── spec_helper.rb ├── support ├── env_helpers.rb ├── examples.rb ├── file_helpers.rb ├── git_helpers.rb ├── logging_helpers.rb ├── matchers.rb ├── ohai_helpers.rb ├── output_helpers.rb ├── path_helpers.rb └── shell_helpers.rb └── unit ├── build_system_metadata_spec.rb ├── build_version_dsl_spec.rb ├── build_version_spec.rb ├── builder_spec.rb ├── buildkite_spec.rb ├── changelog_spec.rb ├── changelogprinter_spec.rb ├── cleanroom_spec.rb ├── compressor_spec.rb ├── compressors ├── base_spec.rb ├── dmg_spec.rb ├── null_spec.rb └── tgz_spec.rb ├── config_spec.rb ├── digestable_spec.rb ├── fetcher_spec.rb ├── fetchers ├── file_fetcher_spec.rb ├── git_fetcher_spec.rb ├── net_fetcher_spec.rb └── path_fetcher_spec.rb ├── file_syncer_spec.rb ├── generator_spec.rb ├── git_cache_spec.rb ├── git_repository_spec.rb ├── health_check_spec.rb ├── library_spec.rb ├── manifest_diff_spec.rb ├── manifest_spec.rb ├── metadata_spec.rb ├── ohai_spec.rb ├── omnibus_spec.rb ├── package_spec.rb ├── packager_spec.rb ├── packagers ├── appx_spec.rb ├── base_spec.rb ├── bff_spec.rb ├── deb_spec.rb ├── ips_spec.rb ├── makeself_spec.rb ├── msi_spec.rb ├── pkg_spec.rb ├── pkgsrc_spec.rb ├── rpm_spec.rb └── solaris_spec.rb ├── project_spec.rb ├── publisher_spec.rb ├── publishers ├── artifactory_publisher_spec.rb └── s3_publisher_spec.rb ├── s3_cacher_spec.rb ├── s3_helpers_spec.rb ├── semantic_version_spec.rb ├── software_spec.rb ├── sugarable_spec.rb └── util_spec.rb /.expeditor/config.yml: -------------------------------------------------------------------------------- 1 | # Documentation available at https://expeditor.chef.io/docs/getting-started/ 2 | --- 3 | 4 | # Slack channel in Chef Software slack to send notifications about build failures, etc 5 | slack: 6 | notify_channel: 7 | - chef-found-notify 8 | 9 | # This publish is triggered by the `built_in:publish_rubygems` artifact_action. 10 | rubygems: 11 | - omnibus 12 | 13 | github: 14 | # This deletes the GitHub PR branch after successfully merged into the release branch 15 | delete_branch_on_merge: true 16 | # allow bumping the minor release via label 17 | minor_bump_labels: 18 | - "Expeditor: Bump Version Minor" 19 | # allow bumping the major release via label 20 | major_bump_labels: 21 | - "Expeditor: Bump Version Major" 22 | 23 | changelog: 24 | rollup_header: Changes not yet released to rubygems.org 25 | 26 | subscriptions: 27 | # These actions are taken, in order they are specified, anytime a Pull Request is merged. 28 | - workload: pull_request_merged:{{github_repo}}:{{release_branch}}:* 29 | actions: 30 | - built_in:bump_version: 31 | ignore_labels: 32 | - "Expeditor: Skip Version Bump" 33 | - "Expeditor: Skip All" 34 | - bash:.expeditor/update_version.sh: 35 | only_if: built_in:bump_version 36 | - built_in:update_changelog: 37 | ignore_labels: 38 | - "Expeditor: Skip Changelog" 39 | - "Expeditor: Skip All" 40 | - built_in:build_gem: 41 | only_if: built_in:bump_version 42 | 43 | - workload: project_promoted:{{agent_id}}:* 44 | actions: 45 | - built_in:rollover_changelog 46 | - built_in:publish_rubygems 47 | 48 | pipelines: 49 | - verify: 50 | description: Pull Request validation tests 51 | public: true 52 | -------------------------------------------------------------------------------- /.expeditor/run_linux_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script runs a passed in command, but first setups up the bundler caching on the repo 4 | 5 | set -ue 6 | 7 | export USER="root" 8 | export LANG=C.UTF-8 LANGUAGE=C.UTF-8 9 | 10 | echo "--- updating Rubygems" 11 | gem install rubygems-update 12 | update_rubygems 13 | gem update --system 14 | 15 | echo "--- bundle install" 16 | 17 | bundle config --local path vendor/bundle 18 | bundle install --jobs=7 --retry=3 19 | 20 | echo "+++ bundle exec task" 21 | bundle exec $@ 22 | -------------------------------------------------------------------------------- /.expeditor/update_version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # After a PR merge, Chef Expeditor will bump the PATCH version in the VERSION file. 4 | # It then executes this file to update any other files/components with that new version. 5 | # 6 | 7 | set -evx 8 | 9 | sed -i -r "s/^(\s*)VERSION = \".+\"/\1VERSION = \"$(cat VERSION)\"/" lib/omnibus/version.rb 10 | 11 | # Once Expeditor finshes executing this script, it will commit the changes and push 12 | # the commit as a new tag corresponding to the value in the VERSION file. -------------------------------------------------------------------------------- /.expeditor/verify.pipeline.yml: -------------------------------------------------------------------------------- 1 | --- 2 | expeditor: 3 | cached_folders: 4 | - vendor 5 | defaults: 6 | buildkite: 7 | retry: 8 | automatic: 9 | limit: 1 10 | timeout_in_minutes: 30 11 | 12 | steps: 13 | 14 | - label: run-lint-and-specs-ruby-3.0 15 | command: 16 | - .expeditor/run_linux_tests.sh rake 17 | expeditor: 18 | executor: 19 | docker: 20 | image: ruby:3.0-buster 21 | 22 | - label: run-lint-and-specs-ruby-3.1 23 | command: 24 | - .expeditor/run_linux_tests.sh rake 25 | expeditor: 26 | executor: 27 | docker: 28 | image: ruby:3.1-buster 29 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Order is important. The last matching pattern has the most precedence. 2 | 3 | * @chef/chef-infra-reviewers @chef/chef-infra-approvers @chef/chef-infra-owners @chef/chef-infra-server-reviewers @chef/chef-infra-server-approvers @chef/chef-infra-server-owners @chef/infra-packages 4 | .expeditor/ @chef/jex-team @chef/infra-packages 5 | *.md @chef/docs-team 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Briefly describe the issue 4 | 5 | ### Omnibus Version 6 | 7 | Tell us which version of Omnibus you are using 8 | 9 | ### Platform Version 10 | 11 | Tell us which Operating System distribution, version and architecture the Omnibus build is being executed on. 12 | 13 | ### Replication Case 14 | 15 | Tell us what steps to take to replicate your problem. See [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) 16 | for information on how to create a good replication case. 17 | 18 | ### Build Output 19 | 20 | The relevant output of the Omnibus build or a link to a gist of the entire build, if there is one. 21 | 22 | The verbose build output (`omnibus build -l internal`) may be useful, but please link to a gist, or truncate it. 23 | 24 | -------------------------------------------------- 25 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | Briefly describe the new feature or fix here 4 | 5 | -------------------------------------------------- 6 | 7 | #### Maintainers 8 | 9 | Please ensure that you check for: 10 | 11 | - [ ] If this change impacts git cache validity, it bumps the git cache 12 | serial number 13 | - [ ] If this change impacts compatibility with omnibus-software, the 14 | corresponding change is reviewed and there is a release plan 15 | - [ ] If this change impacts compatibility with the omnibus cookbook, the 16 | corresponding change is reviewed and there is a release plan 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: bundler 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "06:00" 8 | timezone: America/Los_Angeles 9 | open-pull-requests-limit: 10 10 | ignore: 11 | - dependency-name: license_scout 12 | versions: 13 | - "> 1.0" 14 | - dependency-name: aruba 15 | versions: 16 | - 1.0.0 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### OSX ### 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear on external disk 14 | .Spotlight-V100 15 | .Trashes 16 | 17 | # Directories potentially created on remote AFP share 18 | .AppleDB 19 | .AppleDesktop 20 | Network Trash Folder 21 | Temporary Items 22 | .apdisk 23 | 24 | 25 | ### Windows ### 26 | # Windows image file caches 27 | Thumbs.db 28 | ehthumbs.db 29 | 30 | # Folder config file 31 | Desktop.ini 32 | 33 | # Recycle Bin used on file shares 34 | $RECYCLE.BIN/ 35 | 36 | # Windows Installer files 37 | *.cab 38 | *.msi 39 | *.msm 40 | *.msp 41 | 42 | 43 | ### Ruby ### 44 | *.gem 45 | *.rbc 46 | /.config 47 | /coverage/ 48 | /InstalledFiles 49 | /pkg/ 50 | /spec/reports/ 51 | /test/tmp/ 52 | /test/version_tmp/ 53 | /tmp/ 54 | /spec/tmp 55 | gem_graph.png 56 | 57 | ## Specific to RubyMotion: 58 | .dat* 59 | .repl_history 60 | build/ 61 | 62 | ## Documentation cache and generated files: 63 | /.yardoc/ 64 | /_yardoc/ 65 | /doc/ 66 | /rdoc/ 67 | 68 | ## Environment normalisation: 69 | /.bundle/ 70 | /lib/bundler/man/ 71 | 72 | # for a library or gem, you might want to ignore these files since the code is 73 | # intended to run in multiple environments; otherwise, check them in: 74 | Gemfile.lock 75 | .ruby-version 76 | .ruby-gemset 77 | 78 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 79 | .rvmrc 80 | 81 | 82 | ### TextMate ### 83 | *.tmproj 84 | *.tmproject 85 | tmtags 86 | 87 | # avoid generic ctags files too 88 | tags 89 | gems.tags 90 | gemtags 91 | .tags 92 | .gem.tags 93 | .gemtags 94 | .tags_sorted_by_file 95 | 96 | ### SublimeText ### 97 | # workspace files are user-specific 98 | *.sublime-workspace 99 | 100 | # project files should be checked into the repository, unless a significant 101 | # proportion of contributors will probably not be using SublimeText 102 | # *.sublime-project 103 | 104 | #sftp configuration file 105 | sftp-config.json 106 | 107 | 108 | ### Tower ### 109 | # Tower.app - http://www.git-tower.com/ 110 | Icon.png 111 | 112 | 113 | ### vim ### 114 | [._]*.s[a-w][a-z] 115 | [._]s[a-w][a-z] 116 | *.un~ 117 | Session.vim 118 | .netrwhist 119 | *~ 120 | 121 | 122 | ### Emacs ### 123 | # -*- mode: gitignore; -*- 124 | *~ 125 | \#*\# 126 | /.emacs.desktop 127 | /.emacs.desktop.lock 128 | *.elc 129 | auto-save-list 130 | tramp 131 | .\#* 132 | 133 | # Org-mode 134 | .org-id-locations 135 | *_archive 136 | 137 | # flymake-mode 138 | *_flymake.* 139 | 140 | # eshell files 141 | /eshell/history 142 | /eshell/lastdir 143 | 144 | # elpa packages 145 | /elpa/ 146 | 147 | # reftex files 148 | *.rel 149 | 150 | # AUCTeX auto folder 151 | /auto/ 152 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | -fd 3 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | TargetRubyVersion: 2.6 3 | 4 | # all of these could/should be corrected. Have at it if you want. 5 | 6 | Layout/ClosingHeredocIndentation: 7 | Exclude: 8 | - 'lib/omnibus/licensing.rb' 9 | 10 | Layout/HeredocIndentation: 11 | Exclude: 12 | - 'lib/omnibus/licensing.rb' 13 | 14 | Lint/AmbiguousRegexpLiteral: 15 | Exclude: 16 | - 'spec/functional/builder_spec.rb' 17 | - 'spec/functional/licensing_spec.rb' 18 | 19 | # Configuration parameters: AllowSafeAssignment. 20 | Lint/AssignmentInCondition: 21 | Exclude: 22 | - 'lib/omnibus/build_version.rb' 23 | - 'lib/omnibus/compressors/tgz.rb' 24 | - 'lib/omnibus/file_syncer.rb' 25 | - 'lib/omnibus/packager.rb' 26 | - 'lib/omnibus/publishers/artifactory_publisher.rb' 27 | 28 | Lint/EmptyWhen: 29 | Exclude: 30 | - 'lib/omnibus/health_check.rb' 31 | 32 | Lint/IneffectiveAccessModifier: 33 | Exclude: 34 | - 'lib/omnibus/fetcher.rb' 35 | - 'lib/omnibus/fetchers/git_fetcher.rb' 36 | 37 | Lint/ParenthesesAsGroupedExpression: 38 | Exclude: 39 | - 'lib/omnibus/cli/base.rb' 40 | - 'spec/unit/packagers/ips_spec.rb' 41 | - 'spec/unit/packagers/msi_spec.rb' 42 | - 'spec/unit/project_spec.rb' 43 | - 'spec/unit/s3_cacher_spec.rb' 44 | - 'spec/unit/software_spec.rb' 45 | 46 | Lint/ShadowingOuterLocalVariable: 47 | Exclude: 48 | - 'lib/omnibus.rb' 49 | - 'lib/omnibus/builder.rb' 50 | - 'lib/omnibus/licensing.rb' 51 | - 'lib/omnibus/packagers/deb.rb' 52 | 53 | Lint/UselessAssignment: 54 | Exclude: 55 | - 'lib/omnibus/digestable.rb' 56 | - 'lib/omnibus/exceptions.rb' 57 | - 'lib/omnibus/file_syncer.rb' 58 | - 'lib/omnibus/licensing.rb' 59 | - 'lib/omnibus/software.rb' 60 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | Please refer to the Chef Community Code of Conduct at https://www.chef.io/code-of-conduct/ 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec 4 | 5 | group :docs do 6 | gem "yard" 7 | gem "redcarpet" 8 | gem "github-markup" 9 | end 10 | 11 | group :debug do 12 | gem "pry" 13 | gem "pry-byebug" 14 | gem "pry-stack_explorer" 15 | end 16 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # Maintainers 2 | 3 | This file lists how the `omnibus` project is maintained. 4 | 5 | When making changes to the system, you need two maintainers to provide a :+1: on your pull request. Additionally, you need to not receive a veto from a Lieutenant or the Project Lead. 6 | 7 | Check out [How Chef is Maintained](https://github.com/chef/chef-rfc/blob/master/rfc030-maintenance-policy.md#how-the-project-is-maintained) for details on the process, how to become a maintainer, lieutenant, or the project lead. 8 | 9 | ## Project Lead 10 | 11 | - [Seth Chisamore](https://github.com/schisamo) 12 | 13 | ## Maintainers 14 | 15 | - [Robb Kidd](https://github.com/robbkidd) 16 | - [Seth Chisamore](https://github.com/schisamo) 17 | - [Jeremiah Snapp](https://github.com/jeremiahsnapp) 18 | - [Jaymala Sinha](https://github.com/jaymalasinha) 19 | - [Daniel DeLeo](https://github.com/danielsdeleo) 20 | - [Jay Mundrawala](https://github.com/jaym) 21 | - [Kartik Null Cating-Subramanian](https://github.com/ksubrama) 22 | - [Lamont Granquist](https://github.com/lamont-granquist) 23 | - [Seth Vargo](http://github.com/sethvargo) 24 | - [Steven Danna](https://github.com/stevendanna) 25 | - [Thom May](https://github.com/thommay) 26 | - [Yvonne Lam](http://github.com/yzl) 27 | - [Marc Paradise](http://github.com/marcparadise) 28 | -------------------------------------------------------------------------------- /RELEASE_NOTES.md: -------------------------------------------------------------------------------- 1 | ## Omnibus 7.0: 2 | 3 | ### Deep Signing and Hardened Runtime 4 | 5 | When packaging using the pkg packager omnibus will now deep sign all binaries and libraries in the package based of each software definition's bin_dirs and lib_dirs. When siging binaries the hardened runtime is enabled. 6 | 7 | ## Omnibus 6.0: 8 | 9 | ### Ruby 2.3+ 10 | 11 | This project now requires Ruby 2.3 or later. 12 | 13 | ### Dependency Updates 14 | 15 | Dependencies have been loosened to allow for the latest versoins of Ohai / Fauxhai / Chef-sugar as well as many of the development deps in the Gemfile 16 | 17 | ### FreeBSD 9 EOL 18 | 19 | Support for FreeBSD 9.X has been removed as this is no longer a supported FreeBSD release. 20 | 21 | ### File Source 22 | 23 | You can now source from a file using the :file source. 24 | 25 | ```ruby 26 | version("local_file") do 27 | source file: "../../my_dir/artifact.zip" 28 | end 29 | ``` 30 | 31 | ### Appbundler 0.11 support 32 | 33 | This project now supports and requires Appbundler 0.11. -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | require "rspec/core/rake_task" 4 | %i{unit functional}.each do |type| 5 | RSpec::Core::RakeTask.new(type) do |t| 6 | t.pattern = "spec/#{type}/**/*_spec.rb" 7 | t.rspec_opts = [].tap do |a| 8 | a.push("--color") 9 | a.push("--format progress") 10 | end.join(" ") 11 | end 12 | end 13 | 14 | require "cucumber/rake/task" 15 | Cucumber::Rake::Task.new(:acceptance) do |t| 16 | t.cucumber_opts = [].tap do |a| 17 | a.push("--color") 18 | a.push("--format progress") 19 | a.push("--strict") 20 | end.join(" ") 21 | end 22 | 23 | require "chefstyle" 24 | require "rubocop/rake_task" 25 | desc " Run ChefStyle" 26 | RuboCop::RakeTask.new(:chefstyle) do |task| 27 | task.options << "--display-cop-names" 28 | end 29 | 30 | namespace :travis do 31 | desc "Run tests on Travis" 32 | task ci: %w{chefstyle unit functional acceptance} 33 | end 34 | 35 | task default: %w{travis:ci} 36 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 9.0.25 -------------------------------------------------------------------------------- /bin/omnibus: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # Trap interrupts to quit cleanly. See 4 | # https://twitter.com/mitchellh/status/283014103189053442 5 | Signal.trap("INT") { exit 1 } 6 | 7 | $:.push File.expand_path("../lib", __dir__) 8 | $stdout.sync = true 9 | 10 | require "omnibus/cli" 11 | 12 | # Some platforms do not have a UTF-8 locale, so we need to enforce one 13 | # or else the cacert chain will break among other things 14 | Encoding.default_external = Encoding::UTF_8 15 | 16 | Omnibus::CLI::Runner.new(ARGV.dup).execute! 17 | -------------------------------------------------------------------------------- /docs/Building on Debian.md: -------------------------------------------------------------------------------- 1 | Building Omnibus Packages for Debian 2 | ==================================== 3 | This document details the steps and configurables for building DEB packages with Omnibus. 4 | 5 | 6 | Building a .deb 7 | --------------- 8 | ### Requirements 9 | Omnibus assumes the existence of the `fakeroot` and `dpkg-deb` command on the build system. The [omnibus cookbook](https://supermarket.getchef.com/cookbooks/omnibus) automatically handles this installation. If you are not using the Omnibus cookbook, you must install these packages manually or using another tool. 10 | 11 | ### Configurables 12 | A number of project configuration values are taken into consideration for building Debian packages. These options are further described in the [`Project` documentation](http://www.rubydoc.info/github/chef/omnibus/Omnibus/Project). 13 | 14 | These values are interpolated and evaluated using Omnibus' internal DEB templates. For 99% of users, these templates should be satisfactory. If you encounter an instance where Omnibus' ERB templates do not satisfy a use case, please open an issue. 15 | 16 | Because of the unlikelihood of their necessity, Omnibus does not generate deb-related assets. If you find yourself in a situation where you need to generate highly-customized DEB assets, run the Omnibus new command with the `--deb-assets` flag: 17 | 18 | $ omnibus new NAME --deb-assets 19 | 20 | **If this is an existing project, be sure to answer "NO" when asked if you want to overwrite existing files!** 21 | 22 | With the `--deb-assets` flag, Omnibus will generate the following "stock" resources in `resources/NAME/deb`: 23 | 24 | - `conffiles.erb` - the list of configuration files 25 | - `control.erb` - the Debian spec file 26 | - `md5sums.erb` - the ERB for generating the list of file checksums 27 | 28 | **You should only generate the DEB assets if you cannot set values using attributes!** 29 | 30 | ### DSL 31 | You can further customize the behavior of the packager using the `package` DSL command in your project definition: 32 | 33 | ```ruby 34 | # project.rb 35 | name 'hamlet' 36 | 37 | package :deb do 38 | vendor 'Company ' 39 | license 'Apache 2.0' 40 | priority 'extra' 41 | section 'databases' 42 | signing_passphrase 'acbd1234' 43 | end 44 | ``` 45 | 46 | Some DSL methods available include: 47 | 48 | | DSL Method | Description | 49 | | :------------------: | --------------------------------------------| 50 | | `signing_passphrase` | The passphrase to sign the RPM with | 51 | | `vendor` | The name of the package producer | 52 | | `license` | The default license for the package | 53 | | `priority` | The priority for the package | 54 | | `section` | The section for this package | 55 | 56 | If you are unfamiliar with any of these terms, you should just accept the defaults. For more information on the purpose of any of these configuration options, please see the DEB spec. 57 | 58 | For more information, please see the [`Packager::DEB` documentation](http://www.rubydoc.info/github/chef/omnibus/Omnibus/Packager/DEB). 59 | 60 | ### Notes on DEB-signing 61 | To sign an DEB, you will need a GPG keypair. You can [create your own signing key](http://www.madboa.com/geek/gpg-quickstart/) or [import an existing one](http://irtfweb.ifa.hawaii.edu/~lockhart/gpg/gpg-cs.html). Omnibus will automatically call `gpg` with arguments that assume the real name associated to the GPG key is the same as the name of the project maintainer as specified in your Omnibus config. 62 | -------------------------------------------------------------------------------- /docs/Building on RHEL.md: -------------------------------------------------------------------------------- 1 | Building Omnibus Packages for RHEL 2 | ================================== 3 | This document details the steps and configurables for building RPM packages with Omnibus. 4 | 5 | 6 | Building a .rpm 7 | --------------- 8 | ### Requirements 9 | Omnibus assumes the existence of the `rpmbuild` command on the build system. The [omnibus cookbook](https://supermarket.getchef.com/cookbooks/omnibus) automatically handles this installation. If you are not using the Omnibus cookbook, you must install the package manually or using another tool. 10 | 11 | ### Configurables 12 | The following Project values are taken into consideration when building RPMs: 13 | 14 | - `build_version` 15 | - `config_file` 16 | - `conflicts` 17 | - `description` 18 | - `exclude` 19 | - `extra_package_files` 20 | - `iteration` 21 | - `maintainer` 22 | - `package_name` 23 | - `package_user` 24 | - `package_group` 25 | - `package_scripts_path` 26 | - `replaces` 27 | - `runtime_dependency` 28 | - `url` 29 | 30 | These options are further described in the [`Project` documentation](http://www.rubydoc.info/github/chef/omnibus/Omnibus/Project). 31 | 32 | These values are interpolated and evaluated using Omnibus' internal RPM templates. For 99% of users, these templates should be satisfactory. If you encounter an instance where Omnibus' RPM templates do not satisfy a use case, please open an issue. 33 | 34 | Because of the unlikelihood of their necessity, Omnibus does not generate rpm-related assets. If you find yourself in a situation where you need to generate highly-customized RPM assets, run the Omnibus new command with the `--rpm-assets` flag: 35 | 36 | $ omnibus new NAME --rpm-assets 37 | 38 | **If this is an existing project, be sure to answer "NO" when asked if you want to overwrite existing files!** 39 | 40 | With the `--rpm-assets` flag, Omnibus will generate the following "stock" resources in `resources/NAME/rpm`: 41 | 42 | - `rpmmacros.erb` - the macros file 43 | - `signing.erb` - a Ruby script for signing RPMs 44 | - `spec.erb` - the ERB for generating the spec 45 | 46 | **You should only generate the RPM assets if you cannot set values using attributes!** 47 | 48 | ### DSL 49 | You can further customize the behavior of the packager using the `package` DSL command in your project definition: 50 | 51 | ```ruby 52 | # project.rb 53 | name 'hamlet' 54 | 55 | package :rpm do 56 | signing_passphrase 'acbd1234' 57 | end 58 | ``` 59 | 60 | Some DSL methods available include: 61 | 62 | | DSL Method | Description | 63 | | :------------------: | --------------------------------------------| 64 | | `signing_passphrase` | The passphrase to sign the RPM with | 65 | | `vendor` | The name of the package producer | 66 | | `license` | The default license for the package | 67 | | `priority` | The priority for the package | 68 | | `category` | The category for this package | 69 | 70 | If you are unfamiliar with any of these terms, you should just accept the defaults. For more information on the purpose of any of these configuration options, please see the RPM spec. 71 | 72 | For more information, please see the [`Packager::RPM` documentation](http://www.rubydoc.info/github/chef/omnibus/Omnibus/Packager/RPM). 73 | 74 | ### Notes on RPM-signing 75 | To sign an RPM, you will need a GPG keypair. You can [create your own signing key](http://www.madboa.com/geek/gpg-quickstart/) or [import an existing one](http://irtfweb.ifa.hawaii.edu/~lockhart/gpg/gpg-cs.html). Omnibus automatically generates an `.rpmmacros` config file for `rpmbuild` that assumes that the real name associated to the GPG key is the same as the name of the project maintainer as specified in your Omnibus config. You can override this by creating your own `.rpmmacros` using the steps above. 76 | -------------------------------------------------------------------------------- /docs/Building on Windows.md: -------------------------------------------------------------------------------- 1 | Building Omnibus Packages for Windows 2 | ===================================== 3 | This document details the steps and configurables for building omnibus packages on Windows. Unlike Linux-based systems, the process for building an `.msi` may involve the customization of some assets. 4 | 5 | 6 | Building an .msi 7 | ---------------- 8 | In Windows, an `.msi` is a special executable that contains the set of instructions for installating a piece of software on a target system. Please note, Omnibus does not support the creation of `.exe` files. 9 | 10 | ### Requirements 11 | By default, Omnibus does not generate msi-related assets. To generate the msi assets, run the Omnibus new command with the `--msi-assets` flag: 12 | 13 | $ omnibus new NAME --msi-assets 14 | 15 | **If this is an existing project, be sure to answer "NO" when asked if you want to overwrite existing files!** 16 | 17 | With the `--msi-assets` flag, Omnibus will generate the following "stock" resources in `resources/NAME/msi`: 18 | 19 | - `localization-en-us.wxl.erb` => File that contains the strings that are being used in the MSI user interface 20 | - `parameters.wxi.erb` => File that contains the dynamic information needed for the MSI e.g. version numbers 21 | - `assets/LICENSE.rtf` => License text in Rich Text Format that is displayed during MSI installation 22 | - `assets/*.bmp` => Bitmaps that are displayed during installation 23 | - `assets/*.ico` => Icons that are used in the system for your application 24 | 25 | You should use these stock files and templates as a starting point for building your custom msi. 26 | 27 | These files are XML files that are created based on Windows WIX Schema. By default they will package the files under configured `install_dir` and present a UI that lets users to choose an installation location for the packaged files. You can modify these XML files based on the [WIX documentation](http://wixtoolset.org/documentation/manual/v3/xsd/). 28 | 29 | ### DSL 30 | By default, Omnibus will try to build an msi package when executed on a Windows operating system. You can further customize the behavior of the packager using the `package` DSL command in your project definition: 31 | 32 | ```ruby 33 | # project.rb 34 | name 'hamlet' 35 | 36 | package :msi do 37 | upgrade_code '2CD7259C-776D-4DDB-A4C8-6E544E580AA1' 38 | parameters { 39 | 'KeyThing' => 'ValueThing' 40 | } 41 | localization 'da-dk' 42 | end 43 | ``` 44 | 45 | Note that `upgrade_code` is **required** and will raise an exception if not defined! Once set, this value must persist for all future versions of your package. To generate a GUID in Ruby, run the following command: 46 | 47 | ```bash 48 | ruby -r securerandom -e "puts SecureRandom.uuid" 49 | ``` 50 | 51 | Some DSL methods available include: 52 | 53 | | DSL Method | Description | 54 | | :----------------: | ------------------------------------------------| 55 | | **`upgrade_code`** | The unique GUID for this package | 56 | | `parameters` | And arbirtary list of key-value pairs to render | 57 | | `localization` | The language to display in the UI | 58 | 59 | For more information, please see the [`Packager::MSI` documentation](http://www.rubydoc.info/github/chef/omnibus/Omnibus/Packager/MSI). 60 | -------------------------------------------------------------------------------- /docs/Overview.md: -------------------------------------------------------------------------------- 1 | # Developer's Guide to Omnibus 2 | 3 | ## Overview 4 | 5 | Omnibus is a command-line tool that helps you define and create trusted OS native packages for software that you want to distribute. Read more about omnibus [here](https://github.com/chef/omnibus/blob/main/README.md). 6 | 7 | ## Development setup 8 | 9 | To setup omnibus for development- 10 | 1. Fork and clone the [omnibus repository](https://github.com/chef/omnibus) in GitHub. 11 | 1. Ensure you have a recent version of Ruby installed on your system. 12 | 1. Run `bundle install` in the repository directory. 13 | 1. You will now have the `omnibus` command available in the `./bin` directory. 14 | 15 | ## Execution Flow 16 | 17 | When `omnibus build ` is run, the execution sequence is as illustrated [here](./Sequence%20Diagram%20-%20Omnibus%20Build.pdf). An omnibus project typically includes one or more dependency software definitions. Common reusable software definitions can be referred from the [omnibus-sotware](https://github.com/chef/omnibus-software) repository. The project specific build steps are defined in a counterpart software definition of the same name, in a `build do ... end` block. 18 | 19 | A summary of steps run during project build 20 | 1. The client (typically the CLI) loads the project 21 | 1. Project 'load' involves loading all software dependency definitions. 22 | 1. The 'load' step parses necessary metadata to help determine software source, license information and to apply project specific overrides. 23 | 1. Once all software dependencies are successfully loaded for the current OS, the 'build' step commences. 24 | 1. The 'build' step is composed of these sub-steps 25 | * Based on software definition parsed in the 'load' step, license check is run to ensure that the build adheres to relevant terms in dependencies used. 26 | * After license check is successful, the software source is downloaded or pulled from cache. 27 | * Each software dependency is built in the order specified across all the definitions. Pre-built binaries may be pulled from cache. 28 | * Apart from Windows, on Linux, macOS and other OSes, a health check is run to verify no external or system libraries are linked. 29 | * Once all binaries are ready as part of the payload, the OS native installer package is created and signed. 30 | * An optional compression step optimizes and 'beautifies' the installer package. 31 | -------------------------------------------------------------------------------- /docs/Sequence Diagram - Omnibus Build.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/docs/Sequence Diagram - Omnibus Build.pdf -------------------------------------------------------------------------------- /features/commands/build.feature: -------------------------------------------------------------------------------- 1 | Feature: omnibus build 2 | Background: 3 | Given I have an omnibus project named "hamlet" 4 | 5 | Scenario: When the project does not exist 6 | When I run `omnibus build bacon` 7 | 8 | Then the output should contain: 9 | """ 10 | I could not find a project named `bacon' in any of the project locations: 11 | """ 12 | And the exit status should not be 0 13 | 14 | # These scenarios don't work on appveyor due to no heat.exe/candle.exe/light.exe 15 | # Scenario: When the project has no software definitions 16 | # When I run `omnibus build hamlet` 17 | # 18 | # Then it should pass with "[Project: hamlet] I | Building version manifest" 19 | # And the file "output/version-manifest.json" should exist 20 | # And the file "output/version-manifest.txt" should exist 21 | # And the file "output/LICENSE" should exist 22 | # And the directory "output/LICENSES" should exist 23 | # 24 | # Scenario: When the project has a software definition 25 | # Given a file "config/software/ophelia.rb" with: 26 | # """ 27 | # name "ophelia" 28 | # default_version "1.0.0" 29 | # build do 30 | # command "echo true > #{install_dir}/blah.txt" 31 | # end 32 | # """ 33 | # And I append to "config/projects/hamlet.rb" with "dependency 'ophelia'" 34 | # 35 | # When I run `omnibus build hamlet` 36 | # 37 | # Then it should pass with "[Builder: ophelia] I | $ echo true" 38 | # And the file "output/blah.txt" should contain "true" 39 | # And the file "output/version-manifest.json" should exist 40 | # And the file "output/version-manifest.txt" should exist 41 | # And the file "output/LICENSE" should exist 42 | # And the directory "output/LICENSES" should exist 43 | -------------------------------------------------------------------------------- /features/commands/clean.feature: -------------------------------------------------------------------------------- 1 | Feature: omnibus clean 2 | Scenario: When a bad name is given 3 | * I run `omnibus clean hamlet` 4 | * the output should contain: 5 | """ 6 | I could not find a project named `hamlet' in any of the project locations: 7 | """ 8 | * the exit status should not be 0 9 | 10 | Scenario: When the --purge option is given 11 | * I have an omnibus project named "hamlet" 12 | * I successfully run `omnibus clean hamlet --purge` 13 | * the output should contain "remove output" 14 | 15 | Scenario: When no options are given 16 | * I have an omnibus project named "hamlet" 17 | * I successfully run `omnibus clean hamlet` 18 | * the output should not contain: 19 | """ 20 | remove output 21 | """ 22 | -------------------------------------------------------------------------------- /features/commands/list.feature: -------------------------------------------------------------------------------- 1 | Feature: omnibus list 2 | Scenario: When there are Omnibus projects 3 | * I have an omnibus project named "hamlet" 4 | * I successfully run `omnibus list` 5 | * the output should contain: 6 | """ 7 | Omnibus projects: 8 | * hamlet (1.0.0) 9 | """ 10 | 11 | Scenario: When there are no Omnibus projects 12 | * I successfully run `omnibus list` 13 | * the output should contain: 14 | """ 15 | There are no Omnibus projects! 16 | """ 17 | -------------------------------------------------------------------------------- /features/commands/new.feature: -------------------------------------------------------------------------------- 1 | Feature: omnibus new 2 | Scenario: When the --path option is given 3 | * I successfully run `omnibus new hamlet --path nested/path` 4 | * a file named "nested/path/omnibus-hamlet/config/projects/hamlet.rb" should exist 5 | 6 | Scenario: When no options are given 7 | * I successfully run `omnibus new hamlet` 8 | * a file named "omnibus-hamlet/config/projects/hamlet.rb" should exist 9 | -------------------------------------------------------------------------------- /features/commands/publish.feature: -------------------------------------------------------------------------------- 1 | Feature: omnibus publish 2 | Scenario: Providing platform mappings file 3 | * I have a platform mappings file named "platform_mappings.json" 4 | * I run `omnibus publish artifactory fake * --platform-mappings platform_mappings.json` 5 | * the output should contain: 6 | """ 7 | Publishing will be performed using provided platform mappings. 8 | """ 9 | 10 | Scenario: When a user provides the deprecated `--version-manifest` flag 11 | * I run `omnibus publish artifactory fake * --version-manifest /fake/path/version-manifest.json` 12 | * the output should contain: 13 | """ 14 | The `--version-manifest' option has been deprecated. Version manifest data is now part of the `*.metadata.json' file 15 | """ 16 | -------------------------------------------------------------------------------- /features/commands/version.feature: -------------------------------------------------------------------------------- 1 | Feature: omnibus version 2 | Scenario: When the -v flag is specified 3 | * I successfully run `omnibus -v` 4 | * the output should match /^Omnibus v(.+)$/ 5 | 6 | Scenario: When the --version flag is specified 7 | * I successfully run `omnibus --version` 8 | * the output should match /^Omnibus v(.+)$/ 9 | 10 | Scenario: When the version command is given 11 | * I successfully run `omnibus version` 12 | * the output should match /^Omnibus v(.+)$/ 13 | -------------------------------------------------------------------------------- /features/step_definitions/generator_steps.rb: -------------------------------------------------------------------------------- 1 | require "aruba/api" 2 | 3 | Given(/^I have an omnibus project named "(.+)"$/) do |name| 4 | create_directory(name) 5 | cd(name) 6 | 7 | # Build target dir must be created 8 | abs_path = expand_path(".") 9 | 10 | # Single top level output dir 11 | create_directory("output") 12 | 13 | write_file("config/projects/#{name}.rb", <<-EOH.gsub(/^ {4}/, "")) 14 | name '#{name}' 15 | maintainer 'Mrs. Maintainer' 16 | homepage 'https://example.com' 17 | install_dir "#{abs_path}/output" 18 | 19 | build_version '1.0.0' 20 | 21 | exclude '\.git*' 22 | exclude 'bundler\/git' 23 | 24 | # This is necessary for Windows to pass. 25 | package :msi do 26 | upgrade_code "102FDF98-B9BF-4CE1-A716-2AB9CBCDA403" 27 | end 28 | EOH 29 | 30 | write_file("omnibus.rb", <<-EOH.gsub(/^ {4}/, "")) 31 | # Build configuration 32 | append_timestamp false 33 | cache_dir '#{abs_path}/local/omnibus/cache' 34 | git_cache_dir '#{abs_path}/local/omnibus/cache/git_cache' 35 | source_dir '#{abs_path}/local/omnibus/src' 36 | build_dir '#{abs_path}/local/omnibus/build' 37 | package_dir '#{abs_path}/local/omnibus/pkg' 38 | package_tmp '#{abs_path}/local/omnibus/pkg-tmp' 39 | EOH 40 | end 41 | 42 | Given(/^I debug$/) do 43 | require "pry" 44 | end 45 | 46 | Given(/^I have a platform mappings file named "(.+)"$/) do |name| 47 | write_file(name, <<-EOH.gsub(/^ {4}/, "")) 48 | { 49 | "ubuntu-10.04-x86_64": [ 50 | "ubuntu-10.04-x86_64", 51 | "ubuntu-12.04-x86_64", 52 | "ubuntu-14.04-x86_64" 53 | ] 54 | } 55 | EOH 56 | end 57 | -------------------------------------------------------------------------------- /features/support/env.rb: -------------------------------------------------------------------------------- 1 | require "aruba" 2 | require "aruba/cucumber" 3 | require "aruba/processes/in_process" 4 | 5 | require "omnibus/cli" 6 | 7 | Aruba.configure do |config| 8 | config.command_launcher = :in_process 9 | config.main_class = Omnibus::CLI::Runner 10 | end 11 | 12 | Before do 13 | # Reset anything that might have been cached in the Omnibus project 14 | Omnibus.reset!(true) 15 | end 16 | -------------------------------------------------------------------------------- /lib/omnibus/assets/README-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/lib/omnibus/assets/README-logo.png -------------------------------------------------------------------------------- /lib/omnibus/assets/logo.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/lib/omnibus/assets/logo.psd -------------------------------------------------------------------------------- /lib/omnibus/build_system_metadata.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require "omnibus/build_system_metadata/buildkite" 18 | 19 | module Omnibus 20 | # Provides methods for fetching Omnibus project build metadata from Buildkite 21 | # 22 | # @note Requires environment variables provided whichever platform metdata is being pulled from 23 | # 24 | class BuildSystemMetadata 25 | 26 | class << self 27 | 28 | def to_hash 29 | if !ENV["BUILDKITE"].nil? && !ENV["BUILDKITE"].empty? 30 | Omnibus::Buildkite.to_hash 31 | end 32 | end 33 | 34 | end 35 | end 36 | end -------------------------------------------------------------------------------- /lib/omnibus/changelog.rb: -------------------------------------------------------------------------------- 1 | require "omnibus/git_repository" 2 | 3 | module Omnibus 4 | class ChangeLog 5 | CHANGELOG_TAG = "ChangeLog-Entry".freeze 6 | 7 | attr_reader :end_ref 8 | def initialize(start_ref = nil, end_ref = "HEAD", git_repo = GitRepository.new("./")) 9 | @start_ref = start_ref 10 | @end_ref = end_ref 11 | @git_repo = git_repo 12 | end 13 | 14 | def authors 15 | git_repo.authors(start_ref, end_ref) 16 | end 17 | 18 | def changelog_entries 19 | entries = [] 20 | current_entry = [] 21 | git_repo.commit_messages(start_ref, end_ref).each do |l| 22 | if blank?(l) 23 | entries << current_entry 24 | current_entry = [] 25 | elsif tagged?(l) 26 | entries << current_entry 27 | current_entry = Array(l.sub(/^#{CHANGELOG_TAG}:[\s]*/, "")) 28 | elsif !current_entry.empty? 29 | current_entry << l 30 | end 31 | end 32 | entries << current_entry 33 | entries.reject(&:empty?).map(&:join) 34 | end 35 | 36 | def start_ref 37 | @start_ref ||= git_repo.latest_tag 38 | end 39 | 40 | private 41 | 42 | attr_reader :git_repo 43 | 44 | def blank?(line) 45 | line =~ /^[\s]*$/ 46 | end 47 | 48 | def tagged?(line) 49 | line =~ /^#{CHANGELOG_TAG}:/ 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /lib/omnibus/changelog_printer.rb: -------------------------------------------------------------------------------- 1 | module Omnibus 2 | class ChangeLogPrinter 3 | 4 | def initialize(changelog, diff, source_path = "../") 5 | @changelog = changelog 6 | @diff = diff 7 | @source_path = source_path 8 | end 9 | 10 | def print(new_version) 11 | puts "## #{new_version} (#{Time.now.strftime("%Y-%m-%d")})" 12 | print_changelog 13 | unless diff.empty? 14 | print_components 15 | puts "" 16 | end 17 | print_contributors 18 | end 19 | 20 | private 21 | 22 | attr_reader :changelog, :diff, :source_path 23 | 24 | def print_changelog(cl = changelog, indent = 0) 25 | cl.changelog_entries.each do |entry| 26 | puts "#{" " * indent}* #{entry.sub("\n", "\n #{" " * indent}")}\n" 27 | end 28 | end 29 | 30 | def print_components 31 | puts "### Components\n" 32 | print_new_components 33 | print_updated_components 34 | print_removed_components 35 | end 36 | 37 | def print_new_components 38 | return if diff.added.empty? 39 | 40 | puts "New Components" 41 | diff.added.each do |entry| 42 | puts "* #{entry[:name]} (#{entry[:new_version]})" 43 | end 44 | puts "" 45 | end 46 | 47 | def print_updated_components 48 | return if diff.updated.empty? 49 | 50 | puts "Updated Components" 51 | diff.updated.each do |entry| 52 | puts sprintf("* %s (%.8s -> %.8s)", 53 | entry[:name], entry[:old_version], entry[:new_version]) 54 | repo_path = ::File.join(source_path, entry[:name].to_s) 55 | if entry[:source_type] == :git && ::File.directory?("#{repo_path}/.git") 56 | cl = ChangeLog.new(entry[:old_version], entry[:new_version], GitRepository.new("#{repo_path}")) 57 | print_changelog(cl, 2) 58 | end 59 | end 60 | puts "" 61 | end 62 | 63 | def print_removed_components 64 | return if diff.removed.empty? 65 | 66 | puts "Removed Components" 67 | diff.removed.each do |entry| 68 | puts "* #{entry[:name]} (#{entry[:old_version]})" 69 | end 70 | puts "" 71 | end 72 | 73 | def print_contributors 74 | puts "### Contributors\n" 75 | changelog.authors.each do |author| 76 | puts "* #{author}" 77 | end 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /lib/omnibus/cleaner.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require "thor" unless defined?(Thor) 18 | 19 | module Omnibus 20 | class Cleaner < Thor::Group 21 | include Thor::Actions 22 | 23 | namespace :clean 24 | 25 | argument :name, 26 | banner: "NAME", 27 | desc: "The name of the Omnibus project", 28 | type: :string, 29 | required: true 30 | 31 | class_option :purge, 32 | desc: "Purge the packages and caches", 33 | type: :boolean, 34 | default: false 35 | 36 | def initialize(*) 37 | super 38 | @project = Project.load(name) 39 | end 40 | 41 | def clean_source_dir 42 | FileSyncer.glob("#{Config.source_dir}/**/*").each(&method(:remove_file)) 43 | end 44 | 45 | def clean_build_dir 46 | FileSyncer.glob("#{Config.build_dir}/**/*").each(&method(:remove_file)) 47 | end 48 | 49 | def clean_package_dir 50 | return unless purge? 51 | 52 | FileSyncer.glob("#{Config.package_dir}/**/*").each(&method(:remove_file)) 53 | end 54 | 55 | def clean_cache_dir 56 | return unless purge? 57 | 58 | FileSyncer.glob("#{Config.cache_dir}/**/*").each(&method(:remove_file)) 59 | end 60 | 61 | def clean_install_dir 62 | return unless purge? 63 | 64 | remove_file(@project.install_dir) 65 | end 66 | 67 | private 68 | 69 | def purge? 70 | !!options[:purge] 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /lib/omnibus/cli/base.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013-2014 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # 18 | # This is the base class that all commands and subcommands should extend from. 19 | # It handles all of the Thor nastiness and method mutating, as well as defining 20 | # the global configuration options. 21 | # 22 | module Omnibus 23 | class Command::Base < Thor 24 | class << self 25 | def dispatch(m, args, options, config) 26 | # Handle the case where Thor thinks a trailing --help is actually an 27 | # argument and blows up... 28 | if args.length > 1 && !(args & Thor::HELP_MAPPINGS).empty? 29 | args -= Thor::HELP_MAPPINGS 30 | args.insert(-2, "help") 31 | end 32 | 33 | super 34 | end 35 | 36 | def exit_on_failure? 37 | true 38 | end 39 | end 40 | 41 | include Logging 42 | 43 | def initialize(args, options, config) 44 | super(args, options, config) 45 | 46 | # Set the log_level 47 | if @options[:log_level] 48 | Omnibus.logger.level = @options[:log_level] 49 | end 50 | 51 | # Do not load the Omnibus config if we are asking for help or the version 52 | if %w{help version}.include?(config[:current_command].name) 53 | log.debug(log_key) { "Skipping Omnibus loading (detected help or version)" } 54 | return 55 | end 56 | 57 | if File.exist?(@options[:config]) 58 | log.info(log_key) { "Using config from '#{@options[:config]}'" } 59 | Omnibus.load_configuration(@options[:config]) 60 | else 61 | if @options[:config] == Omnibus::DEFAULT_CONFIG 62 | log.debug(log_key) { "Config file not given - using defaults" } 63 | else 64 | raise "The given config file '#{@options[:config]}' does not exist!" 65 | end 66 | end 67 | 68 | @options[:override].each do |key, value| 69 | if %w{true false nil}.include?(value) 70 | log.debug(log_key) { "Detected #{value.inspect} should be an object" } 71 | value = { "true" => true, "false" => false, "nil" => nil }[value] 72 | end 73 | 74 | if value =~ /\A[[:digit:]]+\Z/ 75 | log.debug(log_key) { "Detected #{value.inspect} should be an integer" } 76 | value = value.to_i 77 | end 78 | 79 | if Config.respond_to?(key) 80 | log.debug(log_key) { "Setting Config.#{key} = #{value.inspect}" } 81 | Config.send(key, value) 82 | else 83 | log.debug (log_key) { "Skipping option '#{key}' - not a config option" } 84 | end 85 | end 86 | end 87 | 88 | class_option :config, 89 | desc: "Path to the Omnibus config file", 90 | aliases: "-c", 91 | type: :string, 92 | default: Omnibus::DEFAULT_CONFIG 93 | class_option :log_level, 94 | desc: "The log level", 95 | aliases: "-l", 96 | type: :string, 97 | enum: Logger::LEVELS.map(&:downcase), 98 | default: "info" 99 | class_option :override, 100 | desc: "Override one or more Omnibus config options", 101 | aliases: "-o", 102 | type: :hash, 103 | default: {} 104 | 105 | # 106 | # Hide the default help task to encourage people to use +-h+ instead of 107 | # Thor's dumb way of asking for help. 108 | # 109 | desc "help [COMMAND]", "Show help output", hide: true 110 | def help(*) 111 | super 112 | end 113 | end 114 | end 115 | -------------------------------------------------------------------------------- /lib/omnibus/cli/cache.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013-2014 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | class Command::Cache < Command::Base 19 | namespace :cache 20 | 21 | # 22 | # List the existing software packages in the cache. 23 | # 24 | # $ omnibus cache existing 25 | # 26 | desc "existing", "List software packages which exist in the cache" 27 | def existing 28 | result = S3Cache.list 29 | 30 | if result.empty? 31 | say("There are no packages in the cache!") 32 | else 33 | say("The following packages are in the cache:") 34 | result.each do |software| 35 | say(" * #{software.name}-#{software.version}") 36 | end 37 | end 38 | end 39 | 40 | # 41 | # List all cached files (by S3 key). 42 | # 43 | # $ omnibus cache list 44 | # 45 | desc "list", "List all cached files (by S3 key)" 46 | def list 47 | result = S3Cache.keys 48 | 49 | if result.empty? 50 | say("There is nothing in the cache!") 51 | else 52 | say("Cached files (by S3 key):") 53 | result.each do |key| 54 | say(" * #{key}") 55 | end 56 | end 57 | end 58 | 59 | # 60 | # List missing software packages. 61 | # 62 | # $ omnibus cache missing 63 | # 64 | desc "missing", "Lists software packages that are required but not yet cached" 65 | def missing 66 | result = S3Cache.missing 67 | 68 | if result.empty? 69 | say("There are no missing packages in the cache.") 70 | else 71 | say("The following packages are missing from the cache:") 72 | result.each do |software| 73 | say(" * #{software.name}-#{software.version}") 74 | end 75 | end 76 | end 77 | 78 | # 79 | # Fetch missing software packages locally 80 | # 81 | # $ omnibus cache fetch 82 | # 83 | desc "fetch", "Fetches missing software packages locally" 84 | def fetch 85 | say("Fetching missing packages...") 86 | S3Cache.fetch_missing 87 | end 88 | 89 | # 90 | # Populate the remote S3 cache from local. 91 | # 92 | # $ omnibus cache populate 93 | # 94 | desc "populate", "Populate the S3 Cache" 95 | def populate 96 | say("Populating the cache...") 97 | S3Cache.populate 98 | end 99 | end 100 | end 101 | -------------------------------------------------------------------------------- /lib/omnibus/cli/publish.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013-2014 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | class Command::Publish < Command::Base 19 | namespace :publish 20 | 21 | # This option is useful for publish packages that were built for a 22 | # particular platform/version but tested on other platform/versions. 23 | # 24 | # For example, one might build on Ubuntu 10.04 and test/publish on 25 | # Ubuntu 10.04, 12.04, and 14.04. 26 | # 27 | # @example JSON 28 | # { 29 | # "ubuntu-10.04-x86_64": [ 30 | # "ubuntu-10.04-x86_64", 31 | # "ubuntu-12.04-x86_64", 32 | # "ubuntu-14.04-x86_64" 33 | # ] 34 | # } 35 | # 36 | class_option :platform_mappings, 37 | desc: "The optional platform mappings JSON file to publish with", 38 | type: :string 39 | 40 | class_option :version_manifest, 41 | desc: "Path to the version-manifest.json file to publish with", 42 | type: :string 43 | 44 | # 45 | # Publish to S3. 46 | # 47 | # $ omnibus publish s3 buckethands pkg/chef* 48 | # 49 | method_option :acl, 50 | type: :string, 51 | desc: "The accessibility of the uploaded packages", 52 | enum: %w{public private}, 53 | default: "private" 54 | method_option :region, 55 | type: :string, 56 | desc: "The region in which the bucket is located", 57 | default: "us-east-1" 58 | desc "s3 BUCKET PATTERN", "Publish to an S3 bucket" 59 | def s3(bucket, pattern) 60 | options[:bucket] = bucket 61 | publish(S3Publisher, pattern, options) 62 | end 63 | 64 | # 65 | # Publish to artifactory. 66 | # 67 | # $ omnibus publish artifactory libs-omnibus-local pkg/chef* 68 | # 69 | method_option :build_record, 70 | type: :boolean, 71 | desc: "Optionally create an Artifactory build record for the published artifacts", 72 | default: true 73 | method_option :properties, 74 | type: :hash, 75 | desc: "Properites to attach to published artifacts", 76 | default: {} 77 | desc "artifactory REPOSITORY PATTERN", "Publish to an Artifactory instance" 78 | def artifactory(repository, pattern) 79 | if options[:version_manifest] 80 | Omnibus.logger.deprecated("ArtifactoryPublisher") do 81 | "The `--version-manifest' option has been deprecated. Version manifest data is now part of the `*.metadata.json' file" 82 | end 83 | end 84 | 85 | options[:repository] = repository 86 | publish(ArtifactoryPublisher, pattern, options) 87 | end 88 | 89 | private 90 | 91 | # 92 | # Shortcut method for executing a publisher. 93 | # 94 | # @return [void] 95 | # 96 | def publish(klass, pattern, options) 97 | if options[:platform_mappings] 98 | options[:platform_mappings] = FFI_Yajl::Parser.parse(File.read(File.expand_path(options[:platform_mappings]))) 99 | end 100 | 101 | klass.publish(pattern, options) do |package| 102 | say("Published '#{package.name}' for #{package.metadata[:platform]}-#{package.metadata[:platform_version]}-#{package.metadata[:arch]}", :green) 103 | end 104 | end 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /lib/omnibus/compressor.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | module Compressor 19 | include Logging 20 | 21 | autoload :Base, "omnibus/compressors/base" 22 | autoload :DMG, "omnibus/compressors/dmg" 23 | autoload :Null, "omnibus/compressors/null" 24 | autoload :TGZ, "omnibus/compressors/tgz" 25 | 26 | # 27 | # Determine the best compressor for the current system. This method returns 28 | # the class, not an instance of the class. 29 | # 30 | # @example 31 | # Compressor.for_current_system([:dmg, :tgz]) #=> Packager::DMG 32 | # 33 | # @param [Array] compressors 34 | # the list of configured compressors 35 | # 36 | # @return [~Compressor::Base] 37 | # 38 | def for_current_system(compressors) 39 | family = Ohai["platform_family"] 40 | 41 | if family == "mac_os_x" 42 | if compressors.include?(:dmg) 43 | return DMG 44 | end 45 | 46 | if compressors.include?(:tgz) 47 | return TGZ 48 | end 49 | end 50 | 51 | if compressors.include?(:tgz) 52 | TGZ 53 | else 54 | log.info(log_key) { "No compressor defined for `#{family}'." } 55 | Null 56 | end 57 | end 58 | module_function :for_current_system 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/omnibus/compressors/base.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require "fileutils" unless defined?(FileUtils) 18 | 19 | module Omnibus 20 | class Compressor::Base < Packager::Base 21 | # The {Project} instance that we are compressing 22 | attr_reader :project 23 | 24 | # The {Packager::Base} instance that produced the compressed file 25 | attr_reader :packager 26 | 27 | # 28 | # Create a new compressor object from the given packager. 29 | # 30 | # @param [Project] project 31 | # 32 | def initialize(project) 33 | @project = project 34 | 35 | # There can now be multiple packagers per platform 36 | # but windows is the only platform that uses multiple 37 | # packagers and it does not use a compressor. So for now, 38 | # we ignore this multi packaging reality in compressors 39 | @packager = project.packagers_for_system[0] 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /lib/omnibus/compressors/null.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the ''License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | class Compressor::Null < Compressor::Base 19 | id :null 20 | 21 | def package_name 22 | "" 23 | end 24 | 25 | def run! 26 | # noop 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/omnibus/core_extensions.rb: -------------------------------------------------------------------------------- 1 | require "omnibus/core_extensions/open_uri" 2 | -------------------------------------------------------------------------------- /lib/omnibus/core_extensions/open_uri.rb: -------------------------------------------------------------------------------- 1 | require "open-uri" unless defined?(OpenURI) 2 | 3 | module OpenURI 4 | class << self 5 | # 6 | # The is a bug in Ruby's implementation of OpenURI that prevents redirects 7 | # from HTTP -> HTTPS. That should totally be a valid redirect, so we 8 | # override that method here and call it a day. 9 | # 10 | # Note: this does NOT permit HTTPS -> HTTP redirects, as that would be a 11 | # major security hole in the fabric of space-time! 12 | # 13 | def default_redirectable?(uri1, uri2) 14 | a, b = uri1.scheme.downcase, uri2.scheme.downcase 15 | 16 | a == b || (a == "http" && b == "https") 17 | end 18 | alias_method :redirectable?, :default_redirectable? 19 | 20 | # 21 | # Permit all redirects. 22 | # 23 | # Note: this DOES permit HTTP -> HTTP redirects, and that is a major 24 | # security hole! 25 | # 26 | # @return [true] 27 | # 28 | def unsafe_redirectable?(uri1, uri2) 29 | a, b = uri1.scheme.downcase, uri2.scheme.downcase 30 | 31 | a == b || (a == "http" && b == "https") || (a == "https" && b == "http") 32 | end 33 | 34 | # 35 | # Override the default open_uri method to search for our custom option to 36 | # permit unsafe redirects. 37 | # 38 | # @example 39 | # open('http://example.com', allow_unsafe_redirects: true) 40 | # 41 | alias_method :original_open_uri, :open_uri 42 | def open_uri(name, *rest, &block) 43 | options = rest.find { |arg| arg.is_a?(Hash) } || {} 44 | 45 | if options.delete(:allow_unsafe_redirects) 46 | class << self 47 | alias_method :redirectable?, :unsafe_redirectable? 48 | end 49 | end 50 | 51 | original_open_uri(name, *rest, &block) 52 | ensure 53 | class << self 54 | alias_method :redirectable?, :default_redirectable? 55 | end 56 | end 57 | end 58 | 59 | # 60 | # Force Kernel#open to always return a Tempfile. This works around the fact 61 | # that the OpenURI-provided Kernel#open returns a StringIO OR a Tempfile 62 | # instances depending on the size of the data being downloaded. In the case 63 | # of Omnibus we always want a Tempfile. 64 | # 65 | # @see http://winstonyw.com/2013/10/02/openuris_open_tempfile_and_stringio/ 66 | # 67 | # rubocop:disable Naming/ConstantName 68 | class Buffer 69 | remove_const :StringMax 70 | StringMax = 0 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /lib/omnibus/fetchers/file_fetcher.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require "fileutils" unless defined?(FileUtils) 18 | 19 | module Omnibus 20 | class FileFetcher < Fetcher 21 | # 22 | # Fetch if the local file checksum is different than the path file 23 | # checksum. 24 | # 25 | # @return [true, false] 26 | # 27 | def fetch_required? 28 | target_shasum != destination_shasum 29 | end 30 | 31 | # 32 | # The version identifier for this file. This is computed using the file 33 | # on disk to the source and the shasum of that file on disk. 34 | # 35 | # @return [String] 36 | # 37 | def version_guid 38 | "file:#{source_file}" 39 | end 40 | 41 | # 42 | # Clean the given path by removing the project directory. 43 | # 44 | # @return [true, false] 45 | # true if the directory was cleaned, false otherwise. 46 | # Since we do not currently use the cache to sync files and 47 | # always fetch from source, there is no need to clean anything. 48 | # The fetch step (which needs to be called before clean) would 49 | # have already removed anything extraneous. 50 | # 51 | def clean 52 | true 53 | end 54 | 55 | # 56 | # Fetch any new files by copying them to the +project_dir+. 57 | # 58 | # @return [void] 59 | # 60 | def fetch 61 | log.info(log_key) { "Copying from `#{source_file}'" } 62 | 63 | create_required_directories 64 | FileUtils.cp(source_file, target_file) 65 | # Reset target shasum on every fetch 66 | @target_shasum = nil 67 | target_shasum 68 | end 69 | 70 | # 71 | # The version for this item in the cache. The is the shasum of the file 72 | # on disk. 73 | # 74 | # This method is called *before* clean but *after* fetch. Since fetch 75 | # automatically cleans, target vs. destination sha doesn't matter. Change this 76 | # if that assumption changes. 77 | # 78 | # @return [String] 79 | # 80 | def version_for_cache 81 | "file:#{source_file}|shasum:#{destination_shasum}" 82 | end 83 | 84 | # 85 | # @return [String, nil] 86 | # 87 | def self.resolve_version(version, source) 88 | version 89 | end 90 | 91 | private 92 | 93 | # 94 | # The path on disk to pull the file from. 95 | # 96 | # @return [String] 97 | # 98 | def source_file 99 | source[:file] 100 | end 101 | 102 | # 103 | # The path on disk where the file is stored. 104 | # 105 | # @return [String] 106 | # 107 | def target_file 108 | File.join(project_dir, File.basename(source_file)) 109 | end 110 | 111 | # 112 | # The shasum of the file **inside** the project. 113 | # 114 | # @return [String, nil] 115 | # 116 | def target_shasum 117 | @target_shasum ||= digest(target_file, :sha256) 118 | rescue Errno::ENOENT 119 | @target_shasum = nil 120 | end 121 | 122 | # 123 | # The shasum of the file **outside** of the project. 124 | # 125 | # @return [String] 126 | # 127 | def destination_shasum 128 | @destination_shasum ||= digest(source_file, :sha256) 129 | end 130 | end 131 | end 132 | -------------------------------------------------------------------------------- /lib/omnibus/fetchers/null_fetcher.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | class NullFetcher < Fetcher 19 | # 20 | # @return [false] 21 | # 22 | def fetch_required? 23 | true 24 | end 25 | 26 | # 27 | # @return [nil] 28 | # 29 | def version_guid 30 | nil 31 | end 32 | 33 | # 34 | # @return [String, nil] 35 | # 36 | def self.resolve_version(version, source) 37 | version 38 | end 39 | 40 | # 41 | # @return [false] 42 | # 43 | def clean 44 | false 45 | end 46 | 47 | # 48 | # @return [void] 49 | # 50 | def fetch 51 | log.info(log_key) { "Fetching `#{name}' (nothing to fetch)" } 52 | 53 | create_required_directories 54 | nil 55 | end 56 | 57 | # 58 | # @return [String] 59 | # 60 | def version_for_cache 61 | nil 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/omnibus/fetchers/path_fetcher.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require "fileutils" unless defined?(FileUtils) 18 | 19 | module Omnibus 20 | class PathFetcher < Fetcher 21 | # 22 | # Fetch if the local directory checksum is different than the path directory 23 | # checksum. 24 | # 25 | # @return [true, false] 26 | # 27 | def fetch_required? 28 | target_shasum != destination_shasum 29 | end 30 | 31 | # 32 | # The version identifier for this path. This is computed using the path 33 | # on disk to the source and the recursive shasum of that path on disk. 34 | # 35 | # @return [String] 36 | # 37 | def version_guid 38 | "path:#{source_path}" 39 | end 40 | 41 | # 42 | # Clean the given path by removing the project directory. 43 | # 44 | # @return [true, false] 45 | # true if the directory was cleaned, false otherwise. 46 | # Since we do not currently use the cache to sync files and 47 | # always fetch from source, there is no need to clean anything. 48 | # The fetch step (which needs to be called before clean) would 49 | # have already removed anything extraneous. 50 | # 51 | def clean 52 | true 53 | end 54 | 55 | # 56 | # Fetch any new files by copying them to the +project_dir+. 57 | # 58 | # @return [void] 59 | # 60 | def fetch 61 | log.info(log_key) { "Copying from `#{source_path}'" } 62 | 63 | create_required_directories 64 | FileSyncer.sync(source_path, project_dir, source_options) 65 | # Reset target shasum on every fetch 66 | @target_shasum = nil 67 | target_shasum 68 | end 69 | 70 | # 71 | # The version for this item in the cache. The is the shasum of the directory 72 | # on disk. 73 | # 74 | # This method is called *before* clean but *after* fetch. Since fetch 75 | # automatically cleans, target vs. destination sha doesn't matter. Change this 76 | # if that assumption changes. 77 | # 78 | # @return [String] 79 | # 80 | def version_for_cache 81 | "path:#{source_path}|shasum:#{destination_shasum}" 82 | end 83 | 84 | # 85 | # @return [String, nil] 86 | # 87 | def self.resolve_version(version, source) 88 | version 89 | end 90 | 91 | private 92 | 93 | # 94 | # The path on disk to pull the files from. 95 | # 96 | # @return [String] 97 | # 98 | def source_path 99 | source[:path] 100 | end 101 | 102 | # 103 | # Options to pass to the underlying FileSyncer 104 | # 105 | # @return [Hash] 106 | # 107 | def source_options 108 | if source[:options] && source[:options].is_a?(Hash) 109 | source[:options] 110 | else 111 | {} 112 | end 113 | end 114 | 115 | # 116 | # The shasum of the directory **inside** the project. 117 | # 118 | # @return [String] 119 | # 120 | def target_shasum 121 | @target_shasum ||= digest_directory(project_dir, :sha256, source_options) 122 | end 123 | 124 | # 125 | # The shasum of the directory **outside** of the project. 126 | # 127 | # @return [String] 128 | # 129 | def destination_shasum 130 | @destination_shasum ||= digest_directory(source_path, :sha256, source_options) 131 | end 132 | end 133 | end 134 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/.kitchen.local.yml.erb: -------------------------------------------------------------------------------- 1 | # 2 | # The .kitchen.local.yml takes preference and is compiled into the top-level 3 | # .kitchen.yml. Uncomment the following section to use VMWare Fusion instead of 4 | # the default Vagrant driver of VirtualBox. 5 | # 6 | 7 | # driver: 8 | # provider: vmware_fusion 9 | # customize: 10 | # memsize: 4096 11 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/.kitchen.yml.erb: -------------------------------------------------------------------------------- 1 | driver: 2 | name: vagrant 3 | forward_agent: yes 4 | customize: 5 | cpus: 2 6 | memory: 2048 7 | synced_folders: 8 | - ['.', '/home/vagrant/<%= config[:name] %>'] 9 | 10 | provisioner: 11 | name: chef_zero 12 | 13 | platforms: 14 | - name: centos-6 15 | run_list: yum-epel::default 16 | - name: centos-7 17 | run_list: yum-epel::default 18 | - name: debian-8 19 | run_list: apt::default 20 | - name: debian-9 21 | run_list: apt::default 22 | - name: freebsd-10 23 | run_list: freebsd::portsnap 24 | - name: freebsd-11 25 | run_list: freebsd::portsnap 26 | - name: ubuntu-14.04 27 | run_list: apt::default 28 | - name: ubuntu-16.04 29 | run_list: apt::default 30 | - name: ubuntu-18.04 31 | run_list: apt::default 32 | 33 | suites: 34 | - name: default 35 | run_list: omnibus::default 36 | attributes: 37 | omnibus: 38 | build_user: vagrant 39 | build_user_group: vagrant 40 | build_user_password: vagrant 41 | install_dir: /opt/<%= config[:name] %> 42 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/Berksfile.erb: -------------------------------------------------------------------------------- 1 | source 'https://supermarket.chef.io' 2 | 3 | cookbook 'omnibus' 4 | 5 | # Uncomment to use the latest version of the Omnibus cookbook from GitHub 6 | # cookbook 'omnibus', github: 'chef-cookbooks/omnibus' 7 | 8 | group :integration do 9 | cookbook 'apt', '~> 2.8' 10 | cookbook 'freebsd', '~> 0.3' 11 | cookbook 'yum-epel', '~> 0.6' 12 | end 13 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/Gemfile.erb: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Install omnibus 4 | gem 'omnibus', '~> <%= Omnibus::VERSION.split('.')[0...-1].join('.') %>' 5 | 6 | # Use Chef's software definitions. It is recommended that you write your own 7 | # software definitions, but you can clone/fork Chef's to get you started. 8 | # gem 'omnibus-software', github: 'chef/omnibus-software' 9 | 10 | # This development group is installed by default when you run `bundle install`, 11 | # but if you are using Omnibus in a CI-based infrastructure, you do not need 12 | # the Test Kitchen-based build lab. You can skip these unnecessary dependencies 13 | # by running `bundle install --without development` to speed up build times. 14 | group :development do 15 | # Use Berkshelf for resolving cookbook dependencies 16 | gem 'berkshelf' 17 | 18 | # Use Test Kitchen with Vagrant for converging the build environment 19 | gem 'test-kitchen' 20 | gem 'kitchen-vagrant' 21 | end 22 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/config/projects/project.rb.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright <%= Time.now.year %> YOUR NAME 3 | # 4 | # All Rights Reserved. 5 | # 6 | 7 | name "<%= config[:name] %>" 8 | maintainer "CHANGE ME" 9 | homepage "https://CHANGE-ME.com" 10 | 11 | # Defaults to C:/<%= config[:name] %> on Windows 12 | # and /opt/<%= config[:name] %> on all other platforms 13 | install_dir "#{default_root}/#{name}" 14 | 15 | build_version Omnibus::BuildVersion.semver 16 | build_iteration 1 17 | 18 | # Creates required build directories 19 | dependency "preparation" 20 | 21 | # <%= config[:name] %> dependencies/components 22 | # dependency "somedep" 23 | 24 | exclude "**/.git" 25 | exclude "**/bundler/git" 26 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/config/software/preparation.rb.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright <%= Time.now.year %> YOUR NAME 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | name "preparation" 18 | description "the steps required to prepare the build" 19 | default_version "1.0.0" 20 | 21 | license :project_license 22 | skip_transitive_dependency_licensing true 23 | 24 | build do 25 | block do 26 | touch "#{install_dir}/embedded/lib/.gitkeep" 27 | touch "#{install_dir}/embedded/bin/.gitkeep" 28 | touch "#{install_dir}/bin/.gitkeep" 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/config/software/zlib.rb.erb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright <%= Time.now.year %> YOUR NAME 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | # These options are required for all software definitions 18 | name "<%= config[:name] %>-zlib" 19 | default_version "1.2.6" 20 | 21 | # A software can specify more than one version that is available for install 22 | version("1.2.6") { source md5: "618e944d7c7cd6521551e30b32322f4a" } 23 | version("1.2.8") { source md5: "44d667c142d7cda120332623eab69f40" } 24 | 25 | # Sources may be URLs, git locations, or path locations 26 | source url: "http://downloads.sourceforge.net/project/libpng/zlib/#{version}/zlib-#{version}.tar.gz" 27 | 28 | # This is the path, inside the tarball, where the source resides 29 | relative_path "zlib-#{version}" 30 | 31 | build do 32 | # Setup a default environment from Omnibus - you should use this Omnibus 33 | # helper everywhere. It will become the default in the future. 34 | env = with_standard_compiler_flags(with_embedded_path) 35 | 36 | # Manipulate any configure flags you wish: 37 | # For some reason zlib needs this flag on solaris 38 | env["CFLAGS"] << " -DNO_VIZ" if solaris? 39 | 40 | # "command" is part of the build DSL. There are a number of handy options 41 | # available, such as "copy", "sync", "ruby", etc. For a complete list, please 42 | # consult the Omnibus gem documentation. 43 | # 44 | # "install_dir" is exposed and refers to the top-level projects +install_dir+ 45 | command "./configure" \ 46 | " --prefix=#{install_dir}/embedded", env: env 47 | 48 | # You can have multiple steps - they are executed in the order in which they 49 | # are read. 50 | # 51 | # "workers" is a DSL method that returns the most suitable number of 52 | # builders for the currently running system. 53 | command "make -j #{workers}", env: env 54 | command "make -j #{workers} install", env: env 55 | end 56 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/gitignore.erb: -------------------------------------------------------------------------------- 1 | *.gem 2 | .bundle 3 | .kitchen/ 4 | .kitchen.local.yml 5 | vendor/bundle 6 | pkg/* 7 | .vagrant 8 | bin/* 9 | files/**/cache/ 10 | vendor/cookbooks 11 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/omnibus.rb.erb: -------------------------------------------------------------------------------- 1 | # 2 | # This file is used to configure the <%= config[:name] %> project. It contains 3 | # some minimal configuration examples for working with Omnibus. For a full list 4 | # of configurable options, please see the documentation for +omnibus/config.rb+. 5 | # 6 | 7 | # Build internally 8 | # ------------------------------ 9 | # By default, Omnibus uses system folders (like +/var+ and +/opt+) to build and 10 | # cache components. If you would to build everything internally, you can 11 | # uncomment the following options. This will prevent the need for root 12 | # permissions in most cases. 13 | # 14 | # Uncomment this line to change the default base directory to "local" 15 | # ------------------------------------------------------------------- 16 | # base_dir './local' 17 | # 18 | # Alternatively you can tune the individual values 19 | # ------------------------------------------------ 20 | # cache_dir './local/omnibus/cache' 21 | # git_cache_dir './local/omnibus/cache/git_cache' 22 | # source_dir './local/omnibus/src' 23 | # build_dir './local/omnibus/build' 24 | # package_dir './local/omnibus/pkg' 25 | # package_tmp './local/omnibus/pkg-tmp' 26 | 27 | # Disable git caching 28 | # ------------------------------ 29 | # use_git_caching false 30 | 31 | # Enable S3 asset caching 32 | # ------------------------------ 33 | # use_s3_caching true 34 | # s3_access_key ENV['AWS_ACCESS_KEY_ID'] 35 | # s3_secret_key ENV['AWS_SECRET_ACCESS_KEY'] 36 | # s3_profile ENV['AWS_S3_PROFILE'] 37 | # s3_iam_role_arn ENV['S3_IAM_ROLE_ARN'] 38 | # s3_bucket ENV['AWS_S3_BUCKET'] 39 | 40 | # Customize compiler bits 41 | # ------------------------------ 42 | # solaris_compiler 'gcc' 43 | # build_retries 5 44 | # fetcher_read_timeout 120 45 | # fetcher_retries 5 46 | 47 | # Load additional software 48 | # ------------------------------ 49 | # software_gems ['omnibus-software', 'my-company-software'] 50 | # local_software_dirs ['/path/to/local/software'] 51 | 52 | # Windows architecture defaults 53 | # ------------------------------ 54 | windows_arch %w{x86 x64}.include?((ENV['OMNIBUS_WINDOWS_ARCH'] || '').downcase) ? 55 | ENV['OMNIBUS_WINDOWS_ARCH'].downcase.to_sym : :x86 56 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/package_scripts/postinst.erb: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Perform necessary <%= config[:name] %> setup steps 4 | # after package is installed. 5 | # 6 | 7 | PROGNAME=`basename $0` 8 | 9 | error_exit() 10 | { 11 | echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2 12 | exit 1 13 | } 14 | 15 | echo "Thank you for installing <%= config[:name] %>!" 16 | 17 | exit 0 18 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/package_scripts/postrm.erb: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Perform necessary <%= config[:name] %> removal steps 4 | # after package is uninstalled. 5 | # 6 | 7 | echo "<%= config[:name] %> has been uninstalled!" 8 | 9 | exit 0 10 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/package_scripts/preinst.erb: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Perform necessary <%= config[:name] %> setup steps 4 | # before package is installed. 5 | # 6 | 7 | echo "You're about to install <%= config[:name] %>!" 8 | -------------------------------------------------------------------------------- /lib/omnibus/generator_files/package_scripts/prerm.erb: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Perform necessary <%= config[:name] %> setup steps 4 | # prior to installing package. 5 | # 6 | 7 | PROGNAME=`basename $0` 8 | 9 | error_exit() 10 | { 11 | echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2 12 | exit 1 13 | } 14 | 15 | exit 0 16 | -------------------------------------------------------------------------------- /lib/omnibus/git_repository.rb: -------------------------------------------------------------------------------- 1 | require "omnibus/util" 2 | 3 | module Omnibus 4 | class GitRepository 5 | include Util 6 | 7 | def initialize(path = "./") 8 | @repo_path = path 9 | end 10 | 11 | def authors(start_ref, end_ref) 12 | formatted_log_between(start_ref, end_ref, "%aN").lines.map(&:chomp).uniq 13 | end 14 | 15 | def commit_messages(start_ref, end_ref) 16 | formatted_log_between(start_ref, end_ref, "%B").lines.to_a 17 | end 18 | 19 | def revision 20 | git("rev-parse HEAD").strip 21 | end 22 | 23 | def latest_tag 24 | git("describe --abbrev=0").chomp 25 | end 26 | 27 | def file_at_revision(path, revision) 28 | git("show #{revision}:#{path}") 29 | end 30 | 31 | private 32 | 33 | attr_reader :repo_path 34 | 35 | def formatted_log_between(start_ref, end_ref, format) 36 | git("log #{start_ref}..#{end_ref} --pretty=\"format:#{format}\"") 37 | end 38 | 39 | def git(cmd) 40 | shellout!("git #{cmd}", cwd: repo_path).stdout 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/omnibus/instrumentation.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013-2014 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | module Instrumentation 19 | include Logging 20 | 21 | def measure(label, &block) 22 | start = Time.now 23 | yield 24 | ensure 25 | elapsed = Time.now - start 26 | log.info(log_key) { "#{label}: #{elapsed.to_f.round(4)}s" } 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/omnibus/logging.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013-2014 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | module Logging 19 | def self.included(base) 20 | base.send(:include, InstanceMethods) 21 | base.send(:extend, ClassMethods) 22 | end 23 | 24 | module ClassMethods 25 | private 26 | 27 | # 28 | # A helpful DSL method for logging an action. 29 | # 30 | # @return [Logger] 31 | # 32 | def log 33 | Omnibus.logger 34 | end 35 | 36 | # 37 | # The key to log with. 38 | # 39 | # @return [String] 40 | # 41 | def log_key 42 | @log_key ||= (name || "(Anonymous)").split("::")[1..-1].join("::") 43 | end 44 | end 45 | 46 | module InstanceMethods 47 | private 48 | 49 | # @see (ClassMethods#log) 50 | def log 51 | self.class.send(:log) 52 | end 53 | 54 | # @see (ClassMethods#log_key) 55 | def log_key 56 | self.class.send(:log_key) 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/omnibus/manifest_diff.rb: -------------------------------------------------------------------------------- 1 | module Omnibus 2 | class EmptyManifestDiff 3 | def updated 4 | [] 5 | end 6 | 7 | def added 8 | [] 9 | end 10 | 11 | def removed 12 | [] 13 | end 14 | 15 | def empty? 16 | true 17 | end 18 | end 19 | 20 | class ManifestDiff 21 | def initialize(first, second) 22 | @first = first 23 | @second = second 24 | end 25 | 26 | def updated 27 | @updated ||= 28 | (first.entry_names & second.entry_names).collect do |name| 29 | diff(first.entry_for(name), second.entry_for(name)) 30 | end.compact 31 | end 32 | 33 | def removed 34 | @removed ||= 35 | (first.entry_names - second.entry_names).collect do |name| 36 | removed_entry(first.entry_for(name)) 37 | end 38 | end 39 | 40 | def added 41 | @added ||= 42 | (second.entry_names - first.entry_names).collect do |name| 43 | new_entry(second.entry_for(name)) 44 | end 45 | end 46 | 47 | def empty? 48 | updated.empty? && removed.empty? && added.empty? 49 | end 50 | 51 | private 52 | 53 | attr_reader :first, :second 54 | 55 | def new_entry(entry) 56 | { name: entry.name, 57 | new_version: entry.locked_version, 58 | source_type: entry.source_type, 59 | source: entry.locked_source } 60 | end 61 | 62 | def removed_entry(entry) 63 | { name: entry.name, 64 | old_version: entry.locked_version, 65 | source_type: entry.source_type, 66 | source: entry.locked_source } 67 | end 68 | 69 | def diff(a, b) 70 | if a == b 71 | nil 72 | else 73 | { name: b.name, 74 | old_version: a.locked_version, 75 | new_version: b.locked_version, 76 | source_type: b.source_type, 77 | source: b.locked_source } 78 | end 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /lib/omnibus/manifest_entry.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | class ManifestEntry 19 | attr_reader :locked_version, :locked_source, :source_type, :described_version, :name, :license 20 | def initialize(name, manifest_data) 21 | @name = name 22 | @locked_version = manifest_data[:locked_version] 23 | @locked_source = manifest_data[:locked_source] 24 | @source_type = manifest_data[:source_type] 25 | @described_version = manifest_data[:described_version] 26 | @license = manifest_data[:license] 27 | end 28 | 29 | def to_hash 30 | { 31 | locked_version: @locked_version, 32 | locked_source: @locked_source, 33 | source_type: @source_type, 34 | described_version: @described_version, 35 | license: @license, 36 | } 37 | end 38 | 39 | def ==(other) 40 | if other.is_a?(ManifestEntry) 41 | (to_hash == other.to_hash) && (name == other.name) 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/omnibus/null_argumentable.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | module NullArgumentable 19 | # 20 | # The "empty" null object. 21 | # 22 | # @return [Object] 23 | # 24 | NULL = Object.new.freeze 25 | 26 | # 27 | # Called when the module is included. 28 | # 29 | # @param [Object] base 30 | # 31 | def self.included(base) 32 | base.extend(ClassMethods) 33 | end 34 | 35 | module ClassMethods 36 | # 37 | # Check if the given object is null. 38 | # 39 | # @return [true, false] 40 | # 41 | def null?(object) 42 | object.equal?(NULL) 43 | end 44 | end 45 | 46 | # @see (NullArgumentable.null?) 47 | def null?(object) 48 | self.class.null?(object) 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/omnibus/ohai.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require "ohai" unless defined?(Ohai::System) 18 | 19 | module Omnibus 20 | class Ohai 21 | PLUGINS = %w{ 22 | cpu 23 | kernel 24 | os 25 | platform}.freeze 26 | 27 | class << self 28 | def method_missing(m, *args, &block) 29 | ohai.send(m, *args, &block) 30 | end 31 | 32 | private 33 | 34 | def ohai 35 | @ohai ||= ::Ohai::System.new.tap { |o| o.all_plugins(PLUGINS) }.data 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /lib/omnibus/package.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require "ffi_yajl" unless defined?(FFI_Yajl) 18 | 19 | module Omnibus 20 | class Package 21 | include Digestable 22 | 23 | # 24 | # @return [String] 25 | # 26 | attr_reader :path 27 | 28 | # 29 | # Create a new package from the given path. 30 | # 31 | # @param [String] path 32 | # the path to the package on disk 33 | # 34 | def initialize(path) 35 | @path = File.expand_path(path) 36 | end 37 | 38 | # 39 | # The shortname of this package (the basename of the file). 40 | # 41 | # @return [String] 42 | # 43 | def name 44 | @name ||= File.basename(path) 45 | end 46 | 47 | # 48 | # The MD5 checksum for this file. 49 | # 50 | # @return [String] 51 | # 52 | def md5 53 | @md5 ||= digest(path, :md5) 54 | end 55 | 56 | # 57 | # The SHA1 checksum for this file. 58 | # 59 | # @return [String] 60 | # 61 | def sha1 62 | @sha1 ||= digest(path, :sha1) 63 | end 64 | 65 | # 66 | # The SHA256 checksum for this file. 67 | # 68 | # @return [String] 69 | # 70 | def sha256 71 | @sha256 ||= digest(path, :sha256) 72 | end 73 | 74 | # 75 | # The SHA512 checksum for this file. 76 | # 77 | # @return [String] 78 | # 79 | def sha512 80 | @sha512 ||= digest(path, :sha512) 81 | end 82 | 83 | # 84 | # The actual contents of the package. 85 | # 86 | # @return [String] 87 | # 88 | def content 89 | @content ||= IO.read(path) 90 | rescue Errno::ENOENT 91 | raise NoPackageFile.new(path) 92 | end 93 | 94 | # 95 | # The parsed contents of the metadata. 96 | # 97 | # @raise [NoPackageMetadataFile] if the {#metadata} does not exist 98 | # @raise [FFI_Yajl::ParseError] if the JSON is not valid 99 | # 100 | # @return [Hash] 101 | # 102 | def metadata 103 | @metadata ||= Metadata.for_package(self) 104 | end 105 | 106 | # 107 | # Set the metadata for this package 108 | # 109 | # @param [Metadata] metadata 110 | # 111 | def metadata=(metadata) 112 | @metadata = metadata 113 | end 114 | 115 | # 116 | # Validate the presence of the required components for the package. 117 | # 118 | # @raise [NoPackageFile] if the package is not present 119 | # @raise [NoPackageMetadataFile] if the metadata file is not present 120 | # 121 | # @return [true] 122 | # 123 | def validate! 124 | unless File.exist?(path) 125 | raise NoPackageFile.new(path) 126 | end 127 | 128 | unless File.exist?(metadata.path) 129 | raise NoPackageMetadataFile.new(metadata.path) 130 | end 131 | 132 | true 133 | end 134 | end 135 | end 136 | -------------------------------------------------------------------------------- /lib/omnibus/packager.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014-2020, Chef Software Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | module Packager 19 | include Logging 20 | include Sugarable 21 | 22 | autoload :Base, "omnibus/packagers/base" 23 | autoload :BFF, "omnibus/packagers/bff" 24 | autoload :DEB, "omnibus/packagers/deb" 25 | autoload :Makeself, "omnibus/packagers/makeself" 26 | autoload :MSI, "omnibus/packagers/msi" 27 | autoload :APPX, "omnibus/packagers/appx" 28 | autoload :PKG, "omnibus/packagers/pkg" 29 | autoload :PKGSRC, "omnibus/packagers/pkgsrc" 30 | autoload :Solaris, "omnibus/packagers/solaris" 31 | autoload :IPS, "omnibus/packagers/ips" 32 | autoload :RPM, "omnibus/packagers/rpm" 33 | 34 | # 35 | # The list of Ohai platform families mapped to the respective packager 36 | # class. 37 | # 38 | # @return [Hash] 39 | # 40 | PLATFORM_PACKAGER_MAP = { 41 | "debian" => DEB, 42 | "fedora" => RPM, 43 | "suse" => RPM, 44 | "rhel" => RPM, 45 | "wrlinux" => RPM, 46 | "amazon" => RPM, 47 | "rocky" => RPM, 48 | "aix" => BFF, 49 | "solaris" => Solaris, 50 | "omnios" => IPS, 51 | "ips" => IPS, 52 | "windows" => [MSI, APPX], 53 | "mac_os_x" => PKG, 54 | "smartos" => PKGSRC, 55 | }.freeze 56 | 57 | # 58 | # Determine the packager(s) for the current system. This method returns the 59 | # class, not an instance of the class. 60 | # 61 | # @example 62 | # Packager.for_current_system #=> [Packager::RPM] 63 | # 64 | # @return [[~Packager::Base]] 65 | # 66 | def for_current_system 67 | family = Ohai["platform_family"] 68 | version = Ohai["platform_version"] 69 | 70 | if family == "solaris2" && ChefUtils::VersionString.new(version).satisfies?(">= 5.11") 71 | family = "ips" 72 | elsif family == "solaris2" && ChefUtils::VersionString.new(version).satisfies?(">= 5.10") 73 | family = "solaris" 74 | end 75 | if klass = PLATFORM_PACKAGER_MAP[family] 76 | klass.is_a?(Array) ? klass : [ klass ] 77 | else 78 | log.warn(log_key) do 79 | "Could not determine packager for `#{family}`, defaulting to `makeself`!" 80 | end 81 | [Makeself] 82 | end 83 | end 84 | module_function :for_current_system 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /lib/omnibus/packagers/appx.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require "omnibus/packagers/windows_base" 18 | 19 | module Omnibus 20 | class Packager::APPX < Packager::WindowsBase 21 | id :appx 22 | 23 | setup do 24 | # Render the manifest 25 | write_manifest_file 26 | 27 | # Copy all the staging assets from vendored Omnibus into the resources 28 | # directory. 29 | FileSyncer.glob("#{Omnibus.source_root}/resources/#{id}/assets/*").each do |file| 30 | copy_file(file, "#{project.install_dir}/#{File.basename(file)}") 31 | end 32 | 33 | # Copy all assets in the user's project directory - this may overwrite 34 | # files copied in the previous step, but that's okay :) 35 | FileSyncer.glob("#{resources_path}/assets/*").each do |file| 36 | copy_file(file, "#{project.install_dir}/#{File.basename(file)}") 37 | end 38 | end 39 | 40 | build do 41 | # Pack the files with makeappx.exe, recursively generate fragment for 42 | # project directory 43 | Dir.chdir(staging_dir) do 44 | appx_file = windows_safe_path(Config.package_dir, package_name) 45 | shellout!(pack_command(appx_file)) 46 | 47 | if signing_identity 48 | sign_package(appx_file) 49 | end 50 | end 51 | end 52 | 53 | # @see Base#package_name 54 | def package_name 55 | log.debug(log_key) { "#{self.class}##{__method__} - package_name: #{project.package_name}" } 56 | log.debug(log_key) { "#{self.class}##{__method__} - build_version: #{project.build_version}" } 57 | log.debug(log_key) { "#{self.class}##{__method__} - build_iteration: #{project.build_iteration}" } 58 | log.debug(log_key) { "#{self.class}##{__method__} - Config.windows_arch: #{Config.windows_arch}" } 59 | 60 | "#{project.package_name}-#{project.build_version}-#{project.build_iteration}-#{Config.windows_arch}.appx" 61 | end 62 | 63 | # 64 | # Write the manifest file into the staging directory. 65 | # 66 | # @return [void] 67 | # 68 | def write_manifest_file 69 | render_template(resource_path("AppxManifest.xml.erb"), 70 | destination: "#{windows_safe_path(project.install_dir)}/AppxManifest.xml", 71 | variables: { 72 | name: project.package_name, 73 | friendly_name: project.friendly_name, 74 | version: windows_package_version, 75 | maintainer: project.maintainer, 76 | certificate_subject: certificate_subject.gsub('"', """), 77 | }) 78 | end 79 | 80 | # 81 | # Get the shell command to run pack in order to create a 82 | # an appx package 83 | # 84 | # @return [String] 85 | # 86 | def pack_command(appx_file) 87 | "makeappx.exe pack /d \"#{windows_safe_path(project.install_dir)}\" /o /p #{appx_file}" 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /lib/omnibus/packagers/pkgsrc.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2016-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | class Packager::PKGSRC < Packager::Base 19 | id :pkgsrc 20 | 21 | PKGTOOLS_VERSION = "20091115".freeze 22 | 23 | build do 24 | write_buildinfo 25 | write_buildver 26 | write_comment 27 | write_packlist 28 | create_pkg 29 | end 30 | 31 | def build_info 32 | staging_dir_path("build-info") 33 | end 34 | 35 | def build_ver 36 | staging_dir_path("build-ver") 37 | end 38 | 39 | def comment_file 40 | staging_dir_path("comment") 41 | end 42 | 43 | def pack_list 44 | staging_dir_path("packlist") 45 | end 46 | 47 | def create_pkg 48 | postinst = "#{project.package_scripts_path}/postinst" 49 | postrm = "#{project.package_scripts_path}/postrm" 50 | 51 | shellout! "cd #{Config.package_dir} && pkg_create -i #{postinst} -k #{postrm} -p #{project.install_dir} -b #{build_ver} -B #{build_info} -c #{comment_file} -d #{comment_file} -f #{pack_list} -I #{project.install_dir} -l -U #{package_name}" 52 | end 53 | 54 | def package_name 55 | "#{project.package_name}-#{project.build_version}.tgz" 56 | end 57 | 58 | def write_buildver 59 | File.open build_ver, "w+" do |f| 60 | f.write"#{project.build_version}-#{project.build_iteration}" 61 | end 62 | end 63 | 64 | def write_buildinfo 65 | buildinfo_content = <<~EOF 66 | MACHINE_ARCH=#{safe_architecture} 67 | OPSYS=#{opsys} 68 | OS_VERSION=#{os_version} 69 | PKGTOOLS_VERSION=#{PKGTOOLS_VERSION} 70 | EOF 71 | 72 | File.open(build_info, "w+") do |f| 73 | f.write(buildinfo_content) 74 | end 75 | end 76 | 77 | def write_comment 78 | File.open(comment_file, "w+") do |f| 79 | f.write(project.description) 80 | end 81 | end 82 | 83 | def write_packlist 84 | File.open pack_list, "w+" do |f| 85 | f.write "@pkgdir #{project.install_dir}\n@cwd #{project.install_dir}/\n" 86 | end 87 | 88 | shellout! "cd #{project.install_dir} && find . -type l -or -type f | sort >> #{pack_list}" 89 | end 90 | 91 | def opsys 92 | Ohai["kernel"]["name"] 93 | end 94 | 95 | def os_version 96 | Ohai["kernel"]["release"] 97 | end 98 | 99 | def safe_architecture 100 | if smartos? 101 | if Ohai["kernel"]["update"] == "86_64" 102 | "x86_64" 103 | else 104 | "i386" 105 | end 106 | else 107 | # FIXME: this undoubtedly will need filling out once we make this go for platforms that aren't SmartOS 108 | Ohai["kernel"]["machine"] 109 | end 110 | end 111 | end 112 | end 113 | -------------------------------------------------------------------------------- /lib/omnibus/publishers/null_publisher.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | class NullPublisher < Publisher 19 | def publish 20 | # noop 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/omnibus/publishers/s3_publisher.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require "omnibus/s3_helpers" 18 | 19 | module Omnibus 20 | class S3Publisher < Publisher 21 | include S3Helpers 22 | 23 | def publish(&block) 24 | log.info(log_key) { "Starting S3 publisher" } 25 | 26 | packages.each do |package| 27 | # Make sure the package is good to go! 28 | log.debug(log_key) { "Validating '#{package.name}'" } 29 | package.validate! 30 | 31 | # Upload the metadata first 32 | log.debug(log_key) { "Uploading '#{package.metadata.name}'" } 33 | 34 | s3_metadata_object = store_object( 35 | key_for(package, package.metadata.name), 36 | FFI_Yajl::Encoder.encode(package.metadata.to_hash, pretty: true), 37 | nil, 38 | access_policy 39 | ) 40 | 41 | log.debug(log_key) { "Uploading is completed. Download URL (#{access_policy}): #{s3_metadata_object.public_url}" } 42 | 43 | # Upload the actual package 44 | log.info(log_key) { "Uploading '#{package.name}'" } 45 | 46 | s3_object = store_object( 47 | key_for(package, package.name), 48 | package.content, 49 | package.metadata[:md5], 50 | access_policy 51 | ) 52 | 53 | log.info(log_key) { "Uploading is completed. Download URL (#{access_policy}): #{s3_object.public_url}" } 54 | 55 | # If a block was given, "yield" the package to the caller 56 | yield(package) if block 57 | end 58 | end 59 | 60 | private 61 | 62 | def s3_configuration 63 | config = { 64 | region: @options[:region], 65 | bucket_name: @options[:bucket], 66 | } 67 | 68 | if Config.publish_s3_iam_role_arn 69 | config[:publish_s3_iam_role_arn] = Config.publish_s3_iam_role_arn 70 | elsif Config.publish_s3_profile 71 | config[:profile] = Config.publish_s3_profile 72 | else 73 | config[:access_key_id] = Config.publish_s3_access_key 74 | config[:secret_access_key] = Config.publish_s3_secret_key 75 | end 76 | 77 | config 78 | end 79 | 80 | # 81 | # The unique upload key for this package. The additional "stuff" is 82 | # postfixed to the end of the path. 83 | # 84 | # @example 85 | # 'el/6/x86_64/chef-11.6.0-1.el6.x86_64.rpm/chef-11.6.0-1.el6.x86_64.rpm' 86 | # 87 | # @param [Package] package 88 | # the package this key is for 89 | # @param [Array] stuff 90 | # the additional things to append 91 | # 92 | # @return [String] 93 | # 94 | def key_for(package, *stuff) 95 | File.join( 96 | Config.s3_publish_pattern % package.metadata, 97 | *stuff 98 | ) 99 | end 100 | 101 | # 102 | # The access policy that corresponds to the +s3_access+ given in the 103 | # initializer option. Any access control that is not the strict string 104 | # +"public"+ is assumed to be private. 105 | # 106 | # @return [String] 107 | # the access policy 108 | # 109 | def access_policy 110 | if @options[:acl].to_s == "public" 111 | "public-read" 112 | else 113 | "private" 114 | end 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /lib/omnibus/reports.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | module Reports 19 | extend self 20 | 21 | PADDING = 3 22 | 23 | # Determine how wide a column should be, taking into account both 24 | # the column name as well as all data in that column. If no data 25 | # will be stored in the column, the width is 0 (i.e., nothing 26 | # should be printed, not even the column header) 27 | def column_width(items, column_name) 28 | widest_item = items.max_by(&:size) 29 | if widest_item 30 | widest = (widest_item.size >= column_name.size) ? widest_item : column_name 31 | widest.size + PADDING 32 | else 33 | 0 34 | end 35 | end 36 | 37 | def non_nil_values(hashes, selector_key) 38 | hashes.map { |v| v[selector_key] }.compact 39 | end 40 | 41 | def pretty_version_map(project) 42 | out = "" 43 | version_map = project.library.version_map 44 | 45 | # Pull out data to print out 46 | versions = non_nil_values(version_map.values, :version) 47 | guids = non_nil_values(version_map.values, :version_guid) 48 | 49 | # We only want the versions that have truly been overridden; 50 | # because we want to output a column only if something was 51 | # overridden, but nothing if no packages were changed 52 | overridden_versions = non_nil_values(version_map.values.select { |v| v[:overridden] }, :default_version) 53 | 54 | # Determine how wide the printed table columns need to be 55 | name_width = column_width(version_map.keys, "Component") 56 | version_width = column_width(versions, "Installed Version") 57 | guid_width = column_width(guids, "Version GUID") 58 | override_width = column_width(overridden_versions, "Overridden From") 59 | 60 | total_width = name_width + version_width + guid_width + override_width 61 | divider = "-" * total_width 62 | 63 | # Print out the column headers 64 | out << "Component".ljust(name_width) 65 | out << "Installed Version".ljust(version_width) 66 | out << "Version GUID".ljust(guid_width) 67 | # Only print out column if something was overridden 68 | out << "Overridden From".ljust(override_width) if override_width > 0 69 | out << "\n" 70 | out << divider << "\n" 71 | 72 | # Print out the table body 73 | version_map.keys.sort.each do |name| 74 | version = version_map[name][:version] 75 | version_guid = version_map[name][:version_guid] 76 | 77 | default_version = version_map[name][:default_version] 78 | overridden = version_map[name][:overridden] 79 | 80 | out << "#{name}".ljust(name_width) 81 | out << version.to_s.ljust(version_width) 82 | out << version_guid.to_s.ljust(guid_width) if version_guid 83 | # Only print out column if something was overridden 84 | out << default_version.ljust(override_width) if overridden 85 | out << "\n" 86 | end 87 | out 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /lib/omnibus/semantic_version.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2015-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require "mixlib/versioning" 18 | 19 | module Omnibus 20 | class SemanticVersion 21 | 22 | def initialize(version_string) 23 | @prefix = if version_string =~ /^v/ 24 | "v" 25 | else 26 | "" 27 | end 28 | @version = Mixlib::Versioning.parse(version_string.gsub(/^v/, "")) 29 | if @version.nil? 30 | raise InvalidVersion, "#{version_string} could not be parsed as a valid version" 31 | end 32 | end 33 | 34 | def to_s 35 | "#{prefix}#{version}" 36 | end 37 | 38 | def next_patch 39 | s = [version.major, version.minor, version.patch + 1].join(".") 40 | self.class.new("#{prefix}#{s}") 41 | end 42 | 43 | def next_minor 44 | s = [version.major, version.minor + 1, 0].join(".") 45 | self.class.new("#{prefix}#{s}") 46 | end 47 | 48 | def next_major 49 | s = [version.major + 1, 0, 0].join(".") 50 | self.class.new("#{prefix}#{s}") 51 | end 52 | 53 | private 54 | 55 | attr_reader :prefix, :version 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/omnibus/sugarable.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014-2020, Chef Software Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | require "chef-utils" unless defined?(ChefUtils::CANARY) 18 | 19 | module Omnibus 20 | module Sugarable 21 | def self.extended(base) 22 | base.send(:extend, ChefUtils) 23 | base.send(:extend, Omnibus::Sugar) 24 | end 25 | 26 | def self.included(base) 27 | base.send(:include, ChefUtils) 28 | base.send(:include, Omnibus::Sugar) 29 | 30 | if base < Cleanroom 31 | # Make all the "sugars" available in the cleanroom (DSL) 32 | ChefUtils.instance_methods.each do |instance_method| 33 | base.send(:expose, instance_method) 34 | end 35 | 36 | # Make all the common "sugars" available in the cleanroom (DSL) 37 | Omnibus::Sugar.instance_methods.each do |instance_method| 38 | base.send(:expose, instance_method) 39 | end 40 | end 41 | end 42 | 43 | # This method is used by Chef Sugar to easily add the DSL. By mimicing 44 | # Chef's +node+ object, we can easily include the existing DSL into 45 | # Omnibus project as if it were Chef. Otherwise, we would need to rewrite 46 | # all the DSL methods. 47 | def node 48 | Ohai 49 | end 50 | end 51 | 52 | # This module is a wrapper for common Chef::Sugar-like functions that 53 | # are common to multiple DSLs (like project and software). The extensions 54 | # below will be injected into CleanRoom, and hence visible to the DSLs. 55 | module Sugar 56 | 57 | # Returns whether the Windows build target is 32-bit (x86). 58 | # If this returns false, the target is x64. Itanium is not supported. 59 | def windows_arch_i386? 60 | Config.windows_arch.to_sym == :x86 61 | end 62 | 63 | def fips_mode? 64 | !!Config.fips_mode 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /lib/omnibus/templating.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | require "erb" unless defined?(Erb) 17 | 18 | module Omnibus 19 | module Templating 20 | def self.included(base) 21 | # This module also requires logging 22 | base.send(:include, Logging) 23 | end 24 | 25 | # 26 | # Render an erb template to a String variable. 27 | # 28 | # @return [String] 29 | # 30 | # @param [String] source 31 | # the path on disk where the ERB template lives 32 | # 33 | # @option options [Fixnum] :mode (default: +0644+) 34 | # the mode of the rendered file 35 | # @option options [Hash] :variables (default: +{}+) 36 | # the list of variables to pass to the template 37 | # 38 | def render_template_content(source, variables = {}) 39 | template = ERB.new(File.read(source), trim_mode: "-") 40 | struct = 41 | if variables.empty? 42 | Struct.new("Empty") 43 | else 44 | Struct.new(*variables.keys).new(*variables.values) 45 | end 46 | 47 | template.result(struct.instance_eval { binding }) 48 | end 49 | 50 | # 51 | # Render an erb template on disk at +source+. If the +:destination+ option 52 | # is given, the file will be rendered at +:destination+, otherwise the 53 | # template is rendered next to +source+, removing the 'erb' extension of the 54 | # template. 55 | # 56 | # @param [String] source 57 | # the path on disk where the ERB template lives 58 | # 59 | # @option options [String] :destination (default: +source+) 60 | # the destination where the rendered ERB should reside 61 | # @option options [Fixnum] :mode (default: +0644+) 62 | # the mode of the rendered file 63 | # @option options [Hash] :variables (default: +{}+) 64 | # the list of variables to pass to the template 65 | # 66 | def render_template(source, options = {}) 67 | destination = options.delete(:destination) || source.chomp(".erb") 68 | mode = options.delete(:mode) || 0644 69 | variables = options.delete(:variables) || {} 70 | 71 | log.info(log_key) { "Rendering `#{source}' to `#{destination}'" } 72 | 73 | unless options.empty? 74 | raise ArgumentError, 75 | "Unknown option(s): #{options.keys.map(&:inspect).join(", ")}" 76 | end 77 | 78 | # String value returned from #render_template_content 79 | result = render_template_content(source, variables) 80 | 81 | File.open(destination, "w", mode) do |file| 82 | file.write(result) 83 | end 84 | 85 | true 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /lib/omnibus/thread_pool.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2014 Mike Heijmans 3 | # Copyright 2014-2018 Chef Software, Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | module Omnibus 19 | class ThreadPool 20 | 21 | # 22 | # Create a new thread pool of the given size. If a block is given, it is 23 | # assumed the thread pool is wrapping an operation and will block until all 24 | # operations complete. 25 | # 26 | # @example Using a block 27 | # ThreadPool.new(5) do |pool| 28 | # complex_things.each do |thing| 29 | # pool.schedule { thing.run } 30 | # end 31 | # end 32 | # 33 | # @example Using the object 34 | # pool = ThreadPool.new(5) 35 | # # ... 36 | # pool.schedule { complex_operation_1 } 37 | # pool.schedule { complex_operation_2 } 38 | # # ... 39 | # pool.schedule { complex_operation_4 } 40 | # # ... 41 | # pool.shutdown 42 | # 43 | # # or 44 | # 45 | # at_exit { pool.shutdown } 46 | # 47 | # @param [Integer] size 48 | # the number of items to put in the thread pool 49 | # @param [Boolean] abort_on_exception 50 | # if the thread should abort the main thread also on a failure 51 | # 52 | def initialize(size, abort_on_exception = true) 53 | @size = size 54 | @jobs = Queue.new 55 | 56 | @pool = Array.new(@size) do |i| 57 | Thread.new do 58 | Thread.abort_on_exception = abort_on_exception 59 | Thread.current[:id] = i 60 | 61 | catch(:exit) do 62 | loop do 63 | job, args = @jobs.pop 64 | job.call(*args) 65 | end 66 | end 67 | end 68 | end 69 | 70 | if block_given? 71 | yield self 72 | shutdown 73 | end 74 | end 75 | 76 | # 77 | # Schedule a single item onto the queue. If arguments are given, those 78 | # arguments are used when calling the block in the queue. This is useful 79 | # if you have arguments that you need to pass in from a parent binding. 80 | # 81 | # @param [Object, Array] args 82 | # the arguments to pass to the block when calling 83 | # @param [Proc] block 84 | # the block to execute 85 | # 86 | # @return [void] 87 | # 88 | def schedule(*args, &block) 89 | @jobs << [block, args] 90 | end 91 | 92 | # 93 | # Stop the thread pool. This method quietly injects an exit clause into the 94 | # queue (sometimes called "poison") and then waits for all threads to 95 | # exit. 96 | # 97 | # @return [true] 98 | # 99 | def shutdown 100 | @size.times do 101 | schedule { throw :exit } 102 | end 103 | 104 | @pool.map(&:join) 105 | 106 | true 107 | end 108 | end 109 | end 110 | -------------------------------------------------------------------------------- /lib/omnibus/version.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2012-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | module Omnibus 18 | VERSION = "9.0.25".freeze 19 | end 20 | -------------------------------------------------------------------------------- /omnibus.gemspec: -------------------------------------------------------------------------------- 1 | lib = File.expand_path("lib", __dir__) 2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 3 | require "omnibus/version" 4 | 5 | Gem::Specification.new do |gem| 6 | gem.name = "omnibus" 7 | gem.version = Omnibus::VERSION 8 | gem.license = "Apache-2.0" 9 | gem.author = "Chef Software, Inc." 10 | gem.email = "releng@chef.io" 11 | gem.summary = "Omnibus is a framework for building self-installing, full-stack software builds." 12 | gem.description = gem.summary 13 | gem.homepage = "https://github.com/chef/omnibus" 14 | 15 | gem.required_ruby_version = ">= 3.0" 16 | 17 | gem.files = %w{ LICENSE README.md Rakefile Gemfile } + Dir.glob("*.gemspec") + Dir.glob("{bin,lib,resources,spec}/**/{*,.kitchen*}") 18 | gem.bindir = "bin" 19 | gem.executables = %w{omnibus} 20 | gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) 21 | gem.require_paths = ["lib"] 22 | 23 | gem.add_dependency "aws-sdk-s3", "~> 1.116.0" 24 | gem.add_dependency "chef-utils", ">= 15.4" 25 | gem.add_dependency "chef-cleanroom", "~> 1.0" 26 | gem.add_dependency "ffi-yajl", "~> 2.2" 27 | gem.add_dependency "mixlib-shellout", ">= 2.0", "< 4.0" 28 | gem.add_dependency "ohai", ">= 16", "< 19" 29 | gem.add_dependency "ruby-progressbar", "~> 1.7" 30 | gem.add_dependency "thor", ">= 0.18", "< 2.0" 31 | gem.add_dependency "license_scout", "~> 1.3.17" 32 | gem.add_dependency "contracts", ">= 0.16.0", "< 0.17.0" 33 | gem.add_dependency "rexml", "~> 3.4" 34 | 35 | if Gem::Version.new(RUBY_VERSION) <= Gem::Version.new("3.1.0") 36 | gem.add_dependency "ffi", "<= 1.17.0" 37 | end 38 | 39 | gem.add_dependency "mixlib-versioning" 40 | gem.add_dependency "pedump" 41 | 42 | gem.add_development_dependency "artifactory", "~> 3.0" 43 | gem.add_development_dependency "aruba", "~> 2.0" 44 | gem.add_development_dependency "chefstyle", "= 2.2.2" 45 | gem.add_development_dependency "fauxhai-ng", ">= 7.5" 46 | gem.add_development_dependency "rspec", "~> 3.0" 47 | gem.add_development_dependency "rspec-json_expectations" 48 | gem.add_development_dependency "rspec-its" 49 | gem.add_development_dependency "webmock" 50 | gem.add_development_dependency "rake" 51 | gem.add_development_dependency "appbundler" 52 | end 53 | -------------------------------------------------------------------------------- /resources/appx/AppxManifest.xml.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | <%= friendly_name %> 8 | <%= maintainer.encode(:xml => :attr) %> 9 | clear.png 10 | 11 | 12 | 6.3 13 | 99.99 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /resources/appx/assets/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/resources/appx/assets/clear.png -------------------------------------------------------------------------------- /resources/bff/config.erb: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Perform necessary <%= name %> post install steps 4 | # after package is installed. 5 | # 6 | 7 | echo "<%= name %> has been configured!" 8 | -------------------------------------------------------------------------------- /resources/bff/gen.template.erb: -------------------------------------------------------------------------------- 1 | Package Name: <%= name %> 2 | Package VRMF: <%= version %> 3 | Update: N 4 | Fileset 5 | Fileset Name: <%= name %> 6 | Fileset VRMF: <%= version %> 7 | Fileset Description: <%= description %> 8 | USRLIBLPPFiles 9 | <% scripts.each do |name, install_path| -%> 10 | <%= name %>: <%= install_path %> 11 | <% end -%> 12 | EOUSRLIBLPPFiles 13 | Bosboot required: N 14 | License agreement acceptance required: N 15 | Include license files in this package: N 16 | Requisites: 17 | ROOT Part: Y 18 | USRFiles 19 | <% files.each do |file| -%> 20 | <%= file %> 21 | <% end -%> 22 | EOUSRFiles 23 | EOFileset 24 | -------------------------------------------------------------------------------- /resources/deb/conffiles.erb: -------------------------------------------------------------------------------- 1 | <% config_files.each do |file| -%> 2 | <%= file %> 3 | <% end -%> 4 | -------------------------------------------------------------------------------- /resources/deb/control.erb: -------------------------------------------------------------------------------- 1 | Package: <%= name %> 2 | Version: <%= version %>-<%= iteration %> 3 | License: <%= license %> 4 | Vendor: <%= vendor %> 5 | Architecture: <%= architecture %> 6 | Maintainer: <%= maintainer %> 7 | Installed-Size: <%= installed_size %> 8 | <% unless dependencies.empty? -%> 9 | Depends: <%= dependencies.join(', ') %> 10 | <% end -%> 11 | <% unless conflicts.empty? -%> 12 | Conflicts: <%= conflicts.join(', ') %> 13 | <% end -%> 14 | <% unless replaces.empty? -%> 15 | Replaces: <%= replaces.join(', ') %> 16 | <% end -%> 17 | Section: <%= section %> 18 | Priority: <%= priority %> 19 | Homepage: <%= homepage %> 20 | <% lines = description.split("\n") -%> 21 | <% firstline, *remainder = lines -%> 22 | Description: <%= firstline %> 23 | <% if remainder.any? -%> 24 | <%= remainder.collect { |l| l =~ /^ *$/ ? " ." : " #{l}" }.join("\n") %> 25 | <% end -%> 26 | -------------------------------------------------------------------------------- /resources/deb/md5sums.erb: -------------------------------------------------------------------------------- 1 | <% md5sums.each do |path, checksum| -%> 2 | <%= checksum %> <%= path %> 3 | <% end -%> 4 | -------------------------------------------------------------------------------- /resources/dmg/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/resources/dmg/background.png -------------------------------------------------------------------------------- /resources/dmg/create_dmg.osascript.erb: -------------------------------------------------------------------------------- 1 | # find disks that start with <%= volume_name %> 2 | set found_disk to do shell script "ls /Volumes/ | grep '<%= volume_name %>*'" 3 | 4 | if found_disk is {} then 5 | set errormsg to "Disk " & found_disk & " not found" 6 | error errormsg 7 | end if 8 | 9 | tell application "Finder" 10 | # In case finder has been closed somehow 11 | reopen 12 | # Reactivate it in case it is "out of focus" 13 | activate 14 | # Deactivate any current selections 15 | set selection to {} 16 | # Set it to the location of the proper volume 17 | set target of Finder window 1 to found_disk 18 | # We like icons 19 | set current view of Finder window 1 to icon view 20 | # No toolbar or statusbar 21 | set toolbar visible of Finder window 1 to false 22 | set statusbar visible of Finder window 1 to false 23 | # How big and where does it live on the desktop 24 | set the bounds of Finder window 1 to {<%= window_bounds %>} 25 | # We now talk to the disk object that is a subset of the "Finder" 26 | tell disk found_disk 27 | # Pull the view options from the Icon View object 28 | # The container window is how we grab hold of the "Finder" window in the 29 | # context of the disk object (the disk object is a sub-thing of the app) 30 | set theViewOptions to the icon view options of container window 31 | set background picture of theViewOptions to file ".support:background.png" 32 | set arrangement of theViewOptions to not arranged 33 | set icon size of theViewOptions to 72 34 | set position of item "<%= pkg_name %>" of container window to {<%= pkg_position %>} 35 | update without registering applications 36 | end tell 37 | end tell 38 | -------------------------------------------------------------------------------- /resources/dmg/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/resources/dmg/icon.png -------------------------------------------------------------------------------- /resources/ips/doc-transform.erb: -------------------------------------------------------------------------------- 1 | $ -> edit group bin sys> 2 | $ -> edit group bin sys> 3 | edit fmri '@.+' ''> 4 | edit fmri '@.+' ''> 5 | edit pkg.debug.depend.file ruby env> 6 | edit pkg.debug.depend.file make env> 7 | edit pkg.debug.depend.file perl env> 8 | edit pkg.debug.depend.path usr/local/bin usr/bin> 9 | -------------------------------------------------------------------------------- /resources/ips/gen.manifestfile.erb: -------------------------------------------------------------------------------- 1 | set name=pkg.fmri value=developer/versioning/<%= fmri_package_name %> 2 | set name=pkg.description value="<%= description %>" 3 | set name=pkg.summary value="<%= summary %>" 4 | set name=variant.arch value=<%= arch %> 5 | set name=info.classification \ 6 | value="org.opensolaris.category.2008:Meta Packages/Group Packages" \ 7 | value="org.opensolaris.category.2008:Applications/System Utilities" 8 | -------------------------------------------------------------------------------- /resources/makeself/makeself.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/resources/makeself/makeself.sh -------------------------------------------------------------------------------- /resources/makeself/makeselfinst.erb: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # WARNING: REQUIRES /bin/sh 3 | # 4 | # - must run on /bin/sh on solaris 9 5 | # - must run on /bin/sh on AIX 6.x 6 | # - if you think you are a bash wizard, you probably do not understand 7 | # this programming language. do not touch. 8 | # - if you are under 40, get peer review from your elders. 9 | # 10 | 11 | ######################################################################### 12 | # HELPERS 13 | ######################################################################### 14 | error_exit() 15 | { 16 | echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2 17 | exit 1 18 | } 19 | 20 | PROGNAME=`basename $0` 21 | EXTRACT_DIR=`dirname $0` 22 | INSTALL_DIR=<%= install_dir %> 23 | 24 | ######################################################################### 25 | # MOVE SELF-EXTRACTING ARCHIVE FILES INTO PLACE 26 | ######################################################################### 27 | rm -rf $INSTALL_DIR/* || error_exit "Cannot remove contents of $INSTALL_DIR" 28 | mkdir -p $INSTALL_DIR || error_exit "Cannot create $INSTALL_DIR" 29 | cp -R $EXTRACT_DIR $INSTALL_DIR || error_exit "Cannot install to $INSTALL_DIR" 30 | rm -f $INSTALL_DIR/$PROGNAME 31 | 32 | # Execute the optional postinst script 33 | if test -f "$INSTALL_DIR/postinst"; then 34 | $INSTALL_DIR/postinst 35 | fi 36 | -------------------------------------------------------------------------------- /resources/msi/CustomActionFastMsi.CA.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/resources/msi/CustomActionFastMsi.CA.dll -------------------------------------------------------------------------------- /resources/msi/assets/LICENSE.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf190 2 | {\fonttbl\f0\fmodern\fcharset0 CourierNewPSMT;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \vieww12000\viewh15840\viewkind0 5 | \deftab720 6 | \pard\pardeftab720\qc 7 | 8 | \f0\fs20 \cf0 All Rights Reserved.} -------------------------------------------------------------------------------- /resources/msi/assets/banner_background.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/resources/msi/assets/banner_background.bmp -------------------------------------------------------------------------------- /resources/msi/assets/dialog_background.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/resources/msi/assets/dialog_background.bmp -------------------------------------------------------------------------------- /resources/msi/assets/project.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/resources/msi/assets/project.ico -------------------------------------------------------------------------------- /resources/msi/assets/project_16x16.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/resources/msi/assets/project_16x16.ico -------------------------------------------------------------------------------- /resources/msi/assets/project_32x32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/resources/msi/assets/project_32x32.ico -------------------------------------------------------------------------------- /resources/msi/bundle.wxs.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /resources/msi/localization-en-us.wxl.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1033 4 | <%= friendly_name %> 5 | <%= maintainer.encode(:xml => :attr) %> 6 | {\WixUI_Font_Bigger}Welcome to the [ProductName] Setup Wizard 7 | 8 | {\WixUI_Font_Title_White}End-User License Agreement 9 | {\WixUI_Font_Normal_White}Please read the following license agreement carefully 10 | 11 | {\WixUI_Font_Title_White}Destination Folder 12 | {\WixUI_Font_Normal_White}Click Next to install to the default folder or click Change to choose another. 13 | 14 | {\WixUI_Font_Title_White}Installing [ProductName] 15 | 16 | {\WixUI_Font_Title_White}Ready to install [ProductName] 17 | 18 | <%= friendly_name %> 19 | 20 | This package requires minimum OS version: Windows 7/Windows Server 2008 R2 or greater. 21 | A newer version of [ProductName] is already installed. 22 | Extracting files, please wait... 23 | 24 | -------------------------------------------------------------------------------- /resources/msi/parameters.wxi.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | " ?> 4 | " ?> 5 | " ?> 6 | <% parameters.each do |key, value| -%> 7 | ="<%= value %>" ?> 8 | <% end -%> 9 | 10 | -------------------------------------------------------------------------------- /resources/pkg/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chef/omnibus/332bce59458ea6e4569f329955fe55bbf9834e2b/resources/pkg/background.png -------------------------------------------------------------------------------- /resources/pkg/distribution.xml.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= friendly_name %> 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | <%= component_pkg %> 21 | 22 | 23 | -------------------------------------------------------------------------------- /resources/pkg/license.html.erb: -------------------------------------------------------------------------------- 1 | All Rights Reserved 2 | 3 | This is a generic Omnibus license file for <%= friendly_name %>. If you are building Mac OS X packages, you should generate a custom license file and description to suit your needs. 4 | -------------------------------------------------------------------------------- /resources/pkg/welcome.html.erb: -------------------------------------------------------------------------------- 1 | This will install <%= friendly_name %> on your Mac. 2 | 3 | -------------------------------------------------- 4 | 5 | This is a generic Omnibus welcome message. If you are building Mac OS X packages, you should generate a custom welcome file to suit your needs. 6 | 7 | If you are not the creator of <%= friendly_name %>, the presence of this message is likely a bug and should be reported to the creator. 8 | -------------------------------------------------------------------------------- /resources/rpm/rpmmacros.erb: -------------------------------------------------------------------------------- 1 | %_signature gpg 2 | %_gpg_path <%= gpg_path %> 3 | %_gpg_name <%= gpg_name %> 4 | -------------------------------------------------------------------------------- /resources/rpm/signing.erb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | unless (rpm_cmd = ARGV[0]) 4 | STDERR.puts 'Usage: sign-rpm RPM_COMMAND' 5 | exit 1 6 | end 7 | 8 | password = '<%= passphrase %>' 9 | 10 | require 'pty' 11 | 12 | puts rpm_cmd 13 | PTY.spawn(rpm_cmd) do |r, w, pid| 14 | # Older versions of rpmsign will prompt right away for the passphrase 15 | prompt = r.read(19) 16 | 17 | if prompt == 'Enter pass phrase: ' 18 | STDOUT.puts prompt 19 | w.write("#{password}\n") 20 | end 21 | 22 | # Keep printing output unti the command exits 23 | loop do 24 | begin 25 | line = r.gets 26 | puts line 27 | if line =~ /Please enter the passphrase to unlock the OpenPGP secret key:/ 28 | w.write("#{password}\n") 29 | elsif (line =~ /failed/) && !(line =~ /warning:/) 30 | STDERR.puts 'RPM signing failure' 31 | exit 1 32 | end 33 | rescue Errno::EIO 34 | break 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /resources/rpm/spec.erb: -------------------------------------------------------------------------------- 1 | # Disable any shell actions, replace them with simply 'true' 2 | %define __spec_prep_post true 3 | %define __spec_prep_pre true 4 | %define __spec_build_post true 5 | %define __spec_build_pre true 6 | %define __spec_install_post true 7 | %define __spec_install_pre true 8 | %define __spec_clean_post true 9 | %define __spec_clean_pre true 10 | 11 | # Use SHA256 checksums for all files 12 | %define _binary_filedigest_algorithm 8 13 | 14 | %define _binary_payload <%= compression %> 15 | 16 | # Disable creation of build-id links 17 | %define _build_id_links none 18 | 19 | # Metadata 20 | Name: <%= name %> 21 | Version: <%= version %> 22 | Release: <%= iteration %><%= dist_tag ? dist_tag : '' %> 23 | Summary: <%= description.split("\n").first.empty? ? "_" : description.split("\n").first %> 24 | AutoReqProv: no 25 | BuildRoot: %buildroot 26 | Prefix: / 27 | Group: <%= category %> 28 | License: <%= license %> 29 | Vendor: <%= vendor %> 30 | URL: <%= homepage %> 31 | Packager: <%= maintainer %> 32 | <% dependencies.each do |name| -%> 33 | Requires: <%= name %> 34 | <% end -%> 35 | <% conflicts.each do |name| -%> 36 | Conflicts: <%= name %> 37 | <% end -%> 38 | <% replaces.each do |name| -%> 39 | Obsoletes: <%= name %> 40 | <%- end -%> 41 | <% # RPM rejects descriptions with blank lines (even between content) -%> 42 | %description 43 | <%= description.gsub(/^\s*$/, " .") %> 44 | 45 | %prep 46 | # noop 47 | 48 | %build 49 | # noop 50 | 51 | %install 52 | # noop 53 | 54 | %clean 55 | # noop 56 | 57 | <% scripts.each do |name, contents| -%> 58 | %<%= name %> 59 | <%= contents %> 60 | <% end -%> 61 | 62 | %files 63 | %defattr(-,<%= user %>,<%= group %>,-) 64 | <% # Output config files and then regular files -%> 65 | <% config_files.each do |file| -%> 66 | %config(noreplace) <%= file %> 67 | <% end -%> 68 | <% # List all files -%> 69 | <% files.each do |file| -%> 70 | <%= file %> 71 | <% end -%> 72 | -------------------------------------------------------------------------------- /spec/fixtures/licensing/license_scout/snoopy/snoopy-dependency-licenses.json: -------------------------------------------------------------------------------- 1 | { 2 | "license_manifest_version": 1, 3 | "project_name": "snoopy", 4 | "dependency_managers": { 5 | "ruby_bundler": [ 6 | { 7 | "name": "inifile", 8 | "version": "3.0.0", 9 | "license": "MIT", 10 | "license_files": [ 11 | "ruby_bundler-inifile-3.0.0-README.md" 12 | ] 13 | }, 14 | { 15 | "name": "bundler-audit", 16 | "version": "0.5.0", 17 | "license": "GPLv3", 18 | "license_files": [ 19 | "ruby_bundler-bundler-audit-0.5.0-COPYING.txt" 20 | ] 21 | } 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /spec/fixtures/licensing/license_scout/zlib/ruby_bundler-mime-types-3.1-Licence.rdoc: -------------------------------------------------------------------------------- 1 | == Licence 2 | 3 | * Copyright 2003–2015 Austin Ziegler and contributors. 4 | 5 | The software in this repository is made available under the MIT license. 6 | 7 | === MIT License 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | this software and associated documentation files (the "Software"), to deal in 11 | the Software without restriction, including without limitation the rights to 12 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 13 | of the Software, and to permit persons to whom the Software is furnished to do 14 | so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /spec/fixtures/licensing/license_scout/zlib/ruby_bundler-mini_portile2-2.1.0-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2016 Luis Lavena and Mike Dalessio 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /spec/fixtures/licensing/license_scout/zlib/zlib-dependency-licenses.json: -------------------------------------------------------------------------------- 1 | { 2 | "license_manifest_version": 1, 3 | "project_name": "zlib", 4 | "dependency_managers": { 5 | "ruby_bundler": [ 6 | { 7 | "name": "inifile", 8 | "version": "3.0.0", 9 | "license": "MIT", 10 | "license_files": [ 11 | "ruby_bundler-inifile-3.0.0-README.md" 12 | ] 13 | }, 14 | { 15 | "name": "mime-types", 16 | "version": "3.1", 17 | "license": "MIT", 18 | "license_files": [ 19 | "ruby_bundler-mime-types-3.1-Licence.rdoc" 20 | ] 21 | }, 22 | { 23 | "name": "mini_portile2", 24 | "version": "2.1.0", 25 | "license": "MIT", 26 | "license_files": [ 27 | "ruby_bundler-mini_portile2-2.1.0-LICENSE.txt" 28 | ] 29 | } 30 | ] 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /spec/fixtures/sample/package-scripts/sample/postinstall: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "INSTALL WORKED" 4 | exit 0 5 | -------------------------------------------------------------------------------- /spec/functional/fetchers/file_fetcher_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe FileFetcher do 5 | include_examples "a software" 6 | 7 | let(:source_file) { File.join(tmp_path, "t", "software") } 8 | let(:target_file) { File.join(project_dir, "software") } 9 | 10 | let(:source) do 11 | { file: source_file } 12 | end 13 | 14 | let(:manifest_entry) do 15 | double(Omnibus::ManifestEntry, 16 | name: "pathelogical", 17 | locked_version: nil, 18 | described_version: nil, 19 | locked_source: source) 20 | end 21 | 22 | subject { described_class.new(manifest_entry, project_dir, build_dir) } 23 | 24 | describe "#fetch_required?" do 25 | context "when the files have different hashes" do 26 | before do 27 | create_file(source_file) { "different" } 28 | create_file(target_file) { "same" } 29 | end 30 | 31 | it "return true" do 32 | expect(subject.fetch_required?).to be_truthy 33 | end 34 | end 35 | 36 | context "when the files have the same hash" do 37 | before do 38 | create_file(source_file) { "same" } 39 | create_file(target_file) { "same" } 40 | end 41 | 42 | it "returns false" do 43 | expect(subject.fetch_required?).to be(false) 44 | end 45 | end 46 | end 47 | 48 | describe "#version_guid" do 49 | it "includes the source file" do 50 | expect(subject.version_guid).to eq("file:#{source_file}") 51 | end 52 | end 53 | 54 | describe "#fetch" do 55 | before do 56 | create_file(source_file) 57 | 58 | remove_file(target_file) 59 | end 60 | 61 | it "fetches new files" do 62 | subject.fetch 63 | 64 | expect(target_file).to be_a_file 65 | end 66 | end 67 | 68 | describe "#clean" do 69 | it "returns true" do 70 | expect(subject.clean).to be_truthy 71 | end 72 | end 73 | 74 | describe "#version_for_cache" do 75 | before do 76 | create_file(source_file) 77 | end 78 | 79 | let(:sha) { "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" } 80 | 81 | it "includes the source_file and shasum" do 82 | expect(subject.version_for_cache).to eq("file:#{source_file}|shasum:#{sha}") 83 | end 84 | end 85 | 86 | describe "#resolve_version" do 87 | it "just returns the version" do 88 | expect(NetFetcher.resolve_version("1.2.3", source)).to eq("1.2.3") 89 | end 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /spec/functional/fetchers/path_fetcher_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe PathFetcher do 5 | include_examples "a software" 6 | 7 | let(:source_path) { File.join(tmp_path, "remote", "software") } 8 | 9 | let(:source) do 10 | { path: source_path } 11 | end 12 | 13 | let(:manifest_entry) do 14 | double(Omnibus::ManifestEntry, 15 | name: "pathelogical", 16 | locked_version: nil, 17 | described_version: nil, 18 | locked_source: source) 19 | end 20 | 21 | before do 22 | create_directory(source_path) 23 | end 24 | 25 | subject { described_class.new(manifest_entry, project_dir, build_dir) } 26 | 27 | describe "#fetch_required?" do 28 | context "when the directories have different files" do 29 | before do 30 | create_file("#{source_path}/directory/file") { "different" } 31 | create_file("#{project_dir}/directory/file") { "same" } 32 | end 33 | 34 | it "return true" do 35 | expect(subject.fetch_required?).to be_truthy 36 | end 37 | end 38 | 39 | context "when the directories have the same files" do 40 | before do 41 | create_file("#{source_path}/directory/file") { "same" } 42 | create_file("#{project_dir}/directory/file") { "same" } 43 | end 44 | 45 | it "returns false" do 46 | expect(subject.fetch_required?).to be(false) 47 | end 48 | end 49 | end 50 | 51 | describe "#version_guid" do 52 | it "includes the source path" do 53 | expect(subject.version_guid).to eq("path:#{source_path}") 54 | end 55 | end 56 | 57 | describe "#fetch" do 58 | before do 59 | create_file("#{source_path}/file_a") 60 | create_file("#{source_path}/file_b") 61 | create_file("#{source_path}/.file_c") 62 | remove_file("#{source_path}/file_d") 63 | 64 | create_file("#{project_dir}/file_a") 65 | remove_file("#{project_dir}/file_b") 66 | remove_file("#{project_dir}/.file_c") 67 | create_file("#{project_dir}/file_d") 68 | end 69 | 70 | it "fetches new files" do 71 | subject.fetch 72 | 73 | expect("#{project_dir}/file_a").to be_a_file 74 | expect("#{project_dir}/file_b").to be_a_file 75 | expect("#{project_dir}/.file_c").to be_a_file 76 | end 77 | 78 | it "removes extraneous files" do 79 | subject.fetch 80 | 81 | expect("#{project_dir}/file_d").to_not be_a_file 82 | end 83 | end 84 | 85 | describe "#clean" do 86 | it "returns true" do 87 | expect(subject.clean).to be_truthy 88 | end 89 | end 90 | 91 | describe "#version_for_cache" do 92 | before do 93 | create_file("#{source_path}/file_a") 94 | create_file("#{source_path}/file_b") 95 | create_file("#{source_path}/.file_c") 96 | end 97 | 98 | let(:sha) { "69553b23b84e69e095b4a231877b38022b1ffb41ae0ecbba6bb2625410c49f7e" } 99 | 100 | it "includes the source_path and shasum" do 101 | expect(subject.version_for_cache).to eq("path:#{source_path}|shasum:#{sha}") 102 | end 103 | end 104 | 105 | describe "#resolve_version" do 106 | it "just returns the version" do 107 | expect(NetFetcher.resolve_version("1.2.3", source)).to eq("1.2.3") 108 | end 109 | end 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /spec/functional/templating_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | class RandomClass 5 | include Templating 6 | end 7 | 8 | describe Templating do 9 | subject { RandomClass.new } 10 | 11 | let(:source) { File.join(tmp_path, "source.erb") } 12 | let(:destination) { File.join(tmp_path, "final") } 13 | let(:mode) { 0644 } 14 | let(:variables) { { name: "Name" } } 15 | let(:contents) do 16 | <<-EOH.gsub(/^ {10}/, "") 17 | <%= name %> 18 | 19 | <% if false -%> 20 | This is magic! 21 | <% end -%> 22 | EOH 23 | end 24 | 25 | let(:options) do 26 | { 27 | destination: destination, 28 | variables: variables, 29 | mode: mode, 30 | } 31 | end 32 | 33 | before do 34 | File.open(source, "w") { |f| f.write(contents) } 35 | end 36 | 37 | describe "#render_template" do 38 | context "when no destination is given" do 39 | let(:destination) { nil } 40 | 41 | it "renders adjacent, without the erb extension" do 42 | subject.render_template(source, options) 43 | expect(File.join(tmp_path, "source")).to be_a_file 44 | end 45 | end 46 | 47 | context "when a destination is given" do 48 | it "renders at the destination" do 49 | subject.render_template(source, options) 50 | expect(destination).to be_a_file 51 | end 52 | end 53 | 54 | context "when a mode is given", :not_supported_on_windows do 55 | let(:mode) { 0755 } 56 | 57 | it "renders the object with the mode" do 58 | subject.render_template(source, options) 59 | expect(destination).to be_an_executable 60 | end 61 | end 62 | end 63 | 64 | describe "#render_template_content" do 65 | context "when an undefined variable is used" do 66 | let(:contents) { "<%= not_a_real_variable %>" } 67 | 68 | it "raise an exception" do 69 | expect do 70 | subject.render_template_content(source, variables) 71 | end.to raise_error(NameError) 72 | end 73 | end 74 | 75 | context "when no variables are present" do 76 | let(:contents) { "static content" } 77 | let(:variables) { {} } 78 | 79 | it "renders the template" do 80 | expect(subject.render_template_content(source, variables)).to eq("static content") 81 | end 82 | end 83 | end 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | Encoding.default_external = Encoding::UTF_8 2 | 3 | require "rspec" 4 | require "rspec/its" 5 | require "rspec/json_expectations" 6 | require "webmock/rspec" 7 | 8 | require "cleanroom/rspec" 9 | 10 | require "omnibus" 11 | 12 | def windows? 13 | !!(RUBY_PLATFORM =~ /mswin|mingw|windows/) 14 | end 15 | 16 | def mac? 17 | !!(RUBY_PLATFORM =~ /darwin/) 18 | end 19 | 20 | RSpec.configure do |config| 21 | config.expect_with :rspec do |c| 22 | c.max_formatted_output_length = 1000 23 | end 24 | 25 | # Custom matchers and shared examples 26 | require_relative "support/examples" 27 | require_relative "support/matchers" 28 | 29 | require_relative "support/env_helpers" 30 | config.include(Omnibus::RSpec::EnvHelpers) 31 | 32 | require_relative "support/file_helpers" 33 | config.include(Omnibus::RSpec::FileHelpers) 34 | 35 | require_relative "support/git_helpers" 36 | config.include(Omnibus::RSpec::GitHelpers) 37 | 38 | require_relative "support/logging_helpers" 39 | config.include(Omnibus::RSpec::LoggingHelpers) 40 | 41 | require_relative "support/ohai_helpers" 42 | config.include(Omnibus::RSpec::OhaiHelpers) 43 | 44 | require_relative "support/output_helpers" 45 | config.include(Omnibus::RSpec::OutputHelpers) 46 | 47 | require_relative "support/path_helpers" 48 | config.include(Omnibus::RSpec::PathHelpers) 49 | 50 | require_relative "support/shell_helpers" 51 | config.include(Omnibus::RSpec::ShellHelpers) 52 | 53 | config.filter_run(focus: true) 54 | config.run_all_when_everything_filtered = true 55 | 56 | config.filter_run_excluding(windows_only: true) unless windows? 57 | config.filter_run_excluding(mac_only: true) unless mac? 58 | config.filter_run_excluding(not_supported_on_windows: true) if windows? 59 | 60 | if config.files_to_run.one? 61 | # Use the documentation formatter for detailed output, 62 | # unless a formatter has already been configured 63 | # (e.g. via a command-line flag). 64 | config.default_formatter = "doc" 65 | config.color = true 66 | end 67 | 68 | config.before(:each) do 69 | # Suppress logging 70 | Omnibus.logger.level = :nothing 71 | 72 | # Reset config 73 | Omnibus.reset! 74 | Omnibus::Config.append_timestamp(false) 75 | 76 | # Clear the tmp_path on each run 77 | FileUtils.rm_rf(tmp_path) 78 | FileUtils.mkdir_p(tmp_path) 79 | 80 | # Don't run Ohai - tests can still override this 81 | stub_ohai(platform: "ubuntu", version: "16.04") 82 | 83 | # Default to real HTTP requests 84 | WebMock.allow_net_connect! 85 | end 86 | 87 | config.after(:each) do 88 | Omnibus.reset! 89 | end 90 | 91 | # Force the expect syntax 92 | config.expect_with :rspec do |c| 93 | c.syntax = :expect 94 | end 95 | 96 | # Run specs in a random order 97 | config.order = "random" 98 | end 99 | 100 | # 101 | # Shard example group for asserting a DSL method 102 | # 103 | # @example 104 | # it_behaves_like 'a cleanroom setter', :name, <<-EOH 105 | # name 'foo' 106 | # EOH 107 | # 108 | RSpec.shared_examples "a cleanroom setter" do |id, string| 109 | it "for `#{id}'" do 110 | expect { subject.evaluate(string) } 111 | .to_not raise_error 112 | end 113 | end 114 | 115 | # 116 | # Shard example group for asserting a DSL method 117 | # 118 | # @example 119 | # it_behaves_like 'a cleanroom getter', :name 120 | # 121 | RSpec.shared_examples "a cleanroom getter" do |id| 122 | it "for `#{id}'" do 123 | expect { subject.evaluate("#{id}") }.to_not raise_error 124 | end 125 | end 126 | -------------------------------------------------------------------------------- /spec/support/env_helpers.rb: -------------------------------------------------------------------------------- 1 | module Omnibus 2 | module RSpec 3 | module EnvHelpers 4 | # 5 | # Stub the given environment key. 6 | # 7 | # @param [String] key 8 | # @param [String] value 9 | # 10 | def stub_env(key, value) 11 | unless @__env_already_stubbed__ 12 | allow(ENV).to receive(:[]).and_call_original 13 | @__env_already_stubbed__ = true 14 | end 15 | 16 | allow(ENV).to receive(:[]).with(key).and_return(value.to_s) 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/support/examples.rb: -------------------------------------------------------------------------------- 1 | RSpec.shared_examples "a software" do |name = "chefdk"| 2 | let(:project_root) { File.join(tmp_path, "software") } 3 | 4 | let(:name) { name } 5 | let(:source) { nil } 6 | let(:version) { "1.0.0" } 7 | 8 | let(:build_dir) { File.join(project_root, "local", "build") } 9 | let(:cache_dir) { File.join(project_root, "local", "cache") } 10 | let(:source_dir) { File.join(project_root, "local", "source") } 11 | let(:project_dir) { File.join(source_dir, "project_dir") } 12 | 13 | let(:patches_dir) { File.join(project_root, "config", "patches", name) } 14 | let(:scripts_dir) { File.join(project_root, "config", "scripts", name) } 15 | let(:softwares_dir) { File.join(project_root, "config", "software", name) } 16 | let(:templates_dir) { File.join(project_root, "config", "templates", name) } 17 | 18 | let(:install_dir) { File.join(project_root, "opt", name) } 19 | let(:bin_dir) { File.join(install_dir, "bin") } 20 | let(:embedded_bin_dir) { File.join(install_dir, "embedded", "bin") } 21 | 22 | let(:software) do 23 | double(Omnibus::Software, 24 | name: name, 25 | version: version, 26 | build_dir: build_dir, 27 | install_dir: install_dir, 28 | project_dir: project_dir, 29 | source: source, 30 | overridden?: false) 31 | end 32 | 33 | before do 34 | Omnibus::Config.cache_dir(cache_dir) 35 | Omnibus::Config.source_dir(source_dir) 36 | 37 | Omnibus::Config.project_root(project_root) 38 | Omnibus::Config.build_retries(0) 39 | Omnibus::Config.use_git_caching(false) 40 | Omnibus::Config.software_gems(nil) 41 | 42 | # Make the directories 43 | FileUtils.mkdir_p(build_dir) 44 | FileUtils.mkdir_p(cache_dir) 45 | FileUtils.mkdir_p(project_dir) 46 | FileUtils.mkdir_p(source_dir) 47 | 48 | FileUtils.mkdir_p(patches_dir) 49 | FileUtils.mkdir_p(scripts_dir) 50 | FileUtils.mkdir_p(softwares_dir) 51 | FileUtils.mkdir_p(templates_dir) 52 | 53 | FileUtils.mkdir_p(install_dir) 54 | FileUtils.mkdir_p(bin_dir) 55 | FileUtils.mkdir_p(embedded_bin_dir) 56 | 57 | allow(software).to receive(:with_embedded_path).and_return( 58 | "PATH" => "#{bin_dir}:#{embedded_bin_dir}:#{ENV["PATH"]}" 59 | ) 60 | 61 | allow(software).to receive(:embedded_bin) do |binary| 62 | p = File.join(embedded_bin_dir, binary) 63 | p.gsub!(%r{/}, '\\') if windows? # rubocop:disable Style/StringLiterals 64 | p 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /spec/support/file_helpers.rb: -------------------------------------------------------------------------------- 1 | module Omnibus 2 | module RSpec 3 | module FileHelpers 4 | def create_directory(*paths) 5 | path = File.join(*paths) 6 | FileUtils.mkdir_p(path) 7 | path 8 | end 9 | 10 | def remove_directory(*paths) 11 | path = File.join(*paths) 12 | FileUtils.rm_rf(path) 13 | path 14 | end 15 | 16 | def copy_file(source, destination) 17 | FileUtils.cp(source, destination) 18 | destination 19 | end 20 | 21 | def remove_file(*paths) 22 | path = File.join(*paths) 23 | FileUtils.rm_f(path) 24 | path 25 | end 26 | 27 | def create_file(*paths, &block) 28 | path = File.join(*paths) 29 | 30 | FileUtils.mkdir_p(File.dirname(path)) 31 | FileUtils.rm(path) if File.exist?(path) 32 | 33 | if block 34 | File.open(path, "wb") { |f| f.write(yield) } 35 | else 36 | FileUtils.touch(path) 37 | end 38 | 39 | path 40 | end 41 | 42 | def create_link(src, dest) 43 | # Windows has no symlinks. Documentation seems to suggest that 44 | # ln will create hard-links - so attempt to elicit the behavior 45 | # we want using hard-links. If your test happens to fail even 46 | # with this, consider what semantics you actually wish to have 47 | # on windows and refactor your test or code. 48 | if windows? 49 | FileUtils.ln(src, dest) unless File.exist?(dest) 50 | else 51 | FileUtils.ln_s(src, dest) unless File.exist?(dest) 52 | end 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/support/logging_helpers.rb: -------------------------------------------------------------------------------- 1 | module Omnibus 2 | module RSpec 3 | module LoggingHelpers 4 | # 5 | # Grab the result of the log command. Since Omnibus uses the block form of 6 | # the logger, this method handles both types of logging. 7 | # 8 | # @example 9 | # output = capture_logging { some_command } 10 | # expect(output).to include('whatever') 11 | # 12 | def capture_logging 13 | original = Omnibus.logger 14 | Omnibus.logger = TestLogger.new 15 | yield 16 | Omnibus.logger.output 17 | ensure 18 | Omnibus.logger = original 19 | end 20 | 21 | class TestLogger < Logger 22 | def initialize(*) 23 | super(StringIO.new) 24 | @level = -1 25 | end 26 | 27 | def output 28 | io.string 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /spec/support/matchers.rb: -------------------------------------------------------------------------------- 1 | require "rspec/expectations" 2 | 3 | # expect('/path/to/directory').to be_a_directory 4 | RSpec::Matchers.define :be_a_directory do 5 | match do |actual| 6 | File.directory?(actual) 7 | end 8 | end 9 | 10 | # expect('/path/to/directory').to be_a_file 11 | RSpec::Matchers.define :be_a_file do 12 | match do |actual| 13 | File.file?(actual) 14 | end 15 | end 16 | 17 | # expect('/path/to/file').to have_content 18 | RSpec::Matchers.define :have_content do |content| 19 | match do |actual| 20 | IO.read(actual) == content 21 | end 22 | end 23 | 24 | # expect('/path/to/file').to have_permissions 25 | RSpec::Matchers.define :have_permissions do |perm| 26 | match do |actual| 27 | m = sprintf("%o", File.stat(actual).mode) 28 | m == perm 29 | end 30 | end 31 | 32 | # expect('/path/to/directory').to be_a_symlink 33 | RSpec::Matchers.define :be_a_symlink do 34 | match do |actual| 35 | File.symlink?(actual) 36 | end 37 | end 38 | 39 | # expect('/path/to/directory').to be_a_symlink_to 40 | RSpec::Matchers.define :be_a_symlink_to do |path| 41 | match do |actual| 42 | File.symlink?(actual) && File.readlink(actual) == path 43 | end 44 | end 45 | 46 | # expect('/path/to/file').to be_an_executable 47 | RSpec::Matchers.define :be_an_executable do 48 | match do |actual| 49 | File.executable?(actual) 50 | end 51 | end 52 | 53 | # expect('/path/to/file').to be_a_hardlink 54 | RSpec::Matchers.define :be_a_hardlink do |path| 55 | match do |actual| 56 | File.stat(actual).nlink > 2 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /spec/support/ohai_helpers.rb: -------------------------------------------------------------------------------- 1 | require "fauxhai" 2 | require "omnibus/ohai" 3 | 4 | module Omnibus 5 | module RSpec 6 | module OhaiHelpers 7 | # 8 | # Stub Ohai with the given data. 9 | # 10 | def stub_ohai(options = {}, &block) 11 | ohai = Mash.from_hash(Fauxhai.mock(options, &block).data) 12 | allow(Ohai).to receive(:ohai).and_return(ohai) 13 | 14 | # If we asked for Windows, we should also specify that magical 15 | # +File::ALT_SEPARATOR+ variable 16 | if options[:platform] && options[:platform] == "windows" 17 | stub_const("File::ALT_SEPARATOR", '\\') # rubocop:disable Style/StringLiterals 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/support/output_helpers.rb: -------------------------------------------------------------------------------- 1 | module Omnibus 2 | module RSpec 3 | module OutputHelpers 4 | # 5 | # Capture stdout within this block. 6 | # 7 | def capture_stdout(&block) 8 | old = $stdout 9 | $stdout = fake = StringIO.new 10 | yield 11 | fake.string 12 | ensure 13 | $stdout = old 14 | end 15 | 16 | # 17 | # Capture stderr within this block. 18 | # 19 | def capture_stderr(&block) 20 | old = $stderr 21 | $stderr = fake = StringIO.new 22 | yield 23 | fake.string 24 | ensure 25 | $stderr = old 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/support/path_helpers.rb: -------------------------------------------------------------------------------- 1 | module Omnibus 2 | module RSpec 3 | module PathHelpers 4 | def fixture_path(*pieces) 5 | File.join(fixtures_path, *pieces) 6 | end 7 | 8 | def tmp_path 9 | File.expand_path("../tmp", __dir__) 10 | end 11 | 12 | private 13 | 14 | def fixtures_path 15 | File.expand_path("../fixtures", __dir__) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/support/shell_helpers.rb: -------------------------------------------------------------------------------- 1 | require "mixlib/shellout" 2 | 3 | module Omnibus 4 | module RSpec 5 | module ShellHelpers 6 | def shellout!(command, options = {}) 7 | cmd = Mixlib::ShellOut.new(command, options) 8 | cmd.environment["HOME"] = "/tmp" unless ENV["HOME"] 9 | cmd.run_command 10 | cmd 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/unit/build_system_metadata_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe BuildSystemMetadata do 5 | 6 | let(:ami_id) { "ami-1234ab5678cd9ef01" } 7 | let(:hostname) { "CHF-V-ABC-DE000.local" } 8 | let(:docker_version) { "20.0.0" } 9 | let(:docker_image) { "artifactory-url.com/release-type/base-platform" } 10 | let(:docker_command) { "docker build . -f images/omnibus_toolchain_containers/platform/Dockerfile -t artifactory-url.com/release-type/omnibus-toolchain-platform -t chefes/omnibus-toolchain-platform --build-arg OS_IMAGE=#{docker_image}" } 11 | 12 | subject(:buildkite_metadata) { Omnibus::Buildkite } 13 | 14 | describe "#to_hash" do 15 | context "builds occur on buildkite" do 16 | 17 | before(:each) do 18 | clear_defaults 19 | end 20 | 21 | it "returns an ami_id if one is found" do 22 | with_ami_id 23 | expect(buildkite_metadata.to_hash[:ami_id]).to eq(ami_id) 24 | end 25 | 26 | it "returns an hostname if one is found" do 27 | with_hostname 28 | expect(buildkite_metadata.to_hash[:hostname]).to eq(hostname) 29 | end 30 | 31 | it "returns is_docker_build if one is found" do 32 | with_docker 33 | expect(buildkite_metadata.to_hash[:is_docker_build]).to eq(true) 34 | end 35 | 36 | it "returns a docker_version if one is found" do 37 | with_docker 38 | expect(buildkite_metadata.to_hash[:docker_version]).to eq(docker_version) 39 | end 40 | 41 | it "returns a docker_image if one is found" do 42 | with_docker 43 | expect(buildkite_metadata.to_hash[:docker_image]).to eq(docker_image) 44 | end 45 | 46 | it "returns an omnibus_version if one is found" do 47 | expect(buildkite_metadata.to_hash[:omnibus_version]).to eq(Omnibus::VERSION) 48 | end 49 | 50 | end 51 | end 52 | 53 | def with_ami_id 54 | stub_env("BUILDKITE_AGENT_META_DATA_AWS_AMI_ID", ami_id) 55 | end 56 | 57 | def with_hostname 58 | stub_env("BUILDKITE_AGENT_META_DATA_HOSTNAME", hostname) 59 | end 60 | 61 | def with_docker 62 | stub_env("BUILDKITE_AGENT_META_DATA_DOCKER", docker_version) 63 | stub_env("BUILDKITE_COMMAND", docker_command) 64 | end 65 | 66 | def clear_defaults 67 | without_ami_id_and_hostname 68 | without_docker 69 | end 70 | 71 | def without_ami_id_and_hostname 72 | stub_env("BUILDKITE_AGENT_META_DATA_AWS_AMI_ID", nil) 73 | stub_env("BUILDKITE_AGENT_META_DATA_HOSTNAME", nil) 74 | end 75 | 76 | def without_docker 77 | stub_env("BUILDKITE_AGENT_META_DATA_DOCKER", nil) 78 | stub_env("BUILDKITE_COMMAND", nil) 79 | end 80 | 81 | end 82 | end -------------------------------------------------------------------------------- /spec/unit/changelog_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe ChangeLog do 5 | describe "#new" do 6 | it "sets the start_ref to the latest tag if none is set" do 7 | repo = double(GitRepository, latest_tag: "1.0") 8 | expect(ChangeLog.new(nil, "2.0", repo).start_ref).to eq("1.0") 9 | end 10 | 11 | it "sets the end_ref to HEAD if none is set" do 12 | expect(ChangeLog.new.end_ref).to eq("HEAD") 13 | end 14 | end 15 | 16 | describe "#changelog_entries" do 17 | it "returns any git log lines with the ChangeLog: tag, removing the tag" do 18 | repo = double(GitRepository, commit_messages: ["ChangeLog-Entry: foobar\n", 19 | "ChangeLog-Entry: wombat\n"]) 20 | changelog = ChangeLog.new("0.0.1", "0.0.2", repo) 21 | expect(changelog.changelog_entries).to eq(%W{foobar\n wombat\n}) 22 | end 23 | 24 | it "returns an empty array if there were no changelog entries" do 25 | repo = double(GitRepository, commit_messages: []) 26 | changelog = ChangeLog.new("0.0.1", "0.0.2", repo) 27 | expect(changelog.changelog_entries).to eq([]) 28 | end 29 | 30 | it "does not return git messages without a ChangeLog: tag" do 31 | repo = double(GitRepository, commit_messages: %W{foobar\n wombat\n}) 32 | changelog = ChangeLog.new("0.0.1", "0.0.2", repo) 33 | expect(changelog.changelog_entries).to eq([]) 34 | end 35 | 36 | it "does not return blank lines" do 37 | repo = double(GitRepository, commit_messages: %W{\n \n}) 38 | changelog = ChangeLog.new("0.0.1", "0.0.2", repo) 39 | expect(changelog.changelog_entries).to eq([]) 40 | end 41 | 42 | it "can handle multi-line ChangeLog entries" do 43 | repo = double(GitRepository, commit_messages: ["ChangeLog-Entry: foobar\n", "foobaz\n"]) 44 | changelog = ChangeLog.new("0.0.1", "0.0.2", repo) 45 | expect(changelog.changelog_entries).to eq(["foobar\nfoobaz\n"]) 46 | end 47 | 48 | it "end a ChangeLog entry at the first blank line" do 49 | repo = double(GitRepository, commit_messages: ["ChangeLog-Entry: foobar\n", "\n", "foobaz\n"]) 50 | changelog = ChangeLog.new("0.0.1", "0.0.2", repo) 51 | expect(changelog.changelog_entries).to eq(["foobar\n"]) 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /spec/unit/cleanroom_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe Cleanroom do 5 | let(:klass) do 6 | Class.new do 7 | include Cleanroom 8 | 9 | def exposed_method 10 | @called = true 11 | end 12 | expose :exposed_method 13 | 14 | def unexposed_method; end 15 | end 16 | end 17 | 18 | let(:instance) { klass.new } 19 | 20 | describe "#evaluate" do 21 | it "exposes public methods" do 22 | expect do 23 | instance.evaluate("exposed_method") 24 | end.to_not raise_error 25 | end 26 | 27 | it "calls exposed methods on the instance" do 28 | instance.evaluate("exposed_method") 29 | expect(instance.instance_variable_get(:@called)).to be_truthy 30 | end 31 | 32 | it "does not expose unexposed methods" do 33 | expect do 34 | instance.evaluate("unexposed_method") 35 | end.to raise_error(NameError) 36 | end 37 | end 38 | 39 | describe "#evaluate_file" do 40 | let(:contents) do 41 | <<-EOH.gsub(/^ {10}/, "") 42 | exposed_method 43 | EOH 44 | end 45 | 46 | let(:filepath) { File.join(tmp_path, "/file/path") } 47 | 48 | before do 49 | allow(IO).to receive(:read).and_call_original 50 | allow(IO).to receive(:read).with(filepath).and_return(contents) 51 | end 52 | 53 | it "evaluates the file and exposes public methods" do 54 | expect { instance.evaluate_file(filepath) }.to_not raise_error 55 | end 56 | 57 | it "calls exposed methods on the instance" do 58 | instance.evaluate_file(filepath) 59 | expect(instance.instance_variable_get(:@called)).to be_truthy 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/unit/compressor_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe Compressor do 5 | describe ".for_current_system" do 6 | context "on macOS" do 7 | before { stub_ohai(platform: "mac_os_x") } 8 | 9 | context "when :dmg is activated" do 10 | it "prefers dmg" do 11 | expect(described_class.for_current_system(%i{tgz dmg})).to eq(Compressor::DMG) 12 | end 13 | end 14 | 15 | context "when :dmg is not activated" do 16 | it "prefers tgz" do 17 | expect(described_class.for_current_system(%i{tgz foo})).to eq(Compressor::TGZ) 18 | end 19 | end 20 | 21 | context "when nothing is given" do 22 | it "returns null" do 23 | expect(described_class.for_current_system([])).to eq(Compressor::Null) 24 | end 25 | end 26 | end 27 | 28 | context "on Ubuntu" do 29 | before { stub_ohai(platform: "ubuntu", version: "16.04") } 30 | 31 | context "when :tgz activated" do 32 | it "prefers tgz" do 33 | expect(described_class.for_current_system(%i{tgz foo})).to eq(Compressor::TGZ) 34 | end 35 | end 36 | 37 | context "when nothing is given" do 38 | it "returns null" do 39 | expect(described_class.for_current_system([])).to eq(Compressor::Null) 40 | end 41 | end 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/unit/compressors/base_spec.rb: -------------------------------------------------------------------------------- 1 | require "stringio" 2 | 3 | module Omnibus 4 | describe Compressor::Base do 5 | let(:packager) { double(Packager::Base) } 6 | let(:project) { double(Project, packagers_for_system: [packager]) } 7 | 8 | describe ".initialize" do 9 | subject { described_class.new(project) } 10 | 11 | it "sets the project" do 12 | expect(subject.project).to eq(project) 13 | end 14 | 15 | it "sets the packager" do 16 | expect(subject.packager).to eq(packager) 17 | end 18 | end 19 | 20 | subject { described_class.new(project) } 21 | 22 | it "inherits from Packager" do 23 | expect(subject).to be_a(Packager::Base) 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/unit/compressors/null_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe Compressor::Null do 5 | let(:packager) { double(Packager::Base) } 6 | let(:project) { double(Project, packagers_for_system: [packager]) } 7 | 8 | subject { described_class.new(project) } 9 | 10 | describe "#id" do 11 | it "is :dmg" do 12 | expect(subject.id).to eq(:null) 13 | end 14 | end 15 | 16 | describe "#run!" do 17 | it "does nothing" do 18 | expect(subject).to_not receive(:instance_eval) 19 | subject.run! 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/unit/compressors/tgz_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe Compressor::TGZ do 5 | let(:project) do 6 | Project.new.tap do |project| 7 | project.name("project") 8 | project.homepage("https://example.com") 9 | project.install_dir("/opt/project") 10 | project.build_version("1.2.3") 11 | project.build_iteration("2") 12 | project.maintainer("Chef Software") 13 | end 14 | end 15 | 16 | subject { described_class.new(project) } 17 | 18 | let(:project_root) { File.join(tmp_path, "project/root") } 19 | let(:package_dir) { File.join(tmp_path, "package/dir") } 20 | let(:staging_dir) { File.join(tmp_path, "staging/dir") } 21 | 22 | before do 23 | create_directory(project_root) 24 | create_directory(package_dir) 25 | create_directory(staging_dir) 26 | 27 | allow(project).to receive(:packagers_for_system) 28 | .and_return([Packager::PKG.new(project)]) 29 | 30 | Config.project_root(project_root) 31 | Config.package_dir(package_dir) 32 | 33 | allow(subject).to receive(:staging_dir) 34 | .and_return(staging_dir) 35 | 36 | allow(subject).to receive(:shellout!) 37 | end 38 | 39 | describe "#package_name" do 40 | it "returns the name of the packager" do 41 | expect(subject.package_name).to eq("project-1.2.3-2.x86_64.pkg.tar.gz") 42 | end 43 | end 44 | 45 | describe "#write_tgz" do 46 | before do 47 | File.open("#{staging_dir}/project-1.2.3-2.x86_64.pkg", "wb") do |f| 48 | f.write " " * 1_000_000 49 | end 50 | end 51 | 52 | it "generates the file" do 53 | subject.write_tgz 54 | expect("#{staging_dir}/project-1.2.3-2.x86_64.pkg.tar.gz").to be_a_file 55 | end 56 | 57 | it "has the correct content" do 58 | subject.write_tgz 59 | file = File.open("#{staging_dir}/project-1.2.3-2.x86_64.pkg.tar.gz", "rb") 60 | contents = file.read 61 | file.close 62 | 63 | expect(contents).to include("\x1F\x8B\b\x00".force_encoding("ASCII-8BIT")) 64 | end 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /spec/unit/digestable_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe Digestable do 5 | let(:path) { "/path/to/file" } 6 | let(:io) { StringIO.new } 7 | 8 | subject { Class.new { include Digestable }.new } 9 | 10 | describe "#digest" do 11 | it "reads the IO in chunks" do 12 | expect(File).to receive(:open).with(path).and_yield(io) 13 | expect(subject.digest(path)).to eq("d41d8cd98f00b204e9800998ecf8427e") 14 | end 15 | end 16 | 17 | describe "#digest_directory" do 18 | let(:path) { "/path/to/dir" } 19 | let(:glob) { "#{path}/**/*" } 20 | let(:subdir) { "/path/to/dir/subdir" } 21 | let(:subfile) { "/path/to/dir/subfile" } 22 | let(:io) { StringIO.new } 23 | 24 | it "inspects the file types of glob entries" do 25 | expect(FileSyncer).to receive(:glob).with(glob).and_return([subdir]) 26 | expect(File).to receive(:ftype).with(subdir).and_return("directory") 27 | expect(subject.digest_directory(path)).to eq("8b91792e7917b1152d8494670caaeb85") 28 | end 29 | 30 | it "inspects the contents of the files" do 31 | expect(FileSyncer).to receive(:glob).with(glob).and_return([subfile]) 32 | expect(File).to receive(:ftype).with(subfile).and_return("file") 33 | expect(File).to receive(:open).with(subfile).and_yield(io) 34 | expect(subject.digest_directory(path)).to eq("c8f023976b95ace2ae3678540fd3b4f1") 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /spec/unit/fetcher_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | require "omnibus/manifest_entry" 3 | 4 | module Omnibus 5 | describe Fetcher do 6 | let(:source_path) { "/local/path" } 7 | let(:project_dir) { "/project/dir" } 8 | let(:build_dir) { "/build/dir" } 9 | 10 | let(:manifest_entry) do 11 | double(Software, 12 | name: "software", 13 | locked_version: "31aedfs", 14 | described_version: "mrfancypants", 15 | locked_source: { path: source_path }) 16 | end 17 | 18 | subject { described_class.new(manifest_entry, project_dir, build_dir) } 19 | 20 | describe "#initialize" do 21 | it "sets the resovled_version to the locked_version" do 22 | expect(subject.resolved_version).to eq("31aedfs") 23 | end 24 | 25 | it "sets the source to the locked_source" do 26 | expect(subject.source).to eq({ path: source_path }) 27 | end 28 | 29 | it "sets the described_version to the described version" do 30 | expect(subject.described_version).to eq("mrfancypants") 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/unit/fetchers/file_fetcher_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe FileFetcher do 5 | let(:source_file) { "/local/file" } 6 | let(:target_file) { "/project/dir/file" } 7 | let(:project_dir) { "/project/dir" } 8 | let(:build_dir) { "/build/dir" } 9 | 10 | let(:manifest_entry) do 11 | double(ManifestEntry, 12 | name: "software", 13 | locked_version: nil, 14 | described_version: nil, 15 | locked_source: { file: source_file }) 16 | end 17 | 18 | subject { described_class.new(manifest_entry, project_dir, build_dir) } 19 | 20 | describe "#fetch_required?" do 21 | context "when the SHAs match" do 22 | before do 23 | allow(subject).to receive(:target_shasum).and_return("abcd1234") 24 | allow(subject).to receive(:destination_shasum).and_return("abcd1234") 25 | end 26 | 27 | it "returns false" do 28 | expect(subject.fetch_required?).to be(false) 29 | end 30 | end 31 | 32 | context "when the SHAs do not match" do 33 | before do 34 | allow(subject).to receive(:target_shasum).and_return("abcd1234") 35 | allow(subject).to receive(:destination_shasum).and_return("efgh5678") 36 | end 37 | 38 | it "returns true" do 39 | expect(subject.fetch_required?).to be_truthy 40 | end 41 | end 42 | end 43 | 44 | describe "#version_guid" do 45 | it "returns the path" do 46 | expect(subject.version_guid).to eq("file:#{source_file}") 47 | end 48 | end 49 | 50 | describe "#clean" do 51 | it "returns true" do 52 | expect(subject.clean).to be_truthy 53 | end 54 | end 55 | 56 | describe "#fetch" do 57 | before do 58 | allow(subject).to receive(:create_required_directories) 59 | end 60 | 61 | it "copies the new files over" do 62 | expect(FileUtils).to receive(:cp).with(source_file, target_file) 63 | subject.fetch 64 | end 65 | end 66 | 67 | describe "#version_for_cache" do 68 | let(:shasum) { "abcd1234" } 69 | 70 | before do 71 | allow(subject).to receive(:digest) 72 | .with(source_file, :sha256) 73 | .and_return(shasum) 74 | end 75 | 76 | it "returns the shasum of the source file" do 77 | expect(subject.version_for_cache).to eq("file:#{source_file}|shasum:#{shasum}") 78 | end 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /spec/unit/fetchers/path_fetcher_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe PathFetcher do 5 | let(:source_path) { "/local/path" } 6 | let(:project_dir) { "/project/dir" } 7 | let(:build_dir) { "/build/dir" } 8 | 9 | let(:manifest_entry) do 10 | double(ManifestEntry, 11 | name: "software", 12 | locked_version: nil, 13 | described_version: nil, 14 | locked_source: { path: source_path }) 15 | end 16 | 17 | subject { described_class.new(manifest_entry, project_dir, build_dir) } 18 | 19 | describe "#fetch_required?" do 20 | context "when the SHAs match" do 21 | before do 22 | allow(subject).to receive(:target_shasum).and_return("abcd1234") 23 | allow(subject).to receive(:destination_shasum).and_return("abcd1234") 24 | end 25 | 26 | it "returns false" do 27 | expect(subject.fetch_required?).to be(false) 28 | end 29 | end 30 | 31 | context "when the SHAs do not match" do 32 | before do 33 | allow(subject).to receive(:target_shasum).and_return("abcd1234") 34 | allow(subject).to receive(:destination_shasum).and_return("efgh5678") 35 | end 36 | 37 | it "returns true" do 38 | expect(subject.fetch_required?).to be_truthy 39 | end 40 | end 41 | end 42 | 43 | describe "#version_guid" do 44 | it "returns the path" do 45 | expect(subject.version_guid).to eq("path:#{source_path}") 46 | end 47 | end 48 | 49 | describe "#clean" do 50 | it "returns true" do 51 | expect(subject.clean).to be_truthy 52 | end 53 | end 54 | 55 | describe "#fetch" do 56 | before do 57 | allow(subject).to receive(:create_required_directories) 58 | allow(FileSyncer).to receive(:sync) 59 | end 60 | 61 | it "copies the new files over" do 62 | expect(FileSyncer).to receive(:sync).with(source_path, project_dir, {}) 63 | subject.fetch 64 | end 65 | end 66 | 67 | describe "#version_for_cache" do 68 | let(:shasum) { "abcd1234" } 69 | 70 | before do 71 | allow(subject).to receive(:digest_directory) 72 | .with(source_path, :sha256, {}) 73 | .and_return(shasum) 74 | end 75 | 76 | it "returns the shasum of the source directory" do 77 | expect(subject.version_for_cache).to eq("path:#{source_path}|shasum:#{shasum}") 78 | end 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /spec/unit/file_syncer_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | require "omnibus/file_syncer" 3 | 4 | module Omnibus 5 | describe FileSyncer do 6 | let(:fixture_dir) { "C:\\test" } 7 | 8 | describe "#glob", :windows_only do 9 | 10 | [ "/", "\\", "\\\\" ].each do |sep| 11 | it "should correctly clean the path with #{sep}" do 12 | pattern = fixture_dir + sep + "postinstall" 13 | expect(Dir).to receive(:glob).with("C:/test/postinstall", File::FNM_DOTMATCH).and_return(["C:/test/postinstall"]) 14 | FileSyncer.glob(pattern) 15 | end 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/unit/git_repository_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe GitRepository do 5 | let(:git_repo) do 6 | path = local_git_repo("foobar", annotated_tags: ["1.0", "2.0", "3.0"]) 7 | Omnibus::GitRepository.new(path) 8 | end 9 | 10 | describe "#authors" do 11 | it "returns an array of authors between two tags" do 12 | expect(git_repo.authors("1.0", "2.0")).to eq(["omnibus"]) 13 | end 14 | 15 | it "returns an empty array if start_ref == end_ref" do 16 | expect(git_repo.authors("3.0", "3.0")).to eq([]) 17 | end 18 | 19 | it "doesn't return duplicates" do 20 | expect(git_repo.authors("1.0", "3.0")).to eq(["omnibus"]) 21 | end 22 | 23 | it "returns an error if the tags don't exist" do 24 | expect { git_repo.authors("1.0", "WUT") }.to raise_error(RuntimeError) 25 | end 26 | end 27 | 28 | describe "#latest_tag" do 29 | it "returns the latest annotated tag" do 30 | expect(git_repo.latest_tag).to eq("3.0") 31 | end 32 | end 33 | 34 | describe "#revision" do 35 | it "returns the current revision at HEAD" do 36 | expect(git_repo.revision).to eq("632501dde2c41f3bdd988b818b4c008e2ff398dc") 37 | end 38 | end 39 | 40 | describe "#file_at_revision" do 41 | it "returns the text of the specified file in a repository at a given revision" do 42 | expect(git_repo.file_at_revision("configure", "1.0")).to eq("echo \"Done!\"") 43 | end 44 | end 45 | 46 | describe "#commit_messages" do 47 | it "returns the raw text from commits between two tags as an array of lines" do 48 | expect(git_repo.commit_messages("1.0", "3.0")).to eq(["Create tag 3.0\n", "\n", "Create tag 2.0\n"]) 49 | end 50 | 51 | it "returns lines with the newline attached" do 52 | expect(git_repo.commit_messages("1.0", "3.0").first[-1]).to eq("\n") 53 | end 54 | 55 | it "returns an empty array if start_ref == end_ref" do 56 | expect(git_repo.commit_messages("3.0", "3.0")).to eq([]) 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/unit/manifest_diff_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe ManifestDiff do 5 | def manifest_entry_for(name, dv, lv) 6 | Omnibus::ManifestEntry.new(name, { described_version: dv, 7 | locked_version: lv, 8 | locked_source: { 9 | git: "git://#{name}@example.com" }, 10 | source_type: :git, 11 | }) 12 | end 13 | 14 | let(:manifest_one) do 15 | m = Omnibus::Manifest.new 16 | m.add("foo", manifest_entry_for("foo", "1.2.4", "deadbeef")) 17 | m.add("bar", manifest_entry_for("bar", "1.2.4", "deadbeef")) 18 | m.add("baz", manifest_entry_for("baz", "1.2.4", "deadbeef")) 19 | m 20 | end 21 | 22 | let(:manifest_two) do 23 | m = Omnibus::Manifest.new 24 | m.add("foo", manifest_entry_for("foo", "1.2.5", "deadbea0")) 25 | m.add("baz", manifest_entry_for("baz", "1.2.4", "deadbeef")) 26 | m.add("quux", manifest_entry_for("quux", "1.2.4", "deadbeef")) 27 | m 28 | end 29 | 30 | subject { described_class.new(manifest_one, manifest_two) } 31 | 32 | describe "#updated" do 33 | it "returns items that existed in the first manifest but have been changed" do 34 | expect(subject.updated).to eq([{ name: "foo", 35 | old_version: "deadbeef", 36 | new_version: "deadbea0", 37 | source_type: :git, 38 | source: { git: "git://foo@example.com" }, 39 | }]) 40 | end 41 | 42 | describe "#removed" do 43 | it "returns items that existed in the first manfiest but don't exist in the second" do 44 | expect(subject.removed).to eq([{ name: "bar", 45 | old_version: "deadbeef", 46 | source_type: :git, 47 | source: { git: "git://bar@example.com" }, 48 | }]) 49 | end 50 | end 51 | 52 | describe "#added" do 53 | it "returns items that did not exist in the first manifest but do exist in the second" do 54 | expect(subject.added).to eq([{ name: "quux", 55 | new_version: "deadbeef", 56 | source_type: :git, 57 | source: { git: "git://quux@example.com" }, 58 | }]) 59 | end 60 | end 61 | 62 | describe "#empty?" do 63 | it "returns false if there have been changes" do 64 | expect(subject.empty?).to eq(false) 65 | end 66 | 67 | it "returns true if nothing changed" do 68 | diff = Omnibus::ManifestDiff.new(manifest_one, manifest_one) 69 | expect(diff.empty?).to eq(true) 70 | end 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /spec/unit/ohai_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe Ohai do 5 | context "using hash notation" do 6 | it "allows fetching values by hash notation" do 7 | expect { Ohai["kernel"] }.to_not raise_error 8 | expect { Ohai["kernel"]["machine"] }.to_not raise_error 9 | end 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/unit/omnibus_spec.rb: -------------------------------------------------------------------------------- 1 | require "omnibus" 2 | require "spec_helper" 3 | 4 | describe Omnibus do 5 | before do 6 | allow(File).to receive(:directory?).and_return(true) 7 | 8 | allow(Gem::Specification).to receive(:find_all_by_name) 9 | .with("omnibus-software") 10 | .and_return([double(gem_dir: File.join(tmp_path, "/gem/omnibus-software"))]) 11 | 12 | allow(Gem::Specification).to receive(:find_all_by_name) 13 | .with("custom-omnibus-software") 14 | .and_return([double(gem_dir: File.join(tmp_path, "/gem/custom-omnibus-software"))]) 15 | 16 | Omnibus::Config.project_root(File.join(tmp_path, "/foo/bar")) 17 | Omnibus::Config.local_software_dirs([File.join(tmp_path, "/local"), File.join(tmp_path, "/other")]) 18 | Omnibus::Config.software_gems(%w{omnibus-software custom-omnibus-software}) 19 | end 20 | 21 | describe "#which" do 22 | it "returns nil when the file does not exist" do 23 | stub_env("PATH", nil) 24 | expect(subject.which("not_a_real_executable")).to be nil 25 | end 26 | 27 | it "returns the path when the file exists" do 28 | 29 | ruby_cmd = windows? ? "ruby.exe" : "ruby" 30 | ruby = Bundler.which(ruby_cmd) 31 | expect(subject.which(ruby)).to eq(ruby) 32 | expect(subject.which(ruby_cmd)).to eq(ruby) 33 | end 34 | end 35 | 36 | describe "#project_path" do 37 | before do 38 | allow(Omnibus).to receive(:project_map) 39 | .and_return("chef" => "/projects/chef") 40 | end 41 | 42 | it "accepts a string" do 43 | expect(subject.project_path("chef")).to eq("/projects/chef") 44 | end 45 | 46 | it "accepts a symbol" do 47 | expect(subject.project_path(:chef)).to eq("/projects/chef") 48 | end 49 | 50 | it "returns nil when the project does not exist" do 51 | expect(subject.project_path("bacon")).to be nil 52 | end 53 | end 54 | 55 | describe "#software_path" do 56 | before do 57 | allow(Omnibus).to receive(:software_map) 58 | .and_return("chef" => "/software/chef") 59 | end 60 | 61 | it "accepts a string" do 62 | expect(subject.software_path("chef")).to eq("/software/chef") 63 | end 64 | 65 | it "accepts a symbol" do 66 | expect(subject.software_path(:chef)).to eq("/software/chef") 67 | end 68 | 69 | it "returns nil when the project does not exist" do 70 | expect(subject.software_path("bacon")).to be nil 71 | end 72 | end 73 | 74 | describe "#possible_paths_for" do 75 | it "searches all paths" do 76 | expect(subject.possible_paths_for("file")).to eq(%w{ 77 | /foo/bar/file 78 | /local/file 79 | /other/file 80 | /gem/omnibus-software/file 81 | /gem/custom-omnibus-software/file 82 | }.map { |path| File.join(tmp_path, path) }) 83 | end 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /spec/unit/package_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe Package do 5 | let(:path) { windows? ? "C:/path/to/files/thing.deb" : "/path/to/files/thing.deb" } 6 | 7 | subject { described_class.new(path) } 8 | 9 | describe ".initialize" do 10 | it "sets the path" do 11 | expect(subject.instance_variables).to include(:@path) 12 | end 13 | end 14 | 15 | describe "#name" do 16 | it "returns the basename of the file" do 17 | expect(subject.name).to eq("thing.deb") 18 | end 19 | end 20 | 21 | describe "#md5" do 22 | let(:md5) { "abcdef123456" } 23 | 24 | before { allow(subject).to receive(:digest).with(path, :md5).and_return(md5) } 25 | 26 | it "returns the md5 of the package at the path" do 27 | expect(subject.md5).to eq(md5) 28 | end 29 | end 30 | 31 | describe "#sha256" do 32 | let(:sha256) { "abcdef123456" } 33 | 34 | before { allow(subject).to receive(:digest).with(path, :sha256).and_return(sha256) } 35 | 36 | it "returns the sha256 of the package at the path" do 37 | expect(subject.sha256).to eq(sha256) 38 | end 39 | end 40 | 41 | describe "#sha512" do 42 | let(:sha512) { "abcdef123456" } 43 | 44 | before { allow(subject).to receive(:digest).with(path, :sha512).and_return(sha512) } 45 | 46 | it "returns the sha512 of the package at the path" do 47 | expect(subject.sha512).to eq(sha512) 48 | end 49 | end 50 | 51 | describe "#content" do 52 | context "when the file exists" do 53 | let(:content) { "BINARY" } 54 | 55 | before { allow(IO).to receive(:read).with(path).and_return(content) } 56 | 57 | it "reads the file" do 58 | expect(subject.content).to eq(content) 59 | end 60 | end 61 | 62 | context "when the file does not exist" do 63 | before { allow(IO).to receive(:read).and_raise(Errno::ENOENT) } 64 | 65 | it "raises an exception" do 66 | expect { subject.content }.to raise_error(NoPackageFile) 67 | end 68 | end 69 | end 70 | 71 | describe "#metadata" do 72 | let(:content) { '{ "platform": "ubuntu" }' } 73 | 74 | before { allow(IO).to receive(:read).and_return(content) } 75 | 76 | it "returns a Metadata object" do 77 | expect(subject.metadata).to be_a(Metadata) 78 | end 79 | 80 | it "reads the information in the file" do 81 | expect(subject.metadata[:platform]).to eq("ubuntu") 82 | end 83 | end 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /spec/unit/packager_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe Packager do 5 | describe ".for_current_system" do 6 | context "on macOS" do 7 | before { stub_ohai(platform: "mac_os_x") } 8 | it "prefers PKG" do 9 | expect(described_class.for_current_system).to eq([Packager::PKG]) 10 | end 11 | end 12 | 13 | context "on Windows" do 14 | before { stub_ohai(platform: "windows", version: "2012R2") } 15 | it "prefers MSI and APPX" do 16 | expect(described_class.for_current_system).to eq([Packager::MSI, Packager::APPX]) 17 | end 18 | end 19 | 20 | context "on Solaris 11" do 21 | before { stub_ohai(platform: "solaris2", version: "5.11") } 22 | it "prefers IPS" do 23 | expect(described_class.for_current_system).to eq([Packager::IPS]) 24 | end 25 | end 26 | 27 | context "on AIX" do 28 | before { stub_ohai(platform: "aix", version: "7") } 29 | it "prefers BFF" do 30 | expect(described_class.for_current_system).to eq([Packager::BFF]) 31 | end 32 | end 33 | 34 | context "on Fedora" do 35 | before { stub_ohai(platform: "fedora", version: "31") } 36 | it "prefers RPM" do 37 | expect(described_class.for_current_system).to eq([Packager::RPM]) 38 | end 39 | end 40 | 41 | context "on Amazon Linux 2" do 42 | before { stub_ohai(platform: "amazon", version: "2") } 43 | it "prefers RPM" do 44 | expect(described_class.for_current_system).to eq([Packager::RPM]) 45 | end 46 | end 47 | 48 | context "on Debian" do 49 | before { stub_ohai(platform: "debian", version: "10") } 50 | it "prefers RPM" do 51 | expect(described_class.for_current_system).to eq([Packager::DEB]) 52 | end 53 | end 54 | 55 | context "on SLES" do 56 | before { stub_ohai(platform: "suse", version: "15") } 57 | it "prefers RPM" do 58 | expect(described_class.for_current_system).to eq([Packager::RPM]) 59 | end 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/unit/packagers/makeself_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe Packager::Makeself do 5 | let(:project) do 6 | Project.new.tap do |project| 7 | project.name("project") 8 | project.homepage("https://example.com") 9 | project.install_dir("/opt/project") 10 | project.build_version("1.2.3") 11 | project.build_iteration("2") 12 | project.maintainer("Chef Software") 13 | end 14 | end 15 | 16 | subject { described_class.new(project) } 17 | 18 | let(:project_root) { File.join(tmp_path, "project/root") } 19 | let(:package_dir) { File.join(tmp_path, "package/dir") } 20 | let(:staging_dir) { File.join(tmp_path, "staging/dir") } 21 | 22 | before do 23 | Config.project_root(project_root) 24 | Config.package_dir(package_dir) 25 | 26 | allow(subject).to receive(:staging_dir).and_return(staging_dir) 27 | create_directory(staging_dir) 28 | end 29 | 30 | describe "#id" do 31 | it "is :makeself" do 32 | expect(subject.id).to eq(:makeself) 33 | end 34 | end 35 | 36 | describe "#package_name" do 37 | before do 38 | allow(subject).to receive(:safe_architecture).and_return("x86_64") 39 | end 40 | 41 | it "includes the name, version, and build iteration" do 42 | expect(subject.package_name).to eq("project-1.2.3_2.x86_64.sh") 43 | end 44 | end 45 | 46 | describe "#write_makeselfinst" do 47 | it "generates the executable file", :not_supported_on_windows do 48 | subject.write_makeselfinst 49 | expect("#{staging_dir}/makeselfinst").to be_an_executable 50 | end 51 | 52 | it "has the correct content" do 53 | subject.write_makeselfinst 54 | contents = File.read("#{staging_dir}/makeselfinst") 55 | 56 | expect(contents).to include("INSTALL_DIR=/opt/project") 57 | end 58 | end 59 | 60 | describe "#write_scripts" do 61 | let(:default_scripts) { %w{ postinst } } 62 | before do 63 | default_scripts.each do |script_name| 64 | create_file("#{project_root}/package-scripts/project/#{script_name}") do 65 | "Contents of #{script_name}" 66 | end 67 | end 68 | end 69 | 70 | it "writes the scripts into the staging dir" do 71 | subject.write_scripts 72 | 73 | default_scripts.each do |script_name| 74 | mapped_name = Packager::Makeself::SCRIPT_MAP[script_name.to_sym] 75 | script_file = "#{staging_dir}/#{mapped_name}" 76 | contents = File.read(script_file) 77 | expect(contents).to include("Contents of #{script_name}") 78 | end 79 | end 80 | end 81 | 82 | describe "#create_makeself_package" do 83 | before do 84 | allow(subject).to receive(:shellout!) 85 | allow(Dir).to receive(:chdir) { |_, &b| b.call } 86 | end 87 | 88 | it "logs a message" do 89 | output = capture_logging { subject.create_makeself_package } 90 | expect(output).to include("Creating makeself package") 91 | end 92 | 93 | it "uses the correct command" do 94 | expect(subject).to receive(:shellout!) 95 | .with(/makeself\.sh/) 96 | subject.create_makeself_package 97 | end 98 | end 99 | end 100 | end 101 | -------------------------------------------------------------------------------- /spec/unit/packagers/pkgsrc_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe Packager::PKGSRC do 5 | let(:project) do 6 | Project.new.tap do |project| 7 | project.name("project") 8 | project.homepage("https://example.com") 9 | project.install_dir("/opt/project") 10 | project.build_version("1.2.3") 11 | project.build_iteration("1") 12 | project.maintainer("Chef Software") 13 | end 14 | end 15 | 16 | subject { described_class.new(project) } 17 | 18 | let(:project_root) { File.join(tmp_path, "project/root") } 19 | let(:package_dir) { File.join(tmp_path, "package/dir") } 20 | let(:staging_dir) { File.join(tmp_path, "staging/dir") } 21 | let(:architecture) { "86_64" } 22 | 23 | before do 24 | # This is here to allow this unit test to run on windows. 25 | allow(File).to receive(:expand_path).and_wrap_original do |m, *args| 26 | m.call(*args).sub(/^[A-Za-z]:/, "") 27 | end 28 | Config.project_root(project_root) 29 | Config.package_dir(package_dir) 30 | 31 | allow(subject).to receive(:staging_dir).and_return(staging_dir) 32 | create_directory(staging_dir) 33 | 34 | stub_ohai(platform: "smartos", version: "5.11") do |data| 35 | data["kernel"]["update"] = architecture 36 | end 37 | end 38 | 39 | describe "#id" do 40 | it "is :pkgsrc" do 41 | expect(subject.id).to eq(:pkgsrc) 42 | end 43 | end 44 | 45 | describe "#package_name" do 46 | it "includes the name and version" do 47 | expect(subject.package_name).to eq("project-1.2.3.tgz") 48 | end 49 | end 50 | 51 | describe "#write_buildver" do 52 | it "writes the build version data" do 53 | subject.write_buildver 54 | contents = File.read("#{staging_dir}/build-ver") 55 | expect(contents).to eq("1.2.3-1") 56 | end 57 | end 58 | 59 | describe "#write_buildinfo" do 60 | it "writes the build metaddata" do 61 | subject.write_buildinfo 62 | contents = File.read("#{staging_dir}/build-info") 63 | expect(contents).to match(/OS_VERSION=5.11/) 64 | expect(contents).to match(/MACHINE_ARCH=x86_64/) 65 | end 66 | end 67 | 68 | describe "#write_packlist" do 69 | it "it writes the list of files" do 70 | expect(subject).to receive(:shellout!) 71 | .with "cd #{project.install_dir} && find . -type l -or -type f | sort >> #{staging_dir}/packlist" 72 | subject.write_packlist 73 | expect(File.read("#{staging_dir}/packlist")).to match(%r{@pkgdir /opt/project}) 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /spec/unit/s3_helpers_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | require "omnibus/s3_helpers" 3 | 4 | module Omnibus 5 | describe S3Helpers do 6 | include Omnibus::S3Helpers 7 | 8 | context "when #s3_configuration is not defined" do 9 | describe "#client" do 10 | it "raises an error if it is not overridden" do 11 | expect { s3_configuration }.to raise_error(RuntimeError, 12 | "You must override s3_configuration") 13 | end 14 | 15 | it "raises an error stating that s3_configuration must be overriden" do 16 | expect { client }.to raise_error(RuntimeError, 17 | "You must override s3_configuration") 18 | end 19 | end 20 | end 21 | 22 | describe "#to_base64_digest" do 23 | it 'turns "c3b5247592ce694f7097873aa07d66fe" into "w7UkdZLOaU9wl4c6oH1m/g=="' do 24 | expect(to_base64_digest("c3b5247592ce694f7097873aa07d66fe")).to eql("w7UkdZLOaU9wl4c6oH1m/g==") 25 | end 26 | 27 | it "allows a nil input without error" do 28 | expect(to_base64_digest(nil)).to be_nil 29 | end 30 | end 31 | end 32 | 33 | context "when #s3_configuration is defined" do 34 | describe "#get_credentials" do 35 | let(:klass) do 36 | Class.new do 37 | include Omnibus::S3Helpers 38 | end 39 | end 40 | let(:instance) { klass.new } 41 | let(:key_pair) { { access_key_id: "key_id", secret_access_key: "access_key" } } 42 | let(:profile) { "my-profile" } 43 | let(:iam_role_arn) { "my-iam-role-arn" } 44 | let(:role_session_name) { "omnibus-assume-role-s3-access" } 45 | let(:config) { { bucket_name: "foo", region: "us-east-1" } } 46 | 47 | it "uses configured key pairs" do 48 | allow_any_instance_of(klass).to receive(:s3_configuration).and_return(config.merge!(key_pair)) 49 | expect(Aws::Credentials).to receive(:new).with( 50 | config[:access_key_id], 51 | config[:secret_access_key] 52 | ) 53 | expect(Aws::SharedCredentials).to_not receive(:new) 54 | instance.send(:get_credentials) 55 | end 56 | 57 | it "prefers shared credentials profiles over key pairs" do 58 | allow_any_instance_of(klass).to receive(:s3_configuration).and_return( 59 | { 60 | **config, 61 | **key_pair, 62 | iam_role_arn: nil, 63 | profile: profile, 64 | } 65 | ) 66 | expect(Aws::Credentials).to_not receive(:new) 67 | expect(Aws::AssumeRoleCredentials).to_not receive(:new) 68 | allow(Aws::SharedCredentials).to receive(:new).with(profile_name: profile) 69 | instance.send(:get_credentials) 70 | end 71 | 72 | it "prefers AWS IAM role arn over profiles and key pairs" do 73 | allow_any_instance_of(klass).to receive(:s3_configuration).and_return( 74 | { 75 | **config, 76 | **key_pair, 77 | profile: profile, 78 | iam_role_arn: iam_role_arn, 79 | } 80 | ) 81 | expect(Aws::Credentials).to_not receive(:new) 82 | expect(Aws::SharedCredentials).to_not receive(:new) 83 | allow(Aws::AssumeRoleCredentials).to receive(:new).with(role_arn: iam_role_arn, role_session_name: role_session_name) 84 | instance.send(:get_credentials) 85 | end 86 | 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /spec/unit/semantic_version_spec.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2015-2018 Chef Software, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | require "spec_helper" 17 | 18 | module Omnibus 19 | describe SemanticVersion do 20 | 21 | it "raises an InvalidVersion error if it doesn't understand the format" do 22 | expect { Omnibus::SemanticVersion.new("wut") }.to raise_error(Omnibus::InvalidVersion) 23 | end 24 | 25 | it "preserves leading the leading v when printing the string" do 26 | v = Omnibus::SemanticVersion.new("v1.0.0") 27 | expect(v.to_s).to eq("v1.0.0") 28 | end 29 | 30 | it "can bump the patch version" do 31 | v = Omnibus::SemanticVersion.new("1.0.0") 32 | expect(v.next_patch.to_s).to eq("1.0.1") 33 | end 34 | 35 | it "can bump the minor version" do 36 | v = Omnibus::SemanticVersion.new("1.1.0") 37 | expect(v.next_minor.to_s).to eq("1.2.0") 38 | end 39 | 40 | it "can bump the major version" do 41 | v = Omnibus::SemanticVersion.new("1.0.0") 42 | expect(v.next_major.to_s).to eq("2.0.0") 43 | end 44 | 45 | it "resets the patch version when bumping minor versions" do 46 | v = Omnibus::SemanticVersion.new("1.1.1") 47 | expect(v.next_minor.to_s).to eq("1.2.0") 48 | end 49 | 50 | it "resets the patch and minor version when bumping major versions" do 51 | v = Omnibus::SemanticVersion.new("1.1.1") 52 | expect(v.next_major.to_s).to eq("2.0.0") 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /spec/unit/sugarable_spec.rb: -------------------------------------------------------------------------------- 1 | require "spec_helper" 2 | 3 | module Omnibus 4 | describe Software do 5 | it "is a sugarable" do 6 | expect(described_class.ancestors).to include(Sugarable) 7 | end 8 | end 9 | 10 | describe Metadata do 11 | it "extends Sugarable" do 12 | expect(described_class.singleton_class.included_modules).to include(Sugarable) 13 | end 14 | 15 | it "is a sugarable" do 16 | expect(described_class.ancestors).to include(Sugarable) 17 | end 18 | end 19 | 20 | describe Packager::Base do 21 | it "is a sugarable" do 22 | expect(described_class.ancestors).to include(Sugarable) 23 | end 24 | end 25 | 26 | describe Project do 27 | it "is a sugarable" do 28 | expect(described_class.ancestors).to include(Sugarable) 29 | end 30 | end 31 | 32 | describe Sugarable do 33 | context "in a cleanroom" do 34 | let(:klass) do 35 | Class.new do 36 | include Cleanroom 37 | include Sugarable 38 | end 39 | end 40 | 41 | let(:instance) { klass.new } 42 | 43 | it "includes the DSL methods" do 44 | expect(klass).to be_method_defined(:windows?) 45 | expect(klass).to be_method_defined(:vagrant?) 46 | expect(klass).to be_method_defined(:_64_bit?) 47 | end 48 | 49 | it "makes the DSL methods available in the cleanroom" do 50 | expect do 51 | instance.evaluate <<-EOH.gsub(/^ {12}/, "") 52 | windows? 53 | vagrant? 54 | EOH 55 | end.to_not raise_error 56 | end 57 | end 58 | end 59 | 60 | describe Sugar do 61 | let(:klass) do 62 | Class.new do 63 | include Sugar 64 | end 65 | end 66 | 67 | let(:instance) { klass.new } 68 | 69 | it "returns the windows architecture being built" do 70 | expect(Omnibus::Config).to receive(:windows_arch).and_return(:x86_64) 71 | expect(instance.windows_arch_i386?).to eq(false) 72 | end 73 | 74 | it "returns whether fips_mode is enabled" do 75 | expect(Omnibus::Config).to receive(:fips_mode).and_return(false) 76 | expect(instance.fips_mode?).to eq(false) 77 | end 78 | end 79 | end 80 | --------------------------------------------------------------------------------