aboutsummaryrefslogtreecommitdiff
path: root/scripts/cmake/vcpkg_extract_source_archive_ex.cmake
blob: a775c2094cd8b0c070133b17c42fcb473c9a3264 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
## # vcpkg_extract_source_archive_ex
##
## Extract an archive into the source directory. Replaces [`vcpkg_extract_source_archive`](vcpkg_extract_source_archive.md).
##
## ## Usage
## ```cmake
## vcpkg_extract_source_archive_ex(
##     OUT_SOURCE_PATH <SOURCE_PATH>
##     ARCHIVE <${ARCHIVE}>
##     [REF <1.0.0>]
##     [NO_REMOVE_ONE_LEVEL]
##     [WORKING_DIRECTORY <${CURRENT_BUILDTREES_DIR}/src>]
##     [PATCHES <a.patch>...]
## )
## ```
## ## Parameters
## ### OUT_SOURCE_PATH
## Specifies the out-variable that will contain the extracted location.
##
## This should be set to `SOURCE_PATH` by convention.
##
## ### ARCHIVE
## The full path to the archive to be extracted.
##
## This is usually obtained from calling [`vcpkg_download_distfile`](vcpkg_download_distfile.md).
##
## ### REF
## A friendly name that will be used instead of the filename of the archive.  If more than 10 characters it will be truncated.
##
## By convention, this is set to the version number or tag fetched
##
## ### WORKING_DIRECTORY
## If specified, the archive will be extracted into the working directory instead of `${CURRENT_BUILDTREES_DIR}/src/`.
##
## Note that the archive will still be extracted into a subfolder underneath that directory (`${WORKING_DIRECTORY}/${REF}-${HASH}/`).
##
## ### PATCHES
## A list of patches to be applied to the extracted sources.
##
## Relative paths are based on the port directory.
##
## ### NO_REMOVE_ONE_LEVEL
## Specifies that the default removal of the top level folder should not occur.
##
## ## Examples
##
## * [bzip2](https://github.com/Microsoft/vcpkg/blob/master/ports/bzip2/portfile.cmake)
## * [sqlite3](https://github.com/Microsoft/vcpkg/blob/master/ports/sqlite3/portfile.cmake)
## * [cairo](https://github.com/Microsoft/vcpkg/blob/master/ports/cairo/portfile.cmake)
include(vcpkg_apply_patches)
include(vcpkg_extract_source_archive)

function(vcpkg_extract_source_archive_ex)
    cmake_parse_arguments(_vesae "NO_REMOVE_ONE_LEVEL" "OUT_SOURCE_PATH;ARCHIVE;REF;WORKING_DIRECTORY" "PATCHES" ${ARGN})

    if(NOT _vesae_ARCHIVE)
        message(FATAL_ERROR "Must specify ARCHIVE parameter to vcpkg_extract_source_archive_ex()")
    endif()

    if(NOT DEFINED _vesae_OUT_SOURCE_PATH)
        message(FATAL_ERROR "Must specify OUT_SOURCE_PATH parameter to vcpkg_extract_source_archive_ex()")
    endif()

    if(NOT DEFINED _vesae_WORKING_DIRECTORY)
        set(_vesae_WORKING_DIRECTORY ${CURRENT_BUILDTREES_DIR}/src)
    endif()

    if(NOT DEFINED _vesae_REF)
        get_filename_component(_vesae_REF ${_vesae_ARCHIVE} NAME_WE)
    endif()

    string(REPLACE "/" "-" SANITIZED_REF "${_vesae_REF}")

    # Take the last 10 chars of the REF
    set(REF_MAX_LENGTH 10)
    string(LENGTH ${SANITIZED_REF} REF_LENGTH)
    math(EXPR FROM_REF ${REF_LENGTH}-${REF_MAX_LENGTH})
    if(FROM_REF LESS 0)
        set(FROM_REF 0)
    endif()
    string(SUBSTRING ${SANITIZED_REF} ${FROM_REF} ${REF_LENGTH} SHORTENED_SANITIZED_REF)

    # Hash the archive hash along with the patches. Take the first 10 chars of the hash
    file(SHA512 ${_vesae_ARCHIVE} PATCHSET_HASH)
    foreach(PATCH IN LISTS _vesae_PATCHES)
        get_filename_component(ABSOLUTE_PATCH "${PATCH}" ABSOLUTE BASE_DIR "${CURRENT_PORT_DIR}")
        file(SHA512 ${ABSOLUTE_PATCH} CURRENT_HASH)
        string(APPEND PATCHSET_HASH ${CURRENT_HASH})
    endforeach()

    string(SHA512 PATCHSET_HASH ${PATCHSET_HASH})
    string(SUBSTRING ${PATCHSET_HASH} 0 10 PATCHSET_HASH)
    set(SOURCE_PATH "${_vesae_WORKING_DIRECTORY}/${SHORTENED_SANITIZED_REF}-${PATCHSET_HASH}")

    if(NOT EXISTS ${SOURCE_PATH})
        set(TEMP_DIR "${_vesae_WORKING_DIRECTORY}/TEMP")
        file(REMOVE_RECURSE ${TEMP_DIR})
        vcpkg_extract_source_archive("${_vesae_ARCHIVE}" "${TEMP_DIR}")

        if(_vesae_NO_REMOVE_ONE_LEVEL)
            set(TEMP_SOURCE_PATH ${TEMP_DIR})
        else()
            file(GLOB _ARCHIVE_FILES "${TEMP_DIR}/*")
            list(LENGTH _ARCHIVE_FILES _NUM_ARCHIVE_FILES)
            set(TEMP_SOURCE_PATH)
            foreach(dir IN LISTS _ARCHIVE_FILES)
                if (IS_DIRECTORY ${dir})
                    set(TEMP_SOURCE_PATH "${dir}")
                    break()
                endif()
            endforeach()

            if(NOT _NUM_ARCHIVE_FILES EQUAL 2 OR NOT TEMP_SOURCE_PATH)
                message(FATAL_ERROR "Could not unwrap top level directory from archive. Pass NO_REMOVE_ONE_LEVEL to disable this.")
            endif()
        endif()

        vcpkg_apply_patches(
            SOURCE_PATH ${TEMP_SOURCE_PATH}
            PATCHES ${_vesae_PATCHES}
        )

        file(RENAME ${TEMP_SOURCE_PATH} ${SOURCE_PATH})
        file(REMOVE_RECURSE ${TEMP_DIR})
    endif()

    set(${_vesae_OUT_SOURCE_PATH} "${SOURCE_PATH}" PARENT_SCOPE)
    message(STATUS "Using source at ${SOURCE_PATH}")
    return()
endfunction()