static void assert_patch_matches_blobs( git_patch *p, git_blob *a, git_blob *b, int hunks, int l0, int l1, int ctxt, int adds, int dels) { const git_diff_delta *delta; size_t tc, ta, td; cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status); cl_assert_equal_oid(git_blob_id(a), &delta->old_file.id); cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size); cl_assert_equal_oid(git_blob_id(b), &delta->new_file.id); cl_assert_equal_sz(git_blob_rawsize(b), delta->new_file.size); cl_assert_equal_i(hunks, (int)git_patch_num_hunks(p)); if (hunks > 0) cl_assert_equal_i(l0, git_patch_num_lines_in_hunk(p, 0)); if (hunks > 1) cl_assert_equal_i(l1, git_patch_num_lines_in_hunk(p, 1)); cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p)); cl_assert_equal_i(ctxt, (int)tc); cl_assert_equal_i(adds, (int)ta); cl_assert_equal_i(dels, (int)td); }
int git_diff_file_content__init_from_blob( git_diff_file_content *fc, git_repository *repo, const git_diff_options *opts, const git_blob *blob, git_diff_file *as_file) { memset(fc, 0, sizeof(*fc)); fc->repo = repo; fc->file = as_file; fc->blob = blob; if (!blob) { fc->flags |= GIT_DIFF_FLAG__NO_DATA; } else { fc->flags |= GIT_DIFF_FLAG__LOADED; fc->file->flags |= GIT_DIFF_FLAG_VALID_OID; fc->file->size = git_blob_rawsize(blob); fc->file->mode = GIT_FILEMODE_BLOB; git_oid_cpy(&fc->file->oid, git_blob_id(blob)); fc->map.len = (size_t)fc->file->size; fc->map.data = (char *)git_blob_rawcontent(blob); } return diff_file_content_init_common(fc, opts); }
void test_filter_custom__order_dependency(void) { git_index *index; git_blob *blob; git_buf buf = { 0 }; /* so if ident and reverse are used together, an interesting thing * happens - a reversed "$Id$" string is no longer going to trigger * ident correctly. When checking out, the filters should be applied * in order CLRF, then ident, then reverse, so ident expansion should * work correctly. On check in, the content should be reversed, then * ident, then CRLF filtered. Let's make sure that works... */ cl_git_mkfile( "empty_standard_repo/.gitattributes", "hero.*.rev-ident text ident prereverse eol=lf\n"); cl_git_mkfile( "empty_standard_repo/hero.1.rev-ident", "This is a test\n$Id$\nHave fun!\n"); cl_git_mkfile( "empty_standard_repo/hero.2.rev-ident", "Another test\n$dI$\nCrazy!\n"); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_add_bypath(index, "hero.1.rev-ident")); cl_git_pass(git_index_add_bypath(index, "hero.2.rev-ident")); cl_repo_commit_from_index(NULL, g_repo, NULL, 0, "Filter chains\n"); git_index_free(index); cl_git_pass(git_blob_lookup(&blob, g_repo, & git_index_get_bypath(index, "hero.1.rev-ident", 0)->oid)); cl_assert_equal_s( "\n!nuf evaH\n$dI$\ntset a si sihT", git_blob_rawcontent(blob)); cl_git_pass(git_blob_filtered_content(&buf, blob, "hero.1.rev-ident", 0)); /* no expansion because id was reversed at checkin and now at ident * time, reverse is not applied yet */ cl_assert_equal_s( "This is a test\n$Id$\nHave fun!\n", buf.ptr); git_blob_free(blob); cl_git_pass(git_blob_lookup(&blob, g_repo, & git_index_get_bypath(index, "hero.2.rev-ident", 0)->oid)); cl_assert_equal_s( "\n!yzarC\n$Id$\ntset rehtonA", git_blob_rawcontent(blob)); cl_git_pass(git_blob_filtered_content(&buf, blob, "hero.2.rev-ident", 0)); /* expansion because reverse was applied at checkin and at ident time, * reverse is not applied yet */ cl_assert_equal_s( "Another test\n$59001fe193103b1016b27027c0c827d036fd0ac8 :dI$\nCrazy!\n", buf.ptr); cl_assert_equal_i(0, git_oid_strcmp( git_blob_id(blob), "8ca0df630d728c0c72072b6101b301391ef10095")); git_blob_free(blob); git_buf_free(&buf); }
void test_diff_blob__can_compare_identical_blobs_with_patch(void) { git_patch *p; const git_diff_delta *delta; cl_git_pass(git_patch_from_blobs(&p, d, NULL, d, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status); cl_assert_equal_sz(delta->old_file.size, git_blob_rawsize(d)); cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id); cl_assert_equal_sz(delta->new_file.size, git_blob_rawsize(d)); cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); cl_git_pass(git_patch_from_blobs(&p, NULL, NULL, NULL, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status); cl_assert_equal_sz(0, delta->old_file.size); cl_assert(git_oid_iszero(&delta->old_file.id)); cl_assert_equal_sz(0, delta->new_file.size); cl_assert(git_oid_iszero(&delta->new_file.id)); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); cl_git_pass(git_patch_from_blobs(&p, alien, NULL, alien, NULL, &opts)); cl_assert(p != NULL); cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_patch_get_delta(p)->status); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); }
/* * The blobs of origin and porigin exactly match, so everything origin is * suspected for can be blamed on the parent. */ static void pass_whole_blame(git_blame *blame, git_blame__origin *origin, git_blame__origin *porigin) { git_blame__entry *e; if (!porigin->blob) git_object_lookup((git_object**)&porigin->blob, blame->repository, git_blob_id(origin->blob), GIT_OBJ_BLOB); for (e=blame->ent; e; e=e->next) { if (!same_suspect(e->suspect, origin)) continue; origin_incref(porigin); origin_decref(e->suspect); e->suspect = porigin; } }
int git_diff_file_content__init_from_src( git_diff_file_content *fc, git_repository *repo, const git_diff_options *opts, const git_diff_file_content_src *src, git_diff_file *as_file) { memset(fc, 0, sizeof(*fc)); fc->repo = repo; fc->file = as_file; if (!src->blob && !src->buf) { fc->flags |= GIT_DIFF_FLAG__NO_DATA; } else { fc->flags |= GIT_DIFF_FLAG__LOADED; fc->file->flags |= GIT_DIFF_FLAG_VALID_ID; fc->file->mode = GIT_FILEMODE_BLOB; if (src->blob) { git_blob_dup((git_blob **)&fc->blob, (git_blob *) src->blob); fc->file->size = git_blob_rawsize(src->blob); git_oid_cpy(&fc->file->id, git_blob_id(src->blob)); fc->file->id_abbrev = GIT_OID_HEXSZ; fc->map.len = (size_t)fc->file->size; fc->map.data = (char *)git_blob_rawcontent(src->blob); fc->flags |= GIT_DIFF_FLAG__FREE_BLOB; } else { fc->file->size = src->buflen; git_odb_hash(&fc->file->id, src->buf, src->buflen, GIT_OBJECT_BLOB); fc->file->id_abbrev = GIT_OID_HEXSZ; fc->map.len = src->buflen; fc->map.data = (char *)src->buf; } } return diff_file_content_init_common(fc, opts); }
int git_attr_file__load( git_attr_file **out, git_repository *repo, git_attr_file_entry *entry, git_attr_file_source source, git_attr_file_parser parser) { int error = 0; git_blob *blob = NULL; git_buf content = GIT_BUF_INIT; const char *data = NULL; git_attr_file *file; struct stat st; *out = NULL; switch (source) { case GIT_ATTR_FILE__IN_MEMORY: /* in-memory attribute file doesn't need data */ break; case GIT_ATTR_FILE__FROM_INDEX: { git_oid id; if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 || (error = git_blob_lookup(&blob, repo, &id)) < 0) return error; data = git_blob_rawcontent(blob); break; } case GIT_ATTR_FILE__FROM_FILE: { int fd; if (p_stat(entry->fullpath, &st) < 0) return git_path_set_error(errno, entry->fullpath, "stat"); if (S_ISDIR(st.st_mode)) return GIT_ENOTFOUND; /* For open or read errors, return ENOTFOUND to skip item */ /* TODO: issue warning when warning API is available */ if ((fd = git_futils_open_ro(entry->fullpath)) < 0) return GIT_ENOTFOUND; error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size); p_close(fd); if (error < 0) return GIT_ENOTFOUND; data = content.ptr; break; } default: giterr_set(GITERR_INVALID, "Unknown file source %d", source); return -1; } if ((error = git_attr_file__new(&file, entry, source)) < 0) goto cleanup; if (parser && (error = parser(repo, file, data)) < 0) { git_attr_file__free(file); goto cleanup; } /* write cache breaker */ if (source == GIT_ATTR_FILE__FROM_INDEX) git_oid_cpy(&file->cache_data.oid, git_blob_id(blob)); else if (source == GIT_ATTR_FILE__FROM_FILE) git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st); /* else always cacheable */ *out = file; cleanup: git_blob_free(blob); git_buf_free(&content); return error; }
static void pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt) { git_commit *commit = origin->commit; int i, num_parents; git_blame__origin *sg_buf[16]; git_blame__origin *porigin, **sg_origin = sg_buf; num_parents = git_commit_parentcount(commit); if (!git_oid_cmp(git_commit_id(commit), &blame->options.oldest_commit)) /* Stop at oldest specified commit */ num_parents = 0; else if (opt & GIT_BLAME_FIRST_PARENT && num_parents > 1) /* Limit search to the first parent */ num_parents = 1; if (!num_parents) { git_oid_cpy(&blame->options.oldest_commit, git_commit_id(commit)); goto finish; } else if (num_parents < (int)ARRAY_SIZE(sg_buf)) memset(sg_buf, 0, sizeof(sg_buf)); else sg_origin = (git_blame__origin **) git__calloc(num_parents, sizeof(*sg_origin)); for (i=0; i<num_parents; i++) { git_commit *p; int j, same; if (sg_origin[i]) continue; git_commit_parent(&p, origin->commit, i); porigin = find_origin(blame, p, origin); if (!porigin) continue; if (porigin->blob && origin->blob && !git_oid_cmp(git_blob_id(porigin->blob), git_blob_id(origin->blob))) { pass_whole_blame(blame, origin, porigin); origin_decref(porigin); goto finish; } for (j = same = 0; j<i; j++) if (sg_origin[j] && !git_oid_cmp(git_blob_id(sg_origin[j]->blob), git_blob_id(porigin->blob))) { same = 1; break; } if (!same) sg_origin[i] = porigin; else origin_decref(porigin); } /* Standard blame */ for (i=0; i<num_parents; i++) { git_blame__origin *porigin = sg_origin[i]; if (!porigin) continue; if (!origin->previous) { origin_incref(porigin); origin->previous = porigin; } if (pass_blame_to_parent(blame, origin, porigin)) goto finish; } /* TODO: optionally find moves in parents' files */ /* TODO: optionally find copies in parents' files */ finish: for (i=0; i<num_parents; i++) if (sg_origin[i]) origin_decref(sg_origin[i]); if (sg_origin != sg_buf) git__free(sg_origin); return; }
int git_attr_file__load( git_attr_file **out, git_repository *repo, git_attr_session *attr_session, git_attr_file_entry *entry, git_attr_file_source source, git_attr_file_parser parser) { int error = 0; git_blob *blob = NULL; git_buf content = GIT_BUF_INIT; git_attr_file *file; struct stat st; bool nonexistent = false; *out = NULL; switch (source) { case GIT_ATTR_FILE__IN_MEMORY: /* in-memory attribute file doesn't need data */ break; case GIT_ATTR_FILE__FROM_INDEX: { git_oid id; if ((error = attr_file_oid_from_index(&id, repo, entry->path)) < 0 || (error = git_blob_lookup(&blob, repo, &id)) < 0) return error; /* Do not assume that data straight from the ODB is NULL-terminated; * copy the contents of a file to a buffer to work on */ git_buf_put(&content, git_blob_rawcontent(blob), git_blob_rawsize(blob)); break; } case GIT_ATTR_FILE__FROM_FILE: { int fd = -1; /* For open or read errors, pretend that we got ENOTFOUND. */ /* TODO: issue warning when warning API is available */ if (p_stat(entry->fullpath, &st) < 0 || S_ISDIR(st.st_mode) || (fd = git_futils_open_ro(entry->fullpath)) < 0 || (error = git_futils_readbuffer_fd(&content, fd, (size_t)st.st_size)) < 0) nonexistent = true; if (fd >= 0) p_close(fd); break; } default: giterr_set(GITERR_INVALID, "Unknown file source %d", source); return -1; } if ((error = git_attr_file__new(&file, entry, source)) < 0) goto cleanup; /* store the key of the attr_reader; don't bother with cache * invalidation during the same attr reader session. */ if (attr_session) file->session_key = attr_session->key; if (parser && (error = parser(repo, file, git_buf_cstr(&content))) < 0) { git_attr_file__free(file); goto cleanup; } /* write cache breakers */ if (nonexistent) file->nonexistent = 1; else if (source == GIT_ATTR_FILE__FROM_INDEX) git_oid_cpy(&file->cache_data.oid, git_blob_id(blob)); else if (source == GIT_ATTR_FILE__FROM_FILE) git_futils_filestamp_set_from_stat(&file->cache_data.stamp, &st); /* else always cacheable */ *out = file; cleanup: git_blob_free(blob); git_buf_free(&content); return error; }
void test_diff_blob__can_compare_against_null_blobs_with_patch(void) { git_blob *e = NULL; git_patch *p; const git_diff_delta *delta; const git_diff_line *line; int l, max_l; cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_DELETED, delta->status); cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id); cl_assert_equal_sz(git_blob_rawsize(d), delta->old_file.size); cl_assert(git_oid_iszero(&delta->new_file.id)); cl_assert_equal_sz(0, delta->new_file.size); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0)); max_l = git_patch_num_lines_in_hunk(p, 0); for (l = 0; l < max_l; ++l) { cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l)); cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)line->origin); } git_patch_free(p); opts.flags |= GIT_DIFF_REVERSE; cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, delta->status); cl_assert(git_oid_iszero(&delta->old_file.id)); cl_assert_equal_sz(0, delta->old_file.size); cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id); cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size); cl_assert_equal_i(1, (int)git_patch_num_hunks(p)); cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0)); max_l = git_patch_num_lines_in_hunk(p, 0); for (l = 0; l < max_l; ++l) { cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l)); cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)line->origin); } git_patch_free(p); opts.flags ^= GIT_DIFF_REVERSE; cl_git_pass(git_patch_from_blobs(&p, alien, NULL, NULL, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_DELETED, delta->status); cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); cl_git_pass(git_patch_from_blobs(&p, NULL, NULL, alien, NULL, &opts)); cl_assert(p != NULL); delta = git_patch_get_delta(p); cl_assert(delta != NULL); cl_assert_equal_i(GIT_DELTA_ADDED, delta->status); cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); cl_assert_equal_i(0, (int)git_patch_num_hunks(p)); git_patch_free(p); }