Initial checkin of ra_pipe stub generation system. Still needs lots of work. * build/ra.idl Initial checkin. * build/gen-pipe.py Initial checkin. git-svn-id: https://svn.apache.org/repos/asf/subversion/branches/ra-pipe-dev@843774 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/build/gen-pipe.py b/build/gen-pipe.py new file mode 100755 index 0000000..7c20bd2 --- /dev/null +++ b/build/gen-pipe.py
@@ -0,0 +1,401 @@ +#!/usr/bin/env python2 +# +# gen-pipe.py -- generate pipe client/server stubs +# +# USAGE: +# gen-pipe.py IDL-FILE CLIENT-HEADER CLIENT-IMPL SERVER-HEADER SERVER-IMPL +# + +import os, sys +import ConfigParser + + +def indent(l,n=2): + return map(lambda x: " "*n + x, l) + +class Callable: + def __init__(self, callable): + self.__call__ = callable + +class Type: + types = {} + + def for_name(parser, name): + return Type.types.setdefault(name,Type(parser,name)) + for_name = Callable(for_name) + + def __init__(self, parser, name): + self.array = 0 + if name.endswith("[]"): + name = name[0:len(name)-2] + self.array = 1 + if name not in parser.options('types'): + print 'Missing type definition: ' + name + sys.exit(1) + self.name = name + self.type = parser.get('types', name) + + def __str__(self): + if not self.array: + return self.type + return self.type + "*"*self.array + + def __func_suffix(self): + if self.array: + return self.name + "_array" + return self.name + + def marshall(self): + return "svn_pipe_marshall_" + self.__func_suffix() + + def unmarshall(self): + return "svn_pipe_unmarshall_" + self.__func_suffix() + + + +class Param: + def __init__(self, name, type): + self.name = name + self.type = type + + def decl(self, out): + t = str(self.type) + s = "" + if not t.endswith("*"): + s += " " + if out: + s += "*" + return "".join([ + t, + s, + self.name + ]); + + def in_decl(self): + return self.decl(0) + + def out_decl(self): + return self.decl(1) + + def marshall(self, var): + return self.type.marshall() + "(" + self.name + ", &" + var + ")"; + + def unmarshall(self, var, ref): + s = ref and "&" or "" + return self.type.unmarshall() + "(" + var + ", " + s + self.name + ")"; + +class Func: + functions = {} + + def for_name(parser, name, type): + if name in Func.functions: + f = Func.functions[name] + return Func.functions[name] + return Func(parser, name, type) + for_name = Callable(for_name) + + def funcs(): + return Func.functions.values() + funcs = Callable(funcs) + + def methods(): + return [x for x in Func.funcs() if not x.type] + methods = Callable(methods) + + def callbacks(): + return [x for x in Func.funcs() if x.type] + callbacks = Callable(callbacks) + + + def __init__(self, parser, name, type): + if not parser.has_section(name): + print 'Missing method definition: ' + name + sys.exit(1) + Func.functions[name]=self + self.name = name + self.type = type + self.ins = [] + self.outs = [] + self.cbs = [] + self.__params(parser, 'in', self.ins) + self.__params(parser, 'out', self.outs) + if parser.has_option(name, 'callbacks'): + self.cbs = map(lambda x: + Func.for_name(parser, + x, + 1), + parser.get(name, 'callbacks').split()) + + def __params(self, parser, option, params): + if not parser.has_option(self.name, option): + return + for param in parser.get(self.name, option).split(): + idx = param.find(")") + if idx == -1: + type = param + name = param + else: + type = param[1:idx] + name = param[idx+1:] + p = Param(name,Type.for_name(parser, type)) + params.append(p) + + + def add_cb_param(self, param): + return self.add_param(param, "CB_ERR") + + def add_param(self, param, err = "METHOD_ERR"): + return [ + err + "("+param.marshall("xmlrpc_value")+");", + "XMLRPC_SetValueID(xmlrpc_value,", + ' "' + param.name + '",', + " " + str(len(param.name)) + ');', + "XMLRPC_AddValueToVector(parameters, xmlrpc_value);" + ] + + def get_cb_param(self, param): + return self.get_param(param, 1, "CB_ERR") + + def get_param(self, param, ref=0, err="METHOD_ERR"): + return [ + 'xmlrpc_value = XMLRPC_VectorGetValueWithID(parameters, "' + param.name + '");', + err + "("+param.unmarshall("xmlrpc_value", ref)+");", + "XMLRPC_CleanupValue(xmlrpc_value);" + ] + + def register(self, callback): + return [ + 'XMLRPC_ServerRegisterMethod(server,', + ' "' + callback.name + '",', + ' ' + callback.name + '_callback);' + ] + + def call(self): + s = ",\n" + " "*(len(self.name)+10) + p = ["userdata"] + \ + map(lambda x: x.name, self.ins) + \ + map(lambda x: "&"+x.name, self.outs) + return " CB_ERR(" + self.name + "(" + s.join(p) + "));" + + def callback_impl(self): + lines = [ + "static XMLRPC_VALUE", + self.name+"_callback(XMLRPC_SERVER server,", + " XMLRPC_REQUEST request,", + " void *userdata)", + "{", + " XMLRPC_VALUE parameters;", + " XMLRPC_VALUE xmlrpc_value;", + ""] + lines += indent(map(lambda x: x.in_decl() + ";", self.ins + self.outs)) + lines += [""] + lines += indent(reduce(list.__add__, + map(self.get_cb_param, self.ins), + [])) + lines += [" XMLRPC_CleanupValue(parameters);", + ""] + lines.append(self.call()) + lines += ["", + ' parameters = XMLRPC_CreateVector("parameters",', + " xmlrpc_vector_struct);"] + lines += indent(reduce(list.__add__, + map(self.add_cb_param, self.outs), + [])) + lines += [ + " return parameters;", + "}", + ""] + return "\n".join(lines) + + def client_impl(self): + lines = [ + self.header(), + "{", + " XMLRPC_SERVER server;", + " XMLRPC_REQUEST request;", + " XMLRPC_REQUEST response;", + " XMLRPC_VALUE parameters;", + " XMLRPC_VALUE xmlrpc_value;", + " STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS output;", + " char *buffer;", + " int len;", + " apr_size_t size;", + "", + " request = XMLRPC_RequestNew();", + ' XMLRPC_RequestSetMethodName(request, "' + self.name + '");', + " XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);", + "", + " memset(&output, 0, sizeof(output));", + " output.version = xmlrpc_version_1_0;", + " XMLRPC_RequestSetOutputOptions(request, &output);", + "", + ' parameters = XMLRPC_CreateVector("parameters",', + " xmlrpc_vector_struct);", + " XMLRPC_RequestSetData(request, parameters);", + ""] + + lines += indent(reduce(list.__add__, + map(self.add_param, self.ins), + [])) + + if self.cbs: + lines.append(" server = XMLRPC_ServerCreate();") + lines += indent(reduce(list.__add__, + map(self.register, self.cbs), + [])); + lines += [ + "", + " for (;;)", + " {", + " buffer = XMLRPC_REQUEST_ToXML(request, &len);", + " if (!buffer) /* !!! */", + " abort();", + " METHOD_ERR(svn_pipe_send(pipe, buffer, len, pool));", + " XMLRPC_FreeRequest(request, 1);", + "" + " METHOD_ERR(svn_pipe_receive(pipe, &buffer, &size, pool));", + " response = XMLRPC_REQUEST_FromXML(buffer, size, NULL);", + " if (!response) /* !!! */", + " abort();", + " if (XMLRPC_RequestGetRequestType(response) !=", + " xmlrpc_request_call)", + " break;"] + + if self.cbs: + lines += [ + " xmlrpc_value = XMLRPC_ServerCallMethod(server, response, userdata);", + " XMLRPC_FreeRequest(response, 1);", + " request = XMLRPC_RequestNew();", + " XMLRPC_RequestSetData(request, xmlrpc_value);", + " XMLRPC_RequestSetRequestType(request, xmlrpc_request_response);", + " XMLRPC_RequestSetOutputOptions(request, &output);" + ] + else: + lines += [ + " /* !!! */", + " abort();"] + + lines += [ + " }", + ""] + lines += indent(reduce(list.__add__, + map(self.get_param, self.outs), + [])) + if self.cbs: + lines.append(' XMLRPC_ServerFree(server);') + + lines += [ + " XMLRPC_RequestFree(response, 1);", + " return SVN_NO_ERROR;", + "}", + ""] + return "\n".join(lines) + + def static_proto(self): + return "static " + self.proto() + + def proto(self): + return self.header() + ";\n" + + def paramlist(self): + return map(lambda x: x.in_decl(), self.ins) + \ + map(lambda x: x.out_decl(), self.outs) + + def header(self, method=0): + s = " "*(len(self.name)+1) + p = [] + p.append("svn_pipe_t *pipe") + p.append("void *userdata") + p.extend(map(lambda x: x.in_decl(), self.ins)) + p.extend(map(lambda x: x.out_decl(), self.outs)) + p.append("apr_pool_t *pool") + return "svn_error_t *\n" + \ + self.name + "(" + \ + (",\n"+s).join(p) + ")" + + +def footer(): + return "\n".join([ + '', + '/* ----------------------------------------------------------------', + ' * local variables:', + ' * eval: (load-file "../../tools/dev/svn-dev.el")', + ' * end:', + ' */', + '']) + +def client_header(): + return "\n".join([ + "/* DO NOT EDIT -- AUTOMATICALLY GENERATED */", + "#ifndef __SVN_PIPE_PROTO_H__", + "#define __SVN_PIPE_PROTO_H__", + "", + "#ifdef __cplusplus", + 'extern "C" {', + "#endif /* __cplusplus */", + "", + "\n".join(map(lambda x: x.proto(), Func.methods())), + "", + "#ifdef __cplusplus", + "}", + "#endif /* __cplusplus */", + "", + "#endif /* __SVN_SVNPIPE_PIPE_CLIENT_H__ */", + footer()]) + +def client_impl(): + return "\n".join([ + '#include "xmlrpc.h"', + '', + '#include "svn_pipe.h"', + '#include "svn_error.h"', + '#include "svn_types.h"', + '#include "svn_string.h"', + '#include "svn_pipe_proto.h"', + "", + "\n".join(map(lambda x: x.callback_impl(), Func.callbacks())), + "", + "\n".join(map(lambda x: x.client_impl(), Func.methods())), + footer()]) + +def main(idl, client_h, client_c, server_h, server_c): + parser = ConfigParser.ConfigParser() + parser.read(idl) + + for name in parser.get('methods', 'names').split(): + Func.for_name(parser, name, 0) + + for name in parser.get('callbacks', 'names').split(): + callback = Func.for_name(parser, name, 1) + for f in Func.methods(): + f.cbs.append(callback) + + fd = open(client_h,"w") + fd.write(client_header()) + fd.close() + + fd = open(client_c,"w") + fd.write(client_impl()) + fd.close() + +# server_h = open("pipe_server.h", "w") +# write_server_h(server_h) +# server_h.close() + +# server_c = open("pipe_server.c", "w") +# write_server_c(server_c) +# server_c.close() + +if __name__ == '__main__': + argc = len(sys.argv) + + if argc != 6 : + print "usage: gen-pipe.py IDL-FILE CLIENT-HEADER CLIENT-IMPL SERVER-HEADER SERVER-IMPL\n" + sys.exit(1) + + main(*sys.argv[1:]) + +### End of file. +# local variables: +# eval: (load-file "../../tools/dev/svn-dev.el") +# end:
diff --git a/build/ra.idl b/build/ra.idl new file mode 100644 index 0000000..c420de2 --- /dev/null +++ b/build/ra.idl
@@ -0,0 +1,154 @@ +[types] +string = char * +revision = svn_revnum_t +time = apr_time_t +hash = apr_hash_t * +boolean = svn_boolean_t +blob = svn_string_t * +integer = int + + +[callbacks] +names = open_tmp_file + append_stream + get_authenticator + get_committed_rev + get_wc_prop + set_wc_prop + +[get_authenticator] +in = (integer)method +out = (integer)authenticator + (integer)baton + +[open_tmp_file] +out = (integer)baton + +[append_stream] +in = (integer)baton + blob + +[get_committed_rev] +in = (string)relpath +out = (revision)rev + +[get_wc_prop] +in = (string)relpath + (string)name +out = (blob)value + +[set_wc_prop] +in = (string)path + (string)name + (blob)value + + +[methods] +names = open + close + get_latest_revnum + get_dated_revision + get_file + get_dir + get_log + +[open] +in = (string)repos_URL + +[close] + +[get_latest_revnum] +out = (revision)latest_revnum + +[get_dated_revision] +in = (time)tm +out = revision + +#svn_error_t *(*get_commit_editor) (void *session_baton, +# const svn_delta_editor_t **editor, +# void **edit_baton, +# svn_revnum_t *new_rev, +# const char **committed_date, +# const char **committed_author, +# const char *log_msg); + +[get_file] +in = (integer)baton + (string)path + revision + (integer)stream +out = (revision)fetched_rev + (hash)props + +[get_dir] +in = (integer)baton + (string)path + revision +out = (hash)dirents + (revision)fetched_rev + (hash)props + +#svn_error_t *(*do_checkout) (void *session_baton, +# svn_revnum_t revision, +# svn_boolean_t recurse, +# const svn_delta_editor_t *editor, +# void *edit_baton); +# +#svn_error_t *(*do_update) (void *session_baton, +# const svn_ra_reporter_t **reporter, +# void **report_baton, +# svn_revnum_t revision_to_update_to, +# const char *update_target, +# svn_boolean_t recurse, +# const svn_delta_edit_fns_t *update_editor, +# void *update_baton); +# +#svn_error_t *(*do_switch) (void *session_baton, +# const svn_ra_reporter_t **reporter, +# void **report_baton, +# svn_revnum_t revision_to_update_to, +# const char *update_target, +# svn_boolean_t recurse, +# const char *switch_url, +# const svn_delta_edit_fns_t *update_editor, +# void *update_baton); +# +#svn_error_t *(*do_status) (void *session_baton, +# const svn_ra_reporter_t **reporter, +# void **report_baton, +# const char *status_target, +# svn_boolean_t recurse, +# const svn_delta_edit_fns_t *status_editor, +# void *status_baton); +# +#svn_error_t *(*do_diff) (void *session_baton, +# const svn_ra_reporter_t **reporter, +# void **report_baton, +# svn_revnum_t revision, +# const char *diff_target, +# svn_boolean_t recurse, +# const char *versus_url, +# const svn_delta_edit_fns_t *diff_editor, +# void *diff_baton); + +[get_log] +in = (integer)baton + (string[])paths + (revision)start + (revision)end + (boolean)discover_changed_paths + (boolean)strict_node_history +callbacks = add_message + +[add_message] +in = (hash)changed_paths + revision + (string)author + (string)date + (string)message + +[check_path] +in = (integer)baton + (string)path + revision +out = kind