Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ set(GIT2CPP_SRC
${GIT2CPP_SOURCE_DIR}/subcommand/revlist_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/revparse_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/revparse_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/rm_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/rm_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/stash_subcommand.cpp
${GIT2CPP_SOURCE_DIR}/subcommand/stash_subcommand.hpp
${GIT2CPP_SOURCE_DIR}/subcommand/status_subcommand.cpp
Expand Down
4 changes: 3 additions & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "subcommand/status_subcommand.hpp"
#include "subcommand/revparse_subcommand.hpp"
#include "subcommand/revlist_subcommand.hpp"
#include "subcommand/rm_subcommand.hpp"

int main(int argc, char** argv)
{
Expand Down Expand Up @@ -55,8 +56,9 @@ int main(int argc, char** argv)
push_subcommand push(lg2_obj, app);
rebase_subcommand rebase(lg2_obj, app);
remote_subcommand remote(lg2_obj, app);
revparse_subcommand revparse(lg2_obj, app);
revlist_subcommand revlist(lg2_obj, app);
revparse_subcommand revparse(lg2_obj, app);
rm_subcommand rm(lg2_obj, app);
stash_subcommand stash(lg2_obj, app);

app.require_subcommand(/* min */ 0, /* max */ 1);
Expand Down
2 changes: 1 addition & 1 deletion src/subcommand/mv_subcommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ void mv_subcommand::run()
if (exists && !m_force)
{
// TODO: replace magic number with enum when diff command is merged
throw git_exception("destination already exists", 128);
throw git_exception("destination already exists", git2cpp_error_code::FILESYSTEM_ERROR);
}

std::error_code ec;
Expand Down
64 changes: 64 additions & 0 deletions src/subcommand/rm_subcommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include <filesystem>
#include <ranges>
#include "rm_subcommand.hpp"
#include "../utils/common.hpp"
#include "../utils/git_exception.hpp"
#include "../wrapper/index_wrapper.hpp"
#include "../wrapper/repository_wrapper.hpp"

namespace fs = std::filesystem;

rm_subcommand::rm_subcommand(const libgit2_object&, CLI::App& app)
{
auto* rm = app.add_subcommand("rm", "Remove files from the working tree and from the index");
rm->add_option("<pathspec>", m_pathspec, "Files to remove");
rm->add_flag("-r", m_recursive, "Allow recursive removal when a leading directory name is given");

rm->callback([this]() { this->run(); });
}

void rm_subcommand::run()
{
auto directory = get_current_git_path();
auto repo = repository_wrapper::open(directory);

index_wrapper index = repo.make_index();

std::vector<std::string> files;
std::vector<std::string> directories;

std::ranges::for_each(m_pathspec, [&](const std::string& path)
{
if (!fs::exists(path))
{
std::string msg = "fatal: pathspec '" + path + "' did not math any file";
throw git_exception(msg, git2cpp_error_code::FILESYSTEM_ERROR);
}
if (fs::is_directory(path))
{
directories.push_back(path);
}
else
{
if (!repo.does_track(path))
{
std::string msg = "fatal: pathsspec '" + path + "'is not tracked";
throw git_exception(msg, git2cpp_error_code::FILESYSTEM_ERROR);
}
files.push_back(path);
}
});

if (!directories.empty() && !m_recursive)
{
std::string msg = "fatal: not removing '" + directories.front() + "' recursively without -r";
throw git_exception(msg, git2cpp_error_code::FILESYSTEM_ERROR);
}

index.remove_entries(files);
index.remove_directories(directories);
index.write();

std::ranges::for_each(files, [](const std::string& path) { fs::remove(path); });
std::ranges::for_each(directories, [](const std::string& path) { fs::remove_all(path); });
}
21 changes: 21 additions & 0 deletions src/subcommand/rm_subcommand.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include <CLI/CLI.hpp>
#include <string>
#include <vector>

#include "../utils/common.hpp"

class rm_subcommand
{
public:

explicit rm_subcommand(const libgit2_object&, CLI::App& app);
void run();

private:

std::vector<std::string> m_pathspec;
bool m_recursive = false;
};

1 change: 1 addition & 0 deletions src/utils/git_exception.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
enum class git2cpp_error_code
{
GENERIC_ERROR = -1,
FILESYSTEM_ERROR = 128,
BAD_ARGUMENT = 129,
};

Expand Down
15 changes: 15 additions & 0 deletions src/wrapper/index_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <git2/index.h>
#include <algorithm>
#include <iostream>
#include <vector>

Expand Down Expand Up @@ -47,6 +48,20 @@ void index_wrapper::remove_entry(const std::string& path)
throw_if_error(git_index_remove_bypath(*this, path.c_str()));
}

void index_wrapper::remove_entries(std::vector<std::string> paths)
{
git_strarray_wrapper array{paths};
throw_if_error(git_index_remove_all(*this, array, NULL, NULL));
}

void index_wrapper::remove_directories(std::vector<std::string> entries)
{
std::for_each(entries.cbegin(), entries.cend(), [this](const std::string& path)
{
throw_if_error(git_index_remove_directory(*this, path.c_str(), 0));
});
}

void index_wrapper::write()
{
throw_if_error(git_index_write(*this));
Expand Down
2 changes: 2 additions & 0 deletions src/wrapper/index_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class index_wrapper : public wrapper_base<git_index>
void add_all();

void remove_entry(const std::string& path);
void remove_entries(std::vector<std::string> paths);
void remove_directories(std::vector<std::string> paths);

bool has_conflict() const;
void output_conflicts();
Expand Down
7 changes: 7 additions & 0 deletions src/wrapper/repository_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ revwalk_wrapper repository_wrapper::new_walker()
return revwalk_wrapper(walker);
}

bool repository_wrapper::does_track(std::string_view path) const
{
unsigned int flags;
throw_if_error(git_status_file(&flags, *this, path.data()));
return !(flags & GIT_STATUS_WT_NEW) && !(flags & GIT_STATUS_IGNORED);
}

// Head

bool repository_wrapper::is_head_unborn() const
Expand Down
2 changes: 2 additions & 0 deletions src/wrapper/repository_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class repository_wrapper : public wrapper_base<git_repository>

revwalk_wrapper new_walker();

bool does_track(std::string_view path) const;

// Head
bool is_head_unborn() const;
reference_wrapper head() const;
Expand Down
13 changes: 0 additions & 13 deletions src/wrapper/status_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,3 @@ auto status_list_wrapper::get_entry_list(git_status_t status) const -> const sta
}
}



// std::ostream& operator<<(std::ostream& out, const status_list_wrapper& slw)
// {
// std::size_t status_list_size = git_status_list_entrycount(slw);
// for (std::size_t i = 0; i < status_list_size; ++i)
// {
// std::cout << i << " ";
// auto entry = git_status_byindex(slw, i);

// }
// return out;
// };
1 change: 1 addition & 0 deletions test/conftest_wasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def pytest_ignore_collect(collection_path: pathlib.Path) -> bool:
"test_reset.py",
"test_revlist.py",
"test_revparse.py",
"test_rm.py",
"test_stash.py",
"test_status.py",
]
Expand Down
Loading