Add diff loading with useability fixes

This commit is contained in:
Twarit
2019-08-15 03:07:52 +05:30
parent cfa85954e9
commit b65c336ce3
14 changed files with 153 additions and 98 deletions

17
demo/.gitattributes vendored Normal file
View File

@@ -0,0 +1,17 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
#Explicitly declare text files you want to always be normalized and converted
#to native line endings on checkout.
*.cpp text
*.c text
*.h text
*.gd text
*.cs text
#Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf
#Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -7,7 +7,10 @@ extends Node
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# This is a test change for the VCS addon
func _some_function():
pass
# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
# pass

View File

@@ -21,6 +21,7 @@ _global_script_class_icons={
[application]
config/name="demo"
run/main_scene="res://demo.tscn"
config/icon="res://icon.png"
[gdnative]

View File

@@ -129,13 +129,11 @@
<ItemGroup>
<ClCompile Include="src\gdlibrary.cpp" />
<ClCompile Include="src\git_api.cpp" />
<ClCompile Include="src\git_callbacks.cpp" />
<ClCompile Include="src\git_common.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\allocation_defs.h" />
<ClInclude Include="src\git_api.h" />
<ClInclude Include="src\git_callbacks.h" />
<ClInclude Include="src\git_common.h" />
</ItemGroup>
<ItemGroup>

View File

@@ -21,9 +21,6 @@
<ClCompile Include="src\git_api.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\git_callbacks.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\git_common.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -35,9 +32,6 @@
<ClInclude Include="src\git_common.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\git_callbacks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\allocation_defs.h">
<Filter>Header Files</Filter>
</ClInclude>

View File

@@ -2,7 +2,7 @@
namespace godot {
bool GitAPI::is_initialized = false;
GitAPI *GitAPI::singleton = NULL;
void GitAPI::_register_methods() {
@@ -13,6 +13,7 @@ void GitAPI::_register_methods() {
register_method("_get_initialization_settings_panel_container", &GitAPI::_get_initialization_settings_panel_container);
register_method("_get_is_vcs_intialized", &GitAPI::_get_is_vcs_intialized);
register_method("_get_modified_files_data", &GitAPI::_get_modified_files_data);
register_method("_get_file_diff", &GitAPI::_get_file_diff);
register_method("_get_project_name", &GitAPI::_get_project_name);
register_method("_get_vcs_name", &GitAPI::_get_vcs_name);
register_method("_initialize", &GitAPI::_initialize);
@@ -31,42 +32,41 @@ void GitAPI::_commit(const String p_msg) {
git_signature *default_sign;
git_oid tree_id, parent_id, commit_id;
git_tree *tree;
git_index *repo_index;
git_commit *parent;
git_index *index;
git_signature_default(&default_sign, repo);
git_reference_name_to_id(&parent_id, repo, "HEAD");
/* Get the index and write it to a tree */
git_repository_index(&index, repo);
git_repository_index(&repo_index, repo);
for (int i = 0; i < staged_files.size(); i++) {
git_index_add_bypath(index, ((String)staged_files[i]).alloc_c_string());
git_index_add_bypath(repo_index, ((String)staged_files[i]).alloc_c_string());
}
git_index_write_tree(&tree_id, index);
git_index_write_tree(&tree_id, repo_index);
git_tree_lookup(&tree, repo, &tree_id);
/* Get HEAD as a commit object to use as the parent of the commit */
GIT2_CALL(git_reference_name_to_id(&parent_id, repo, "HEAD"), "Could not get HEAD reference for parent ID", NULL);
git_commit_lookup(&parent, repo, &parent_id);
/* Do the commit */
git_commit_create_v(
&commit_id,
repo,
"HEAD", /* The commit will update the position of HEAD */
default_sign,
default_sign,
NULL, /* UTF-8 encoding */
p_msg.alloc_c_string(),
tree, /* The tree from the index */
1, /* Only one parent */
parent /* No need to make a list with create_v */
&commit_id,
repo,
"HEAD",
default_sign,
default_sign,
NULL,
p_msg.alloc_c_string(),
tree,
1,
parent
);
staged_files.clear();
git_index_write(repo_index);
git_index_free(repo_index);
git_signature_free(default_sign);
git_index_free(index);
git_commit_free(parent);
git_tree_free(tree);
}
@@ -81,10 +81,13 @@ void GitAPI::_stage_file(const String p_file_path) {
void GitAPI::_unstage_file(const String p_file_path) {
staged_files.erase(p_file_path);
if (staged_files.find(p_file_path) != -1) {
staged_files.erase(p_file_path);
}
}
void GitAPI::create_gitignore() {
void GitAPI::create_gitignore_and_gitattributes() {
File *file = File::_new();
@@ -101,37 +104,61 @@ void GitAPI::create_gitignore() {
);
file->close();
}
if (!file->file_exists("res://.gitattributes")) {
file->open("res://.gitattributes", File::ModeFlags::WRITE);
file->store_string(
"# Set the default behavior, in case people don't have core.autocrlf set.\n"
"* text=auto\n\n"
"#Explicitly declare text files you want to always be normalized and converted\n"
"#to native line endings on checkout.\n"
"*.cpp text\n"
"*.c text\n"
"*.h text\n"
"*.gd text\n"
"*.cs text\n\n"
"#Declare files that will always have CRLF line endings on checkout.\n"
"*.sln text eol=crlf\n\n"
"#Denote all files that are truly binary and should not be modified.\n"
"*.png binary\n"
"*.jpg binary\n");
file->close();
}
}
void GitAPI::create_initial_commit() {
git_signature *sig;
git_index *index;
git_oid tree_id, commit_id;
git_index *repo_index;
git_tree *tree;
GIT2_CALL(git_signature_default(&sig, repo), "Unable to create a commit signature. Perhaps 'user.name' and 'user.email' are not set", NULL);
GIT2_CALL(git_repository_index(&index, repo), "Could not create intial commit", NULL);
GIT2_CALL(git_index_write_tree(&tree_id, index), "Could not create intial commit", NULL);
git_index_free(index);
GIT2_CALL(git_repository_index(&repo_index, repo), "Could not get repository index", NULL);
GIT2_CALL(git_index_write_tree(&tree_id, repo_index), "Could not create intial commit", NULL);
GIT2_CALL(git_tree_lookup(&tree, repo, &tree_id), "Could not create intial commit", NULL);
GIT2_CALL(
git_commit_create_v(
&commit_id,
repo,
"HEAD",
sig,
sig,
NULL,
"Initial commit",
tree,
0
&commit_id,
repo,
"HEAD",
sig,
sig,
NULL,
"Initial commit",
tree,
0
),
"Could not create the initial commit",
NULL);
git_index_write(repo_index);
git_index_free(repo_index);
git_tree_free(tree);
git_signature_free(sig);
}
@@ -153,12 +180,11 @@ bool GitAPI::_get_is_vcs_intialized() {
Dictionary GitAPI::_get_modified_files_data() {
git_status_options opts = GIT_STATUS_OPTIONS_INIT;
opts.flags += GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
opts.flags += GIT_STATUS_OPT_INCLUDE_UNTRACKED;
opts.flags += GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS;
opts.flags += GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX;
git_status_list *statuses = NULL;
opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
opts.flags = GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
opts.flags |= GIT_STATUS_OPT_INCLUDE_UNTRACKED | GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX | GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
git_status_list *statuses = NULL;
GIT2_CALL(git_status_list_new(&statuses, repo, &opts), "Could not get status information from repository", NULL);
Dictionary diff; // Schema is <file_path, status>
@@ -209,6 +235,28 @@ Dictionary GitAPI::_get_modified_files_data() {
return diff;
}
String GitAPI::_get_file_diff(const String file_path) {
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
git_diff *diff;
char *pathspec = file_path.alloc_c_string();
opts.context_lines = 0;
opts.interhunk_lines = 0;
opts.flags = GIT_DIFF_DISABLE_PATHSPEC_MATCH | GIT_DIFF_INCLUDE_UNTRACKED;
opts.pathspec.strings = &pathspec;
opts.pathspec.count = 1;
git_diff_index_to_workdir(&diff, repo, NULL, &opts);
diff_content_container = "";
git_diff_print(diff, GIT_DIFF_FORMAT_PATCH, diff_line_callback_function, NULL);
git_diff_free(diff);
return diff_content_container;
}
String GitAPI::_get_project_name() {
return String("project");
@@ -223,6 +271,8 @@ bool GitAPI::_initialize(const String p_project_root_path) {
ERR_FAIL_COND_V(p_project_root_path == "", false);
singleton = this;
int init = git_libgit2_init();
if (init > 1) {
@@ -237,7 +287,7 @@ bool GitAPI::_initialize(const String p_project_root_path) {
GIT2_CALL(git_repository_init(&repo, p_project_root_path.alloc_c_string(), 0), "Could not initialize repository", NULL);
if (git_repository_head_unborn(repo) == 1) {
create_gitignore();
create_gitignore_and_gitattributes();
create_initial_commit();
}
@@ -250,6 +300,7 @@ bool GitAPI::_initialize(const String p_project_root_path) {
bool GitAPI::_shut_down() {
git_repository_free(repo);
GIT2_CALL(git_libgit2_shutdown(), "Could not shutdown Git Addon", NULL);
return true;

View File

@@ -9,11 +9,10 @@
#include <Directory.hpp>
#include <File.hpp>
#include <git2.h>
#include <git_common.h>
#include <allocation_defs.h>
#include <git_callbacks.h>
#include <git2.h>
namespace godot {
@@ -21,20 +20,21 @@ class GitAPI : public EditorVCSInterface {
GODOT_CLASS(GitAPI, EditorVCSInterface)
static bool is_initialized;
static GitAPI *singleton;
Array staged_files;
PanelContainer *init_settings_panel_container;
Button *init_settings_button;
git_repository *repo;
void _commit(const String p_msg);
Control *_get_commit_dock_panel_container();
Control *_get_initialization_settings_panel_container();
bool _get_is_vcs_intialized();
Dictionary _get_modified_files_data();
String _get_file_diff(const String file_path);
String _get_project_name();
String _get_vcs_name();
bool _initialize(const String p_project_root_path);
@@ -45,7 +45,13 @@ class GitAPI : public EditorVCSInterface {
public:
static void _register_methods();
void create_gitignore();
static GitAPI *get_singleton() { return singleton; }
bool is_initialized;
String diff_content_container;
void create_gitignore_and_gitattributes();
void create_initial_commit();
void _init();

View File

@@ -1,24 +0,0 @@
#include <git_callbacks.h>
int status_callback(const char *p_path, const char *p_matched_pathspec, void *p_payload) {
StatusPayload p = *(StatusPayload *)(p_payload);
int ret;
unsigned int status;
if (git_status_file(&status, p.repo, p_path)) {
return -1;
}
if ((status & GIT_STATUS_WT_MODIFIED) || (status & GIT_STATUS_WT_NEW)) {
godot::Godot::print("Staged '%s'", p_path);
ret = 0;
} else {
ret = 1;
}
return ret;
}

View File

@@ -1,11 +0,0 @@
#ifndef GIT_CALLBACKS_H
#define GIT_CALLBACKS_H
#include <Godot.hpp>
#include <git2.h>
#include <git_common.h>
int status_callback(const char *p_path, const char *p_matched_pathspec, void *p_payload);
#endif // !GIT_CALLBACKS_H

View File

@@ -1,4 +1,5 @@
#include <git_common.h>
#include <git_api.h>
void check_git2_errors(int error, const char *message, const char *extra) {
@@ -24,3 +25,25 @@ void check_git2_errors(int error, const char *message, const char *extra) {
printf("Git API: %s [%d]%s%s\n", message, error, lg2spacer, lg2msg);
}
}
extern "C" int diff_line_callback_function(const git_diff_delta *delta, const git_diff_hunk *hunk, const git_diff_line *line, void *payload) {
// NULL terminate the line text
char *content = new char[line->content_len + 1];
memcpy(content, line->content, line->content_len);
static int i = 0;
content[line->content_len] = '\0';
godot::String prefix;
switch (line->origin) {
case GIT_DIFF_LINE_ADD_EOFNL:
case GIT_DIFF_LINE_ADDITION: prefix = "+"; break;
case GIT_DIFF_LINE_DEL_EOFNL:
case GIT_DIFF_LINE_DELETION: prefix = "-"; break;
}
godot::GitAPI::get_singleton()->diff_content_container += "\n" + prefix + godot::String(content);
return 0;
}

View File

@@ -7,11 +7,8 @@
void check_git2_errors(int error, const char *message, const char *extra);
extern "C" int diff_line_callback_function(const git_diff_delta *delta, const git_diff_hunk *hunk, const git_diff_line *line, void *payload);
#define GIT2_CALL(function_call, m_error_msg, m_additional_msg) check_git2_errors(function_call, m_error_msg, m_additional_msg);
struct StatusPayload {
git_repository *repo;
};
#endif // !GIT_COMMON_H