Beispiel #1
0
func writeIndexEntries(repo *libgit.Repository, prefix string, entries []*GitIndexEntry) ([20]byte, error) {
	content := bytes.NewBuffer(nil)
	// [mode] [file/folder name]\0[SHA-1 of referencing blob or tree as [20]byte]

	lastname := ""
	firstIdxForTree := -1

	for idx, obj := range entries {
		nameBits := strings.Split(obj.PathName, "/")

		// Either it's the last entry and we haven't written a tree yet, or it's not the last
		// entry but the directory changed
		if (nameBits[0] != lastname || idx == len(entries)-1) && lastname != "" {
			var islice []*GitIndexEntry
			if idx == len(entries)-1 {
				islice = entries[firstIdxForTree:]
			} else {
				islice = entries[firstIdxForTree:idx]
			}
			subsha1, err := writeIndexSubtree(repo, lastname, islice)
			if err != nil {
				panic(err)
			}
			// Write the object
			fmt.Fprintf(content, "%o %s\x00", 0040000, lastname)
			content.Write(subsha1[:])

			// Reset the data keeping track of what this tree is.
			lastname = ""
			firstIdxForTree = -1
		}
		if len(nameBits) == 1 {
			//write the blob for the file portion
			fmt.Fprintf(content, "%o %s\x00", obj.Mode, obj.PathName)
			content.Write(obj.Sha1[:])
			lastname = ""
		} else {
			lastname = nameBits[0]
			if firstIdxForTree == -1 {
				firstIdxForTree = idx
			}
		}
	}

	sha1, err := repo.StoreObjectLoose(libgit.ObjectTree, bytes.NewReader(content.Bytes()))
	return [20]byte(sha1), err
}
Beispiel #2
0
func CommitTree(repo *libgit.Repository, args []string) string {
	content := bytes.NewBuffer(nil)

	var parents []string
	var messageString, messageFile string
	var skipNext bool
	var tree string
	for idx, val := range args {
		if idx == 0 && val[0] != '-' {
			tree = val
			continue
		}

		if skipNext == true {
			skipNext = false
			continue
		}
		switch val {
		case "-p":
			parents = append(parents, args[idx+1])
			skipNext = true
		case "-m":
			messageString += "\n" + args[idx+1] + "\n"
			skipNext = true
		case "-F":
			messageFile = args[idx+1]
			skipNext = true

		}
	}
	if messageString == "" {
		if messageFile != "" {
			// TODO: READ commit message from messageFile here
		} else {
			// If neither messageString nor messageFile are set, read
			// from STDIN
		}
		panic("Must provide message with -m parameter to commit-tree")
	}
	if tree == "" {
		tree = args[len(args)-1]
	}
	// TODO: Validate tree id
	fmt.Fprintf(content, "tree %s\n", tree)
	for _, val := range parents {
		fmt.Fprintf(content, "parent %s\n", val)
	}

	author := getAuthor(repo)
	t := time.Now()
	_, tzoff := t.Zone()
	// for some reason t.Zone() returns the timezone offset in seconds
	// instead of hours, so convert it to an hour format string
	tzStr := fmt.Sprintf("%+03d00", tzoff/(60*60))
	fmt.Fprintf(content, "author %s %d %s\n", author, t.Unix(), tzStr)
	fmt.Fprintf(content, "committer %s %d %s\n", author, t.Unix(), tzStr)
	fmt.Fprintf(content, "%s", messageString)
	fmt.Printf("%s", content.Bytes())
	sha1, err := repo.StoreObjectLoose(libgit.ObjectCommit, bytes.NewReader(content.Bytes()))
	if err != nil {
		return ""
	}
	return fmt.Sprintf("%s", sha1)
}
Beispiel #3
0
// Adds a file to the index, without writing it to disk.
// To write it to disk after calling this, use GitIndex.WriteIndex
//
// This will do the following:
// write git object blob of file contents to .git/objects
// normalize os.File name to path relative to gitRoot
// search GitIndex for normalized name
//	if GitIndexEntry found
//		update GitIndexEntry to point to the new object blob
// 	else
// 		add new GitIndexEntry if not found
//
func (g *GitIndex) AddFile(repo *libgit.Repository, file *os.File) {

	sha1, err := repo.StoreObjectLoose(libgit.ObjectBlob, file)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error storing object: %s", err)
	}
	fmt.Printf("Sha1: %s\n", sha1)
	fmt.Printf("Name is %s\n", file.Name())
	name := getNormalizedName(file)
	for _, entry := range g.Objects {
		if entry.PathName == name {
			entry.Sha1 = sha1

			fstat, err := file.Stat()
			if err != nil {
				panic(err)
			}
			modTime := fstat.ModTime()
			entry.Mtime = uint32(modTime.Unix())
			entry.Mtimenano = uint32(modTime.Nanosecond())
			entry.Fsize = uint32(fstat.Size())
			return
		}
	}
	fstat, err := file.Stat()
	if err != nil {
		panic(err)
	}
	modTime := fstat.ModTime()
	stat := fstat.Sys().(*syscall.Stat_t)
	csec, cnano := stat.Ctim.Unix()

	var mode uint32
	if fstat.IsDir() {
		// This should really recursively call add for each file in the directory.
		panic("Add can't handle directories. yet.")
	} else {
		// if it's a regular file, just assume it's 0644 for now
		mode = 0x81A4

	}
	// mode is
	/*
	     32-bit mode, split into (high to low bits)

	       4-bit object type
	         valid values in binary are 1000 (regular file), 1010 (symbolic link)
	         and 1110 (gitlink)

	       3-bit unused

	       9-bit unix permission. Only 0755 and 0644 are valid for regular files.
	       Symbolic links and gitlinks have value 0 in this field.

	   Flags is
	    A 16-bit 'flags' field split into (high to low bits)

	       1-bit assume-valid flag

	       1-bit extended flag (must be zero in version 2)

	       2-bit stage (during merge)

	       12-bit name length if the length is less than 0xFFF; otherwise 0xFFF
	       is stored in this field.

	*/
	//var flags uint16 = 0x8000 // start with "assume-valid" flag
	var flags uint16 = 0x8000 // start with "assume-valid" flag
	if len(name) >= 0x0FFF {
		flags |= 0x0FFF
	} else {
		flags |= (uint16(len(name)) & 0x0FFF)
	}

	g.Objects = append(g.Objects, &GitIndexEntry{
		fixedIndexEntry{
			uint32(csec),                 // right?
			uint32(cnano),                // right?
			uint32(modTime.Unix()),       // right
			uint32(modTime.Nanosecond()), // right
			uint32(stat.Dev),             // right
			uint32(stat.Ino),             // right
			mode,
			stat.Uid,             // right?
			stat.Gid,             // right?
			uint32(fstat.Size()), // right
			sha1,                 // this is right
			flags,                // right
		},
		name,
	})
	g.NumberIndexEntries += 1
	sort.Sort(ByPath(g.Objects))
	return
}