diff --git a/doc/build-helpers/fetchers.chapter.md b/doc/build-helpers/fetchers.chapter.md index d37a2fecaccd..567d47a1499b 100644 --- a/doc/build-helpers/fetchers.chapter.md +++ b/doc/build-helpers/fetchers.chapter.md @@ -755,6 +755,9 @@ Used with Subversion. Expects `url` to a Subversion directory, `rev`, and `hash` Used with Git. Expects `url` to a Git repo, `rev`, and `hash`. `rev` in this case can be full the git commit id (SHA1 hash) or a tag name like `refs/tags/v1.0`. +If you want to fetch a tag you should pass the `tag` parameter instead of `rev` which has the same effect as setting `rev = "refs/tags"/${version}"`. +This is safer than just setting `rev = version` w.r.t. possible branch and tag name conflicts. + Additionally, the following optional arguments can be given: *`fetchSubmodules`* (Boolean) @@ -833,7 +836,7 @@ A number of fetcher functions wrap part of `fetchurl` and `fetchzip`. They are m ## `fetchFromGitHub` {#fetchfromgithub} -`fetchFromGitHub` expects four arguments. `owner` is a string corresponding to the GitHub user or organization that controls this repository. `repo` corresponds to the name of the software repository. These are located at the top of every GitHub HTML page as `owner`/`repo`. `rev` corresponds to the Git commit hash or tag (e.g `v1.0`) that will be downloaded from Git. Finally, `hash` corresponds to the hash of the extracted directory. Again, other hash algorithms are also available, but `hash` is currently preferred. +`fetchFromGitHub` expects four arguments. `owner` is a string corresponding to the GitHub user or organization that controls this repository. `repo` corresponds to the name of the software repository. These are located at the top of every GitHub HTML page as `owner`/`repo`. `rev` corresponds to the Git commit hash or tag (e.g `v1.0`) that will be downloaded from Git. If you need to fetch a tag however, you should prefer to use the `tag` parameter which achieves this in a safer way with less boilerplate. Finally, `hash` corresponds to the hash of the extracted directory. Again, other hash algorithms are also available, but `hash` is currently preferred. To use a different GitHub instance, use `githubBase` (defaults to `"github.com"`). diff --git a/pkgs/build-support/fetchgit/default.nix b/pkgs/build-support/fetchgit/default.nix index 4c40cbcef7e1..f2b4726fef09 100644 --- a/pkgs/build-support/fetchgit/default.nix +++ b/pkgs/build-support/fetchgit/default.nix @@ -13,13 +13,16 @@ in lib.makeOverridable (lib.fetchers.withNormalizedHash { } ( # NOTE Please document parameter additions or changes in # doc/build-helpers/fetchers.chapter.md -{ url, rev ? "HEAD", leaveDotGit ? deepClone +{ url +, tag ? null +, rev ? null +, leaveDotGit ? deepClone , outputHash ? lib.fakeHash, outputHashAlgo ? null , fetchSubmodules ? true, deepClone ? false , branchName ? null , sparseCheckout ? [] , nonConeMode ? false -, name ? urlToName url rev +, name ? null , # Shell code executed after the file has been fetched # successfully. This can do things like check or transform the file. postFetch ? "" @@ -59,12 +62,30 @@ lib.makeOverridable (lib.fetchers.withNormalizedHash { } ( assert deepClone -> leaveDotGit; assert nonConeMode -> (sparseCheckout != []); +let + revWithTag = + let + warningMsg = "fetchgit requires one of either `rev` or `tag` to be provided (not both)."; + otherIsNull = other: lib.assertMsg (other == null) warningMsg; + in + if tag != null then + assert (otherIsNull rev); + "refs/tags/${tag}" + else if rev != null then + assert (otherIsNull tag); + rev + else + # FIXME fetching HEAD if no rev or tag is provided is problematic at best + "HEAD"; +in + if builtins.isString sparseCheckout then # Changed to throw on 2023-06-04 throw "Please provide directories/patterns for sparse checkout as a list of strings. Passing a (multi-line) string is not supported any more." else stdenvNoCC.mkDerivation { - inherit name; + name = if name != null then name else urlToName url revWithTag; + builder = ./builder.sh; fetcher = ./nix-prefetch-git; @@ -79,7 +100,8 @@ stdenvNoCC.mkDerivation { # > from standard in as a newline-delimited list instead of from the arguments. sparseCheckout = builtins.concatStringsSep "\n" sparseCheckout; - inherit url rev leaveDotGit fetchLFS fetchSubmodules deepClone branchName nonConeMode postFetch; + inherit url leaveDotGit fetchLFS fetchSubmodules deepClone branchName nonConeMode postFetch; + rev = revWithTag; postHook = if netrcPhase == null then null else '' ${netrcPhase} diff --git a/pkgs/build-support/fetchgithub/default.nix b/pkgs/build-support/fetchgithub/default.nix index d27a3df7d3df..f80e01295533 100644 --- a/pkgs/build-support/fetchgithub/default.nix +++ b/pkgs/build-support/fetchgithub/default.nix @@ -1,7 +1,10 @@ { lib, fetchgit, fetchzip }: lib.makeOverridable ( -{ owner, repo, rev, name ? "source" +{ owner, repo +, tag ? null +, rev ? null +, name ? "source" , fetchSubmodules ? false, leaveDotGit ? null , deepClone ? false, private ? false, forceFetchGit ? false , fetchLFS ? false @@ -11,11 +14,16 @@ lib.makeOverridable ( , ... # For hash agility }@args: +assert (lib.assertMsg (lib.xor (tag == null) (rev == null)) "fetchFromGitHub requires one of either `rev` or `tag` to be provided (not both)."); + let position = (if args.meta.description or null != null then builtins.unsafeGetAttrPos "description" args.meta - else builtins.unsafeGetAttrPos "rev" args + else if tag != null then + builtins.unsafeGetAttrPos "tag" args + else + builtins.unsafeGetAttrPos "rev" args ); baseUrl = "https://${githubBase}/${owner}/${repo}"; newMeta = meta // { @@ -24,7 +32,7 @@ let # to indicate where derivation originates, similar to make-derivation.nix's mkDerivation position = "${position.file}:${toString position.line}"; }; - passthruAttrs = removeAttrs args [ "owner" "repo" "rev" "fetchSubmodules" "forceFetchGit" "private" "githubBase" "varPrefix" ]; + passthruAttrs = removeAttrs args [ "owner" "repo" "tag" "rev" "fetchSubmodules" "forceFetchGit" "private" "githubBase" "varPrefix" ]; varBase = "NIX${lib.optionalString (varPrefix != null) "_${varPrefix}"}_GITHUB_PRIVATE_"; useFetchGit = fetchSubmodules || (leaveDotGit == true) || deepClone || forceFetchGit || fetchLFS || (sparseCheckout != []); # We prefer fetchzip in cases we don't need submodules as the hash @@ -53,10 +61,10 @@ let fetcherArgs = (if useFetchGit then { - inherit rev deepClone fetchSubmodules sparseCheckout fetchLFS; url = gitRepoUrl; + inherit tag rev deepClone fetchSubmodules sparseCheckout fetchLFS; url = gitRepoUrl; } // lib.optionalAttrs (leaveDotGit != null) { inherit leaveDotGit; } else { - url = "${baseUrl}/archive/${rev}.tar.gz"; + url = "${baseUrl}/archive/${if tag != null then "refs/tags/${tag}" else rev}.tar.gz"; passthru = { inherit gitRepoUrl;