Exemple #1
0
static int find_blob(git_oid *blob, git_tree *tree, const char *target)
{
	size_t i;
	const git_tree_entry *entry;

	for (i=0; i<git_tree_entrycount(tree); i++) {
		entry = git_tree_entry_byindex(tree, i);

		if (!strcmp(git_tree_entry_name(entry), target)) {
			/* found matching note object - return */

			git_oid_cpy(blob, git_tree_entry_id(entry));
			return 0;
		}
	}

	return note_error_notfound();
}
Exemple #2
0
/*
 *  call-seq:
 *    tree.each { |entry| block }
 *    tree.each -> enumerator
 *
 *  Call +block+ with each of the entries of the subtree as a +Hash+. If no +block+
 *  is given, an +enumerator+ is returned instead.
 *
 *  Note that only the entries in the root of the tree are yielded; if you need to
 *  list also entries in subfolders, use +tree.walk+ instead.
 *
 *    tree.each { |entry| puts entry.inspect }
 *
 *  generates:
 *
 *    {:name => "foo.txt", :type => :blob, :oid => "d8786bfc97485e8d7b19b21fb88c8ef1f199fc3f", :filemode => 0}
 *    {:name => "bar.txt", :type => :blob, :oid => "de5ba987198bcf2518885f0fc1350e5172cded78", :filemode => 0}
 *    ...
 */
