Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Generate an almost-right Project.toml file from a REQUIRE file in Julia 1.0 <= VERSION < 1.1-
using Pkg
function imports(pkg_dir::AbstractString)
imported = Set{String}()
for (root, dirs, files) in walkdir(pkg_dir)
for file in files
if endswith(file, ".jl")
union!(imported, open(imports, joinpath(root, file)))
end
end
end
return imported
end
function imports(io::IO)
imported = Set{String}()
while !eof(io)
line = readline(io)
if (m = match(r"^\s*(?:using|import) ([\w\.\ ,]+)", line)) !== nothing
union!(imported, split(m[1], r"\s*,\s*"))
end
end
return imported
end
function imported_pkg_names(pkg_dir::AbstractString)
imported = collect(imports(pkg_dir))
filter!(n -> !startswith(n, "."), imported)
return sort!(unique!(map(n -> replace(n, r"\..*" => ""), imported)))
end
function package_specs(pkg_dir::AbstractString)
ctx = Pkg.Types.Context()
pkg = PackageSpec(name=basename(abspath(pkg_dir)))
# Determine UUID of the package we're investigating
Pkg.Operations.registry_resolve!(ctx.env, [pkg])
# Determine the UUID of the dependencies based upon the REQUIRE
fix_deps_map = Dict{Base.UUID,Vector{PackageSpec}}()
Pkg.Operations.collect_require!(ctx, pkg, pkg_dir, fix_deps_map)
dep_pkgs = fix_deps_map[pkg.uuid]
dep_names = Set(map(p -> p.name, dep_pkgs))
test_pkgs = if isfile(joinpath(pkg_dir, "test", "REQUIRE"))
empty!(fix_deps_map)
Pkg.Operations.collect_require!(ctx, pkg, joinpath(pkg_dir, "test"), fix_deps_map)
fix_deps_map[pkg.uuid]
else
Vector{PackageSpec}()
end
# Scan the package itself for any missing imports typically from use of the stdlib
dep_names = Set(map(p -> p.name, dep_pkgs))
for name in imported_pkg_names(joinpath(pkg_dir, "src"))
if !(name in dep_names)
push!(dep_pkgs, PackageSpec(name))
union!(dep_names, [name])
end
end
Pkg.Operations.registry_resolve!(ctx.env, dep_pkgs)
Pkg.Operations.stdlib_resolve!(ctx, dep_pkgs)
test_names = union(dep_names, Set(map(p -> p.name, test_pkgs)))
for name in imported_pkg_names(joinpath(pkg_dir, "test"))
if !(name in test_names)
push!(test_pkgs, PackageSpec(name))
union!(test_names, [name])
end
end
Pkg.Operations.registry_resolve!(ctx.env, test_pkgs)
Pkg.Operations.stdlib_resolve!(ctx, test_pkgs)
sort!(dep_pkgs, by=p -> p.name)
sort!(test_pkgs, by=p -> p.name)
return pkg, dep_pkgs, test_pkgs
end
function project_file(io::IO, pkg::PackageSpec, deps::Vector{PackageSpec}, test_deps::Vector{PackageSpec}=PackageSpec[])
deps = sort(deps, by=p -> p.name)
test_deps = sort(test_deps, by=p -> p.name)
print(io, """
name = "$(pkg.name)"
uuid = "$(pkg.uuid)"
authors = []
version = "$(Base.thispatch(pkg.version))"
[deps]
$(join(["$(p.name) = \"$(p.uuid)\"" for p in deps], "\n"))
[compat]
$(join(["$(p.name) = \"$(p.version)\"" for p in deps], "\n"))
julia = "0.7, 1.0"
"""
)
if !isempty(test_deps)
print(io, """
[extras]
$(join(["$(p.name) = \"$(p.uuid)\"" for p in test_deps], "\n"))
[targets]
test = [$(join(["\"$(p.name)\"" for p in test_deps], ", "))]
"""
)
end
end
function project_file(pkg_dir::AbstractString)
project_toml_path = joinpath(pkg_dir, "Project.toml")
isfile(project_toml_path) && throw(ArgumentError("Project.toml already exists at: $project_toml_path"))
pkg, deps, test_deps = package_specs(pkg_dir)
open(project_toml_path, "w") do io
project_file(io, pkg, deps, test_deps)
end
end
#=
project_file("/Users/omus/.julia/dev/ModelAnalysis")
=#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment