diff options
| author | 2011-03-23 19:57:43 (JST) | |
|---|---|---|
| committer | 2011-03-26 19:03:42 (JST) | |
| commit | 14f28923a2ed31fba9bf7042e8e2dff21717c333 (patch) | |
| tree | e3943ff98a2a59f4503e96bbc4ea135d80aa8c81 | |
| parent | d87bba846d368e560193a1f75de6d66bffe986cf (diff) | |
| download | cgit-14f28923a2ed31fba9bf7042e8e2dff21717c333.zip cgit-14f28923a2ed31fba9bf7042e8e2dff21717c333.tar.gz | |
cgit_open_filter: hand down repo configuration to script
The environment variables can be used to (for example) resolve
the following situation:
Suppose a server setup in which each repository has a trac
instance; the commit filter needs to know with which
repository it's dealing in order to be able to resolve the
#123 ticket numbers in the commit messages into hyperlinks
into the correct trac instance.
Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
| -rw-r--r-- | shared.c | 78 |
1 files changed, 77 insertions, 1 deletions
| @@ -7,6 +7,8 @@ | |||
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include "cgit.h" | 9 | #include "cgit.h" |
| 10 | #include <stdio.h> | ||
| 11 | #include <linux/limits.h> | ||
| 10 | 12 | ||
| 11 | struct cgit_repolist cgit_repolist; | 13 | struct cgit_repolist cgit_repolist; |
| 12 | struct cgit_context ctx; | 14 | struct cgit_context ctx; |
| @@ -376,6 +378,70 @@ int cgit_parse_snapshots_mask(const char *str) | |||
| 376 | return rv; | 378 | return rv; |
| 377 | } | 379 | } |
| 378 | 380 | ||
| 381 | typedef struct { | ||
| 382 | char * name; | ||
| 383 | char * value; | ||
| 384 | } cgit_env_var; | ||
| 385 | |||
| 386 | static char * prepare_env(struct cgit_repo * repo) { | ||
| 387 | cgit_env_var env_vars[] = { | ||
| 388 | { .name = "CGIT_REPO_URL", .value = repo->url }, | ||
| 389 | { .name = "CGIT_REPO_NAME", .value = repo->name }, | ||
| 390 | { .name = "CGIT_REPO_PATH", .value = repo->path }, | ||
| 391 | { .name = "CGIT_REPO_OWNER", .value = repo->owner }, | ||
| 392 | { .name = "CGIT_REPO_DEFBRANCH", .value = repo->defbranch }, | ||
| 393 | { .name = "CGIT_REPO_SECTION", .value = repo->section }, | ||
| 394 | { .name = "CGIT_REPO_CLONE_URL", .value = repo->clone_url } | ||
| 395 | }; | ||
| 396 | int env_var_count = ARRAY_SIZE(env_vars); | ||
| 397 | long values_space = (env_var_count * (PATH_MAX + 64)); | ||
| 398 | |||
| 399 | void * buffer; | ||
| 400 | char ** vars; | ||
| 401 | char * values; | ||
| 402 | int vars_index = 0; | ||
| 403 | unsigned int chars_printed; | ||
| 404 | |||
| 405 | /* Allocate buffer for environment variables: first in the buffer is an | ||
| 406 | * array of pointers to argument strings, terminated with a NULL pointer. | ||
| 407 | * After that the argument strings are placed after each other */ | ||
| 408 | buffer = malloc(((env_var_count + 1) * sizeof(char *)) + values_space); | ||
| 409 | if (!buffer) | ||
| 410 | return NULL; | ||
| 411 | |||
| 412 | vars = buffer; | ||
| 413 | values = (char *) &vars[env_var_count + 1]; | ||
| 414 | |||
| 415 | /* loop over all defined environment variables and their values */ | ||
| 416 | while (vars_index < env_var_count) { | ||
| 417 | char * name = env_vars[vars_index].name; | ||
| 418 | char * value = env_vars[vars_index].value; | ||
| 419 | |||
| 420 | if (!value) | ||
| 421 | value = ""; | ||
| 422 | |||
| 423 | chars_printed = snprintf(values, (values_space - 1), "%s=%s", name, | ||
| 424 | value); | ||
| 425 | if (chars_printed > (values_space - 1)) { | ||
| 426 | /* Buffer space exhausted: stop adding variables. | ||
| 427 | * Not all environment variables are defined, but the best we can | ||
| 428 | * do is to provide the ones that _are_ defined */ | ||
| 429 | break; | ||
| 430 | } | ||
| 431 | |||
| 432 | values[chars_printed] = '\0'; | ||
| 433 | *&vars[vars_index] = values; | ||
| 434 | values += (chars_printed + 1); | ||
| 435 | values_space -= (chars_printed + 1); | ||
| 436 | vars_index++; | ||
| 437 | } | ||
| 438 | |||
| 439 | /* terminate the array with pointers */ | ||
| 440 | *&vars[vars_index] = NULL; | ||
| 441 | |||
| 442 | return (char *) buffer; | ||
| 443 | } | ||
| 444 | |||
| 379 | int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo) | 445 | int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo) |
| 380 | { | 446 | { |
| 381 | 447 | ||
| @@ -384,10 +450,20 @@ int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo) | |||
| 384 | chk_zero(pipe(filter->pipe_fh), "Unable to create pipe to subprocess"); | 450 | chk_zero(pipe(filter->pipe_fh), "Unable to create pipe to subprocess"); |
| 385 | filter->pid = chk_non_negative(fork(), "Unable to create subprocess"); | 451 | filter->pid = chk_non_negative(fork(), "Unable to create subprocess"); |
| 386 | if (filter->pid == 0) { | 452 | if (filter->pid == 0) { |
| 453 | char * env = NULL; | ||
| 454 | |||
| 387 | close(filter->pipe_fh[1]); | 455 | close(filter->pipe_fh[1]); |
| 388 | chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO), | 456 | chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO), |
| 389 | "Unable to use pipe as STDIN"); | 457 | "Unable to use pipe as STDIN"); |
| 390 | execvp(filter->cmd, filter->argv); | 458 | |
| 459 | if (repo) | ||
| 460 | env = prepare_env(repo); | ||
| 461 | |||
| 462 | execve(filter->cmd, filter->argv, (char **)env); | ||
| 463 | |||
| 464 | if (env) | ||
| 465 | free(env); | ||
| 466 | |||
| 391 | die("Unable to exec subprocess %s: %s (%d)", filter->cmd, | 467 | die("Unable to exec subprocess %s: %s (%d)", filter->cmd, |
| 392 | strerror(errno), errno); | 468 | strerror(errno), errno); |
| 393 | } | 469 | } |
