Ejemplo n.º 1
0
static int parse_patch_hunks(
	git_patch_parsed *patch,
	git_patch_parse_ctx *ctx)
{
	git_patch_hunk *hunk;
	int error = 0;

	while (git_parse_ctx_contains_s(&ctx->parse_ctx, "@@ -")) {
		hunk = git_array_alloc(patch->base.hunks);
		GITERR_CHECK_ALLOC(hunk);

		memset(hunk, 0, sizeof(git_patch_hunk));

		hunk->line_start = git_array_size(patch->base.lines);
		hunk->line_count = 0;

		if ((error = parse_hunk_header(hunk, ctx)) < 0 ||
			(error = parse_hunk_body(patch, hunk, ctx)) < 0)
			goto done;
	}

	patch->base.delta->flags |= GIT_DIFF_FLAG_NOT_BINARY;

done:
	return error;
}
Ejemplo n.º 2
0
static int mark_uninteresting(git_revwalk *walk, git_commit_list_node *commit)
{
	int error;
	unsigned short i;
	git_array_t(git_commit_list_node *) pending = GIT_ARRAY_INIT;
	git_commit_list_node **tmp;

	assert(commit);

	do {
		commit->uninteresting = 1;

		if ((error = git_commit_list_parse(walk, commit)) < 0)
			return error;

		for (i = 0; i < commit->out_degree; ++i)
			if (!commit->parents[i]->uninteresting) {
				git_commit_list_node **node = git_array_alloc(pending);
				GITERR_CHECK_ALLOC(node);
				*node = commit->parents[i];
			}

		tmp = git_array_pop(pending);
		commit = tmp ? *tmp : NULL;

	} while (commit != NULL);

	git_array_clear(pending);

	return 0;
}
Ejemplo n.º 3
0
static int rebase_open_merge(git_rebase *rebase)
{
	git_buf state_path = GIT_BUF_INIT, buf = GIT_BUF_INIT, cmt = GIT_BUF_INIT;
	git_oid current_id = {{0}};
	git_rebase_operation *operation;
	size_t i, msgnum = 0, end;
	int error;

	if ((error = git_buf_puts(&state_path, rebase->state_path)) < 0)
		goto done;

	/* Read 'msgnum' if it exists (otherwise, let msgnum = 0) */
	if ((error = rebase_readint(&msgnum, &buf, &state_path, MSGNUM_FILE)) < 0 &&
		error != GIT_ENOTFOUND)
		goto done;

	if (msgnum) {
		rebase->started = 1;
		rebase->current = msgnum - 1;
	}

	/* Read 'end' */
	if ((error = rebase_readint(&end, &buf, &state_path, END_FILE)) < 0)
		goto done;

	/* Read 'current' if it exists */
	if ((error = rebase_readoid(&current_id, &buf, &state_path, CURRENT_FILE)) < 0 &&
		error != GIT_ENOTFOUND)
		goto done;

	/* Read cmt.* */
	git_array_init_to_size(rebase->operations, end);
	GITERR_CHECK_ARRAY(rebase->operations);

	for (i = 0; i < end; i++) {
		operation = git_array_alloc(rebase->operations);
		GITERR_CHECK_ALLOC(operation);

		git_buf_clear(&cmt);

		if ((error = git_buf_printf(&cmt, "cmt.%" PRIuZ, (i+1))) < 0 ||
			(error = rebase_readoid((git_oid *)&operation->id, &buf, &state_path, cmt.ptr)) < 0)
			goto done;
	}

	/* Read 'onto_name' */
	if ((error = rebase_readfile(&buf, &state_path, ONTO_NAME_FILE)) < 0)
		goto done;

	rebase->onto_name = git_buf_detach(&buf);

done:
	git_buf_free(&cmt);
	git_buf_free(&state_path);
	git_buf_free(&buf);

	return error;
}
Ejemplo n.º 4
0
static int rebase_init_operations(
	git_rebase *rebase,
	git_repository *repo,
	const git_annotated_commit *branch,
	const git_annotated_commit *upstream,
	const git_annotated_commit *onto)
{
	git_revwalk *revwalk = NULL;
	git_commit *commit;
	git_oid id;
	bool merge;
	git_rebase_operation *operation;
	int error;

	if (!upstream)
		upstream = onto;

	if ((error = git_revwalk_new(&revwalk, rebase->repo)) < 0 ||
		(error = git_revwalk_push(revwalk, git_annotated_commit_id(branch))) < 0 ||
		(error = git_revwalk_hide(revwalk, git_annotated_commit_id(upstream))) < 0)
		goto done;

	git_revwalk_sorting(revwalk, GIT_SORT_REVERSE | GIT_SORT_TIME);

	while ((error = git_revwalk_next(&id, revwalk)) == 0) {
		if ((error = git_commit_lookup(&commit, repo, &id)) < 0)
			goto done;

		merge = (git_commit_parentcount(commit) > 1);
		git_commit_free(commit);

		if (merge)
			continue;

		operation = git_array_alloc(rebase->operations);
		operation->type = GIT_REBASE_OPERATION_PICK;
		git_oid_cpy((git_oid *)&operation->id, &id);
	}

	error = 0;

done:
	git_revwalk_free(revwalk);
	return error;
}
Ejemplo n.º 5
0
static int diff_driver_add_patterns(
	git_diff_driver *drv, const char *regex_str, int regex_flags)
{
	int error = 0;
	const char *scan, *end;
	git_diff_driver_pattern *pat = NULL;
	git_buf buf = GIT_BUF_INIT;

	for (scan = regex_str; scan; scan = end) {
		/* get pattern to fill in */
		if ((pat = git_array_alloc(drv->fn_patterns)) == NULL) {
			error = -1;
			break;
		}

		pat->flags = regex_flags;
		if (*scan == '!') {
			pat->flags |= REG_NEGATE;
			++scan;
		}

		if ((end = strchr(scan, '\n')) != NULL) {
			error = git_buf_set(&buf, scan, end - scan);
			end++;
		} else {
			error = git_buf_sets(&buf, scan);
		}
		if (error < 0)
			break;

		if ((error = regcomp(&pat->re, buf.ptr, regex_flags)) < 0) {
			/* if regex fails to compile, warn? fail? */
			error = giterr_set_regex(&pat->re, error);
			regfree(&pat->re);
			break;
		}
	}

	if (error && pat != NULL)
		(void)git_array_pop(drv->fn_patterns); /* release last item */
	git_buf_free(&buf);

	return error;
}
Ejemplo n.º 6
0
static git_rebase_operation *rebase_operation_alloc(
	git_rebase *rebase,
	git_rebase_operation_t type,
	git_oid *id,
	const char *exec)
{
	git_rebase_operation *operation;

	assert((type == GIT_REBASE_OPERATION_EXEC) == !id);
	assert((type == GIT_REBASE_OPERATION_EXEC) == !!exec);

	if ((operation = git_array_alloc(rebase->operations)) == NULL)
		return NULL;

	operation->type = type;
	git_oid_cpy((git_oid *)&operation->id, id);
	operation->exec = exec;

	return operation;
}
Ejemplo n.º 7
0
static int validate_tree_and_parents(git_array_oid_t *parents, git_repository *repo, const git_oid *tree,
				     git_commit_parent_callback parent_cb, void *parent_payload,
				     const git_oid *current_id, bool validate)
{
	size_t i;
	int error;
	git_oid *parent_cpy;
	const git_oid *parent;

	if (validate && !git_object__is_valid(repo, tree, GIT_OBJECT_TREE))
		return -1;

	i = 0;
	while ((parent = parent_cb(i, parent_payload)) != NULL) {
		if (validate && !git_object__is_valid(repo, parent, GIT_OBJECT_COMMIT)) {
			error = -1;
			goto on_error;
		}

		parent_cpy = git_array_alloc(*parents);
		GITERR_CHECK_ALLOC(parent_cpy);

		git_oid_cpy(parent_cpy, parent);
		i++;
	}

	if (current_id && (parents->size == 0 || git_oid_cmp(current_id, git_array_get(*parents, 0)))) {
		giterr_set(GITERR_OBJECT, "failed to create commit: current tip is not the first parent");
		error = GIT_EMODIFIED;
		goto on_error;
	}

	return 0;

on_error:
	git_array_clear(*parents);
	return error;
}
Ejemplo n.º 8
0
static int parse_hunk_body(
	git_patch_parsed *patch,
	git_patch_hunk *hunk,
	git_patch_parse_ctx *ctx)
{
	git_diff_line *line;
	int error = 0;

	int oldlines = hunk->hunk.old_lines;
	int newlines = hunk->hunk.new_lines;

	for (;
		ctx->parse_ctx.remain_len > 1 &&
		(oldlines || newlines) &&
		!git_parse_ctx_contains_s(&ctx->parse_ctx, "@@ -");
		git_parse_advance_line(&ctx->parse_ctx)) {

		char c;
		int origin;
		int prefix = 1;

		if (ctx->parse_ctx.line_len == 0 || ctx->parse_ctx.line[ctx->parse_ctx.line_len - 1] != '\n') {
			error = git_parse_err("invalid patch instruction at line %"PRIuZ,
				ctx->parse_ctx.line_num);
			goto done;
		}

		git_parse_peek(&c, &ctx->parse_ctx, 0);

		switch (c) {
		case '\n':
			prefix = 0;
			/* fall through */

		case ' ':
			origin = GIT_DIFF_LINE_CONTEXT;
			oldlines--;
			newlines--;
			break;

		case '-':
			origin = GIT_DIFF_LINE_DELETION;
			oldlines--;
			break;

		case '+':
			origin = GIT_DIFF_LINE_ADDITION;
			newlines--;
			break;

		default:
			error = git_parse_err("invalid patch hunk at line %"PRIuZ, ctx->parse_ctx.line_num);
			goto done;
		}

		line = git_array_alloc(patch->base.lines);
		GITERR_CHECK_ALLOC(line);

		memset(line, 0x0, sizeof(git_diff_line));

		line->content = ctx->parse_ctx.line + prefix;
		line->content_len = ctx->parse_ctx.line_len - prefix;
		line->content_offset = ctx->parse_ctx.content_len - ctx->parse_ctx.remain_len;
		line->origin = origin;

		hunk->line_count++;
	}

	if (oldlines || newlines) {
		error = git_parse_err(
			"invalid patch hunk, expected %d old lines and %d new lines",
			hunk->hunk.old_lines, hunk->hunk.new_lines);
		goto done;
	}

	/* Handle "\ No newline at end of file".  Only expect the leading
	 * backslash, though, because the rest of the string could be
	 * localized.  Because `diff` optimizes for the case where you
	 * want to apply the patch by hand.
	 */
	if (git_parse_ctx_contains_s(&ctx->parse_ctx, "\\ ") &&
		git_array_size(patch->base.lines) > 0) {

		line = git_array_get(patch->base.lines, git_array_size(patch->base.lines) - 1);

		if (line->content_len < 1) {
			error = git_parse_err("cannot trim trailing newline of empty line");
			goto done;
		}

		line->content_len--;

		git_parse_advance_line(&ctx->parse_ctx);
	}

done:
	return error;
}
Ejemplo n.º 9
0
int git_commit__parse_raw(void *_commit, const char *data, size_t size)
{
	git_commit *commit = _commit;
	const char *buffer_start = data, *buffer;
	const char *buffer_end = buffer_start + size;
	git_oid parent_id;
	size_t header_len;
	git_signature dummy_sig;

	buffer = buffer_start;

	/* Allocate for one, which will allow not to realloc 90% of the time  */
	git_array_init_to_size(commit->parent_ids, 1);
	GITERR_CHECK_ARRAY(commit->parent_ids);

	/* The tree is always the first field */
	if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0)
		goto bad_buffer;

	/*
	 * TODO: commit grafts!
	 */

	while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) {
		git_oid *new_id = git_array_alloc(commit->parent_ids);
		GITERR_CHECK_ALLOC(new_id);

		git_oid_cpy(new_id, &parent_id);
	}

	commit->author = git__malloc(sizeof(git_signature));
	GITERR_CHECK_ALLOC(commit->author);

	if (git_signature__parse(commit->author, &buffer, buffer_end, "author ", '\n') < 0)
		return -1;

	/* Some tools create multiple author fields, ignore the extra ones */
	while (!git__prefixncmp(buffer, buffer_end - buffer, "author ")) {
		if (git_signature__parse(&dummy_sig, &buffer, buffer_end, "author ", '\n') < 0)
			return -1;

		git__free(dummy_sig.name);
		git__free(dummy_sig.email);
	}

	/* Always parse the committer; we need the commit time */
	commit->committer = git__malloc(sizeof(git_signature));
	GITERR_CHECK_ALLOC(commit->committer);

	if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0)
		return -1;

	/* Parse add'l header entries */
	while (buffer < buffer_end) {
		const char *eoln = buffer;
		if (buffer[-1] == '\n' && buffer[0] == '\n')
			break;

		while (eoln < buffer_end && *eoln != '\n')
			++eoln;

		if (git__prefixncmp(buffer, buffer_end - buffer, "encoding ") == 0) {
			buffer += strlen("encoding ");

			commit->message_encoding = git__strndup(buffer, eoln - buffer);
			GITERR_CHECK_ALLOC(commit->message_encoding);
		}

		if (eoln < buffer_end && *eoln == '\n')
			++eoln;
		buffer = eoln;
	}

	header_len = buffer - buffer_start;
	commit->raw_header = git__strndup(buffer_start, header_len);
	GITERR_CHECK_ALLOC(commit->raw_header);

	/* point "buffer" to data after header, +1 for the final LF */
	buffer = buffer_start + header_len + 1;

	/* extract commit message */
	if (buffer <= buffer_end)
		commit->raw_message = git__strndup(buffer, buffer_end - buffer);
	else
		commit->raw_message = git__strdup("");
	GITERR_CHECK_ALLOC(commit->raw_message);

	return 0;

bad_buffer:
	giterr_set(GITERR_OBJECT, "failed to parse bad commit object");
	return -1;
}