diff --git a/docs/make.jl b/docs/make.jl index 6144212..21a5143 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -22,8 +22,9 @@ DocMeta.setdocmeta!(PkgGraph, :DocTestSetup, :(using PkgGraph); recursive=true, println("") # ..including Documenter.HTML(…) construction call makedocs( source = srcmod, - # modules = [PkgGraph], + modules = [PkgGraph], # ↪ To get a warning if there are any docstrings not mentioned in the markdown. + # Might also be necessary to run doctests! sitename = "PkgGraph.jl", # ↪ Displayed in page title and navbar. doctest = true, diff --git a/docs/src/ref/end-user.md b/docs/src/ref/end-user.md index ff8bd2b..bf22cd3 100644 --- a/docs/src/ref/end-user.md +++ b/docs/src/ref/end-user.md @@ -18,35 +18,3 @@ PkgGraph.open ```@docs PkgGraph.create ``` - -## Settings - -These are keyword arguments that can be used with [`PkgGraph.open`](@ref) and -[`PkgGraph.create`](@ref).\ -(They are also fields to [`PkgGraph.Options`](@ref)). - -#### `jll` -Whether to include binary 'JLL' dependencies in the graph -(default: `true`) - -#### `stdlib` -Whether to include packages from the standard library in the graph -(default: `true`) - -#### `mode` -Either `:light` (default) or `:dark`.\ -Whether to use black lines and black text on a white background, or vice versa.\ -Note that locally-generated SVGs get both colour-schemes simultaneously (through [`SVG.add_darkmode`](@ref)), so this option is irrelevant for them. - -#### `bg` -Background colour for the image.\ -Default is `"transparent"`.\ -`"white"` (in combination with `mode = :light`) might be a sensible value when you are -creating a PNG but do not know on what background it will be seen. (A light-mode PNG with transparent background looks bad on a dark background). - -#### `style` -Custom Graphviz styling. See [`default_style`](@ref). - -#### `base_url` -See [`url`](@ref). -By default, the first entry in [`webapps`](@ref). diff --git a/docs/src/ref/internals.md b/docs/src/ref/internals.md index baa187e..f5fc664 100644 --- a/docs/src/ref/internals.md +++ b/docs/src/ref/internals.md @@ -33,12 +33,6 @@ url webapps ``` -## Settings object - -```@docs -Options -``` - ## Graphs.jl conversion ```@docs diff --git a/src/PkgGraph.jl b/src/PkgGraph.jl index 52d325a..ba31793 100644 --- a/src/PkgGraph.jl +++ b/src/PkgGraph.jl @@ -27,7 +27,6 @@ using URIs: escapeuri using Base: @kwdef include("includes/dotcommand.jl") include("includes/webapps.jl") -include("includes/options.jl") include("includes/enduser.jl") # No package exports (no namespace pollution) diff --git a/src/includes/enduser.jl b/src/includes/enduser.jl index bca6709..ddc810e 100644 --- a/src/includes/enduser.jl +++ b/src/includes/enduser.jl @@ -1,13 +1,15 @@ """ - open(pkgname; kw...) + open(pkgname, base_url = first(webapps); kw...) Open the browser to an image of `pkgname`'s dependency graph. -See [Settings](@ref) for possible keyword arguments. +See [`url`](@ref) for more on `base_url`, and for possible keyword +arguments see [`depgraph`](@ref) and [`to_dot_str`](@ref) . """ -function open(pkgname; dryrun = false, kw...) - link = url(pkgname, Options(; kw...)) +function open(pkgname, base_url = first(webapps); dryrun = false, kw...) + dotstr = depgraph_as_dotstr(pkgname; kw...) + link = url(dotstr, base_url) if !dryrun DefaultApplication.open(link) # ↪ Passing a URL (and not a file) opens the browser on all @@ -32,13 +34,14 @@ light and dark-mode CSS. To only create the image, without automatically opening it, pass `open = false`. -See [Settings](@ref) for more keyword arguments. +See [`depgraph`](@ref) and [`to_dot_str`](@ref) for more keyword +arguments. """ function create(pkgname, dir=tempdir(); fmt=:png, bg=bg(fmt), open=true, dryrun=false, kw...) if !is_dot_available() && !dryrun error("`dot` program not found on `PATH`. Get it at https://graphviz.org/download/") end - dotstr = to_dot_str(pkgname, Options(; bg, kw...)) + dotstr = depgraph_as_dotstr(pkgname; bg, kw...) imgpath = output_path(pkgname, dir, fmt) if !dryrun create_dot_image(dotstr, fmt, imgpath) @@ -51,3 +54,25 @@ function create(pkgname, dir=tempdir(); fmt=:png, bg=bg(fmt), open=true, dryrun= end bg(fmt) = (fmt == :png ? :white : :transparent) + +depgraph_as_dotstr(pkgname; kw...) = begin + edges = depgraph(pkgname; select(kw, depgraph)...) + dotstr = to_dot_str( + edges; + select(kw, to_dot_str)..., + emptymsg="($pkgname has no dependencies)", + ) +end + +""" +Extract the keyword arguments from `kw` that are applicable to the +single-method function `f`. +""" +select(kw, f) = begin + m = only(methods(f)) + kwargnames_f = Base.kwarg_decl(m) + selected_kw = [ + name => val for (name, val) in kw + if name in kwargnames_f + ] +end diff --git a/src/includes/options.jl b/src/includes/options.jl deleted file mode 100644 index c0eee59..0000000 --- a/src/includes/options.jl +++ /dev/null @@ -1,33 +0,0 @@ - -""" - Options(; kw...) - -Convenience object to gather all settings (kwargs) of different -functions in one place. - -See [Settings](@ref) for available properties. -""" -@kwdef struct Options - # ↪ i.e. see docs/src/ref/end-user.md for field documentation. - jll = true - stdlib = true - style = default_style() - base_url = first(webapps) - mode = :light - bg = "transparent" -end - -DepGraph.depgraph(pkg, o::Options) = - depgraph(pkg; o.jll, o.stdlib) - -DotString.to_dot_str(pkg, o::Options) = - to_dot_str( - depgraph(pkg, o); - o.style, - o.mode, - o.bg, - emptymsg = "($pkg has no dependencies)", - ) - -url(pkg, o::Options) = - url(o.base_url, to_dot_str(pkg, o)) diff --git a/src/modules/DepGraph.jl b/src/modules/DepGraph.jl index 989ab0d..ed84d08 100644 --- a/src/modules/DepGraph.jl +++ b/src/modules/DepGraph.jl @@ -10,6 +10,7 @@ export STDLIB, STDLIB_NAMES include("DepGraph/project.jl") +export packages_in_active_manifest include("DepGraph/registry.jl") diff --git a/src/modules/DotString.jl b/src/modules/DotString.jl index 7fb2ee2..7514fd6 100644 --- a/src/modules/DotString.jl +++ b/src/modules/DotString.jl @@ -4,65 +4,7 @@ module DotString export to_dot_str, default_style -""" - to_dot_str( - edges; - mode = :light, - bg = "transparent", - style = default_style(), - indent = 4, - emptymsg = nothing, - ) - -Build a string that represents the given directed graph in the -[Graphviz DOT format ↗](https://graphviz.org/doc/info/lang.html). - -`mode` and `bg` specify the colour scheme and background colour for the -graph (see [Settings](@ref)). - -`style` is a list of strings, inserted as lines in the output (after the -lines generated for `mode` and `bg`, and just before the graph edge -lines). To use Graphviz's default style, pass `style = []`. For the -default see [`default_style`](@ref). For more on how dot-graphs can be -styled, see [Styling Graphviz output](@ref). - -`indent` is the number of spaces to indent each line in the "`digraph`" -block with. - -If there are no `edges`, a single node with `emptymsg` is created. If -`emptymsg` is `nothing` (default), no nodes are created, and the image -rendered from the DOT-string will be empty. - -## Example: - -```jldoctest -julia> edges = [:A => :B, "yes" => "no"]; - -julia> style = ["node [color=\\"red\\"]"]; - -julia> using PkgGraph - -julia> PkgGraph.to_dot_str(edges; style, bg=:blue, indent=2) |> println -digraph { - bgcolor = "blue" - node [fillcolor="white", fontcolor="black", color="black"] - edge [color="black"] - node [color="red"] - A -> B - yes -> no -} - -julia> emptymsg="(empty graph)"; - -julia> PkgGraph.to_dot_str([]; emptymsg, mode=:dark, style=[]) |> println -digraph { - bgcolor = "transparent" - node [fillcolor="black", fontcolor="white", color="white"] - edge [color="white"] - onlynode [label=\" (empty graph) \", shape=\"plaintext\"] -} -``` -""" +@doc readchomp(joinpath(@__DIR__, "to_dot_string.md")) function to_dot_str( edges; mode = :light, diff --git a/src/modules/to_dot_string.md b/src/modules/to_dot_string.md new file mode 100644 index 0000000..9e27e56 --- /dev/null +++ b/src/modules/to_dot_string.md @@ -0,0 +1,75 @@ +```julia +to_dot_str( + edges; + mode = :light, + bg = "transparent", + style = default_style(), + indent = 4, + emptymsg = nothing, +) +``` + +Build a string that represents the given directed graph in the +[Graphviz DOT format ↗](https://graphviz.org/doc/info/lang.html). + +## Keyword arguments + +### `mode` +Either `:light` (default) or `:dark`.\ +Whether to use black lines and black text on a white background, or vice +versa.\ +Note that locally-generated SVGs get both colour-schemes simultaneously, +so this option is irrelevant for them. + +### `bg` +Background colour for the image.\ +Default is `"transparent"`.\ +`"white"` (in combination with `mode = :light`) might be a sensible +value when you are creating a PNG but do not know on what background it +will be seen. (A light-mode PNG with transparent background looks bad on +a dark background). + +### `style` +A list of strings, inserted as lines in the output (after the lines +generated for `mode` and `bg`, and just before the graph edge lines). To +use Graphviz's default style, pass `style = []`. For the default see +[`default_style`](@ref). For more on how dot-graphs can be styled, see +[Styling Graphviz output](@ref). + +### `indent` +The number of spaces to indent each line in the "`digraph`" block with. + +### `emtpymsg` +If there are no `edges`, a single node with `emptymsg` is created. If +`emptymsg` is `nothing` (default), no nodes are created, and the image +rendered from the DOT-string will be empty. + +## Example: + +```jldoctest +julia> edges = [:A => :B, "yes" => "no"]; + +julia> style = ["node [color=\"red\"]"]; + +julia> using PkgGraph + +julia> PkgGraph.to_dot_str(edges; style, bg=:blue, indent=2) |> println +digraph { + bgcolor = "blue" + node [fillcolor="white", fontcolor="black", color="black"] + edge [color="black"] + node [color="red"] + A -> B + yes -> no +} + +julia> emptymsg="(empty graph)"; + +julia> PkgGraph.to_dot_str([]; emptymsg, mode=:dark, style=[]) |> println +digraph { + bgcolor = "transparent" + node [fillcolor="black", fontcolor="white", color="white"] + edge [color="white"] + onlynode [label=" (empty graph) ", shape="plaintext"] +} +``` diff --git a/test/integration/all.jl b/test/integration/all.jl index 1784435..74711bc 100644 --- a/test/integration/all.jl +++ b/test/integration/all.jl @@ -2,7 +2,7 @@ using PkgGraph using Test -@testset "integration" begin +@testset "integration" verbose=true begin include("deps-as-dot.jl") include("graphsjl_example.jl") end diff --git a/test/integration/deps-as-dot.jl b/test/integration/deps-as-dot.jl index 58f121d..4d7c9ab 100644 --- a/test/integration/deps-as-dot.jl +++ b/test/integration/deps-as-dot.jl @@ -1,9 +1,7 @@ -using PkgGraph: Options - @testset "deps-as-dot" begin - @test PkgGraph.to_dot_str(:TOML, Options()) == + @test PkgGraph.depgraph_as_dotstr(:TOML) == """ digraph { bgcolor = "transparent" @@ -17,7 +15,7 @@ using PkgGraph: Options } """ - @test PkgGraph.to_dot_str(:TOML, Options(style=[], mode=:dark, bg=:white)) == + @test PkgGraph.depgraph_as_dotstr(:TOML, style=[], mode=:dark, bg=:white) == """ digraph { bgcolor = "white" @@ -29,7 +27,7 @@ using PkgGraph: Options } """ - @test PkgGraph.to_dot_str(:URIs, Options(style=[])) == + @test PkgGraph.depgraph_as_dotstr(:URIs, style=[]) == """ digraph { bgcolor = "transparent" diff --git a/test/runtests.jl b/test/runtests.jl index 49e712f..a47fb91 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -7,3 +7,5 @@ using Test include("unit/all.jl") include("integration/all.jl") end + +nothing # To not print big "Test.DefaultTestSet(…)", when running manually diff --git a/test/unit/DepGraph.jl b/test/unit/DepGraph.jl index 023e4bb..38374c7 100644 --- a/test/unit/DepGraph.jl +++ b/test/unit/DepGraph.jl @@ -38,6 +38,7 @@ using Test # The latter does not have Graphs in its manifest; so it comes from registry, and there # deps have different order (also on julia 1.6 there's no registry querying). # Heeence, why `../standalone` exists. + @assert dirname(Base.active_project()) == dirname(@__DIR__) "Please use [activate_standalone.jl]" @test PkgGraph.depgraph("Graphs"; jll = false, stdlib = false) == [ "Graphs" => "ArnoldiMethod" "ArnoldiMethod" => "StaticArrays"