defmodule Dragon.Tools.File.Synchronize do @moduledoc """ Lightweight file synchronizer. For performance, do not synchronize files to the build folder unless: * original timestamp is different * file size is different """ use Dragon.Context ############################################################################## def file_difference(file1, file2) do case {File.stat(file1), File.stat(file2)} do {{:ok, %{size: size, type: type, mtime: mtime, mode: mode}}, {:ok, %{size: size, type: type, mtime: mtime, mode: mode}}} -> false {{:ok, stat}, result} -> {stat, result} end end def synchronize(%Dragon{files: %{file: files}} = dragon), do: synchronize(dragon, Map.keys(files)) def synchronize(dragon), do: {:ok, dragon} ############################################################################## def synchronize(%Dragon{root: root, build: build} = dragon, [file | rest]) do src = Path.join(root, file) dst = Path.join(build, file) Dragon.Tools.File.makedirs_for_file(dst) diff = file_difference(src, dst) if diff != false do # cleanup first case diff do {_, {:ok, %{type: :directory}}} -> File.rmdir!(dst) {_, {:ok, %{type: :regular}}} -> File.rm!(dst) _ -> nil end {stat, _} = diff synchronize_file(src, dst, stat) end synchronize(dragon, rest) end def synchronize(%Dragon{} = dragon, _), do: {:ok, dragon} def synchronize_file(src, dst, stat) do stdout([:green, "Synchronizing file: ", :reset, :bright, src]) case File.cp(src, dst) do :ok -> # update modified time to match File.touch(dst, stat.mtime) end end end