I've attached a short example of what I am trying to do on in svn for the
benefit of any apr folks who may be able to look at this.
Basically I'm calling the run_pre_revprop_change_hook(), and it's hanging in
apr_file_flush(...) specifically in FlushFileBuffers it seems.
The hook script (shown below), is hanging in getc().
Any ideas why this isn't working?
Note that log.txt never includes anything from stdin.
int main(int argc, char **argv)
{
std::ofstream file("log.txt");
file << "Repos is: " << argv[1] << std::endl;
file << "Rev is: " << argv[2] << std::endl;
file << "Propname is: " << argv[3] << std::endl;
while (!std::cin.eof()) {
std::string s;
std::cin >> s;
file << s << std::endl;
}
file << std::ends;
file.close();
return 0;
}
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kevin Pilch-Bisson
[EMAIL PROTECTED]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~svn_error_t *
svn_io_start_cmd(apr_proc_t *pcmd_proc,
const char *path,
const char *cmd,
const char *const *args,
svn_boolean_t inherit,
apr_file_t *infile,
apr_file_t *outfile,
apr_file_t *errfile,
apr_pool_t *pool)
{
apr_status_t apr_err;
apr_procattr_t *cmdproc_attr;
unsigned int num_args;
const char **args_native;
const char *cmd_native;
/* Create the process attributes. */
apr_err = apr_procattr_create (&cmdproc_attr, pool);
if (apr_err)
return svn_error_createf
(apr_err, 0, NULL, pool,
"svn_io_start_cmd: error creating %s process attributes",
cmd);
/* Make sure we invoke cmd directly, not through a shell. */
apr_err = apr_procattr_cmdtype_set (cmdproc_attr,
inherit?APR_PROGRAM_PATH:APR_PROGRAM);
if (apr_err)
return svn_error_createf
(apr_err, 0, NULL, pool,
"svn_io_start_cmd: error setting %s process cmdtype",
cmd);
/* Set the process's working directory. */
if (path)
{
const char *path_native;
SVN_ERR (svn_utf_cstring_from_utf8 (&path_native, path, pool));
apr_err = apr_procattr_dir_set (cmdproc_attr, path_native);
if (apr_err)
return svn_error_createf
(apr_err, 0, NULL, pool,
"svn_io_start_cmd: error setting %s process directory",
cmd);
}
/* Use requested inputs and outputs.
### Unfortunately each of these apr functions creates a pipe and then
overwrites the pipe file descriptor with the descriptor we pass
in. The pipes can then never be closed. This is an APR bug. */
if (infile)
{
apr_err = apr_procattr_child_in_set (cmdproc_attr, infile, NULL);
if (apr_err)
return svn_error_createf
(apr_err, 0, NULL, pool,
"svn_io_start_cmd: error setting %s process child input",
cmd);
}
if (outfile)
{
apr_err = apr_procattr_child_out_set (cmdproc_attr, outfile, NULL);
if (apr_err)
return svn_error_createf
(apr_err, 0, NULL, pool,
"svn_io_start_cmd: error setting %s process child outfile",
cmd);
}
if (errfile)
{
apr_err = apr_procattr_child_err_set (cmdproc_attr, errfile, NULL);
if (apr_err)
return svn_error_createf
(apr_err, 0, NULL, pool,
"svn_io_start_cmd: error setting %s process child errfile",
cmd);
}
/* Convert cmd and args from UTF-8 */
SVN_ERR (svn_utf_cstring_from_utf8 (&cmd_native, cmd, pool));
for (num_args = 0; args[num_args]; num_args++)
;
args_native = apr_palloc (pool, (num_args + 1) * sizeof(char *));
args_native[num_args] = NULL;
while (num_args--)
{
SVN_ERR (svn_utf_cstring_from_utf8 (&args_native[num_args],
args[num_args],
pool));
}
/* Start the cmd command. */
apr_err = apr_proc_create (pcmd_proc, cmd_native, args_native, NULL,
cmdproc_attr, pool);
if (apr_err)
return svn_error_createf
(apr_err, 0, NULL, pool,
"svn_io_start_cmd: error starting %s process",
cmd);
return SVN_NO_ERROR;
}
svn_error_t *
svn_io_wait_for_cmd(apr_proc_t *cmd_proc,
int *exitcode,
apr_exit_why_e *exitwhy,
apr_pool_t *pool)
{
apr_status_t apr_err;
apr_exit_why_e exitwhy_val;
int exitcode_val;
/* The Win32 apr_proc_wait doesn't set this... */
exitwhy_val = APR_PROC_EXIT;
/* Wait for the cmd command to finish. */
apr_err = apr_proc_wait (cmd_proc, &exitcode_val, &exitwhy_val, APR_WAIT);
if (APR_STATUS_IS_CHILD_NOTDONE (apr_err))
return svn_error_create
(apr_err, 0, NULL, pool,
"svn_io_wait_for_cmd: error waiting for process");
if (exitwhy)
*exitwhy = exitwhy_val;
else if (! APR_PROC_CHECK_EXIT(exitwhy_val))
return svn_error_createf
(SVN_ERR_EXTERNAL_PROGRAM, 0, NULL, pool,
"svn_io_wait_for_cmd: error exitwhy %d for process",
exitwhy_val);
if (exitcode)
*exitcode = exitcode_val;
else if (exitcode_val != 0)
return svn_error_createf
(SVN_ERR_EXTERNAL_PROGRAM, 0, NULL, pool,
"svn_io_wait_for_cmd: error exitcode %d for process",
exitcode_val);
return SVN_NO_ERROR;
}
static svn_error_t *
run_pre_revprop_change_hook (svn_repos_t *repos,
svn_revnum_t rev,
const char *name,
const svn_string_t *value,
apr_pool_t *pool)
{
const char *args[5];
apr_status_t apr_err;
svn_error_t *err;
apr_proc_t cmd_proc;
apr_file_t *read_errhandle, *write_errhandle;
apr_file_t *read_inhandle, *write_inhandle;
apr_exit_why_e exitwhy;
int exitcode;
/* Create a pipe to access stderr of the child. */
apr_err = apr_file_pipe_create(&read_errhandle, &write_errhandle, pool);
if (apr_err)
return svn_error_create
(apr_err, 0, NULL, pool,
"can't create pipe for pre-revprop-change hook");
/* Create a pipe to access stdin of the child. */
apr_err = apr_file_pipe_create(&read_inhandle, &write_inhandle, pool);
if (apr_err)
return svn_error_create
(apr_err, 0, NULL, pool,
"can't create pipe for pre-revprop-change hook");
args[0] = /* hook; */ "C:\\svn\\test\\test-repos\\hooks\\hook.exe";
args[1] = svn_repos_path (repos, pool);
args[2] = apr_psprintf (pool, "%" SVN_REVNUM_T_FMT, rev);
args[3] = name;
args[4] = NULL;
err = svn_io_start_cmd (&cmd_proc, ".", /* "pre-rev-prop-change", */
"C:\\svn\\test\\test-repos\\hooks\\hook.exe",
args, FALSE, read_inhandle, NULL,
write_errhandle, pool);
/* Now the process is running, waiting for the new property value as its
stdin. */
apr_err = apr_file_write_full (write_inhandle, value->data,
value->len, NULL);
if (!err && apr_err)
{
return svn_error_create
(apr_err, 0, NULL, pool,
"can't write new value to pre-rev-prop-change hook");
}
apr_err = apr_file_flush (write_inhandle);
if (!err && apr_err)
return svn_error_create (apr_err, 0, NULL, pool,
"can't flush data to the stdin pipe");
/* Close the write handle so the script gets an eof. */
apr_err = apr_file_close (write_inhandle);
if (!err && apr_err)
return svn_error_create (apr_err, 0, NULL, pool,
"can't close write end of stdin pipe");
if (!err)
err = svn_io_wait_for_cmd (&cmd_proc, &exitcode, &exitwhy, pool);
/* Clean up all the pipes, except the one we read stderr from. */
apr_err = apr_file_close (read_inhandle);
if (!err && apr_err)
return svn_error_create (apr_err, 0, NULL, pool,
"can't close read end of stdin pipe");
apr_err = apr_file_close (write_errhandle);
if (!err && apr_err)
return svn_error_create (apr_err, 0, NULL, pool,
"can't close write end of stderr pipe");
/* Function failed. */
if (err)
{
err = svn_error_create
(SVN_ERR_REPOS_HOOK_FAILURE, 0, err, pool,
"failed to run pre-rev-prop-change hook");
}
if (!err)
{
/* Command failed. */
if (! APR_PROC_CHECK_EXIT (exitwhy) || exitcode != 0)
{
svn_stringbuf_t *error;
/* Read the file's contents into a stringbuf, allocated in POOL.*/
SVN_ERR (svn_string_from_aprfile (&error, read_errhandle, pool));
err = svn_error_createf
(SVN_ERR_REPOS_HOOK_FAILURE, 0, err, pool,
"%s hook failed with error output:\n%s",
name, error->data);
}
}
/* Hooks are falible, and so hook failure is "expected" to occur at
times. When such a failure happens we still want to close the pipe */
apr_err = apr_file_close(read_errhandle);
if (!err && apr_err)
return svn_error_create
(apr_err, 0, NULL, pool,
"can't close read end of stderr pipe");
return err;
}