Convert REQUIRE to Project.toml and Manifest.toml

packages

#1

Is there a standard process or function that allows one to upgrade old packages using the REQUIRE file to the new package format using Project.toml and Manifest.toml ?

Apologies if I missed this documentation online.


#2

This is what I do:

  1. Steal the format from an existing Project.toml, e.g. https://github.com/JuliaLang/Pkg.jl/blob/master/Project.toml, and create your own Project.toml in your repository.
  2. You probably only need “name” and “uuid” in the top section, so you can delete the rest or change it for your package if you want.
  3. Replace the package name there with your package name.
  4. Get a uuid for your package using using Pkg; Pkg.METADATA_compatible_uuid(pkg_name) where pkg_name is the name of your package as a String without .jl (watch your spelling!).
  5. Replace the uuid in the Project.toml and delete the list of deps there, keeping the header. Save the file!
  6. cd into the repository of the package, most likely in your .julia/dev/pkg_name folder.
  7. In a Julia session, run ]activate .
  8. Open the REQUIRE file in another window.
  9. Run ]add dep_name for all your dependencies in the REQUIRE file. This will automatically update the Project.toml and Manifest.toml, creating the latter if it doesn’t exit.
  10. You may want to add an extra [compat] section as shown in https://docs.julialang.org/en/v1/stdlib/Pkg/index.html#Compatibility-1 to support certain versions of packages or Julia.
  11. Add your test dependencies as well and then copy the test deps’ lines from the Project.toml file’s [deps] section to the [extras] section, and list the package names in the [targets] section as shown in https://github.com/KristofferC/JuAFEM.jl/blob/master/Project.toml.

And now you should be having Project.toml and Manifest.toml files in your repo. Apparently, you still need to keep your REQUIRE files there for registered packages. Anyways after doing the above, you can close that Julia session and open a new one in the default v1.0 environment, and pretend like none of this had to happen. Hopefully, some expert can correct me if I got something off.


Developing and using my own code
#3

Here is my quick-and-dirty Julia function to automate a similar workflow:

"""
    generate_project_toml([name::String])

Generate Project.toml file for the existing current project at `\$PWD`.
It activates the generated Project.toml and then adds packages based on
REQUIRE file.
"""
function generate_project_toml(name::AbstractString = guess_project_name())
    if isfile("Project.toml")
        error("Project.toml exists.")
    end

    if !isfile("REQUIRE")
        error("REQUIRE file not found.")
    end
    deps = read_require("REQUIRE")

    pkg = Base.identify_package(name)
    project_toml = """
    name = $(repr(name))
    uuid = "$(pkg.uuid)"
    """
    write("Project.toml", project_toml)

    @info "Activating \$PWD (to run `Pkg.add`)"
    Pkg.activate(pwd())
    Pkg.add(deps)
end

"""
    guess_project_name() :: String

Guess project name using Git.  It works even in worktree repository.
"""
function guess_project_name()
    path = abspath(rstrip(read(`git rev-parse --git-dir`, String)))
    prev = ""
    while path != prev
        if basename(path) == ".git"
            return basename(dirname(path))
        end
        prev, path = path, dirname(path)
    end
    error("Project not found")
end

function read_require(path)
    deps = String[]
    for line in readlines(path)
        name, = split(line)
        if name == "julia"
            continue
        end
        push!(deps, name)
    end
    return deps
end