fpm_generator.f90 Source File


Source Code

module fpm_generator
    use module_scanner, only: module_info
  use registry_resolver, only: resolve_module_to_package, load_registry, load_registry_from_path, resolve_module_with_version
    implicit none
    private
    public :: generate_fpm_with_deps, generate_fpm_with_deps_from_config

contains

  subroutine generate_fpm_with_deps(project_dir, name, modules, n_modules, is_preprocessed_file, custom_flags)
        character(len=*), intent(in) :: project_dir, name
        type(module_info), dimension(:), intent(in) :: modules
        integer, intent(in) :: n_modules
        logical, intent(in), optional :: is_preprocessed_file
        character(len=*), intent(in), optional :: custom_flags

        character(len=512) :: toml_path
        character(len=128) :: package_name, package_names(100)
        character(len=256) :: git_url, git_urls(100)
        character(len=32) :: version, versions(100)
        logical :: found
        integer :: unit, i, j, n_deps
        logical :: already_added

        ! Load registry if not already loaded
        call load_registry()

        toml_path = trim(project_dir)//'/fpm.toml'

        ! Resolve dependencies
        n_deps = 0
        do i = 1, n_modules
call resolve_module_with_version(modules(i)%name, package_name, git_url, version, found)

            if (found) then
                ! Print resolution info for test validation
        print '(a,a,a,a)', '  Module ', trim(modules(i)%name), ' -> package ', trim(package_name)

                ! Check if already added
                already_added = .false.
                do j = 1, n_deps
                    if (trim(package_names(j)) == trim(package_name)) then
                        already_added = .true.
                        exit
                    end if
                end do

                if (.not. already_added) then
                    n_deps = n_deps + 1
                    package_names(n_deps) = package_name
                    git_urls(n_deps) = git_url
                    versions(n_deps) = version
                end if
            end if
        end do

        ! Generate fpm.toml
        open (newunit=unit, file=toml_path, status='replace')

        ! Basic metadata
        write (unit, '(a)') 'name = "'//trim(name)//'"'
        write (unit, '(a)') 'version = "0.1.0"'
        write (unit, '(a)') ''

        ! Build settings - removed to allow auto-discovery of library sources
        ! FPM will auto-discover sources in src/ directory

        ! Fortran settings - conditional based on file type
        write (unit, '(a)') '[fortran]'
        if (present(is_preprocessed_file)) then
            if (is_preprocessed_file) then
                write (unit, '(a)') 'implicit-typing = false  # Enforces implicit none'
            end if
        end if
        write (unit, '(a)') 'implicit-external = false'
        write (unit, '(a)') 'source-form = "free"'
        write (unit, '(a)') ''

        ! Executable definition
        write (unit, '(a)') '[[executable]]'
        write (unit, '(a)') 'name = "'//trim(name)//'"'
        write (unit, '(a)') 'main = "main.f90"'
        write (unit, '(a)') ''

        ! Dependencies
        if (n_deps > 0) then
            write (unit, '(a)') '[dependencies]'
            do i = 1, n_deps
                if (len_trim(versions(i)) > 0) then
                    write (unit, '(a)') trim(package_names(i))//' = { git = "'// &
                        trim(git_urls(i))//'", tag = "'//trim(versions(i))//'" }'
                else
                    write (unit, '(a)') trim(package_names(i))//' = { git = "'// &
                        trim(git_urls(i))//'" }'
                end if
            end do
        else
            write (unit, '(a)') '[executable.dependencies]'
        end if

        close (unit)

    end subroutine generate_fpm_with_deps

  subroutine generate_fpm_with_deps_from_config(project_dir, name, modules, n_modules, config_dir, &
                                                  is_preprocessed_file, custom_flags)
        character(len=*), intent(in) :: project_dir, name, config_dir
        type(module_info), dimension(:), intent(in) :: modules
        integer, intent(in) :: n_modules
        logical, intent(in), optional :: is_preprocessed_file
        character(len=*), intent(in), optional :: custom_flags

        character(len=512) :: toml_path, registry_path
        character(len=128) :: package_name, package_names(100)
        character(len=256) :: git_url, git_urls(100)
        character(len=32) :: version, versions(100)
        logical :: found
        integer :: unit, i, j, n_deps
        logical :: already_added

        ! Load registry from custom config directory
        registry_path = trim(config_dir)//'/registry.toml'
        call load_registry_from_path(registry_path)

        toml_path = trim(project_dir)//'/fpm.toml'

        ! Resolve dependencies
        n_deps = 0
        do i = 1, n_modules
call resolve_module_with_version(modules(i)%name, package_name, git_url, version, found)

            if (found) then
                ! Print resolution info for test validation
        print '(a,a,a,a)', '  Module ', trim(modules(i)%name), ' -> package ', trim(package_name)

                ! Check if already added
                already_added = .false.
                do j = 1, n_deps
                    if (trim(package_names(j)) == trim(package_name)) then
                        already_added = .true.
                        exit
                    end if
                end do

                if (.not. already_added) then
                    n_deps = n_deps + 1
                    package_names(n_deps) = package_name
                    git_urls(n_deps) = git_url
                    versions(n_deps) = version
                end if
            end if
        end do

        ! Generate fpm.toml
        open (newunit=unit, file=toml_path, status='replace')

        ! Basic metadata
        write (unit, '(a)') 'name = "'//trim(name)//'"'
        write (unit, '(a)') 'version = "0.1.0"'
        write (unit, '(a)') ''

        ! Build settings - removed to allow auto-discovery of library sources
        ! FPM will auto-discover sources in src/ directory

        ! Fortran settings - conditional based on file type
        write (unit, '(a)') '[fortran]'
        if (present(is_preprocessed_file)) then
            if (is_preprocessed_file) then
                write (unit, '(a)') 'implicit-typing = false  # Enforces implicit none'
            end if
        end if
        write (unit, '(a)') 'implicit-external = false'
        write (unit, '(a)') 'source-form = "free"'
        write (unit, '(a)') ''

        ! Executable definition
        write (unit, '(a)') '[[executable]]'
        write (unit, '(a)') 'name = "'//trim(name)//'"'
        write (unit, '(a)') 'main = "main.f90"'
        write (unit, '(a)') ''

        ! Dependencies
        if (n_deps > 0) then
            write (unit, '(a)') '[dependencies]'
            do i = 1, n_deps
                if (len_trim(versions(i)) > 0) then
                    write (unit, '(a)') trim(package_names(i))//' = { git = "'// &
                        trim(git_urls(i))//'", tag = "'//trim(versions(i))//'" }'
                else
                    write (unit, '(a)') trim(package_names(i))//' = { git = "'// &
                        trim(git_urls(i))//'" }'
                end if
            end do
        else
            write (unit, '(a)') '[executable.dependencies]'
        end if

        close (unit)

    end subroutine generate_fpm_with_deps_from_config

end module fpm_generator