static VALUE rb_git_tree_each(VALUE self)
{
	git_tree *tree;
	size_t i, count;
	Data_Get_Struct(self, git_tree, tree);

	if (!rb_block_given_p())
		return rb_funcall(self, rb_intern("to_enum"), 0);

	count = git_tree_entrycount(tree);

	for (i = 0; i < count; ++i) {
		const git_tree_entry *entry = git_tree_entry_byindex(tree, i);
		rb_yield(rb_git_treeentry_fromC(entry));
	}

	return Qnil;
}
Exemple #3
0
int ReadTreeRecursive(git_repository &repo, git_tree * tree, CStringA base, int (*CallBack) (const unsigned char *, const char *, int, const char *, unsigned int, int, void *),void *data)
{
	size_t count = git_tree_entrycount(tree);
	for (int i = 0; i < count; i++)
	{
		const git_tree_entry *entry = git_tree_entry_byindex(tree, i);
		if (entry == NULL)
			continue;
		int mode = git_tree_entry_attributes(entry);
		if( CallBack(git_tree_entry_id(entry)->id,
			base,
			base.GetLength(),
			git_tree_entry_name(entry),
			mode,
			0,
			data) == READ_TREE_RECURSIVE
		  )
		{
			if(mode&S_IFDIR)
			{
				git_object *object = NULL;
				git_tree_entry_2object(&object, &repo, entry);
				if (object == NULL)
					continue;
				CStringA parent = base;
				parent += git_tree_entry_name(entry);
				parent += "/";
				ReadTreeRecursive(repo, (git_tree*)object, parent, CallBack, data);
				git_object_free(object);
			}
		}

	}

	return 0;
}
Exemple #4
0
void test_object_tree_write__subtree(void)
{
	/* write a hierarchical tree from a memory */
	git_treebuilder *builder;
	git_tree *tree;
	git_oid id, bid, subtree_id, id2, id3;
	git_oid id_hiearar;

	git_oid_fromstr(&id, first_tree);
	git_oid_fromstr(&id2, second_tree);
	git_oid_fromstr(&id3, third_tree);
	git_oid_fromstr(&bid, blob_oid);

	/* create subtree */
	cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
	cl_git_pass(git_treebuilder_insert(
		NULL, builder, "new.txt", &bid, GIT_FILEMODE_BLOB)); /* -V536 */
	cl_git_pass(git_treebuilder_write(&subtree_id, builder));
	git_treebuilder_free(builder);

	/* create parent tree */
	cl_git_pass(git_tree_lookup(&tree, g_repo, &id));
	cl_git_pass(git_treebuilder_new(&builder, g_repo, tree));
	cl_git_pass(git_treebuilder_insert(
		NULL, builder, "new", &subtree_id, GIT_FILEMODE_TREE)); /* -V536 */
	cl_git_pass(git_treebuilder_write(&id_hiearar, builder));
	git_treebuilder_free(builder);
	git_tree_free(tree);

	cl_assert(git_oid_cmp(&id_hiearar, &id3) == 0);

	/* check data is correct */
	cl_git_pass(git_tree_lookup(&tree, g_repo, &id_hiearar));
	cl_assert(2 == git_tree_entrycount(tree));
	git_tree_free(tree);
}
Exemple #5
0
int main (int argc, char** argv)
{
  // ### Opening the Repository

  // There are a couple of methods for opening a repository, this being the simplest.
  // There are also [methods][me] for specifying the index file and work tree locations, here
  // we are assuming they are in the normal places.
  //
  // [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository
  git_repository *repo;
  if (argc > 1) {
    git_repository_open(&repo, argv[1]);
  } else {
    git_repository_open(&repo, "/opt/libgit2-test/.git");
  }

  // ### SHA-1 Value Conversions

  // For our first example, we will convert a 40 character hex value to the 20 byte raw SHA1 value.
  printf("*Hex to Raw*\n");
  char hex[] = "fd6e612585290339ea8bf39c692a7ff6a29cb7c3";

  // The `git_oid` is the structure that keeps the SHA value. We will use this throughout the example
  // for storing the value of the current SHA key we're working with.
  git_oid oid;
  git_oid_fromstr(&oid, hex);

  // Once we've converted the string into the oid value, we can get the raw value of the SHA.
  printf("Raw 20 bytes: [%.20s]\n", (&oid)->id);

  // Next we will convert the 20 byte raw SHA1 value to a human readable 40 char hex value.
  printf("\n*Raw to Hex*\n");
  char out[41];
  out[40] = '\0';

  // If you have a oid, you can easily get the hex value of the SHA as well.
  git_oid_fmt(out, &oid);
  printf("SHA hex string: %s\n", out);

  // ### Working with the Object Database
  // **libgit2** provides [direct access][odb] to the object database.
  // The object database is where the actual objects are stored in Git. For
  // working with raw objects, we'll need to get this structure from the
  // repository.
  // [odb]: http://libgit2.github.com/libgit2/#HEAD/group/odb
  git_odb *odb;
  git_repository_odb(&odb, repo);

  // #### Raw Object Reading

  printf("\n*Raw Object Read*\n");
  git_odb_object *obj;
  git_otype otype;
  const unsigned char *data;
  const char *str_type;
  int error;

  // We can read raw objects directly from the object database if we have the oid (SHA)
  // of the object.  This allows us to access objects without knowing thier type and inspect
  // the raw bytes unparsed.
  error = git_odb_read(&obj, odb, &oid);

  // A raw object only has three properties - the type (commit, blob, tree or tag), the size
  // of the raw data and the raw, unparsed data itself.  For a commit or tag, that raw data
  // is human readable plain ASCII text. For a blob it is just file contents, so it could be
  // text or binary data. For a tree it is a special binary format, so it's unlikely to be
  // hugely helpful as a raw object.
  data = (const unsigned char *)git_odb_object_data(obj);
  otype = git_odb_object_type(obj);

  // We provide methods to convert from the object type which is an enum, to a string
  // representation of that value (and vice-versa).
  str_type = git_object_type2string(otype);
  printf("object length and type: %d, %s\n",
      (int)git_odb_object_size(obj),
      str_type);

  // For proper memory management, close the object when you are done with it or it will leak
  // memory.
  git_odb_object_free(obj);

  // #### Raw Object Writing

  printf("\n*Raw Object Write*\n");

  // You can also write raw object data to Git. This is pretty cool because it gives you
  // direct access to the key/value properties of Git.  Here we'll write a new blob object
  // that just contains a simple string.  Notice that we have to specify the object type as
  // the `git_otype` enum.
  git_odb_write(&oid, odb, "test data", sizeof("test data") - 1, GIT_OBJ_BLOB);

  // Now that we've written the object, we can check out what SHA1 was generated when the
  // object was written to our database.
  git_oid_fmt(out, &oid);
  printf("Written Object: %s\n", out);

  // ### Object Parsing
  // libgit2 has methods to parse every object type in Git so you don't have to work directly
  // with the raw data. This is much faster and simpler than trying to deal with the raw data
  // yourself.

  // #### Commit Parsing
  // [Parsing commit objects][pco] is simple and gives you access to all the data in the commit
  // - the // author (name, email, datetime), committer (same), tree, message, encoding and parent(s).
  // [pco]: http://libgit2.github.com/libgit2/#HEAD/group/commit

  printf("\n*Commit Parsing*\n");

  git_commit *commit;
  git_oid_fromstr(&oid, "f0877d0b841d75172ec404fc9370173dfffc20d1");

  error = git_commit_lookup(&commit, repo, &oid);

  const git_signature *author, *cmtter;
  const char *message;
  time_t ctime;
  unsigned int parents, p;

  // Each of the properties of the commit object are accessible via methods, including commonly
  // needed variations, such as `git_commit_time` which returns the author time and `_message`
  // which gives you the commit message.
  message  = git_commit_message(commit);
  author   = git_commit_author(commit);
  cmtter   = git_commit_committer(commit);
  ctime    = git_commit_time(commit);

  // The author and committer methods return [git_signature] structures, which give you name, email
  // and `when`, which is a `git_time` structure, giving you a timestamp and timezone offset.
  printf("Author: %s (%s)\n", author->name, author->email);

  // Commits can have zero or more parents. The first (root) commit will have no parents, most commits
  // will have one, which is the commit it was based on, and merge commits will have two or more.
  // Commits can technically have any number, though it's pretty rare to have more than two.
  parents  = git_commit_parentcount(commit);
  for (p = 0;p < parents;p++) {
    git_commit *parent;
    git_commit_parent(&parent, commit, p);
    git_oid_fmt(out, git_commit_id(parent));
    printf("Parent: %s\n", out);
    git_commit_free(parent);
  }

  // Don't forget to close the object to prevent memory leaks. You will have to do this for
  // all the objects you open and parse.
  git_commit_free(commit);

  // #### Writing Commits
  //
  // libgit2 provides a couple of methods to create commit objects easily as well. There are four
  // different create signatures, we'll just show one of them here.  You can read about the other
  // ones in the [commit API docs][cd].
  // [cd]: http://libgit2.github.com/libgit2/#HEAD/group/commit

  printf("\n*Commit Writing*\n");
  git_oid tree_id, parent_id, commit_id;
  git_tree *tree;
  git_commit *parent;

  // Creating signatures for an authoring identity and time is pretty simple - you will need to have
  // this to create a commit in order to specify who created it and when.  Default values for the name
  // and email should be found in the `user.name` and `user.email` configuration options.  See the `config`
  // section of this example file to see how to access config values.
  git_signature_new((git_signature **)&author, "Scott Chacon", "*****@*****.**",
      123456789, 60);
  git_signature_new((git_signature **)&cmtter, "Scott A Chacon", "*****@*****.**",
      987654321, 90);

  // Commit objects need a tree to point to and optionally one or more parents.  Here we're creating oid
  // objects to create the commit with, but you can also use
  git_oid_fromstr(&tree_id, "28873d96b4e8f4e33ea30f4c682fd325f7ba56ac");
  git_tree_lookup(&tree, repo, &tree_id);
  git_oid_fromstr(&parent_id, "f0877d0b841d75172ec404fc9370173dfffc20d1");
  git_commit_lookup(&parent, repo, &parent_id);

  // Here we actually create the commit object with a single call with all the values we need to create
  // the commit.  The SHA key is written to the `commit_id` variable here.
  git_commit_create_v(
    &commit_id, /* out id */
    repo,
    NULL, /* do not update the HEAD */
    author,
    cmtter,
    NULL, /* use default message encoding */
    "example commit",
    tree,
    1, parent);

  // Now we can take a look at the commit SHA we've generated.
  git_oid_fmt(out, &commit_id);
  printf("New Commit: %s\n", out);

  // #### Tag Parsing
  // You can parse and create tags with the [tag management API][tm], which functions very similarly
  // to the commit lookup, parsing and creation methods, since the objects themselves are very similar.
  // [tm]: http://libgit2.github.com/libgit2/#HEAD/group/tag
  printf("\n*Tag Parsing*\n");
  git_tag *tag;
  const char *tmessage, *tname;
  git_otype ttype;

  // We create an oid for the tag object if we know the SHA and look it up in the repository the same
  // way that we would a commit (or any other) object.
  git_oid_fromstr(&oid, "bc422d45275aca289c51d79830b45cecebff7c3a");

  error = git_tag_lookup(&tag, repo, &oid);

  // Now that we have the tag object, we can extract the information it generally contains: the target
  // (usually a commit object), the type of the target object (usually 'commit'), the name ('v1.0'),
  // the tagger (a git_signature - name, email, timestamp), and the tag message.
  git_tag_target((git_object **)&commit, tag);
  tname = git_tag_name(tag);    // "test"
  ttype = git_tag_type(tag);    // GIT_OBJ_COMMIT (otype enum)
  tmessage = git_tag_message(tag); // "tag message\n"
  printf("Tag Message: %s\n", tmessage);

  git_commit_free(commit);

  // #### Tree Parsing
  // [Tree parsing][tp] is a bit different than the other objects, in that we have a subtype which is the
  // tree entry.  This is not an actual object type in Git, but a useful structure for parsing and
  // traversing tree entries.
  //
  // [tp]: http://libgit2.github.com/libgit2/#HEAD/group/tree
  printf("\n*Tree Parsing*\n");

  const git_tree_entry *entry;
  git_object *objt;

  // Create the oid and lookup the tree object just like the other objects.
  git_oid_fromstr(&oid, "2a741c18ac5ff082a7caaec6e74db3075a1906b5");
  git_tree_lookup(&tree, repo, &oid);

  // Getting the count of entries in the tree so you can iterate over them if you want to.
  int cnt = git_tree_entrycount(tree); // 3
  printf("tree entries: %d\n", cnt);

  entry = git_tree_entry_byindex(tree, 0);
  printf("Entry name: %s\n", git_tree_entry_name(entry)); // "hello.c"

  // You can also access tree entries by name if you know the name of the entry you're looking for.
  entry = git_tree_entry_byname(tree, "hello.c");
  git_tree_entry_name(entry); // "hello.c"

  // Once you have the entry object, you can access the content or subtree (or commit, in the case
  // of submodules) that it points to.  You can also get the mode if you want.
  git_tree_entry_to_object(&objt, repo, entry); // blob

  // Remember to close the looked-up object once you are done using it
  git_object_free(objt);

  // #### Blob Parsing
  //
  // The last object type is the simplest and requires the least parsing help. Blobs are just file
  // contents and can contain anything, there is no structure to it. The main advantage to using the
  // [simple blob api][ba] is that when you're creating blobs you don't have to calculate the size
  // of the content.  There is also a helper for reading a file from disk and writing it to the db and
  // getting the oid back so you don't have to do all those steps yourself.
  //
  // [ba]: http://libgit2.github.com/libgit2/#HEAD/group/blob

  printf("\n*Blob Parsing*\n");
  git_blob *blob;

  git_oid_fromstr(&oid, "af7574ea73f7b166f869ef1a39be126d9a186ae0");
  git_blob_lookup(&blob, repo, &oid);

  // You can access a buffer with the raw contents of the blob directly.
  // Note that this buffer may not be contain ASCII data for certain blobs (e.g. binary files):
  // do not consider the buffer a NULL-terminated string, and use the `git_blob_rawsize` attribute to
  // find out its exact size in bytes
  printf("Blob Size: %ld\n", git_blob_rawsize(blob)); // 8
  git_blob_rawcontent(blob); // "content"

  // ### Revwalking
  //
  // The libgit2 [revision walking api][rw] provides methods to traverse the directed graph created
  // by the parent pointers of the commit objects.  Since all commits point back to the commit that
  // came directly before them, you can walk this parentage as a graph and find all the commits that
  // were ancestors of (reachable from) a given starting point.  This can allow you to create `git log`
  // type functionality.
  //
  // [rw]: http://libgit2.github.com/libgit2/#HEAD/group/revwalk

  printf("\n*Revwalking*\n");
  git_revwalk *walk;
  git_commit *wcommit;

  git_oid_fromstr(&oid, "f0877d0b841d75172ec404fc9370173dfffc20d1");

  // To use the revwalker, create a new walker, tell it how you want to sort the output and then push
  // one or more starting points onto the walker.  If you want to emulate the output of `git log` you
  // would push the SHA of the commit that HEAD points to into the walker and then start traversing them.
  // You can also 'hide' commits that you want to stop at or not see any of their ancestors.  So if you
  // want to emulate `git log branch1..branch2`, you would push the oid of `branch2` and hide the oid
  // of `branch1`.
  git_revwalk_new(&walk, repo);
  git_revwalk_sorting(walk, GIT_SORT_TOPOLOGICAL | GIT_SORT_REVERSE);
  git_revwalk_push(walk, &oid);

  const git_signature *cauth;
  const char *cmsg;

  // Now that we have the starting point pushed onto the walker, we can start asking for ancestors. It
  // will return them in the sorting order we asked for as commit oids.
  // We can then lookup and parse the commited pointed at by the returned OID;
  // note that this operation is specially fast since the raw contents of the commit object will
  // be cached in memory
  while ((git_revwalk_next(&oid, walk)) == 0) {
    error = git_commit_lookup(&wcommit, repo, &oid);
    cmsg  = git_commit_message(wcommit);
    cauth = git_commit_author(wcommit);
    printf("%s (%s)\n", cmsg, cauth->email);
    git_commit_free(wcommit);
  }

  // Like the other objects, be sure to free the revwalker when you're done to prevent memory leaks.
  // Also, make sure that the repository being walked it not deallocated while the walk is in
  // progress, or it will result in undefined behavior
  git_revwalk_free(walk);

  // ### Index File Manipulation
  //
  // The [index file API][gi] allows you to read, traverse, update and write the Git index file
  // (sometimes thought of as the staging area).
  //
  // [gi]: http://libgit2.github.com/libgit2/#HEAD/group/index

  printf("\n*Index Walking*\n");

  git_index *index;
  unsigned int i, ecount;

  // You can either open the index from the standard location in an open repository, as we're doing
  // here, or you can open and manipulate any index file with `git_index_open_bare()`. The index
  // for the repository will be located and loaded from disk.
  git_repository_index(&index, repo);

  // For each entry in the index, you can get a bunch of information including the SHA (oid), path
  // and mode which map to the tree objects that are written out.  It also has filesystem properties
  // to help determine what to inspect for changes (ctime, mtime, dev, ino, uid, gid, file_size and flags)
  // All these properties are exported publicly in the `git_index_entry` struct
  ecount = git_index_entrycount(index);
  for (i = 0; i < ecount; ++i) {
    git_index_entry *e = git_index_get(index, i);

    printf("path: %s\n", e->path);
    printf("mtime: %d\n", (int)e->mtime.seconds);
    printf("fs: %d\n", (int)e->file_size);
  }

  git_index_free(index);

  // ### References
  //
  // The [reference API][ref] allows you to list, resolve, create and update references such as
  // branches, tags and remote references (everything in the .git/refs directory).
  //
  // [ref]: http://libgit2.github.com/libgit2/#HEAD/group/reference

  printf("\n*Reference Listing*\n");

  // Here we will implement something like `git for-each-ref` simply listing out all available
  // references and the object SHA they resolve to.
  git_strarray ref_list;
  git_reference_list(&ref_list, repo, GIT_REF_LISTALL);

  const char *refname;
  git_reference *ref;

  // Now that we have the list of reference names, we can lookup each ref one at a time and
  // resolve them to the SHA, then print both values out.
  for (i = 0; i < ref_list.count; ++i) {
    refname = ref_list.strings[i];
    git_reference_lookup(&ref, repo, refname);

    switch (git_reference_type(ref)) {
    case GIT_REF_OID:
      git_oid_fmt(out, git_reference_oid(ref));
      printf("%s [%s]\n", refname, out);
      break;

    case GIT_REF_SYMBOLIC:
      printf("%s => %s\n", refname, git_reference_target(ref));
      break;
    default:
      fprintf(stderr, "Unexpected reference type\n");
      exit(1);
    }
  }

  git_strarray_free(&ref_list);

  // ### Config Files
  //
  // The [config API][config] allows you to list and updatee config values in
  // any of the accessible config file locations (system, global, local).
  //
  // [config]: http://libgit2.github.com/libgit2/#HEAD/group/config

  printf("\n*Config Listing*\n");

  const char *email;
  int32_t j;

  git_config *cfg;

  // Open a config object so we can read global values from it.
  git_config_open_ondisk(&cfg, "~/.gitconfig");

  git_config_get_int32(cfg, "help.autocorrect", &j);
  printf("Autocorrect: %d\n", j);

  git_config_get_string(cfg, "user.email", &email);
  printf("Email: %s\n", email);

  // Finally, when you're done with the repository, you can free it as well.
  git_repository_free(repo);

  return 0;
}
Exemple #6
0
Py_ssize_t
Tree_len(Tree *self)
{
    assert(self->tree);
    return (Py_ssize_t)git_tree_entrycount(self->tree);
}
Exemple #7
0
END_TEST

