nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at devShellTools-shell 228 lines 7.8 kB view raw
1{ 2 stdenv, 3 lib, 4 buildGoModule, 5 fetchFromGitHub, 6 makeWrapper, 7 coreutils, 8 runCommand, 9 runtimeShell, 10 writeText, 11 terraform-providers, 12 installShellFiles, 13}: 14 15let 16 generic = 17 { 18 version, 19 hash, 20 vendorHash ? null, 21 ... 22 }@attrs: 23 let 24 attrs' = builtins.removeAttrs attrs [ 25 "version" 26 "hash" 27 "vendorHash" 28 ]; 29 in 30 buildGoModule ( 31 { 32 pname = "terraform"; 33 inherit version vendorHash; 34 35 src = fetchFromGitHub { 36 owner = "hashicorp"; 37 repo = "terraform"; 38 rev = "v${version}"; 39 inherit hash; 40 }; 41 42 ldflags = [ 43 "-s" 44 "-w" 45 "-X 'github.com/hashicorp/terraform/version.dev=no'" 46 ]; 47 48 postPatch = '' 49 # Between go 1.23 and 1.24 the following GODEBUG setting was removed, and a new 50 # similar one was added. 51 # https://github.com/golang/go/issues/72111 52 # The setting is configured upstream due to the following timeouts caused by 53 # the TLS handshake using post-quantum crypto with servers that don't support it 54 # https://tldr.fail/ 55 substituteInPlace go.mod \ 56 --replace-quiet 'godebug tlskyber=0' 'godebug tlsmlkem=0' 57 ''; 58 postConfigure = '' 59 # speakeasy hardcodes /bin/stty https://github.com/bgentry/speakeasy/issues/22 60 substituteInPlace vendor/github.com/bgentry/speakeasy/speakeasy_unix.go \ 61 --replace-fail "/bin/stty" "${coreutils}/bin/stty" 62 ''; 63 64 nativeBuildInputs = [ installShellFiles ]; 65 66 postInstall = '' 67 # https://github.com/posener/complete/blob/9a4745ac49b29530e07dc2581745a218b646b7a3/cmd/install/bash.go#L8 68 installShellCompletion --bash --name terraform <(echo complete -C terraform terraform) 69 ''; 70 71 preCheck = '' 72 export HOME=$TMPDIR 73 export TF_SKIP_REMOTE_TESTS=1 74 ''; 75 76 subPackages = [ "." ]; 77 78 meta = { 79 description = "Tool for building, changing, and versioning infrastructure"; 80 homepage = "https://www.terraform.io/"; 81 changelog = "https://github.com/hashicorp/terraform/blob/v${version}/CHANGELOG.md"; 82 license = lib.licenses.bsl11; 83 maintainers = with lib.maintainers; [ 84 Chili-Man 85 kalbasit 86 timstott 87 zimbatm 88 zowoq 89 techknowlogick 90 qjoly 91 ]; 92 mainProgram = "terraform"; 93 }; 94 } 95 // attrs' 96 ); 97 98 pluggable = 99 terraform: 100 let 101 withPlugins = 102 plugins: 103 let 104 actualPlugins = plugins terraform.plugins; 105 106 # Wrap PATH of plugins propagatedBuildInputs, plugins may have runtime dependencies on external binaries 107 wrapperInputs = lib.unique ( 108 lib.flatten (lib.catAttrs "propagatedBuildInputs" (builtins.filter (x: x != null) actualPlugins)) 109 ); 110 111 passthru = { 112 withPlugins = newplugins: withPlugins (x: newplugins x ++ actualPlugins); 113 full = withPlugins (p: lib.filter lib.isDerivation (lib.attrValues p.actualProviders)); 114 115 # Expose wrappers around the override* functions of the terraform 116 # derivation. 117 # 118 # Note that this does not behave as anyone would expect if plugins 119 # are specified. The overrides are not on the user-visible wrapper 120 # derivation but instead on the function application that eventually 121 # generates the wrapper. This means: 122 # 123 # 1. When using overrideAttrs, only `passthru` attributes will 124 # become visible on the wrapper derivation. Other overrides that 125 # modify the derivation *may* still have an effect, but it can be 126 # difficult to follow. 127 # 128 # 2. Other overrides may work if they modify the terraform 129 # derivation, or they may have no effect, depending on what 130 # exactly is being changed. 131 # 132 # 3. Specifying overrides on the wrapper is unsupported. 133 # 134 # See nixpkgs#158620 for details. 135 overrideDerivation = f: (pluggable (terraform.overrideDerivation f)).withPlugins plugins; 136 overrideAttrs = f: (pluggable (terraform.overrideAttrs f)).withPlugins plugins; 137 override = x: (pluggable (terraform.override x)).withPlugins plugins; 138 }; 139 in 140 # Don't bother wrapping unless we actually have plugins, since the wrapper will stop automatic downloading 141 # of plugins, which might be counterintuitive if someone just wants a vanilla Terraform. 142 if actualPlugins == [ ] then 143 terraform.overrideAttrs (orig: { 144 passthru = orig.passthru // passthru; 145 }) 146 else 147 lib.appendToName "with-plugins" ( 148 stdenv.mkDerivation { 149 inherit (terraform) meta pname version; 150 nativeBuildInputs = [ makeWrapper ]; 151 152 # Expose the passthru set with the override functions 153 # defined above, as well as any passthru values already 154 # set on `terraform` at this point (relevant in case a 155 # user overrides attributes). 156 passthru = terraform.passthru // passthru; 157 158 buildCommand = '' 159 # Create wrappers for terraform plugins because Terraform only 160 # walks inside of a tree of files. 161 for providerDir in ${toString actualPlugins} 162 do 163 for file in $(find $providerDir/libexec/terraform-providers -type f) 164 do 165 relFile=''${file#$providerDir/} 166 mkdir -p $out/$(dirname $relFile) 167 cat <<WRAPPER > $out/$relFile 168 #!${runtimeShell} 169 exec "$file" "$@" 170 WRAPPER 171 chmod +x $out/$relFile 172 done 173 done 174 175 # Create a wrapper for terraform to point it to the plugins dir. 176 mkdir -p $out/bin/ 177 makeWrapper "${terraform}/bin/terraform" "$out/bin/terraform" \ 178 --set NIX_TERRAFORM_PLUGIN_DIR $out/libexec/terraform-providers \ 179 --prefix PATH : "${lib.makeBinPath wrapperInputs}" 180 ''; 181 } 182 ); 183 in 184 withPlugins (_: [ ]); 185 186 plugins = removeAttrs terraform-providers [ 187 "override" 188 "overrideDerivation" 189 "recurseForDerivations" 190 ]; 191in 192rec { 193 # Constructor for other terraform versions 194 mkTerraform = attrs: pluggable (generic attrs); 195 196 terraform_1 = mkTerraform { 197 version = "1.12.2"; 198 hash = "sha256-ilQ1rscGD66OT6lHsBgWELayC24B2D7l6iH6vtvqzFI="; 199 vendorHash = "sha256-zWNLIurNP5e/AWr84kQCb2+gZIn6EAsuvr0ZnfSq7Zw="; 200 patches = [ ./provider-path-0_15.patch ]; 201 passthru = { 202 inherit plugins; 203 tests = { inherit terraform_plugins_test; }; 204 }; 205 }; 206 207 # Tests that the plugins are being used. Terraform looks at the specific 208 # file pattern and if the plugin is not found it will try to download it 209 # from the Internet. With sandboxing enable this test will fail if that is 210 # the case. 211 terraform_plugins_test = 212 let 213 mainTf = writeText "main.tf" '' 214 resource "random_id" "test" {} 215 ''; 216 terraform = terraform_1.withPlugins (p: [ p.random ]); 217 test = runCommand "terraform-plugin-test" { buildInputs = [ terraform ]; } '' 218 set -e 219 # make it fail outside of sandbox 220 export HTTP_PROXY=http://127.0.0.1:0 HTTPS_PROXY=https://127.0.0.1:0 221 cp ${mainTf} main.tf 222 terraform init 223 touch $out 224 ''; 225 in 226 test; 227 228}