meta.f90 Source File


Source Code

!> Implementation of the metapackage configuration data.
!>
!> A metapackage table can currently have the following fields
!>
!>```toml
!>[metapackages]
!>fpm = "0.1.0"
!>openmp = bool
!>stdlib = bool
!>```
module fpm_manifest_metapackages
    use fpm_error, only: error_t, fatal_error, syntax_error
    use fpm_toml, only : toml_table, toml_key, toml_stat, get_value
    use fpm_environment
    implicit none
    private

    public :: metapackage_config_t, new_meta_config, is_meta_package
    public :: metapackage_request_t, new_meta_request


    !> Configuration data for a single metapackage request
    type :: metapackage_request_t

        !> Request flag
        logical :: on = .false.

        !> Metapackage name
        character(len=:), allocatable :: name

        !> Version Specification string
        character(len=:), allocatable :: version

    end type metapackage_request_t


    !> Configuration data for metapackages
    type :: metapackage_config_t

        !> Request MPI support
        type(metapackage_request_t) :: mpi

        !> Request OpenMP support
        type(metapackage_request_t) :: openmp

        !> Request stdlib support
        type(metapackage_request_t) :: stdlib

        !> fortran-lang minpack
        type(metapackage_request_t) :: minpack

    end type metapackage_config_t


contains

    !> Destroy a metapackage request
    elemental subroutine request_destroy(self)

        !> Instance of the request
        class(metapackage_request_t), intent(inout) :: self

        self%on = .false.
        if (allocated(self%version)) deallocate(self%version)
        if (allocated(self%name)) deallocate(self%name)

    end subroutine request_destroy

    !> Parse version string of a metapackage request
    subroutine request_parse(self, version_request, error)

        ! Instance of this metapackage
        type(metapackage_request_t), intent(inout) :: self

        ! Parse version request
        character(len=*), intent(in) :: version_request

        ! Error message
        type(error_t), allocatable, intent(out) :: error

        ! wildcard = use any versions
        if (version_request=="*") then

            ! Any version is OK
            self%on = .true.
            self%version = version_request

        else

            call fatal_error(error,'Value <'//version_request//'> for metapackage '//self%name//&
                                   'is not currently supported. Try "*" instead. ')
            return

        end if

    end subroutine request_parse

    !> Construct a new metapackage request from the dependencies table
    subroutine new_meta_request(self, key, table, meta_allowed, error)

        type(metapackage_request_t), intent(out) :: self

        !> The package name
        character(len=*), intent(in) :: key

        !> Instance of the TOML data structure
        type(toml_table), intent(inout) :: table

        !> List of keys allowed to be metapackages
        logical, intent(in), optional :: meta_allowed(:)

        !> Error handling
        type(error_t), allocatable, intent(out) :: error


        integer :: stat,i
        character(len=:), allocatable :: value
        logical, allocatable :: allow_meta(:)
        type(toml_key), allocatable :: keys(:)

        call request_destroy(self)

        !> Set name
        self%name = key
        if (.not.is_meta_package(key)) then
            call fatal_error(error,"Error reading fpm.toml: <"//key//"> is not a valid metapackage name")
            return
        end if

        !> The toml table is not checked here because it already passed
        !> the "new_dependencies" check

        call table%get_keys(keys)

        !> Set list of entries that are allowed to be metapackages
        if (present(meta_allowed)) then
            if (size(meta_allowed)/=size(keys)) then
                 call fatal_error(error,"Internal error: list of metapackage-enable entries does not match table size")
                 return
            end if
            allow_meta = meta_allowed
        else
            allocate(allow_meta(size(keys)),source=.true.)
        endif


        do i=1,size(keys)

            ! Skip standard dependencies
            if (.not.allow_meta(i)) cycle

            if (keys(i)%key==key) then
                call get_value(table, key, value)
                if (.not. allocated(value)) then
                    call syntax_error(error, "Could not retrieve version string for metapackage key <"//key//">. Check syntax")
                    return
                else
                    call request_parse(self, value, error)
                    return
                endif
            end if
        end do

        ! Key is not present, metapackage not requested
        return

    end subroutine new_meta_request

    !> Construct a new build configuration from a TOML data structure
    subroutine new_meta_config(self, table, meta_allowed, error)

        !> Instance of the build configuration
        type(metapackage_config_t), intent(out) :: self

        !> Instance of the TOML data structure
        type(toml_table), intent(inout) :: table

        !> List of keys allowed to be metapackages
        logical, intent(in) :: meta_allowed(:)

        !> Error handling
        type(error_t), allocatable, intent(out) :: error

        integer :: stat

        !> The toml table is not checked here because it already passed
        !> the "new_dependencies" check
        call new_meta_request(self%openmp, "openmp", table, meta_allowed, error)
        if (allocated(error)) return

        call new_meta_request(self%stdlib, "stdlib", table, meta_allowed, error)
        if (allocated(error)) return

        call new_meta_request(self%minpack, "minpack", table, meta_allowed, error)
        if (allocated(error)) return

        call new_meta_request(self%mpi, "mpi", table, meta_allowed, error)
        if (allocated(error)) return

    end subroutine new_meta_config

    !> Check local schema for allowed entries
    logical function is_meta_package(key)

        !> Instance of the TOML data structure
        character(*), intent(in) :: key

        select case (key)

            !> Supported metapackages
            case ("openmp","stdlib","mpi","minpack")
                is_meta_package = .true.

            case default
                is_meta_package = .false.

        end select

    end function is_meta_package

end module fpm_manifest_metapackages