diff options
author | Robb Kidd <rkidd@chef.io> | 2019-08-30 19:31:59 -0400 |
---|---|---|
committer | Robb Kidd <robb@thekidds.org> | 2019-11-01 14:22:33 -0400 |
commit | 5d07a4f67b37e6755513fab0d577af2444215ae0 (patch) | |
tree | eeb3833fb4364693ff5df3a97e3ac45228d47f2a /habitat | |
parent | aacd5f3b50a412b1b6cd14057b10ac043f1e839c (diff) | |
download | chef-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.ps1 | 138 |
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 +} |