mirror of
https://github.com/cpm-cmake/CPM.cmake.git
synced 2025-11-21 01:47:28 -05:00
Infer package name and version from URL (#220)
* Function to extract name and version from url. Some tests * Rewrite. Previous version was not safe enough. More tests * Allow underscore as a name-version separator (<name>_<ver>) * CPMAddPackage can infer name and version from url * Allow URL parse from single arg and uncomment tests * Info about shorthand syntax in README * Fix style * Fixed typo Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com> * Explicit hash algorithm in shorthand URL example. Also added tests which include a hash algorithm provided We can't document a default until it's confirmed here: https://gitlab.kitware.com/cmake/cmake/-/issues/21859 Co-authored-by: Lars Melchior <TheLartians@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
492e762591
commit
a3d1048ad6
11
README.md
11
README.md
@@ -62,6 +62,17 @@ CPMAddPackage("uri@version#tag")
|
|||||||
|
|
||||||
In the shorthand syntax if the URI is of the form `gh:user/name`, it is interpreted as GitHub URI and converted to `https://github.com/user/name.git`. If the URI is of the form `gl:user/name`, it is interpreted as a [GitLab](https://gitlab.com/explore/) URI and coverted to `https://gitlab.com/user/name.git`. Otherwise the URI used verbatim as a git URL. All packages added using the shorthand syntax will be added using the [EXCLUDE_FROM_ALL](https://cmake.org/cmake/help/latest/prop_tgt/EXCLUDE_FROM_ALL.html) flag.
|
In the shorthand syntax if the URI is of the form `gh:user/name`, it is interpreted as GitHub URI and converted to `https://github.com/user/name.git`. If the URI is of the form `gl:user/name`, it is interpreted as a [GitLab](https://gitlab.com/explore/) URI and coverted to `https://gitlab.com/user/name.git`. Otherwise the URI used verbatim as a git URL. All packages added using the shorthand syntax will be added using the [EXCLUDE_FROM_ALL](https://cmake.org/cmake/help/latest/prop_tgt/EXCLUDE_FROM_ALL.html) flag.
|
||||||
|
|
||||||
|
The single-argument syntax also works for URLs:
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
# An archive package from a given url. The version is inferred
|
||||||
|
CPMAddPackage("https://example.com/my-package-1.2.3.zip")
|
||||||
|
# An archive package from a given url with an MD5 hash provided
|
||||||
|
CPMAddPackage("https://example.com/my-package-1.2.3.zip#MD5=68e20f674a48be38d60e129f600faf7d")
|
||||||
|
# An archive package from a given url. The version is explicitly given
|
||||||
|
CPMAddPackage("https://example.com/my-package.zip@1.2.3")
|
||||||
|
```
|
||||||
|
|
||||||
After calling `CPMAddPackage` or `CPMFindPackage`, the following variables are defined in the local scope, where `<dependency>` is the name of the dependency.
|
After calling `CPMAddPackage` or `CPMFindPackage`, the following variables are defined in the local scope, where `<dependency>` is the name of the dependency.
|
||||||
|
|
||||||
- `<dependency>_SOURCE_DIR` is the path to the source of the dependency.
|
- `<dependency>_SOURCE_DIR` is the path to the source of the dependency.
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ endif()
|
|||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
include(CMakeParseArguments)
|
include(CMakeParseArguments)
|
||||||
|
|
||||||
# Infer package name from git repository uri (path or url)
|
# Try to infer package name from git repository uri (path or url)
|
||||||
function(cpm_package_name_from_git_uri URI RESULT)
|
function(cpm_package_name_from_git_uri URI RESULT)
|
||||||
if("${URI}" MATCHES "([^/:]+)/?.git/?$")
|
if("${URI}" MATCHES "([^/:]+)/?.git/?$")
|
||||||
set(${RESULT}
|
set(${RESULT}
|
||||||
@@ -146,6 +146,52 @@ function(cpm_package_name_from_git_uri URI RESULT)
|
|||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
# Try to infer package name and version from a url
|
||||||
|
function(cpm_package_name_and_ver_from_url url outName outVer)
|
||||||
|
if(url MATCHES "[/\\?]([a-zA-Z0-9_\\.-]+)\\.(tar|tar\\.gz|tar\\.bz2|zip|ZIP)(\\?|/|$)")
|
||||||
|
# We matched an archive
|
||||||
|
set(filename "${CMAKE_MATCH_1}")
|
||||||
|
|
||||||
|
if(filename MATCHES "([a-zA-Z0-9_\\.-]+)[_-]v?(([0-9]+\\.)*[0-9]+[a-zA-Z0-9]*)")
|
||||||
|
# We matched <name>-<version> (ie foo-1.2.3)
|
||||||
|
set(${outName}
|
||||||
|
"${CMAKE_MATCH_1}"
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
||||||
|
set(${outVer}
|
||||||
|
"${CMAKE_MATCH_2}"
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
||||||
|
elseif(filename MATCHES "(([0-9]+\\.)+[0-9]+[a-zA-Z0-9]*)")
|
||||||
|
# We couldn't find a name, but we found a version
|
||||||
|
#
|
||||||
|
# In many cases (which we don't handle here) the url would look something like
|
||||||
|
# `irrelevant/ACTUAL_PACKAGE_NAME/irrelevant/1.2.3.zip`. In such a case we can't possibly
|
||||||
|
# distinguish the package name from the irrelevant bits. Moreover if we try to match the
|
||||||
|
# package name from the filename, we'd get bogus at best.
|
||||||
|
unset(${outName} PARENT_SCOPE)
|
||||||
|
set(${outVer}
|
||||||
|
"${CMAKE_MATCH_1}"
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
# Boldly assume that the file name is the package name.
|
||||||
|
#
|
||||||
|
# Yes, something like `irrelevant/ACTUAL_NAME/irrelevant/download.zip` will ruin our day, but
|
||||||
|
# such cases should be quite rare. No popular service does this... we think.
|
||||||
|
set(${outName}
|
||||||
|
"${filename}"
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
||||||
|
unset(${outVer} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# No ideas yet what to do with non-archives
|
||||||
|
unset(${outName} PARENT_SCOPE)
|
||||||
|
unset(${outVer} PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
# Initialize logging prefix
|
# Initialize logging prefix
|
||||||
if(NOT CPM_INDENT)
|
if(NOT CPM_INDENT)
|
||||||
set(CPM_INDENT
|
set(CPM_INDENT
|
||||||
@@ -274,11 +320,6 @@ function(cpm_parse_add_package_single_arg arg outArgs)
|
|||||||
set(out "GIT_REPOSITORY;${arg}")
|
set(out "GIT_REPOSITORY;${arg}")
|
||||||
set(packageType "git")
|
set(packageType "git")
|
||||||
else()
|
else()
|
||||||
# This error here is temporary. We can't provide URLs from here until we support inferring the
|
|
||||||
# package name from an url. When this is supported, remove this error as well as commented out
|
|
||||||
# tests in test/unit/parse_add_package_single_arg.cmake
|
|
||||||
message(FATAL_ERROR "CPM: Unsupported package type of '${arg}'")
|
|
||||||
|
|
||||||
# Fall back to a URL
|
# Fall back to a URL
|
||||||
set(out "URL;${arg}")
|
set(out "URL;${arg}")
|
||||||
set(packageType "archive")
|
set(packageType "archive")
|
||||||
@@ -349,7 +390,7 @@ function(CPMAddPackage)
|
|||||||
EXCLUDE_FROM_ALL
|
EXCLUDE_FROM_ALL
|
||||||
)
|
)
|
||||||
|
|
||||||
set(multiValueArgs OPTIONS)
|
set(multiValueArgs URL OPTIONS)
|
||||||
|
|
||||||
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
|
cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}")
|
||||||
|
|
||||||
@@ -397,6 +438,24 @@ function(CPMAddPackage)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(DEFINED CPM_ARGS_URL)
|
||||||
|
# If a name or version aren't provided, try to infer them from the URL
|
||||||
|
list(GET CPM_ARGS_URL 0 firstUrl)
|
||||||
|
cpm_package_name_and_ver_from_url(${firstUrl} nameFromUrl verFromUrl)
|
||||||
|
# If we fail to obtain name and version from the first URL, we could try other URLs if any.
|
||||||
|
# However multiple URLs are expected to be quite rare, so for now we won't bother.
|
||||||
|
|
||||||
|
# If the caller provided their own name and version, they trump the inferred ones.
|
||||||
|
if(NOT DEFINED CPM_ARGS_NAME)
|
||||||
|
set(CPM_ARGS_NAME ${nameFromUrl})
|
||||||
|
endif()
|
||||||
|
if(NOT DEFINED CPM_ARGS_VERSION)
|
||||||
|
set(CPM_ARGS_VERSION ${verFromUrl})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS URL "${CPM_ARGS_URL}")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Check for required arguments
|
# Check for required arguments
|
||||||
|
|
||||||
if(NOT DEFINED CPM_ARGS_NAME)
|
if(NOT DEFINED CPM_ARGS_NAME)
|
||||||
|
|||||||
60
test/unit/package_name_and_ver_from_url.cmake
Normal file
60
test/unit/package_name_and_ver_from_url.cmake
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
||||||
|
|
||||||
|
include(${CPM_PATH}/CPM.cmake)
|
||||||
|
include(${CPM_PATH}/testing.cmake)
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url("https://example.com/coolpack-1.2.3.zip" name ver)
|
||||||
|
assert_equal("coolpack" ${name})
|
||||||
|
assert_equal("1.2.3" ${ver})
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url("https://example.com/cool-pack-v1.3.tar.gz" name ver)
|
||||||
|
assert_equal("cool-pack" ${name})
|
||||||
|
assert_equal("1.3" ${ver})
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url(
|
||||||
|
"https://subd.zip.com/download.php?Cool.Pack-v1.2.3rc0.tar" name ver
|
||||||
|
)
|
||||||
|
assert_equal("Cool.Pack" ${name})
|
||||||
|
assert_equal("1.2.3rc0" ${ver})
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url(
|
||||||
|
"http://evil-1.2.tar.gz.com/Plan9_1.2.3a.tar.bz2?download" name ver
|
||||||
|
)
|
||||||
|
assert_equal("Plan9" ${name})
|
||||||
|
assert_equal("1.2.3a" ${ver})
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url(
|
||||||
|
"http://evil-1.2.tar.gz.com/Plan_9-1.2.3a.tar.bz2?download" name ver
|
||||||
|
)
|
||||||
|
assert_equal("Plan_9" ${name})
|
||||||
|
assert_equal("1.2.3a" ${ver})
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url(
|
||||||
|
"http://evil-1.2.tar.gz.com/Plan-9_1.2.3a.tar.bz2?download" name ver
|
||||||
|
)
|
||||||
|
assert_equal("Plan-9" ${name})
|
||||||
|
assert_equal("1.2.3a" ${ver})
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url("https://sf.com/distrib/SFLib-0.999.4.tar.gz/download" name ver)
|
||||||
|
assert_equal("SFLib" ${name})
|
||||||
|
assert_equal("0.999.4" ${ver})
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url("https://example.com/coolpack/v5.6.5rc44.zip" name ver)
|
||||||
|
assert_not_defined(name)
|
||||||
|
assert_equal("5.6.5rc44" ${ver})
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url("evil-1.3.zip.com/coolpack/release999.000beta.ZIP" name ver)
|
||||||
|
assert_not_defined(name)
|
||||||
|
assert_equal("999.000beta" ${ver})
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url("https://example.com/Foo55.tar.gz" name ver)
|
||||||
|
assert_equal("Foo55" ${name})
|
||||||
|
assert_not_defined(ver)
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url("https://example.com/foo" name ver)
|
||||||
|
assert_not_defined(name)
|
||||||
|
assert_not_defined(ver)
|
||||||
|
|
||||||
|
cpm_package_name_and_ver_from_url("example.zip.com/foo" name ver)
|
||||||
|
assert_not_defined(name)
|
||||||
|
assert_not_defined(ver)
|
||||||
@@ -47,18 +47,19 @@ assert_equal(
|
|||||||
"${args}"
|
"${args}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# The following test cases are to be used in the future, once single-argument archives are supported
|
cpm_parse_add_package_single_arg("https://example.org/foo.tar.gz" args)
|
||||||
|
assert_equal("URL;https://example.org/foo.tar.gz" "${args}")
|
||||||
|
|
||||||
# cpm_parse_add_package_single_arg("https://example.org/foo.tar.gz" args)
|
cpm_parse_add_package_single_arg("https://example.org/foo.tar.gz#baadf00d@1.2.0" args)
|
||||||
|
assert_equal("URL;https://example.org/foo.tar.gz;URL_HASH;baadf00d;VERSION;1.2.0" "${args}")
|
||||||
|
|
||||||
# assert_equal("URL;https://example.org/foo.tar.gz" "${args}")
|
cpm_parse_add_package_single_arg("https://example.org/foo.tar.gz#MD5=baadf00d" args)
|
||||||
|
assert_equal("URL;https://example.org/foo.tar.gz;URL_HASH;MD5=baadf00d" "${args}")
|
||||||
|
|
||||||
# cpm_parse_add_package_single_arg("https://example.org/foo.tar.gz#baadf00d@1.2.0" args)
|
cpm_parse_add_package_single_arg("https://example.org/Foo.zip#SHA3_512=1337" args)
|
||||||
|
assert_equal("URL;https://example.org/Foo.zip;URL_HASH;SHA3_512=1337" "${args}")
|
||||||
|
|
||||||
# assert_equal("URL;https://example.org/foo.tar.gz;URL_HASH;baadf00d;VERSION;1.2.0" "${args}")
|
cpm_parse_add_package_single_arg("ftp://user:pass@server/pathname.zip#fragment#0ddb411@0" args)
|
||||||
|
assert_equal(
|
||||||
# cpm_parse_add_package_single_arg("ftp://user:password@server/pathname.zip#fragment#0ddb411@0"
|
"URL;ftp://user:pass@server/pathname.zip#fragment;URL_HASH;0ddb411;VERSION;0" "${args}"
|
||||||
# args)
|
)
|
||||||
|
|
||||||
# assert_equal("URL;ftp://user:password@server/pathname.zip#fragment;URL_HASH;0ddb411;VERSION;0"
|
|
||||||
# "${args}")
|
|
||||||
|
|||||||
Reference in New Issue
Block a user