<commit_before>/*
 * Copyright (C) the libgit2 contributors. All rights reserved.
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */
#include "git2/describe.h"
#include "git2/strarray.h"
#include "git2/diff.h"
#include "git2/status.h"

#include "common.h"
#include "commit.h"
#include "commit_list.h"
#include "oidmap.h"
#include "refs.h"
#include "revwalk.h"
#include "tag.h"
#include "vector.h"
#include "repository.h"

/* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */

struct commit_name {
	git_tag *tag;
	unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
	unsigned name_checked:1;
	git_oid sha1;
	char *path;

	/* Khash workaround. They original key has to still be reachable */
	git_oid peeled; 
};

static void *oidmap_value_bykey(git_oidmap *map, const git_oid *key)
{
	khint_t pos = git_oidmap_lookup_index(map, key);

	if (!git_oidmap_valid_index(map, pos))
		return NULL;

	return git_oidmap_value_at(map, pos);
}

static struct commit_name *find_commit_name(
	git_oidmap *names,
	const git_oid *peeled)
{
	return (struct commit_name *)(oidmap_value_bykey(names, peeled));
}

static int replace_name(
	git_tag **tag,
	git_repository *repo,
	struct commit_name *e,
	unsigned int prio,
	const git_oid *sha1)
{
	git_time_t e_time = 0, t_time = 0;

	if (!e || e->prio < prio)
		return 1;

	if (e->prio == 2 && prio == 2) {
		/* Multiple annotated tags point to the same commit.
		 * Select one to keep based upon their tagger date.
		 */
		git_tag *t = NULL;

		if (!e->tag) {
			if (git_tag_lookup(&t, repo, &e->sha1) < 0)
				return 1;
			e->tag = t;
		}

		if (git_tag_lookup(&t, repo, sha1) < 0)
			return 0;

		*tag = t;

		if (e->tag->tagger)
			e_time = e->tag->tagger->when.time;

		if (t->tagger)
			t_time = t->tagger->when.time;

		if (e_time < t_time)
			return 1;
	}

	return 0;
}

static int add_to_known_names(
	git_repository *repo,
	git_oidmap *names,
	const char *path,
	const git_oid *peeled,
	unsigned int prio,
	const git_oid *sha1)
{
	struct commit_name *e = find_commit_name(names, peeled);
	bool found = (e != NULL);

	git_tag *tag = NULL;
	if (replace_name(&tag, repo, e, prio, sha1)) {
		if (!found) {
			e = git__malloc(sizeof(struct commit_name));
			GITERR_CHECK_ALLOC(e);

			e->path = NULL;
			e->tag = NULL;
		}

		if (e->tag)
			git_tag_free(e->tag);
		e->tag = tag;
		e->prio = prio;
		e->name_checked = 0;
		git_oid_cpy(&e->sha1, sha1);
		git__free(e->path);
		e->path = git__strdup(path);
		git_oid_cpy(&e->peeled, peeled);

		if (!found) {
			int ret;

			git_oidmap_insert(names, &e->peeled, e, ret);
			if (ret < 0)
				return -1;
		}
	}
	else
		git_tag_free(tag);

	return 0;
}

static int retrieve_peeled_tag_or_object_oid(
	git_oid *peeled_out,
	git_oid *ref_target_out,
	git_repository *repo,
	const char *refname)
{
	git_reference *ref;
	git_object *peeled = NULL;
	int error;

	if ((error = git_reference_lookup_resolved(&ref, repo, refname, -1)) < 0)
		return error;

	if ((error = git_reference_peel(&peeled, ref, GIT_OBJ_ANY)) < 0)
		goto cleanup;

	git_oid_cpy(ref_target_out, git_reference_target(ref));
	git_oid_cpy(peeled_out, git_object_id(peeled));

	if (git_oid_cmp(ref_target_out, peeled_out) != 0)
		error = 1; /* The reference was pointing to a annotated tag */
	else
		error = 0; /* Any other object */

cleanup:
	git_reference_free(ref);
	git_object_free(peeled);
	return error;
}

typedef struct git_describe_result {
	int dirty;
	int exact_match;
	int fallback_to_id;
	git_oid commit_id;
	git_repository *repo;
	struct commit_name *name;
	struct possible_tag *tag;
} git_describe_result;

struct get_name_data
{
	git_describe_options *opts;
	git_repository *repo;
	git_oidmap *names;
	git_describe_result *result;
};

static int commit_name_dup(struct commit_name **out, struct commit_name *in)<commit_msg>describe: make mingw happy<commit_after>/*
 * Copyright (C) the libgit2 contributors. All rights reserved.
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */
#include "git2/describe.h"
#include "git2/strarray.h"
#include "git2/diff.h"
#include "git2/status.h"

