Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Safety check before running File.rm_rf! in doc gen #1707

Merged
merged 3 commits into from
May 29, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 28 additions & 2 deletions lib/ex_doc/formatter/epub.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ defmodule ExDoc.Formatter.EPUB do
"""
@spec run(list, ExDoc.Config.t()) :: String.t()
def run(project_nodes, config) when is_map(config) do
parent = config.output
config = normalize_config(config)
File.rm_rf!(config.output)
File.mkdir_p!(Path.join(config.output, "OEBPS"))
setup_output(config, parent)

project_nodes = HTML.render_all(project_nodes, ".xhtml", config, highlight_tag: "samp")

Expand Down Expand Up @@ -44,6 +44,32 @@ defmodule ExDoc.Formatter.EPUB do
Path.relative_to_cwd(epub)
end

defp setup_output(config, parent) do
safety_path = Path.join(parent, ".ex_doc")

cond do
File.exists?(safety_path) ->
File.rm_rf!(config.output)
mkdir_output!(config.output, parent)

not File.exists?(parent) ->
mkdir_output!(config.output, parent)

true ->
raise """
ex_doc cannot output to #{config.output}:
Directory already exists and is not managed by ex_doc.

Try giving an unexisting directory as `--output`.
"""
end
end

defp mkdir_output!(path, parent) do
File.mkdir_p!(Path.join(path, "OEBPS"))
File.touch!(Path.join(parent, ".ex_doc"))
end

defp normalize_config(config) do
output =
config.output
Expand Down
42 changes: 31 additions & 11 deletions lib/ex_doc/formatter/html.ex
Original file line number Diff line number Diff line change
Expand Up @@ -147,20 +147,40 @@ defmodule ExDoc.Formatter.HTML do
end

defp output_setup(build, config) do
if File.exists?(build) do
build
|> File.read!()
|> String.split("\n", trim: true)
|> Enum.map(&Path.join(config.output, &1))
|> Enum.each(&File.rm/1)

File.rm(build)
else
File.rm_rf!(config.output)
File.mkdir_p!(config.output)
safety_path = Path.join(config.output, ".ex_doc")

cond do
File.exists?(build) ->
build
|> File.read!()
|> String.split("\n", trim: true)
|> Enum.map(&Path.join(config.output, &1))
|> Enum.each(&File.rm/1)

File.rm(build)

File.exists?(safety_path) ->
File.rm_rf!(config.output)
mkdir_output!(config.output)

not File.exists?(config.output) ->
mkdir_output!(config.output)

true ->
raise """
ex_doc cannot output to #{config.output}:
Directory already exists and is not managed by ex_doc.

Try giving an unexisting directory as `--output`.
"""
end
end
viniciusmuller marked this conversation as resolved.
Show resolved Hide resolved

defp mkdir_output!(path) do
File.mkdir_p!(path)
File.touch!(Path.join(path, ".ex_doc"))
end

defp generate_build(files, build) do
entries = Enum.map(files, &[&1, "\n"])
File.write!(build, entries)
Expand Down
12 changes: 12 additions & 0 deletions test/ex_doc/formatter/epub_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ defmodule ExDoc.Formatter.EPUBTest do
assert File.regular?(tmp_dir <> "/epub/another_dir/#{doc_config(context)[:project]}.epub")
end

test "fails if trying to write to existing directory", context do
assert_raise RuntimeError, ~r/Directory already exists and is not managed by ex_doc/, fn ->
config = doc_config(context)

new_output = config[:output] <> "/new-dir"
File.mkdir_p!(new_output)

new_config = Keyword.put(config, :output, new_output)
generate_docs(new_config)
end
end

test "generates an EPUB file with a standardized structure", %{tmp_dir: tmp_dir} = context do
generate_docs_and_unzip(context, doc_config(context))

Expand Down
6 changes: 6 additions & 0 deletions test/ex_doc/formatter/html/erlang_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ defmodule ExDoc.Formatter.HTML.ErlangTest do
@moduletag :otp_eep48
@moduletag :tmp_dir

setup %{tmp_dir: tmp_dir} do
output = tmp_dir <> "/doc"
File.mkdir!(output)
File.touch!("#{output}/.ex_doc")
end

test "smoke test", c do
erlc(c, :foo, ~S"""
%% @doc
Expand Down
6 changes: 6 additions & 0 deletions test/ex_doc/formatter/html/search_items_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ defmodule ExDoc.Formatter.HTML.SearchItemsTest do

@moduletag :tmp_dir

setup %{tmp_dir: tmp_dir} do
output = tmp_dir <> "/doc"
File.mkdir!(output)
File.touch!("#{output}/.ex_doc")
end

test "Elixir module", c do
modules =
elixirc(c, ~S'''
Expand Down
18 changes: 18 additions & 0 deletions test/ex_doc/formatter/html_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ defmodule ExDoc.Formatter.HTMLTest do

@moduletag :tmp_dir

setup %{tmp_dir: tmp_dir} do
output = tmp_dir <> "/html"
File.mkdir_p!(output)
File.touch!(output <> "/.ex_doc")
end

defp read_wildcard!(path) do
[file] = Path.wildcard(path)
File.read!(file)
Expand Down Expand Up @@ -146,6 +152,18 @@ defmodule ExDoc.Formatter.HTMLTest do
refute content_module =~ re[:index][:refresh]
end

test "fails if trying to write to existing directory", context do
assert_raise RuntimeError, ~r/Directory already exists and is not managed by ex_doc/, fn ->
config = doc_config(context)

new_output = config[:output] <> "/new-dir"
File.mkdir_p!(new_output)

new_config = Keyword.put(config, :output, new_output)
generate_docs(new_config)
end
end

test "allows to set the authors of the document", %{tmp_dir: tmp_dir} = context do
generate_docs(doc_config(context, authors: ["John Doe", "Jane Doe"]))
content_index = File.read!(tmp_dir <> "/html/api-reference.html")
Expand Down
4 changes: 4 additions & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ defmodule TestHelper do
def elixirc(context, filename \\ "nofile", code) do
dir = context.tmp_dir

output_dir = context.tmp_dir <> "/html"
File.mkdir_p!(output_dir)
File.write!(output_dir <> "/.ex_doc", "")

src_path = Path.join([dir, filename])
src_path |> Path.dirname() |> File.mkdir_p!()
File.write!(src_path, code)
Expand Down