BEGIN_TEST(read1, "read a tree from the repository")
	git_oid id;
	git_repository *repo;
	git_tree *tree;
	git_tree_entry *entry;
	git_object *obj;

	must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));

	git_oid_mkstr(&id, tree_oid);

	must_pass(git_tree_lookup(&tree, repo, &id));

	must_be_true(git_tree_entrycount(tree) == 3);

	/* GH-86: git_object_lookup() should also check the type if the object comes from the cache */
	must_be_true(git_object_lookup(&obj, repo, &id, GIT_OBJ_TREE) == 0);
	must_be_true(git_object_lookup(&obj, repo, &id, GIT_OBJ_BLOB) == GIT_EINVALIDTYPE);

	entry = git_tree_entry_byname(tree, "README");
	must_be_true(entry != NULL);

	must_be_true(strcmp(git_tree_entry_name(entry), "README") == 0);

	must_pass(git_tree_entry_2object(&obj, repo, entry));

	git_repository_free(repo);
END_TEST
int CRepositoryBrowser::ReadTreeRecursive(git_repository &repo, const git_tree * tree, CShadowFilesTree * treeroot)
{
	size_t count = git_tree_entrycount(tree);
	bool hasSubfolders = false;

	for (size_t i = 0; i < count; ++i)
	{
		const git_tree_entry *entry = git_tree_entry_byindex(tree, i);
		if (entry == NULL)
			continue;

		const int mode = git_tree_entry_filemode(entry);

		CString base = CUnicodeUtils::GetUnicode(git_tree_entry_name(entry), CP_UTF8);

		const git_oid *oid = git_tree_entry_id(entry);
		CShadowFilesTree * pNextTree = &treeroot->m_ShadowTree[base];
		pNextTree->m_sName = base;
		pNextTree->m_pParent = treeroot;
		pNextTree->m_hash = CGitHash((char *)oid->id);

		if (mode == GIT_FILEMODE_COMMIT)
			pNextTree->m_bSubmodule = true;
		else if (mode & S_IFDIR)
		{
			hasSubfolders = true;
			pNextTree->m_bFolder = true;
			pNextTree->m_bLoaded = false;

			TVINSERTSTRUCT tvinsert = {0};
			tvinsert.hParent = treeroot->m_hTree;
			tvinsert.hInsertAfter = TVI_SORT;
			tvinsert.itemex.mask = TVIF_DI_SETITEM | TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE | TVIF_CHILDREN;
			tvinsert.itemex.pszText = base.GetBuffer(base.GetLength());
			tvinsert.itemex.cChildren = 1;
			tvinsert.itemex.lParam = (LPARAM)pNextTree;
			tvinsert.itemex.iImage = m_nIconFolder;
			tvinsert.itemex.iSelectedImage = m_nOpenIconFolder;
			pNextTree->m_hTree = m_RepoTree.InsertItem(&tvinsert);
			base.ReleaseBuffer();
		}
		else
		{
			if (mode == GIT_FILEMODE_BLOB_EXECUTABLE)
				pNextTree->m_bExecutable = true;
			if (mode == GIT_FILEMODE_LINK)
				pNextTree->m_bSymlink = true;
			CAutoBlob blob;
			git_blob_lookup(blob.GetPointer(), &repo, oid);
			if (!blob)
				continue;

			pNextTree->m_iSize = git_blob_rawsize(blob);
		}
	}

	if (!hasSubfolders)
	{
		TVITEM tvitem = { 0 };
		tvitem.hItem = treeroot->m_hTree;
		tvitem.mask = TVIF_CHILDREN;
		tvitem.cChildren = 0;
		m_RepoTree.SetItem(&tvitem);
	}

	return 0;
}
Exemple #9
0
static int tree_iterator__push_frame(tree_iterator *ti)
{
	int error = 0;
	tree_iterator_frame *head = ti->head, *tf = NULL;
	size_t i, n_entries = 0;

	if (head->current >= head->n_entries || !head->entries[head->current]->tree)
		return GIT_ITEROVER;

	for (i = head->current; i < head->next; ++i)
		n_entries += git_tree_entrycount(head->entries[i]->tree);

	tf = git__calloc(sizeof(tree_iterator_frame) +
		n_entries * sizeof(tree_iterator_entry *), 1);
	GITERR_CHECK_ALLOC(tf);

	tf->n_entries = n_entries;

	tf->up     = head;
	head->down = tf;
	ti->head   = tf;

	for (i = head->current, n_entries = 0; i < head->next; ++i) {
		git_tree *tree = head->entries[i]->tree;
		size_t j, max_j = git_tree_entrycount(tree);

		for (j = 0; j < max_j; ++j) {
			tree_iterator_entry *entry = git_pool_malloc(&ti->pool, 1);
			GITERR_CHECK_ALLOC(entry);

			entry->parent = head->entries[i];
			entry->te     = git_tree_entry_byindex(tree, j);
			entry->tree   = NULL;

			tf->entries[n_entries++] = entry;
		}
	}

	/* if ignore_case, sort entries case insensitively */
	if (iterator__ignore_case(ti))
		git__tsort_r(
			(void **)tf->entries, tf->n_entries, tree_iterator__ci_cmp, tf);

	/* pick tf->current based on "start" (or start at zero) */
	if (head->startlen > 0) {
		git__bsearch_r((void **)tf->entries, tf->n_entries, head,
			tree_iterator__search_cmp, ti, &tf->current);

		while (tf->current &&
			   !tree_iterator__search_cmp(head, tf->entries[tf->current-1], ti))
			tf->current--;

		if ((tf->start = strchr(head->start, '/')) != NULL) {
			tf->start++;
			tf->startlen = strlen(tf->start);
		}
	}

	ti->path_has_filename = ti->entry_is_current = false;

	if ((error = tree_iterator__set_next(ti, tf)) < 0)
		return error;

	/* autoexpand as needed */
	if (!iterator__include_trees(ti) && tree_iterator__at_tree(ti))
		return tree_iterator__push_frame(ti);

	return 0;
}
Exemple #10
0
AGBMergeIterator * agb_merge__create_iterator(const git_tree * head_tree, const git_tree * branch_tree, const git_tree * base_tree, uint32_t merge_iterator_options ) {

	if(!head_tree) return NULL;	
	if(!branch_tree) return NULL;	
	if(!base_tree) return NULL;

	// Allocate enough space for all the entries of all three trees.
	// We'll go through and prune out duplicates later.
	
	size_t n_entries = 0;
	n_entries += git_tree_entrycount(head_tree);
	n_entries += git_tree_entrycount(branch_tree);
	n_entries += git_tree_entrycount(base_tree);

	AGBMergeEntry * all_entries = (AGBMergeEntry *) malloc( n_entries * sizeof(AGBMergeEntry) );

	memset(all_entries, 0, n_entries * sizeof(AGBMergeEntry) );

	// printf("BEFORE FILL\n");
	// debug_dump_me(all_entries, n_entries);


	AGBMergeEntry * cursor = all_entries;

	cursor+=copy_entries(cursor,head_tree,AGB_MERGE_LOCAL);
	cursor+=copy_entries(cursor,branch_tree,AGB_MERGE_REMOTE);
	cursor+=copy_entries(cursor,base_tree,AGB_MERGE_BASE);

	// printf("AFTER FILL\n");
	// debug_dump_me(all_entries, n_entries);

	qsort(all_entries, n_entries, sizeof(AGBMergeEntry), &sort_entries);

	// printf("AFTER SORT\n");
	// debug_dump_me(all_entries, n_entries);

	// Now we merge the duplicate filename entries.
	AGBMergeEntry * write_point = all_entries;
	AGBMergeEntry * read_point = all_entries;
	int n_merged_entries = n_entries>0 ? 1 : 0;
	for(size_t i=0; i<n_entries; ++i) {
		if(strcmp(read_point->name,write_point->name)==0) {
			for(int j=0; j<3; ++j) {
				if(read_point->treeentries[j]!=NULL) {
					write_point->treeentries[j]=read_point->treeentries[j];
				}
			}
			read_point++;
			continue;
		}

		//They differ so move the write point on, and write into it.	
		write_point++;
		if(read_point!=write_point) {
			memcpy(write_point,read_point,sizeof(AGBMergeEntry));
		}
		n_merged_entries++;
		read_point++;
	}
	// printf("AFTER MERGE\n");
	// debug_dump_me(all_entries, n_entries);


	// Now (optionally) prune out the unchanged values
	if( (merge_iterator_options & agb_merge_iterator_options_ALL_ENTRIES)==0 ) {
		int n_changed = 0;
		write_point = all_entries;
		read_point = all_entries;
		for(int i=0; i<n_merged_entries; ++i ) {
			if( // Something changed
					agb_git_tree_entry_equal(read_point->treeentries[AGB_MERGE_LOCAL], read_point->treeentries[AGB_MERGE_BASE])==0 ||
					agb_git_tree_entry_equal(read_point->treeentries[AGB_MERGE_REMOTE], read_point->treeentries[AGB_MERGE_BASE])==0
			  ) {
				if(read_point!=write_point) {
					memcpy(write_point,read_point,sizeof(AGBMergeEntry));
				}
				read_point++;
				write_point++;
				n_changed++;
				continue;
			}
			// Nothing changed, skip it.
			read_point++;
		}
		n_merged_entries = n_changed;
		//printf("AFTER FILTER\n");
		//debug_dump_me(all_entries, n_entries);
	}

	// Now we only need the merged entries;

	AGBMergeEntry * merged_entries = (AGBMergeEntry *) malloc( n_merged_entries * sizeof(AGBMergeEntry) );

	memcpy(merged_entries, all_entries,  n_merged_entries * sizeof(AGBMergeEntry));
	

	free(all_entries);

	AGBMergeIterator * retval = (AGBMergeIterator*)malloc(sizeof(AGBMergeIterator));
	memset(retval,0, sizeof(AGBMergeIterator));
	retval->trees[AGB_MERGE_LOCAL] = head_tree;
	retval->trees[AGB_MERGE_REMOTE] = branch_tree;
	retval->trees[AGB_MERGE_BASE] = base_tree;

	retval->entries = merged_entries;
	retval->n_entries = n_merged_entries;

	return retval;
}
Exemple #11
0
void test_object_tree_write__cruel_paths(void)
{
	static const char *the_paths[] = {
		"C:\\",
		" : * ? \" \n < > |",
		"a\\b",
		"\\\\b\a",
		":\\",
		"COM1",
		"foo.aux",
		REP1024("1234"), /* 4096 char string */
		REP1024("12345678"), /* 8192 char string */
		"\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD", /* Ūnĭcōde̽ */
		NULL
	};
	git_treebuilder *builder;
	git_tree *tree;
	git_oid id, bid, subid;
	const char **scan;
	int count = 0, i, j;
	git_tree_entry *te;

	git_oid_fromstr(&bid, blob_oid);

	/* create tree */
	cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
	for (scan = the_paths; *scan; ++scan) {
		cl_git_pass(git_treebuilder_insert(
			NULL, builder, *scan, &bid, GIT_FILEMODE_BLOB));
		count++;
	}
	cl_git_pass(git_treebuilder_write(&id, builder));
	git_treebuilder_free(builder);

	/* check data is correct */
	cl_git_pass(git_tree_lookup(&tree, g_repo, &id));

	cl_assert_equal_i(count, git_tree_entrycount(tree));

	for (scan = the_paths; *scan; ++scan) {
		const git_tree_entry *cte = git_tree_entry_byname(tree, *scan);
		cl_assert(cte != NULL);
		cl_assert_equal_s(*scan, git_tree_entry_name(cte));
	}
	for (scan = the_paths; *scan; ++scan) {
		cl_git_pass(git_tree_entry_bypath(&te, tree, *scan));
		cl_assert_equal_s(*scan, git_tree_entry_name(te));
		git_tree_entry_free(te);
	}

	git_tree_free(tree);

	/* let's try longer paths */
	cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));
	for (scan = the_paths; *scan; ++scan) {
		cl_git_pass(git_treebuilder_insert(
			NULL, builder, *scan, &id, GIT_FILEMODE_TREE));
	}
	cl_git_pass(git_treebuilder_write(&subid, builder));
	git_treebuilder_free(builder);

	/* check data is correct */
	cl_git_pass(git_tree_lookup(&tree, g_repo, &subid));

	cl_assert_equal_i(count, git_tree_entrycount(tree));

	for (i = 0; i < count; ++i) {
		for (j = 0; j < count; ++j) {
			git_buf b = GIT_BUF_INIT;
			cl_git_pass(git_buf_joinpath(&b, the_paths[i], the_paths[j]));
			cl_git_pass(git_tree_entry_bypath(&te, tree, b.ptr));
			cl_assert_equal_s(the_paths[j], git_tree_entry_name(te));
			git_tree_entry_free(te);
			git_buf_free(&b);
		}
	}

	git_tree_free(tree);
}
Exemple #12
0
void test_object_tree_write__removing_and_re_adding_in_treebuilder(void)
{
	git_treebuilder *builder;
	int i, aardvark_i, apple_i, apple_after_i, apple_extra_i, last_i;
	git_oid entry_oid, tree_oid;
	git_tree *tree;

	cl_git_pass(git_oid_fromstr(&entry_oid, blob_oid));

	cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));

	cl_assert_equal_i(0, (int)git_treebuilder_entrycount(builder));

	for (i = 0; _entries[i].filename; ++i)
		cl_git_pass(git_treebuilder_insert(NULL,
			builder, _entries[i].filename, &entry_oid, _entries[i].attr));

	cl_assert_equal_i(6, (int)git_treebuilder_entrycount(builder));

	cl_git_pass(git_treebuilder_remove(builder, "apple"));
	cl_assert_equal_i(5, (int)git_treebuilder_entrycount(builder));

	cl_git_pass(git_treebuilder_remove(builder, "apple_after"));
	cl_assert_equal_i(4, (int)git_treebuilder_entrycount(builder));

	cl_git_pass(git_treebuilder_insert(
		NULL, builder, "before_last", &entry_oid, GIT_FILEMODE_BLOB));
	cl_assert_equal_i(5, (int)git_treebuilder_entrycount(builder));

	/* reinsert apple_after */
	cl_git_pass(git_treebuilder_insert(
		NULL, builder, "apple_after", &entry_oid, GIT_FILEMODE_BLOB));
	cl_assert_equal_i(6, (int)git_treebuilder_entrycount(builder));

	cl_git_pass(git_treebuilder_remove(builder, "last"));
	cl_assert_equal_i(5, (int)git_treebuilder_entrycount(builder));

	/* reinsert last */
	cl_git_pass(git_treebuilder_insert(
		NULL, builder, "last", &entry_oid, GIT_FILEMODE_BLOB));
	cl_assert_equal_i(6, (int)git_treebuilder_entrycount(builder));

	cl_git_pass(git_treebuilder_insert(
		NULL, builder, "apple_extra", &entry_oid, GIT_FILEMODE_BLOB));
	cl_assert_equal_i(7, (int)git_treebuilder_entrycount(builder));

	cl_git_pass(git_treebuilder_write(&tree_oid, builder));

	git_treebuilder_free(builder);

	cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_oid));

	cl_assert_equal_i(7, (int)git_tree_entrycount(tree));

	cl_assert(git_tree_entry_byname(tree, ".first") != NULL);
	cl_assert(git_tree_entry_byname(tree, "apple") == NULL);
	cl_assert(git_tree_entry_byname(tree, "apple_after") != NULL);
	cl_assert(git_tree_entry_byname(tree, "apple_extra") != NULL);
	cl_assert(git_tree_entry_byname(tree, "last") != NULL);

	aardvark_i = apple_i = apple_after_i = apple_extra_i = last_i = -1;

	for (i = 0; i < 7; ++i) {
		const git_tree_entry *entry = git_tree_entry_byindex(tree, i);

		if (!strcmp(entry->filename, "aardvark"))
			aardvark_i = i;
		else if (!strcmp(entry->filename, "apple"))
			apple_i = i;
		else if (!strcmp(entry->filename, "apple_after"))
			apple_after_i = i;
		else if (!strcmp(entry->filename, "apple_extra"))
			apple_extra_i = i;
		else if (!strcmp(entry->filename, "last"))
			last_i = i;
	}

	cl_assert_equal_i(-1, apple_i);
	cl_assert_equal_i(6, last_i);
	cl_assert(aardvark_i < apple_after_i);
	cl_assert(apple_after_i < apple_extra_i);

	git_tree_free(tree);
}
Exemple #13
0
/*
 * And the Lord said: Is this tree properly sorted?
 */