#include "common.h"
#include "commit.h"
#include "commit_list.h"
#include "oidmap.h"
#include "refs.h"
#include "revwalk.h"
#include "tag.h"
#include "vector.h"
#include "repository.h"

/* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */

struct commit_name {
	git_tag *tag;
	unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
	unsigned name_checked:1;
	git_oid sha1;
	char *path;

	/* Khash workaround. They original key has to still be reachable */
	git_oid peeled; 
};

static void *oidmap_value_bykey(git_oidmap *map, const git_oid *key)
{
	khint_t pos = git_oidmap_lookup_index(map, key);

	if (!git_oidmap_valid_index(map, pos))
		return NULL;

	return git_oidmap_value_at(map, pos);
}

static struct commit_name *find_commit_name(
	git_oidmap *names,
	const git_oid *peeled)
{
	return (struct commit_name *)(oidmap_value_bykey(names, peeled));
}

static int replace_name(
	git_tag **tag,
	git_repository *repo,
	struct commit_name *e,
	unsigned int prio,
	const git_oid *sha1)
{
	git_time_t e_time = 0, t_time = 0;

	if (!e || e->prio < prio)
		return 1;

	if (e->prio == 2 && prio == 2) {
		/* Multiple annotated tags point to the same commit.
		 * Select one to keep based upon their tagger date.
		 */
		git_tag *t = NULL;

		if (!e->tag) {
			if (git_tag_lookup(&t, repo, &e->sha1) < 0)
				return 1;
			e->tag = t;
		}

		if (git_tag_lookup(&t, repo, sha1) < 0)
			return 0;

		*tag = t;

		if (e->tag->tagger)
			e_time = e->tag->tagger->when.time;

		if (t->tagger)
			t_time = t->tagger->when.time;

		if (e_time < t_time)
			return 1;
	}

	return 0;
}

static int add_to_known_names(
	git_repository *repo,
	git_oidmap *names,
	const char *path,
	const git_oid *peeled,
	unsigned int prio,
	const git_oid *sha1)
{
	struct commit_name *e = find_commit_name(names, peeled);
	bool found = (e != NULL);

	git_tag *tag = NULL;
	if (replace_name(&tag, repo, e, prio, sha1)) {
		if (!found) {
			e = git__malloc(sizeof(struct commit_name));
			GITERR_CHECK_ALLOC(e);

			e->path = NULL;
			e->tag = NULL;
		}

		if (e->tag)
			git_tag_free(e->tag);
		e->tag = tag;
		e->prio = prio;
		e->name_checked = 0;
		git_oid_cpy(&e->sha1, sha1);
		git__free(e->path);
		e->path = git__strdup(path);
		git_oid_cpy(&e->peeled, peeled);

		if (!found) {
			int ret;

			git_oidmap_insert(names, &e->peeled, e, ret);
			if (ret < 0)
				return -1;
		}
	}
	else
		git_tag_free(tag);

	return 0;
}

static int retrieve_peeled_tag_or_object_oid(
	git_oid *peeled_out,
	git_oid *ref_target_out,
	git_repository *repo,
	const char *refname)
{
	git_reference *ref;
	git_object *peeled = NULL;
	int error;

	if ((error = git_reference_lookup_resolved(&ref, repo, refname, -1)) < 0)
		return error;

	if ((error = git_reference_peel(&peeled, ref, GIT_OBJ_ANY)) < 0)
		goto cleanup;

	git_oid_cpy(ref_target_out, git_reference_target(ref));
	git_oid_cpy(peeled_out, git_object_id(peeled));

	if (git_oid_cmp(ref_target_out, peeled_out) != 0)
		error = 1; /* The reference was pointing to a annotated tag */
	else
		error = 0; /* Any other object */

cleanup:
	git_reference_free(ref);
	git_object_free(peeled);
	return error;
}

struct git_describe_result {
	int dirty;
	int exact_match;
	int fallback_to_id;
	git_oid commit_id;
	git_repository *repo;
	struct commit_name *name;
	struct possible_tag *tag;
};

struct get_name_data
{
	git_describe_options *opts;
	git_repository *repo;
	git_oidmap *names;
	git_describe_result *result;
};

static int commit_name_dup(struct commit_name **out, struct commit_name *in)
{'fraction_non_alphanumeric': 0.13102046003304105, 'fraction_numerical': 0.01677468547464735, 'mean_word_length': 4.103761348897535, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 53, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3657325', 'n_tokens_mistral': 3392, 'n_tokens_neox': 3097, 'n_words': 792}