Skip to content

Commit 22a6888

Browse files
committed
Don't delete docs when uploading docs with shared prefix
Private packages with a shared prefix, such that ecto is a prefix of ecto_sql, would delete the docs of ecto_sql when ecto was uploaded. This is because we list bucket files by prefix so that ecto/ would list all files under the ecto directory. The trailing / was removed by Path.join so we would also list the files of ecto_sql. This was only happened for private packages. Closes hexpm/hexpm#1252.
1 parent 20a09a7 commit 22a6888

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

lib/hexdocs/bucket.ex

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ defmodule Hexdocs.Bucket do
1919
meta: [{"surrogate-key", key}]
2020
]
2121

22+
Logger.info("Uploading docs_public_bucket #{path}")
23+
2224
case Hexdocs.Store.put(:docs_public_bucket, path, sitemap, opts) do
2325
{:ok, 200, _headers, _body} ->
2426
:ok
@@ -205,6 +207,10 @@ defmodule Hexdocs.Bucket do
205207
&delete_key?(&1, paths, repository, package, versions, upload_type)
206208
)
207209

210+
Enum.each(keys_to_delete, fn key ->
211+
Logger.info("Deleting #{bucket} #{key}")
212+
end)
213+
208214
Hexdocs.Store.delete_many(bucket, keys_to_delete)
209215
end
210216

@@ -253,7 +259,8 @@ defmodule Hexdocs.Bucket do
253259
defp cache_control(false = _public?), do: "private, max-age=3600"
254260

255261
defp repository_path("hexpm", path), do: path
256-
defp repository_path(repository, path), do: Path.join(repository, path)
262+
# Don't use Path.join as it removes trailing / which is needed for bucket listing
263+
defp repository_path(repository, path), do: Enum.join([repository, "/", path])
257264

258265
defp purge_hexdocs_cache("hexpm", package, versions, :both) do
259266
keys = Enum.map(versions, &docspage_versioned_cdn_key("hexpm", package, &1))

lib/hexdocs/queue.ex

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ defmodule Hexdocs.Queue do
139139

140140
defp handle_record(%{"eventName" => "ObjectRemoved:" <> _, "s3" => s3}) do
141141
key = s3["object"]["key"]
142+
start = System.os_time(:millisecond)
142143
Logger.info("OBJECT DELETED #{key}")
143144

144145
case key_components(key) do
@@ -147,7 +148,9 @@ defmodule Hexdocs.Queue do
147148
all_versions = all_versions(repository, package)
148149
Hexdocs.Bucket.delete(repository, package, version, all_versions)
149150
update_index_sitemap(repository, key)
150-
Logger.info("FINISHED DELETING DOCS #{key}")
151+
152+
elapsed = System.os_time(:millisecond) - start
153+
Logger.info("FINISHED DELETING DOCS #{key} #{elapsed}ms")
151154
:ok
152155

153156
{:ok, _repository, _package, _version} ->

test/hexdocs/bucket_test.exs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,25 @@ defmodule Hexdocs.BucketTest do
5252
refute Store.get(@bucket, "buckettest/#{test}/remove.html")
5353
end
5454

55+
test "dont overwrite package which same prefix name", %{test: test} do
56+
version = Version.parse!("0.0.1")
57+
test = Atom.to_string(test)
58+
prefix_name = String.slice(test, -1000, String.length(test) - 1)
59+
60+
Bucket.upload("buckettest", "#{test}", version, [], [
61+
{"file2", ""}
62+
])
63+
64+
Bucket.upload("buckettest", "#{prefix_name}", version, [], [
65+
{"file1", ""}
66+
])
67+
68+
assert Store.get(@bucket, "buckettest/#{prefix_name}/file1")
69+
assert Store.get(@bucket, "buckettest/#{prefix_name}/#{version}/file1")
70+
assert Store.get(@bucket, "buckettest/#{test}/file2")
71+
assert Store.get(@bucket, "buckettest/#{test}/#{version}/file2")
72+
end
73+
5574
test "newer beta docs do not overwrite stable main docs", %{test: test} do
5675
first = Version.parse!("0.5.0")
5776
second = Version.parse!("1.0.0-beta")

0 commit comments

Comments
 (0)