Skip to content
This repository has been archived by the owner on Oct 8, 2020. It is now read-only.

Commit

Permalink
Merge 9009302 into 7453538
Browse files Browse the repository at this point in the history
  • Loading branch information
scouten committed Sep 21, 2019
2 parents 7453538 + 9009302 commit 13f3815
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 1 deletion.
38 changes: 37 additions & 1 deletion lib/xgit/repository/working_tree.ex
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,40 @@ defmodule Xgit.Repository.WorkingTree do
end
end

@typedoc ~S"""
Error code reasons returned by `reset_dir_cache/1`.
"""
@type reset_dir_cache_reason :: WriteIndexFile.to_iodevice_reason()

@doc ~S"""
Reset the dir cache to empty and rewrite the index file accordingly.
## Return Values
`:ok` if successful.
`{:error, reason}` if unable. The relevant reason codes may come from:
* `Xgit.Repository.WorkingTree.WriteIndexFile.to_iodevice/2`.
"""
@spec reset_dir_cache(working_tree :: t) ::
:ok | {:error, reset_dir_cache_reason}
def reset_dir_cache(working_tree) when is_pid(working_tree),
do: GenServer.call(working_tree, :reset_dir_cache)

defp handle_reset_dir_cache(%{work_dir: work_dir} = state) do
index_path = Path.join([work_dir, ".git", "index"])

with {:ok, iodevice}
when is_pid(iodevice) <- TrailingHashDevice.open_file_for_write(index_path),
:ok <- WriteIndexFile.to_iodevice(DirCache.empty(), iodevice),
:ok <- File.close(iodevice) do
cover {:reply, :ok, state}
else
{:error, reason} -> cover {:reply, {:error, reason}, state}
end
end

@typedoc ~S"""
Error code reasons returned by `update_dir_cache/3`.
"""
Expand Down Expand Up @@ -167,7 +201,7 @@ defmodule Xgit.Repository.WorkingTree do
`{:ok, dir_cache}` where `dir_cache` is the original `dir_cache` with the new
entries added (and properly sorted) and targeted entries removed.
`{:error, :reason}` if unable. The relevant reason codes may come from:
`{:error, reason}` if unable. The relevant reason codes may come from:
* `Xgit.Core.DirCache.add_entries/2`
* `Xgit.Core.DirCache.remove_entries/2`
Expand Down Expand Up @@ -213,6 +247,8 @@ defmodule Xgit.Repository.WorkingTree do

def handle_call(:dir_cache, _from, state), do: handle_dir_cache(state)

def handle_call(:reset_dir_cache, _from, state), do: handle_reset_dir_cache(state)

def handle_call({:update_dir_cache, add, remove}, _from, state),
do: handle_update_dir_cache(add, remove, state)

Expand Down
173 changes: 173 additions & 0 deletions test/xgit/repository/working_tree/reset_dir_cache_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
defmodule Xgit.Repository.WorkingTree.ResetDirCacheTest do
use Xgit.GitInitTestCase, async: true

alias Xgit.Core.DirCache
alias Xgit.Repository
alias Xgit.Repository.OnDisk
alias Xgit.Repository.WorkingTree

import FolderDiff

describe "reset_dir_cache/1" do
test "happy path: can generate correct empty index file",
%{ref: ref, xgit: xgit} do
# An initialized git repo doesn't have an index file at all.
# Adding and removing a file generates an empty index file.

{_output, 0} =
System.cmd(
"git",
[
"update-index",
"--add",
"--cacheinfo",
"100644",
"18832d35117ef2f013c4009f5b2128dfaeff354f",
"hello.txt"
],
cd: ref
)

{_output, 0} =
System.cmd(
"git",
[
"update-index",
"--remove",
"hello.txt"
],
cd: ref
)

assert :ok = OnDisk.create(xgit)
{:ok, repo} = OnDisk.start_link(work_dir: xgit)
working_tree = Repository.default_working_tree(repo)

assert :ok = WorkingTree.reset_dir_cache(working_tree)

assert_folders_are_equal(ref, xgit)
end

test "can reset an index file when entries existed",
%{ref: ref, xgit: xgit} do
{_output, 0} =
System.cmd(
"git",
[
"update-index",
"--add",
"--cacheinfo",
"100644",
"18832d35117ef2f013c4009f5b2128dfaeff354f",
"hello.txt"
],
cd: ref
)

{_output, 0} =
System.cmd(
"git",
[
"update-index",
"--add",
"--cacheinfo",
"100644",
"d670460b4b4aece5915caf5c68d12f560a9fe3e4",
"test_content.txt"
],
cd: ref
)

assert :ok = OnDisk.create(xgit)
{:ok, repo} = OnDisk.start_link(work_dir: xgit)
working_tree = Repository.default_working_tree(repo)

assert :ok =
WorkingTree.update_dir_cache(
working_tree,
[
%DirCache.Entry{
assume_valid?: false,
ctime: 0,
ctime_ns: 0,
dev: 0,
extended?: false,
gid: 0,
ino: 0,
intent_to_add?: false,
mode: 0o100644,
mtime: 0,
mtime_ns: 0,
name: 'hello.txt',
object_id: "18832d35117ef2f013c4009f5b2128dfaeff354f",
size: 0,
skip_worktree?: false,
stage: 0,
uid: 0
},
%DirCache.Entry{
assume_valid?: false,
ctime: 0,
ctime_ns: 0,
dev: 0,
extended?: false,
gid: 0,
ino: 0,
intent_to_add?: false,
mode: 0o100644,
mtime: 0,
mtime_ns: 0,
name: 'test_content.txt',
object_id: "d670460b4b4aece5915caf5c68d12f560a9fe3e4",
size: 0,
skip_worktree?: false,
stage: 0,
uid: 0
}
],
[]
)

assert_folders_are_equal(ref, xgit)

{_output, 0} =
System.cmd(
"git",
[
"update-index",
"--remove",
"hello.txt"
],
cd: ref
)

{_output, 0} =
System.cmd(
"git",
[
"update-index",
"--remove",
"test_content.txt"
],
cd: ref
)

assert :ok = WorkingTree.reset_dir_cache(working_tree)

assert_folders_are_equal(ref, xgit)
end

test "error: can't replace malformed index file", %{xgit: xgit} do
git_dir = Path.join(xgit, '.git')
File.mkdir_p!(git_dir)

index = Path.join(git_dir, 'index')
File.mkdir_p!(index)

{:ok, repo} = OnDisk.start_link(work_dir: xgit)
working_tree = Repository.default_working_tree(repo)

assert {:error, :eisdir} = WorkingTree.reset_dir_cache(working_tree)
end
end
end

0 comments on commit 13f3815

Please sign in to comment.