void test_object_tree_write__sorted_subtrees(void)
{
	git_treebuilder *builder;
	git_tree *tree;
	unsigned int i;
	int position_c = -1, position_cake = -1, position_config = -1;

	struct {
		unsigned int attr;
		const char *filename;
	} entries[] = {
		{ GIT_FILEMODE_BLOB, ".gitattributes" },
	  	{ GIT_FILEMODE_BLOB, ".gitignore" },
	  	{ GIT_FILEMODE_BLOB, ".htaccess" },
	  	{ GIT_FILEMODE_BLOB, "Capfile" },
	  	{ GIT_FILEMODE_BLOB, "Makefile"},
	  	{ GIT_FILEMODE_BLOB, "README"},
	  	{ GIT_FILEMODE_TREE, "app"},
	  	{ GIT_FILEMODE_TREE, "cake"},
	  	{ GIT_FILEMODE_TREE, "config"},
	  	{ GIT_FILEMODE_BLOB, "c"},
	  	{ GIT_FILEMODE_BLOB, "git_test.txt"},
	  	{ GIT_FILEMODE_BLOB, "htaccess.htaccess"},
	  	{ GIT_FILEMODE_BLOB, "index.php"},
	  	{ GIT_FILEMODE_TREE, "plugins"},
	  	{ GIT_FILEMODE_TREE, "schemas"},
	  	{ GIT_FILEMODE_TREE, "ssl-certs"},
	  	{ GIT_FILEMODE_TREE, "vendors"}
	};

	git_oid bid, tid, tree_oid;

	cl_git_pass(git_oid_fromstr(&bid, blob_oid));
	cl_git_pass(git_oid_fromstr(&tid, first_tree));

	cl_git_pass(git_treebuilder_new(&builder, g_repo, NULL));

	for (i = 0; i < ARRAY_SIZE(entries); ++i) {
		git_oid *id = entries[i].attr == GIT_FILEMODE_TREE ?  &tid : &bid; 

		cl_git_pass(git_treebuilder_insert(NULL,
			builder, entries[i].filename, id, entries[i].attr));
	}

	cl_git_pass(git_treebuilder_write(&tree_oid, builder));

	cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_oid));
	for (i = 0; i < git_tree_entrycount(tree); i++) {
		const git_tree_entry *entry = git_tree_entry_byindex(tree, i);

		if (strcmp(entry->filename, "c") == 0)
			position_c = i;

		if (strcmp(entry->filename, "cake") == 0)
			position_cake = i;

		if (strcmp(entry->filename, "config") == 0)
			position_config = i;
	}

	git_tree_free(tree);

	cl_assert(position_c != -1);
	cl_assert(position_cake != -1);
	cl_assert(position_config != -1);

	cl_assert(position_c < position_cake);
	cl_assert(position_cake < position_config);

	git_treebuilder_free(builder);
}
Exemple #14
0
/**
 * Merges two tree objects, producing a third tree.
 * The base tree allows the algorithm to distinguish between adds and deletes.
 * The algorithm always prefers the item from tree 1 when there is a conflict.
 */
