Add execution priority to plugins

This commit is contained in:
Chris de Graaf 2019-09-20 09:31:56 +07:00
parent 980452fde3
commit 0cf6d47ada
No known key found for this signature in database
GPG Key ID: 150FFDD9B0073C7B
12 changed files with 68 additions and 49 deletions

View File

@ -19,9 +19,8 @@ However, it's probably desirable to customize the template to your liking with v
```jl
t = Template(;
dir="~/code",
ssh=true,
manifest=true,
plugins=[
Git(; manifest=true, ssh=true),
Codecov(),
TravisCI(; x86=true),
Documenter{TravisCI}(),

View File

@ -94,6 +94,7 @@ view
Finally, we implement [`hook`](@ref), which is the real workhorse for the plugin.
TODO prehook and posthook in examples
TODO priority
```@docs
prehook

View File

@ -5,8 +5,10 @@
function Base.show(io::IO, ::MIME"text/plain", p::T) where T <: Plugin
indent = get(io, :indent, 0)
print(io, repeat(' ', indent), T, ":")
foreach(fieldnames(T)) do n
print(io, repeat(' ', indent), T)
ns = fieldnames(T)
isempty(ns) || print(io, ":")
foreach(ns) do n
println(io)
print(io, repeat(' ', indent + 2), n, ": ", show_field(getfield(p, n)))
end
@ -28,7 +30,7 @@ function Base.show(io::IO, m::MIME"text/plain", t::Template)
print(io, " plugins: None")
else
print(io, repeat(' ', 2), "plugins:")
foreach(sort(collect(values(t.plugins)); by=string)) do p
foreach(sort(t.plugins; by=string)) do p
println(io)
show(IOContext(io, :indent => 4), m, p)
end

View File

@ -1,4 +1,5 @@
const TEMPLATES_DIR = normpath(joinpath(@__DIR__, "..", "templates"))
const DEFAULT_PRIORITY = 1000
"""
A simple plugin that, in general, creates a single file.
@ -59,6 +60,14 @@ By default, the tags are `"{{"` and `"}}"`.
"""
tags(::Plugin) = "{{", "}}"
"""
priority(::Plugin) -> Int
Determines the order in which plugins are processed (higher goes first).
The default priority (`DEFAULT_PRIORITY`), is `$DEFAULT_PRIORITY`.
"""
priority(::Plugin) = DEFAULT_PRIORITY
"""
gitignore(::Plugin) -> Vector{String}
@ -131,7 +140,7 @@ At this point, `pkg_dir` is an empty directory that will eventually contain the
!!! note
`pkg_dir` only stays empty until the first plugin chooses to create a file.
Don't count on the order in which the plugins are sorted!
See also: [`priority`](@ref).
"""
prehook(::Plugin, ::Template, ::AbstractString) = nothing

View File

@ -254,10 +254,10 @@ end
"""
is_ci(::Type{T}) -> Bool
is_ci(::Plugin) -> Bool
Determine whether or not `T` is a CI plugin.
Determine whether or not a plugin is a CI plugin.
If you are adding a CI plugin, you should implement this function and return `true`.
"""
is_ci(::Type) = false
is_ci(::Type{<:Union{AppVeyor, TravisCI, CirrusCI, GitLabCI}}) = true
is_ci(::Plugin) = false
is_ci(::Union{AppVeyor, TravisCI, CirrusCI, GitLabCI}) = true

View File

