Patchwork [3,of,3,V4,RFC] model (2): c-hglib: hg_add() level 1 function

login
register
mail settings
Submitter Iulian Stana
Date Sept. 1, 2013, 6:43 p.m.
Message ID <b0f19995f83af968f61c.1378061003@doppler>
Download mbox | patch
Permalink /patch/2301/
State Superseded
Headers show

Comments

Iulian Stana - Sept. 1, 2013, 6:43 p.m.
# HG changeset patch
# User Iulian Stana <julian.stana@gmail.com>
# Date 1378060042 -10800
#      Sun Sep 01 21:27:22 2013 +0300
# Node ID b0f19995f83af968f61c45eea89ca195d2dbe56f
# Parent  0d7faa1c7ad6bc680fe2bc2cdad0c3becaabd603
model (2): c-hglib: hg_add() level 1 function

This mechanism could be called model (2):

(2) Wait for the commandserv to complete *all* his actions in response to
    the issued command, which is cache the commandserv response somewhere,
    and return the actual exitcode (channel 'r' from commandserv)
    as the result of the chglib API call"


The add command and more other mercurial commands, are not performing any kind
of parse data. The most important thing on those commands is the exitcode, if
everything works well or not.

More than that those commands will have a quickly exit. There is needed a short
time to process them.

But sometimes the command server could send some error or debug data, that
probably the user would like to know about, or to process it.

To handle error data, the mercurial commands will use a callback function passed
by users. In case of passing a NULL pointer the error data will be ignored.

In this case the user will handle errors in his own way.

Patch

diff --git a/client.c b/client.c
--- a/client.c
+++ b/client.c
@@ -17,7 +17,57 @@ 
 #define CHANGESET "\\0{rev}\\n{node}\\n{tags}\\n{branch}\\n{author}\
 						\\n{date|isodate}\\n{desc}"
 
+/* return the output data. */
+char *get_output_data(hg_handle *handle)
+{
+       return handle->out_data;
+}
 
+/* Read and add to some pointers the received data from cmdserver. */
+int runcommand(hg_handle *handle, int (*callback)(const char *msg, size_t len),
+				char *(*prompt)(const char *msg, size_t len))
+{
+	char buff[4096];
+	int exitcode;
+	int ns;
+	char *err = "unexpected data on required channel";
+	char *w_data;
+	while(hg_next_channel(handle) != 'r'){
+		/* output channels 'o', 'e' channels verify in rawread func. */
+		while(ns = hg_rawread(handle, buff, 4096), ns > 0){
+			if(hg_current_channel(handle) == 'o'){
+				char *out = handle->out_data;
+				adding_data(&handle->out_data, buff,
+					(!out)? 0 : handle->out_data_size, ns);
+				handle->out_data_size += ns;
+			}
+			else if(hg_current_channel(handle) == 'e'){
+				if(callback)
+					callback(buff, strlen(buff));
+			}
+		}
+		switch (hg_next_channel(handle)){
+			case 'I':
+				break;
+			case 'L':
+				w_data = prompt(handle->out_data, 
+						strlen(handle->out_data));
+				hg_rawwrite(handle, w_data, strlen(w_data));
+				break;
+			case 'r':
+				break;
+		/* a channel that we don't know and can't ignore*/
+			default:
+				if(callback)
+					callback(err, strlen(err));
+				return 1;
+		}
+	}
+	if(hg_next_channel(handle) == 'r'){
+		exitcode = hg_exitcode(handle);
+	}
+	return exitcode;
+}
 
 /**
  * \brief 'Parse a changeset'. It's more like pointing to the correct position.
@@ -91,6 +141,22 @@ 
 	return new_cset_size;
 }
 
+/* The high level add command for hglib API.*/
+int hg_add(hg_handle *handle, int (*callback)(const char *msg, size_t len), 
+							char *argument[])
+{
+	int exitcode;
+	char **command = cmdbuilder("add", argument, NULL);
+
+	if(hg_rawcommand(handle, command) < 0){
+		return -1;
+	}
+	free(command);
+
+	exitcode = runcommand(handle, callback, NULL);
+
+	return exitcode;
+}
 
 /* The high level log command for hglib API. */
 hg_csetstream_buffer *hg_log(hg_handle *handle, char *option[])
diff --git a/client.h b/client.h
--- a/client.h
+++ b/client.h
@@ -233,6 +233,30 @@ 
  * */
 int hg_exitcode(hg_handle *handle);
 
+/* return the output data. */
+char *get_output_data(hg_handle *handle);
+
+/**
+ * \brief hg_add command for hglib API.
+ *
+ * Add the specified files on the next commit.
+ * If no files are given, add all files to the repository.
+ *
+ *      dryrun - do no perform actions
+ *      subrepos - recurse into subrepositories
+ *      include - include names matching the given patterns
+ *      exclude - exclude names matching the given patterns
+ *
+ * \param handle The handle of the connection, wherewith I want to communicate
+ * \param option The option list for mercurial add command.
+ * \retval exitcode  To indicate the end of add_command.
+ *
+ * errno can be:
+ *      - hg_rawcommand errors
+ * */
+int hg_add(hg_handle *handle, int (*callback)(const char *msg, size_t len), 
+							char *argument[]);
+
 /**
  * \brief hg_log command for hglib API.
  *
diff --git a/main.c b/main.c
--- a/main.c
+++ b/main.c
@@ -89,11 +89,16 @@ 
 {
 	printf("Select test case to run:\n");
 	printf("1) log \n");
+	printf("2) add \n");
 	printf("\n");
 	printf("Your choice: ");
 }
 
-
+int callback(const char *msg, size_t len)
+{
+	printf("message = %s\n", msg);
+	return 1;
+}
 
 /***** Main function. *******/
 /**
@@ -106,7 +111,7 @@ 
 
 	print_select_case();
 	scanf("%d", &select_case);
-	if(select_case < 1 || select_case > 1){
+	if(select_case < 1 || select_case > 2){
 		printf("Your choice is not an option...\n");
 		return -1;
 	}
@@ -122,6 +127,19 @@ 
 			hg_close(&handle);
 			clean_tmp();
 			break;
+		case 2:
+			setup_tmp();
+			
+			system("touch 'foo_bar'");
+
+			handle = hg_open(NULL, "");
+			hg_add(handle, &callback, NULL);
+			char *commit_arg[] = {"-m", "-l", NULL};
+			system("hg st");
+			hg_commit(handle, &callback, commit_arg);
+			hg_close(&handle);
+			clean_tmp();
+			break;
 	}
 
 	return 0;