mirror of
https://github.com/radareorg/radare2.git
synced 2024-11-27 23:20:40 +00:00
303 lines
6.7 KiB
C
303 lines
6.7 KiB
C
/* radare - LGPL - Copyright 2021-2023 - RHL120, pancake */
|
|
// GIT commands as APIs
|
|
#define R_LOG_ORIGIN "vc.git"
|
|
#include <rvc.h>
|
|
|
|
extern const RvcPlugin r_vc_plugin_git;
|
|
|
|
static Rvc *open_git(const char *path) {
|
|
char *git_path = r_file_new (path, ".git", NULL);
|
|
if (!git_path || !r_file_is_directory (git_path)) {
|
|
char *escpath = r_str_escape (path);
|
|
int ret = r_sys_cmdf ("git init \"%s\" > /dev/null", escpath);
|
|
if (ret != 0) {
|
|
R_LOG_WARN ("git init failed");
|
|
}
|
|
if (!r_file_is_directory (git_path)) {
|
|
free (git_path);
|
|
return NULL;
|
|
}
|
|
}
|
|
free (git_path);
|
|
Rvc *vc = R_NEW (Rvc);
|
|
if (!vc) {
|
|
return NULL;
|
|
}
|
|
vc->path = r_str_new (path);
|
|
if (!vc->path) {
|
|
free (vc);
|
|
return NULL;
|
|
}
|
|
vc->db = NULL;
|
|
vc->p = &r_vc_plugin_git;
|
|
return vc;
|
|
}
|
|
|
|
static bool _git_branch(Rvc *vc, const char *name) {
|
|
char *escpath = r_str_escape (vc->path);
|
|
if (!escpath) {
|
|
return false;
|
|
}
|
|
char *escname = r_str_escape (name);
|
|
if (!escname) {
|
|
free (escpath);
|
|
return false;
|
|
}
|
|
int ret = r_sys_cmdf ("git -C \"%s\" branch \"%s\"", escpath, escname);
|
|
free (escpath);
|
|
free (escname);
|
|
return !ret;
|
|
}
|
|
|
|
static bool checkout_git(Rvc *vc, const char *name) {
|
|
char *escpath = r_str_escape (vc->path);
|
|
char *escname = r_str_escape (name);
|
|
int ret = r_sys_cmdf ("git -C \"%s\" checkout \"%s\"", escpath, escname);
|
|
free (escname);
|
|
free (escpath);
|
|
return !ret;
|
|
}
|
|
|
|
static bool add_git(Rvc *vc, const RList *files) {
|
|
RListIter *iter;
|
|
const char *fname;
|
|
char *cwd = r_sys_getdir ();
|
|
if (!cwd) {
|
|
return false;
|
|
}
|
|
if (!r_sys_chdir (vc->path)) {
|
|
free (cwd);
|
|
return false;
|
|
}
|
|
bool ret = true;
|
|
r_list_foreach (files, iter, fname) {
|
|
char *escfname = r_str_escape (fname);
|
|
if (!escfname) {
|
|
ret = false;
|
|
break;
|
|
}
|
|
ret &= !r_sys_cmdf ("git add \"%s\"", escfname);
|
|
free (escfname);
|
|
}
|
|
if (!r_sys_chdir (cwd)) {
|
|
free (cwd);
|
|
return false;
|
|
}
|
|
free (cwd);
|
|
return ret;
|
|
}
|
|
|
|
static bool commit_git(Rvc *vc, const char *_message, const char *author, const RList *files) {
|
|
char *message = _message? strdup (_message): NULL;
|
|
if (!add_git (vc, files)) {
|
|
return false;
|
|
}
|
|
char *escauth;
|
|
if (!author) {
|
|
char *user = r_sys_whoami ();
|
|
escauth = r_str_escape (user);
|
|
free (user);
|
|
} else {
|
|
escauth = r_str_escape (author);
|
|
}
|
|
if (!escauth) {
|
|
return false;
|
|
}
|
|
if (R_STR_ISEMPTY (message)) {
|
|
R_FREE (message);
|
|
message = strdup ("default message");
|
|
}
|
|
if (R_STR_ISEMPTY (message)) {
|
|
R_FREE (message);
|
|
char *epath = r_str_escape (vc->path);
|
|
if (epath) {
|
|
// XXX ensure CWD in the same line?
|
|
int res = r_sys_cmdf ("git -C \"%s\" commit --author \"%s <%s@localhost>\"", epath, escauth, escauth);
|
|
free (escauth);
|
|
free (epath);
|
|
return res == 0;
|
|
}
|
|
return false;
|
|
}
|
|
char *epath = r_str_escape (vc->path);
|
|
if (epath) {
|
|
char *emsg = r_str_escape (message);
|
|
if (emsg) {
|
|
int res = r_sys_cmdf ("git -C \"%s\" commit -m \"%s\" --author \"%s <%s@localhost>\"",
|
|
epath, emsg, escauth, escauth);
|
|
free (escauth);
|
|
free (message);
|
|
free (epath);
|
|
free (emsg);
|
|
return res == 0;
|
|
}
|
|
}
|
|
free (message);
|
|
return false;
|
|
}
|
|
|
|
#if 0
|
|
R_API RList *rvc_git_get_branches(Rvc *rvc) {
|
|
r_return_val_if_fail (rvc, NULL);
|
|
return rvc->p->get_branches (rvc);
|
|
}
|
|
|
|
static bool XXX_git_commit(Rvc *rvc, const char *message, const char *author, const RList *files) {
|
|
r_return_val_if_fail (rvc && message && author && files, false);
|
|
if (rvc->p->type == RVC_TYPE_RVC) {
|
|
#if 0
|
|
author = author? author : r_config_get (core->config, "cfg.user");
|
|
#endif
|
|
r_vc_commit (rvc, message, author, files);
|
|
return rvc_save (rvc);
|
|
}
|
|
return r_vc_git_commit (rvc, message, author, files);
|
|
}
|
|
#endif
|
|
|
|
#if 0
|
|
R_API bool r_vc_git_repo_exists(const RCore *core, const char *path) {
|
|
char *frp = !strcmp (r_config_get (core->config, "prj.vc.type"), "rvc")?
|
|
r_file_new (path, ".rvc", NULL):
|
|
r_file_new (path, ".git", NULL);
|
|
if (frp) {
|
|
bool ret = r_file_is_directory (frp);
|
|
free (frp);
|
|
return ret;
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
R_API RList *branches_git(Rvc *rvc) {
|
|
RList *ret = NULL;
|
|
char *esc_path = r_str_escape (rvc->path);
|
|
if (esc_path) {
|
|
char *output = r_sys_cmd_strf ("git -C %s branch --color=never", esc_path);
|
|
r_str_trim (output);
|
|
free (esc_path);
|
|
if (!R_STR_ISEMPTY (output)) {
|
|
ret = r_str_split_duplist (output, "\n", true);
|
|
RListIter *iter;
|
|
char *name;
|
|
r_list_foreach (ret, iter, name) {
|
|
if (*(char *)iter->data == '*') {
|
|
iter->data = r_str_new (name + 2);
|
|
free (name);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static RList *uncommited_git(Rvc *rvc) {
|
|
RList *ret = NULL;
|
|
char *esc_path = r_str_escape (rvc->path);
|
|
if (esc_path) {
|
|
char *output = r_sys_cmd_strf ("git -C %s status --short",
|
|
esc_path);
|
|
free (esc_path);
|
|
if (!R_STR_ISEMPTY (output)) {
|
|
r_str_trim(output);
|
|
ret = r_str_split_duplist (output, "\n", true);
|
|
free (output);
|
|
RListIter *iter;
|
|
char *i;
|
|
r_list_foreach (ret, iter, i) {
|
|
//after we add one to the output, there maybe
|
|
//a space so trim that
|
|
char *ni = r_str_trim_dup (i + 2);
|
|
if (!ni) {
|
|
r_list_free (ret);
|
|
ret = NULL;
|
|
break;
|
|
}
|
|
free (i);
|
|
iter->data = ni;
|
|
}
|
|
} else {
|
|
ret = r_list_new ();
|
|
}
|
|
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static bool log_git(Rvc *rvc) {
|
|
bool ret = true;
|
|
char *esc_path = r_str_escape (rvc->path);
|
|
if (esc_path) {
|
|
ret = !r_sys_cmdf ("git -C %s log", esc_path);
|
|
free (esc_path);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
R_API char *curbranch_git(Rvc *rvc) {
|
|
char *ret = NULL;
|
|
char *esc_path = r_str_escape (rvc->path);
|
|
if (esc_path) {
|
|
char *branch = r_sys_cmd_strf ("git -C %s rev-parse --abbrev-ref HEAD", esc_path);
|
|
if (!R_STR_ISEMPTY (branch)) {
|
|
ret = r_str_ndup (branch, strlen (branch) - 1);
|
|
}
|
|
free (branch);
|
|
free (esc_path);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static bool reset_git(Rvc *rvc) {
|
|
char *esc_path = r_str_escape (rvc->path);
|
|
if (esc_path) {
|
|
bool ret = r_sys_cmdf ("git -C %s checkout .", esc_path);
|
|
free (esc_path);
|
|
return !ret;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool clone_git(const Rvc *rvc, const char *dst) {
|
|
char *esc_src = r_str_escape (rvc->path);
|
|
char *esc_dst = r_str_escape (dst);
|
|
bool ret = false;
|
|
if (esc_src && esc_dst) {
|
|
ret = !r_sys_cmdf ("git clone %s %s", esc_src, esc_dst);
|
|
}
|
|
free (esc_src);
|
|
free (esc_dst);
|
|
return ret;
|
|
}
|
|
|
|
static void close_git(Rvc *vc, bool save) {
|
|
if (vc) {
|
|
free (vc->path);
|
|
free (vc);
|
|
}
|
|
}
|
|
|
|
R_API bool save_git(Rvc *vc) {
|
|
//do nothing, since git commands are automatically executed
|
|
return true;
|
|
}
|
|
|
|
const RvcPlugin r_vc_plugin_git = {
|
|
.name = "git",
|
|
.type = RVC_TYPE_GIT,
|
|
.commit = commit_git,
|
|
.branch = _git_branch,
|
|
.checkout = checkout_git,
|
|
.branches = branches_git,
|
|
.uncommited = uncommited_git,
|
|
.log = log_git,
|
|
.curbranch = curbranch_git,
|
|
.reset = reset_git,
|
|
.clone = clone_git,
|
|
.close = close_git,
|
|
.save = save_git,
|
|
// .init = init_git,
|
|
.open = open_git,
|
|
};
|