summaryrefslogtreecommitdiff
path: root/habitat
diff options
context:
space:
mode:
authorRobb Kidd <rkidd@chef.io>2019-08-30 19:31:59 -0400
committerRobb Kidd <robb@thekidds.org>2019-11-01 14:22:33 -0400
commit5d07a4f67b37e6755513fab0d577af2444215ae0 (patch)
treeeeb3833fb4364693ff5df3a97e3ac45228d47f2a /habitat
parentaacd5f3b50a412b1b6cd14057b10ac043f1e839c (diff)
downloadchef-5d07a4f67b37e6755513fab0d577af2444215ae0.tar.gz
a plan for Windows!
Based on Stuart Preston's work. Currently depends on the very large ruby-plus-devkit package[1] that is a repackaging of RubyInstaller+DevKit[2]. The DevKit is essentially MSYS2, which is its own software distribution. It can get large. It is depended on currently because it RubyInstaller+DevKit has been the most common Ruby on Windows solution for build environment and library ecosystem. Whatever Ruby this plan ultimately depends on is expected to have its executables on the PATH and any gems it ships with (say, bundler, rake, etc) added to GEM_PATH which is totally a thing a package can do in SetupEnvironment and pushing directories onto GEM_HOME. [1] https://bldr.habitat.sh/#/pkgs/chef/ruby-plus-devkit https://github.com/chef/chef-plans/tree/master/ruby-plus-devkit [2] https://rubyinstaller.org/about/comparison/ * bundle install'ing With core/git not being fully capable of supporting a `bundle install` because of semi-hardcoded paths to binaries, git is baked into the "devkit" portion of Chef's chef/ruby-plus-devkit. That means `bundle install` works, so this build uses a pattern established in the chef omnibus software definition: 1. bundle install the Ruby dependencies 2. gem install the local gems 3. install the git-ref'd gems At the end of these steps, all the gems are "installed" in the standard directories under GEM_HOME/gems and binstubs are in GEM_HOME/bin. * add the other Ruby binstubs to the PATH Gems got their bundle/gem installed binstubs placed in GEM_HOME/bin a.k.a vendor/bin. That path has been added to the package's bin paths for use in the build and later in testing. Appbundler is executed in Invoke-Install to create our precisely-pinned binstubs for only the gems that supply executables we expect users of chef-client to use. Those appbundled binstubs are placed into the package's bin directory under $pkg_prefix/bin. While the binstubs under vendor/bin aren't locked down with appbundler, they're worth having on the PATH, particularly for testing the build. * Trimming the Fat Remove many of the byproducts of gems that appear in $pkg_prefix. Some C-extension build logs. Other gems' spec directories. We keep the chef gem's spec directory because we will be testing builds with the functional portion of the test suite. * Stripping the FS_ROOT The studio's FS_ROOT appears in the Gemfiles generated by appbundler. Added a function to remove the build environment's FS_ROOT from a given file. Currently only using it on the chef gem's Gemfile so that it can be used with `bundle install` and `bundle exec` to test the build. * build in "${HAB_CACHE_SRC_PATH}/${pkg_dirname}" "${HAB_CACHE_SRC_PATH}/${pkg_dirname}" is $CACHE_PATH, but we can't use CACHE_PATH directly because it seems the Windows plan build script doesn't actually set that variable unless pkg_version is computed and updated; probably a bug, need to investigate. Mainly opted for this to take advantage of the clean-room features of builds done in the CACHE directory. Use git to archive up only the version-controlled files and place that archive where Hab would normally download a source artifact. Set the $pkg_filename so the plan build knows what to archive and unpack. No-Op the Verify function because the archive "downloaded" was just created. For Install, set the location of the Gemfile for bundler via an environment variable instead of a `bundle config --local` command so that there is no need to clean up the generated `.bundle/config`. * have the plan check for a minimum hab version The Windows plan must be built with Hab version 0.85.0 or greater because of its use of the -IsPath option when setting/pushing paths in SetupEnvironment. This change adds a version check to the Begin build callback to bail with an informative error message when the required minimum version isn't present. Otherwise, the error that appears is the slightly arcane: ``` An error occured in the build! You cannot call a method on a null-valued expression. At C:\hab\pkgs\core\hab-studio\0.83.0\20190712234514\bin\hab-plan-build.ps1:1447 char:5 + $pathArray = $path.Split($separator) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : InvokeMethodOnNull ``` Co-authored-by: Stuart Preston <stuart@chef.io> Co-authored-by: John Snow <thelunaticscripter@outlook.com> Signed-off-by: Robb Kidd <robb@thekidds.org>
Diffstat (limited to 'habitat')
-rw-r--r--habitat/plan.ps1138
1 files changed, 138 insertions, 0 deletions
diff --git a/habitat/plan.ps1 b/habitat/plan.ps1
new file mode 100644
index 0000000000..1a90a204c9
--- /dev/null
+++ b/habitat/plan.ps1
@@ -0,0 +1,138 @@
+$pkg_name="chef-infra-client"
+$pkg_origin="chef"
+$pkg_version=(Get-Content $PLAN_CONTEXT/../VERSION)
+$pkg_description="Chef Infra Client is an agent that runs locally on every node that is under management by Chef Infra. This package is binary-only to provide Chef Infra Client executables. It does not define a service to run."
+$pkg_maintainer="The Chef Maintainers <maintainers@chef.io>"
+$pkg_upstream_url="https://github.com/chef/chef"
+$pkg_license=@("Apache-2.0")
+$pkg_filename="${pkg_name}-${pkg_version}.zip"
+$pkg_bin_dirs=@(
+ "bin"
+ "vendor/bin"
+)
+$pkg_deps=@(
+ "core/cacerts"
+ "chef/ruby-plus-devkit"
+)
+
+function Invoke-Begin {
+ $hab_version = (hab --version)
+ $hab_minor_version = $hab_version.split('.')[1]
+ if ( -not $? -Or $hab_minor_version -lt 85 ) {
+ Write-Warning "(╯°□°)╯︵ ┻━┻ I CAN'T WORK UNDER THESE CONDITIONS!"
+ Write-Warning ":habicat: I'm being built with $hab_version. I need at least Hab 0.85.0, because I use the -IsPath option for setting/pushing paths in SetupEnvironment."
+ throw "unable to build: required minimum version of Habitat not installed"
+ } else {
+ Write-BuildLine ":habicat: I think I have the version I need to build."
+ }
+}
+
+function Invoke-SetupEnvironment {
+ Push-RuntimeEnv -IsPath GEM_PATH "$pkg_prefix/vendor"
+
+ Set-RuntimeEnv -IsPath SSL_CERT_FILE "$(Get-HabPackagePath cacerts)/ssl/cert.pem"
+ Set-RuntimeEnv LANG "en_US.UTF-8"
+ Set-RuntimeEnv LC_CTYPE "en_US.UTF-8"
+}
+
+function Invoke-Download() {
+ Write-BuildLine " ** Locally creating archive of latest repository commit at ${HAB_CACHE_SRC_PATH}/${pkg_filename}"
+ # source is in this repo, so we're going to create an archive from the
+ # appropriate path within the repo and place the generated tarball in the
+ # location expected by do_unpack
+ try {
+ Push-Location (Resolve-Path "$PLAN_CONTEXT/../").Path
+ git archive --format=zip --output="${HAB_CACHE_SRC_PATH}/${pkg_filename}" HEAD
+ } finally {
+ Pop-Location
+ }
+}
+
+function Invoke-Verify() {
+ Write-BuildLine " ** Skipping checksum verification on the archive we just created."
+ return 0
+}
+
+function Invoke-Prepare {
+ $env:GEM_HOME = "$pkg_prefix/vendor"
+
+ try {
+ Push-Location "${HAB_CACHE_SRC_PATH}/${pkg_dirname}"
+
+ Write-BuildLine " ** Configuring bundler for this build environment"
+ bundle config --local without server docgen maintenance pry travis integration ci chefstyle
+ bundle config --local jobs 4
+ bundle config --local retry 5
+ bundle config --local silence_root_warning 1
+ } finally {
+ Pop-Location
+ }
+}
+
+function Invoke-Build {
+ try {
+ Push-Location "${HAB_CACHE_SRC_PATH}/${pkg_dirname}"
+
+ Write-BuildLine " ** Using bundler to retrieve the Ruby dependencies"
+ bundle install
+ Write-BuildLine " ** Running the chef project's 'rake install' to install the path-based gems so they look like any other installed gem."
+ bundle exec rake install # this needs to be 'bundle exec'd because a Rakefile makes reference to Bundler
+ Write-BuildLine " ** Also 'rake install' any gem sourced as a git reference."
+ foreach($git_gem in (Get-ChildItem "$env:GEM_HOME/bundler/gems")) {
+ try {
+ Push-Location $git_gem
+ Write-BuildLine " -- and $git_gem too"
+ rake install # this needs to NOT be 'bundle exec'd else bundler complains about dev deps not being installed
+ } finally {
+ Pop-Location
+ }
+ }
+ } finally {
+ Pop-Location
+ }
+}
+
+function Invoke-Install {
+ try {
+ Push-Location $pkg_prefix
+ $env:BUNDLE_GEMFILE="${HAB_CACHE_SRC_PATH}/${pkg_dirname}/Gemfile"
+
+ foreach($gem in ("chef-bin", "chef", "inspec-core-bin", "ohai")) {
+ Write-BuildLine "** generating binstubs for $gem with precise version pins"
+ appbundler.bat "${HAB_CACHE_SRC_PATH}/${pkg_dirname}" $pkg_prefix/bin $gem
+ if (-not $?) { throw "Failed to create appbundled binstubs for $gem"}
+ }
+ Remove-StudioPathFrom -File $pkg_prefix/vendor/gems/chef-$pkg_version*/Gemfile
+ } finally {
+ Pop-Location
+ }
+}
+
+function Invoke-After {
+ # Trim the fat before packaging
+
+ # We don't need the cache of downloaded .gem files ...
+ Remove-Item $pkg_prefix/vendor/cache -Recurse -Force
+ # ... or bundler's cache of git-ref'd gems
+ Remove-Item $pkg_prefix/vendor/bundler -Recurse -Force
+
+ # We don't need the gem docs.
+ Remove-Item $pkg_prefix/vendor/doc -Recurse -Force
+ # We don't need to ship the test suites for every gem dependency,
+ # only Chef's for package verification.
+ Get-ChildItem $pkg_prefix/vendor/gems -Filter "spec" -Directory -Recurse -Depth 1 `
+ | Where-Object -FilterScript { $_.FullName -notlike "*chef-$pkg_version*" } `
+ | Remove-Item -Recurse -Force
+ # Remove the byproducts of compiling gems with extensions
+ Get-ChildItem $pkg_prefix/vendor/gems -Include @("gem_make.out", "mkmf.log", "Makefile") -File -Recurse `
+ | Remove-Item -Force
+}
+
+function Remove-StudioPathFrom {
+ Param(
+ [Parameter(Mandatory=$true)]
+ [String]
+ $File
+ )
+ (Get-Content $File) -replace ($env:FS_ROOT -replace "\\","/"),"" | Set-Content $File
+}