40117350cfcb17ecd7238dc8ab666af59c88f750
[akkoma] / lib / mix / tasks / migrate_local_uploads.ex
1 defmodule Mix.Tasks.MigrateLocalUploads do
2 use Mix.Task
3 import Mix.Ecto
4 alias Pleroma.{Upload, Uploaders.Local, Uploaders.S3}
5 require Logger
6
7 @log_every 50
8 @shortdoc "Migrate uploads from local to remote storage"
9
10 def run([target_uploader | args]) do
11 delete? = Enum.member?(args, "--delete")
12 Application.ensure_all_started(:pleroma)
13
14 local_path = Pleroma.Config.get!([Local, :uploads])
15 uploader = Module.concat(Pleroma.Uploaders, target_uploader)
16
17 unless Code.ensure_loaded?(uploader) do
18 raise("The uploader #{inspect(uploader)} is not an existing/loaded module.")
19 end
20
21 target_enabled? = Pleroma.Config.get([Upload, :uploader]) == uploader
22
23 unless target_enabled? do
24 Pleroma.Config.put([Upload, :uploader], uploader)
25 end
26
27 Logger.info("Migrating files from local #{local_path} to #{to_string(uploader)}")
28
29 if delete? do
30 Logger.warn(
31 "Attention: uploaded files will be deleted, hope you have backups! (--delete ; cancel with ^C)"
32 )
33
34 :timer.sleep(:timer.seconds(5))
35 end
36
37 uploads = File.ls!(local_path)
38 total_count = length(uploads)
39
40 uploads
41 |> Task.async_stream(
42 fn uuid ->
43 u_path = Path.join(local_path, uuid)
44
45 {name, path} =
46 cond do
47 File.dir?(u_path) ->
48 files = for file <- File.ls!(u_path), do: {{file, uuid}, Path.join([u_path, file])}
49 List.first(files)
50
51 File.exists?(u_path) ->
52 # {uuid, u_path}
53 raise "should_dedupe local storage not supported yet sorry"
54 end
55
56 {:ok, _} =
57 Upload.store({:from_local, name, path}, should_dedupe: false, uploader: uploader)
58
59 if delete? do
60 File.rm_rf!(u_path)
61 end
62
63 Logger.debug("uploaded: #{inspect(name)}")
64 end,
65 timeout: 150_000
66 )
67 |> Stream.chunk_every(@log_every)
68 |> Enum.reduce(0, fn done, count ->
69 count = count + length(done)
70 Logger.info("Uploaded #{count}/#{total_count} files")
71 count
72 end)
73
74 Logger.info("Done!")
75 end
76
77 def run(_) do
78 Logger.error("Usage: migrate_local_uploads UploaderName [--delete]")
79 end
80 end