Project: Chef Habitat (App Definition and Development / Application Definition & Image Build)
File: build_helpers.md

+++ title = "Build Helpers" description = "Define package buildtime actions with helper functions." gh_repo = "habitat" [menu] [menu.habitat] title = "Build Helpers" identifier = "habitat/reference/build-helpers" parent = "habitat/reference" +++ The following helper functions can be useful in your plan to help you build your package correctly. `Attach()` specifically is to help with debugging - the other helper functions are to help you in building your package. {{< note >}} Most of the following helper functions are not available in Powershell plans (`plan.ps1`). However in most cases, the standard Powershell cmdlets provide the same functionality. For example: use `Resolve-Path` instead of `abspath` or `Get-Command` instead of `exists`. {{< /note >}} attach() : `plan.sh` only. Attaches your script to an interactive debugging session, which lets you check the state of variables, call arbitrary functions, and turn on higher levels of logging by using the `set -x` command and switch. To use attach, add `attach` to any callback or part of your plan.sh file and the debugging session with start up when hab-plan-build comes to that part in the file. {{< note >}} Use the native Powershell cmdlet `Set-PSBreakpoint` for debugging plan.ps1 functions. You can set its `-Command` parameter to any build phase function. {{< /note >}} download_file() : `plan.sh` only. Downloads a file from a source URL to a local file and uses an optional shasum to determine if an existing file can be used. ```bash downloadfile <sourceurl> <local_file> [<shasum>] ``` If an existing file is present and the third argument is set with a shasum digest, the file will be checked to see if it's valid. If so, the function ends early and returns 0. Otherwise, the shasums do not match so the file-on-disk is removed and a normal download proceeds as though no previous file existed. This is designed to restart an interrupted download. Any valid `wget` URL will work. Downloads every time, even if the file exists locally: ```bash download_file http://example.com/file.tar.gz file.tar.gz ``` Downloads if no local file is found: ```bash downloadfile http://example.com/file.tar.gz file.tar.gz expectedshasum ``` File matches checksum: download is skipped, local file is used: ```bash downloadfile http://example.com/file.tar.gz file.tar.gz expectedshasum ``` File doesn't match checksum: local file removed, download attempted: ```bash downloadfile http://example.com/file.tar.gz file.tar.gz mismatchingshasum ``` Will return 0 if a file was downloaded or if a valid cached file was found. pkg\path\for()/Get-HabPackagePath : Returns the path for a build or runtime package dependency on stdout from the list of dependencies referenced in `pkgdeps` or

This is useful if you need to install or reference specific dependencies from within a callback, such as `dobuild()` or `do_install()`. Here's an example of how to use this function to retrieve the path to the perl binary in the core/perl package: ```bash perlpath="$(pkgpathfor core/perl)/bin/perl" ``` fix_interpreter() : `plan.sh` only. Edits the `#!` shebang of the target file in-place. This is useful for changing hard-coded paths defined by your source files to the equivalent path in a Chef Habitat package. You must include the required package that provides the expected path for the shebang in pkg_deps. This function performs a greedy match against the specified interpreter in the target file(s). To use this function in your plan, you must specify the following arguments: The target file or files The name of the package that contains the interpreter The relative directory and binary path to the interpreter For example, to replace all the files in `node_modules/.bin` that have `#!/usr/bin/env` with the coreutils path to `bin/env` (/hab/pkgs/core/coreutils/8.24/20160219013458/bin/env), you must quote the wildcard target as shown below. ```bash fixinterpreter "nodemodules/.bin/*" core/coreutils bin/env ``` For a single target, reference the file directly: ```bash fixinterpreter nodemodules/.bin/concurrent core/coreutils bin/env ``` pkg\interpreter\for() : `plan.sh` only. Returns the path for the given package and interpreter by reading it from the INTERPRETERS metadata in the package. The directory of the interpreter needs to be specified, as an interpreter binary might live in `bin`, `sbin`, or `libexec`, depending on the software. The following shows how to call pkginterpreterfor with the package and interpreter arguments specified. ```bash pkginterpreterfor core/coreutils bin/env ``` This function will return 0 if the specified package and interpreter were found, and 1 if the package could not be found or the interpreter is not specified for that package. pkg_version() : An optional way to determine the value for `$pkgversion`. The function must print the computed version string to standard output and will be called when the Plan author invokes the `updatepkg_version()` helper in a `plan.sh` or `Set-PkgVersion` in a `plan.ps1`. update\pkg\version()/Set-PkgVersion : Updates the value for `$pkgversion` by calling a Plan author-provided `pkgversion()` function. This function must be explicitly called in a Plan in or after the `dobefore()`/`Invoke-Before` build phase but before the `doprepare()`/`Invoke-Prepare` build phase. The `$pkg_version` variable will be updated and any other relevant variables will be recomputed. The following examples show how to use these functions to set a dynamic version