@ -45,10 +45,10 @@ badges(::Coveralls) = Badge(
gitignore(::Union{Codecov, Coveralls}) = COVERAGE_GITIGNORE
"""
is_coverage(::Type{T}) -> Bool
is_coverage(::Plugin) -> Bool
Determine whether or not `T` is a coverage plugin.
Determine whether or not a plugin is a coverage plugin.
If you are adding a coverage plugin, you should implement this function and return `true`.
"""
is_coverage(::Type) = false
is_coverage(::Type{<:Union{Codecov, Coveralls}}) = true
is_coverage(::Plugin) = false
is_coverage(::Union{Codecov, Coveralls}) = true

View File

@ -50,7 +50,7 @@ end
# Create the .gitignore.
function hook(p::Git, t::Template, pkg_dir::AbstractString)
ignore = mapreduce(gitignore, append!, values(t.plugins))
ignore = mapreduce(gitignore, append!, t.plugins)
# Only ignore manifests at the repo root.
p.manifest || "Manifest.toml" in ignore || push!(ignore, "/Manifest.toml")
unique!(sort!(ignore))

View File

@ -5,8 +5,10 @@ Creates a `Project.toml`.
"""
struct ProjectFile <: Plugin end
# Create Project.toml in the prehook because other hooks might depend on it.
function prehook(::ProjectFile, t::Template, pkg_dir::AbstractString)
# Other plugins like Tests will modify this file.
priority(::ProjectFile) = typemax(Int) - DEFAULT_PRIORITY + 1
function hook(::ProjectFile, t::Template, pkg_dir::AbstractString)
toml = Dict(
"name" => basename(pkg_dir),
"uuid" => uuid4(),

View File

@ -29,19 +29,18 @@ function view(p::Readme, t::Template, pkg::AbstractString)
done = DataType[]
foreach(badge_order()) do T
if hasplugin(t, T)
bs = badges(t.plugins[T], t, pkg)
append!(strings, badges(t.plugins[T], t, pkg))
append!(strings, badges(getplugin(t, T), t, pkg))
push!(done, T)
end
end
foreach(setdiff(keys(t.plugins), done)) do T
bs = badges(t.plugins[T], t, pkg)
append!(strings, badges(t.plugins[T], t, pkg))
# And the rest go after, in no particular order.
foreach(setdiff(map(typeof, t.plugins), done)) do T
append!(strings, badges(getplugin(t, T), t, pkg))
end
return Dict(
"BADGES" => strings,
"HAS_CITATION" => hasplugin(t, Citation) && t.plugins[Citation].readme,
"HAS_CITATION" => hasplugin(t, Citation) && getplugin(t, Citation).readme,
"HAS_INLINE_BADGES" => !isempty(strings) && p.inline_badges,
"PKG" => pkg,
)

View File

@ -54,7 +54,7 @@ struct Template
dir::String
host::String
julia_version::VersionNumber
plugins::Dict{DataType, <:Plugin}
plugins::Vector{<:Plugin}
user::String
end
@ -72,33 +72,17 @@ function Template(::Val{false}; kwargs...)
host = replace(getkw(kwargs, :host), r".*://" => "")
julia_version = getkw(kwargs, :julia_version)
# User-supplied plugins come first, so that deduping the list will remove the defaults.
plugins = Plugin[]
append!(plugins, getkw(kwargs, :plugins))
disabled = getkw(kwargs, :disable_defaults)
enabled = filter(p -> !(typeof(p) in disabled), default_plugins())
append!(enabled, getkw(kwargs, :plugins))
# This comprehension resolves duplicate plugin types by overwriting,
# which means that default plugins get replaced by user values.
plugins = Dict(typeof(p) => p for p in enabled)
append!(plugins, filter(p -> !(typeof(p) in disabled), default_plugins()))
plugins = unique(typeof, plugins)
sort!(plugins; by=priority, rev=true)
return Template(authors, dir, host, julia_version, plugins, user)
end
# Does the template have a plugin that satisfies some predicate?
hasplugin(t::Template, f::Function) = any(f, keys(t.plugins))
hasplugin(t::Template, ::Type{T}) where T <: Plugin = hasplugin(t, U -> U <: T)
# Get a keyword, or compute some default value.
getkw(kwargs, k) = get(() -> defaultkw(k), kwargs, k)
# Default Template keyword values.
defaultkw(s::Symbol) = defaultkw(Val(s))
defaultkw(::Val{:authors}) = default_authors()
defaultkw(::Val{:dir}) = Pkg.devdir()
defaultkw(::Val{:disable_defaults}) = DataType[]
defaultkw(::Val{:host}) = "github.com"
defaultkw(::Val{:julia_version}) = default_version()
defaultkw(::Val{:plugins}) = Plugin[]
defaultkw(::Val{:user}) = default_user()
"""
(::Template)(pkg::AbstractString)
@ -113,7 +97,7 @@ function (t::Template)(pkg::AbstractString)
try
foreach((prehook, hook, posthook)) do h
@info "Running $(h)s"
foreach(values(t.plugins)) do p
foreach(t.plugins) do p
h(p, t, pkg_dir)
end
end
@ -124,3 +108,26 @@ function (t::Template)(pkg::AbstractString)
@info "New package is at $pkg_dir"
end
# Does the template have a plugin that satisfies some predicate?
hasplugin(t::Template, f::Function) = any(f, t.plugins)
hasplugin(t::Template, ::Type{T}) where T <: Plugin = hasplugin(t, p -> p isa T)
# Get a plugin by type.
function getplugin(t::Template, ::Type{T}) where T <: Plugin
i = findfirst(p -> p isa T, t.plugins)
i === nothing ? nothing : t.plugins[i]
end
# Get a keyword, or compute some default value.
getkw(kwargs, k) = get(() -> defaultkw(k), kwargs, k)
# Default Template keyword values.
defaultkw(s::Symbol) = defaultkw(Val(s))
defaultkw(::Val{:authors}) = default_authors()
defaultkw(::Val{:dir}) = Pkg.devdir()
defaultkw(::Val{:disable_defaults}) = DataType[]
defaultkw(::Val{:host}) = "github.com"
defaultkw(::Val{:julia_version}) = default_version()
defaultkw(::Val{:plugins}) = Plugin[]
defaultkw(::Val{:user}) = default_user()

View File

@ -39,7 +39,7 @@ const LICENSES_DIR = joinpath(TEMPLATES_DIR, "licenses")
License:
path: "$(joinpath(LICENSES_DIR, "MIT"))"
destination: "LICENSE"
ProjectFile:
ProjectFile
Readme:
file: "$(joinpath(TEMPLATES_DIR, "README.md"))"
destination: "README.md"

View File

@ -28,7 +28,7 @@
@testset "plugins / disabled_defaults" begin
function test_plugins(plugins, expected, disabled=DataType[])
t = tpl(; plugins=plugins, disable_defaults=disabled)
@test issetequal(values(t.plugins), expected)
@test issetequal(t.plugins, expected)
end
defaults = PT.default_plugins()