static int sync_merge_trees(git_oid *out,
                            git_repository *repo,
                            const git_oid *base_id,
                            const git_oid *id1,
                            const git_oid *id2)
{
    int e = 0;
    git_tree *base_tree = NULL;
    git_tree *tree1 = NULL;
    git_tree *tree2 = NULL;
    git_treebuilder *tb = NULL;
    size_t size1, size2;
    size_t i1 = 0;
    size_t i2 = 0;
    const git_tree_entry *e1 = NULL;
    const git_tree_entry *e2 = NULL;
    enum { ONLY1 = 1, ONLY2 = 2, BOTH = 3 } state = BOTH;

    git_check(git_tree_lookup(&base_tree, repo, base_id));
    git_check(git_tree_lookup(&tree1, repo, id1));
    git_check(git_tree_lookup(&tree2, repo, id2));
    git_check(git_treebuilder_new(&tb, repo, NULL));
    size1 = git_tree_entrycount(tree1);
    size2 = git_tree_entrycount(tree2);

    while (1)
    {
        // Advance to next file:
        if (state == ONLY1 || state == BOTH)
        {
            e1 = i1 < size1 ? git_tree_entry_byindex(tree1, i1++) : NULL;
        }
        if (state == ONLY2 || state == BOTH)
        {
            e2 = i2 < size2 ? git_tree_entry_byindex(tree2, i2++) : NULL;
        }

        // Determine state:
        if (e1 && e2)
        {
            int s = strcmp(git_tree_entry_name(e1), git_tree_entry_name(e2));
            state = s < 0 ? ONLY1 :
                    s > 0 ? ONLY2 :
                    BOTH;
        }
        else if (e1 && !e2)
        {
            state = ONLY1;
        }
        else if (!e1 && e2)
        {
            state = ONLY2;
        }
        else
        {
            break;
        }

        // Grab the entry in question:
        const git_tree_entry *entry =
            (state == ONLY1 || state == BOTH) ? e1 : e2;
        const git_tree_entry *base_entry =
            git_tree_entry_byname(base_tree, git_tree_entry_name(entry));

        // Decide what to do with the entry:
        if (state == BOTH && base_entry &&
            GIT_OBJ_TREE == git_tree_entry_type(e1) &&
            GIT_OBJ_TREE == git_tree_entry_type(e2) &&
            GIT_OBJ_TREE == git_tree_entry_type(base_entry))
        {
            // Merge sub-trees:
            git_oid new_tree;
            git_check(sync_merge_trees(&new_tree, repo,
                git_tree_entry_id(base_entry),
                git_tree_entry_id(e1),
                git_tree_entry_id(e2)));
            git_check(git_treebuilder_insert(NULL, tb,
                git_tree_entry_name(e1),
                &new_tree,
                git_tree_entry_filemode(e1)));
        }
        else if (state == BOTH && base_entry)
        {
            if (git_oid_cmp(git_tree_entry_id(base_entry), git_tree_entry_id(e1)))
            {
                // Entry `e1` has changes, so use that:
                git_check(git_treebuilder_insert(NULL, tb,
                    git_tree_entry_name(e1),
                    git_tree_entry_id(e1),
                    git_tree_entry_filemode(e1)));
            }
            else
            {
                // Entry `e1` has no changes, so use `e2`:
                git_check(git_treebuilder_insert(NULL, tb,
                    git_tree_entry_name(e2),
                    git_tree_entry_id(e2),
                    git_tree_entry_filemode(e2)));
            }
        }
        else if (state == BOTH || !base_entry)
        {
            // Entry was added, or already present:
            git_check(git_treebuilder_insert(NULL, tb,
                git_tree_entry_name(entry),
                git_tree_entry_id(entry),
                git_tree_entry_filemode(entry)));
        }
        // Otherwise, the entry was deleted.
    }

    // Write tree:
    git_check(git_treebuilder_write(out, tb));

exit:
    if (base_tree)      git_tree_free(base_tree);
    if (tree1)          git_tree_free(tree1);
    if (tree2)          git_tree_free(tree2);
    if (tb)             git_treebuilder_free(tb);
    return e;
}
Exemple #15
0
size_t QGitTree::entryCount()
{
    return git_tree_entrycount(data());
}