This plan concatenates a static file in the source root of the project to determine the version in the `before` phase: {{< foundation_tabs tabs-id="bash-powershell-panel1" >}} {{< foundation_tab active="true" panel-link="bash-panel1" tab-text="Bash">}} {{< foundation_tab panel-link="powershell-panel1" tab-text="Powershell" >}} {{< /foundation_tabs >}} {{< foundationtabspanels tabs-id="bash-powershell-panel1" >}} {{< foundationtabspanel active="true" panel-id="bash-panel1" >}} ```bash pkg_version() { cat "$SRC_PATH/version.txt" } do_before() { dodefaultbefore updatepkgversion } ``` {{< /foundationtabspanel >}} {{< foundationtabspanel panel-id="powershell-panel1" >}} ```powershell function pkg_version { Get-Content "$SRC_PATH/version.txt" } Invoke-Before { Invoke-DefaultBefore Set-PkgVersion } ``` {{< /foundationtabspanel >}} {{< /foundationtabspanels >}} The `pkg_version` function in this plan dynamically creates a version with a date stamp to format the final version string to standard output. As the downloaded file is required before running the version logic, this helper function is called in the `download` build phase: {{< foundation_tabs tabs-id="bash-powershell-panel2" >}} {{< foundation_tab active="true" panel-link="bash-panel2" tab-text="Bash">}} {{< foundation_tab panel-link="powershell-panel2" tab-text="Powershell" >}} {{< /foundation_tabs >}} {{< foundationtabspanels tabs-id="bash-powershell-panel2" >}} {{< foundationtabspanel active="true" panel-id="bash-panel2" >}} ```bash pkg_version() { local build_date builddate=$(cat $HABCACHESRCPATH/$pkg_filename \ | grep 'Certificate data from Mozilla' \ | sed 's/^## Certificate data from Mozilla as of: //') date --date="$build_date" "+%Y.%m.%d" } do_download() { dodefaultdownload updatepkgversion } ``` {{< /foundationtabspanel >}} {{< foundationtabspanel panel-id="powershell-panel2" >}} ```powershell function pkg_version { $matchStr = "## Certificate data from Mozilla as of: " foreach($line in (Get-Content "$HABCACHESRCPATH/$pkgfilename")) { if($line.StartsWith($matchStr)) { $build_date = $line.Substring($matchStr.Length) } } } function Invoke-Download { Invoke-DefaultDownload Set-PkgVersion } ``` {{< /foundationtabspanel >}} {{< /foundationtabspanels >}} abspath() : `plan.sh` only. Return the absolute path for a path, which might be absolute or relative. exists() : `plan.sh` only. Checks that the command exists. Returns 0 if it does, 1 if it does not. build_line()/Write-BuildLine : Print a line of build output. Takes a string as its only argument. ```bash buildline "Checksum verified - ${pkgshasum}" ``` warn()/Write-Warning : Print a warning line on stderr. Takes a string as its only argument. ```bash warn "Checksum failed" ``` debug()/Write-Debug : Prints a line only if the `$DEBUG` environment value is set to 1. The `debug` function takes a string as its only argument. ```bash DEBUG=1 debug "Only if things are set" ``` exit_with() : `plan.sh` only. Exits the program with an error message and a status code. ```bash exit_with "Something bad happened" 55 ``` trim() : `plan.sh` only. Trims leading and trailing whitespace characters from a bash variable. record() : `plan.sh` only. Takes a session name and command to run as arguments function appends a timestamp to the log file. Alternative to piping build through tee. ```bash record mysoftware build /src/mysoftware ```