示例#1
0
            public static bool TryGetFromObjectFile(string filePath, out GitCommitObject commitObject)
            {
                commitObject = default;
                try
                {
                    using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        // We skip the 2 bytes zlib header magic number.
                        fs.Seek(2, SeekOrigin.Begin);
                        using (var defStream = new DeflateStream(fs, CompressionMode.Decompress))
                        {
                            byte[] buffer    = new byte[8192];
                            int    readBytes = defStream.Read(buffer, 0, buffer.Length);
                            defStream.Close();

                            if (_commitByteArray.SequenceEqual(buffer.Take(_commitByteArray.Length)))
                            {
                                string strContent  = Encoding.UTF8.GetString(buffer, 0, readBytes);
                                string dataContent = strContent.Substring(strContent.IndexOf('\0') + 1);
                                commitObject = new GitCommitObject(dataContent);
                                return(true);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "Error getting commit object from object file");
                }

                return(false);
            }
            public static bool TryGetFromPackageOffset(GitPackageOffset packageOffset, out GitCommitObject commitObject)
            {
                commitObject = default;

                string packFile = Path.ChangeExtension(packageOffset.FilePath, ".pack");

                if (File.Exists(packFile))
                {
                    // packfile format explanation:
                    // https://codewords.recurse.com/issues/three/unpacking-git-packfiles#:~:text=idx%20file%20contains%20the%20index,pack%20file.&text=Objects%20in%20a%20packfile%20can,of%20storing%20the%20whole%20object.

                    using (var fs = new FileStream(packFile, FileMode.Open, FileAccess.Read, FileShare.Read))
                        using (var br = new BigEndianBinaryReader(fs))
                        {
                            // Move to the offset of the object
                            fs.Seek(packageOffset.Offset, SeekOrigin.Begin);
                            int    objectSize;
                            byte[] packData = br.ReadBytes(2);

                            if (packData[0] < 128)
                            {
                                objectSize = (int)(packData[0] & 0x0f);
                                packData   = br.ReadBytes(objectSize);
                            }
                            else
                            {
                                objectSize = (((ushort)(packData[1] & 0x7f)) * 16) + ((ushort)(packData[0] & 0x0f));
                                packData   = br.ReadBytes(objectSize * 100);
                            }

                            using (var ms = new MemoryStream(packData, 2, packData.Length - 2))
                                using (var defStream = new DeflateStream(ms, CompressionMode.Decompress))
                                {
                                    byte[] buffer    = new byte[8192];
                                    int    readBytes = defStream.Read(buffer, 0, buffer.Length);
                                    defStream.Close();
                                    string strContent = Encoding.UTF8.GetString(buffer, 0, readBytes);
                                    commitObject = new GitCommitObject(strContent);
                                    return(true);
                                }
                        }
                }

                return(false);
            }
示例#3
0
            public static bool TryGetFromPackageOffset(GitPackageOffset packageOffset, out GitCommitObject commitObject)
            {
                commitObject = default;
                try
                {
                    string packFile = Path.ChangeExtension(packageOffset.FilePath, ".pack");
                    if (File.Exists(packFile))
                    {
                        // packfile format explanation:
                        // https://codewords.recurse.com/issues/three/unpacking-git-packfiles#:~:text=idx%20file%20contains%20the%20index,pack%20file.&text=Objects%20in%20a%20packfile%20can,of%20storing%20the%20whole%20object.

                        using (var fs = new FileStream(packFile, FileMode.Open, FileAccess.Read, FileShare.Read))
                            using (var br = new BigEndianBinaryReader(fs))
                            {
                                // Move to the offset of the object
                                fs.Seek(packageOffset.Offset, SeekOrigin.Begin);
                                byte[] packData = br.ReadBytes(2);

                                // Extract the object size (https://codewords.recurse.com/images/three/varint.svg)
                                int objectSize = (int)(packData[0] & 0x0F);
                                if (packData[0] >= 128)
                                {
                                    int shift = 4;
                                    objectSize += (packData[1] & 0x7F) << shift;
                                    if (packData[1] >= 128)
                                    {
                                        byte pData;
                                        do
                                        {
                                            shift      += 7;
                                            pData       = br.ReadByte();
                                            objectSize += (pData & 0x7F) << shift;
                                        }while (pData >= 128);
                                    }
                                }

                                // Check if the object size is in the aceptable range
                                if (objectSize > 0 && objectSize < ushort.MaxValue)
                                {
                                    // Advance 2 bytes to skip the zlib magic number
                                    uint zlibMagicNumber = br.ReadUInt16();
                                    if ((byte)zlibMagicNumber == 0x78)
                                    {
                                        // Read the git commit object
                                        using (var defStream = new DeflateStream(br.BaseStream, CompressionMode.Decompress))
                                        {
                                            byte[] buffer    = new byte[objectSize];
                                            int    readBytes = defStream.Read(buffer, 0, buffer.Length);
                                            defStream.Close();
                                            string strContent = Encoding.UTF8.GetString(buffer, 0, readBytes);
                                            commitObject = new GitCommitObject(strContent);
                                            return(true);
                                        }
                                    }
                                    else
                                    {
                                        Log.Warning("The commit data doesn't have a valid zlib header magic number.");
                                    }
                                }
                                else
                                {
                                    Log.Warning <int>("The object size is outside of an acceptable range: {objectSize}", objectSize);
                                }
                            }
                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "Error loading commit information from package offset");
                }

                return(false);
            }
示例#4
0
        private static GitInfo GetFrom(DirectoryInfo gitDirectory)
        {
            if (gitDirectory == null)
            {
                return(new GitInfo());
            }

            GitInfo gitInfo = new GitInfo();

            try
            {
                gitInfo.SourceRoot = gitDirectory.Parent?.FullName;

                // Get Git commit
                string headPath = Path.Combine(gitDirectory.FullName, "HEAD");
                if (File.Exists(headPath))
                {
                    string head = File.ReadAllText(headPath).Trim();

                    // Symbolic Reference
                    if (head.StartsWith("ref:"))
                    {
                        gitInfo.Branch = head.Substring(4).Trim();

                        string refPath     = Path.Combine(gitDirectory.FullName, gitInfo.Branch);
                        string infoRefPath = Path.Combine(gitDirectory.FullName, "info", "refs");

                        if (File.Exists(refPath))
                        {
                            // Get the commit from the .git/{refPath} file.
                            gitInfo.Commit = File.ReadAllText(refPath).Trim();
                        }
                        else if (File.Exists(infoRefPath))
                        {
                            // Get the commit from the .git/info/refs file.
                            string[] lines = File.ReadAllLines(infoRefPath);
                            foreach (string line in lines)
                            {
                                string[] hashRef = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
                                if (hashRef[1] == gitInfo.Branch)
                                {
                                    gitInfo.Commit = hashRef[0];
                                }
                            }
                        }
                    }
                    else
                    {
                        // Hash reference
                        gitInfo.Commit = head;
                    }
                }

                // Process Git Config
                string            configPath = Path.Combine(gitDirectory.FullName, "config");
                List <ConfigItem> lstConfigs = GetConfigItems(configPath);
                if (lstConfigs != null && lstConfigs.Count > 0)
                {
                    var remote = "origin";

                    var branchItem = lstConfigs.Find(i => i.Type == "branch" && i.Merge == gitInfo.Branch);
                    if (branchItem != null)
                    {
                        gitInfo.Branch = branchItem.Name;
                        remote         = branchItem.Remote;
                    }

                    var remoteItem = lstConfigs.Find(i => i.Type == "remote" && i.Name == remote);
                    if (remoteItem != null)
                    {
                        gitInfo.Repository = remoteItem.Url;
                    }
                }

                // Get author and committer data
                if (!string.IsNullOrEmpty(gitInfo.Commit))
                {
                    string folder         = gitInfo.Commit.Substring(0, 2);
                    string file           = gitInfo.Commit.Substring(2);
                    string objectFilePath = Path.Combine(gitDirectory.FullName, "objects", folder, file);
                    if (File.Exists(objectFilePath))
                    {
                        // Load and parse object file
                        if (GitCommitObject.TryGetFromObjectFile(objectFilePath, out var commitObject))
                        {
                            gitInfo.AuthorDate     = commitObject.AuthorDate;
                            gitInfo.AuthorEmail    = commitObject.AuthorEmail;
                            gitInfo.AuthorName     = commitObject.AuthorName;
                            gitInfo.CommitterDate  = commitObject.CommitterDate;
                            gitInfo.CommitterEmail = commitObject.CommitterEmail;
                            gitInfo.CommitterName  = commitObject.CommitterName;
                            gitInfo.Message        = commitObject.Message;
                            gitInfo.PgpSignature   = commitObject.PgpSignature;
                        }
                    }
                    else
                    {
                        // Search git object file from the pack files
                        string   packFolder = Path.Combine(gitDirectory.FullName, "objects", "pack");
                        string[] files      = Directory.GetFiles(packFolder, "*.idx", SearchOption.TopDirectoryOnly);
                        foreach (string idxFile in files)
                        {
                            if (GitPackageOffset.TryGetPackageOffset(idxFile, gitInfo.Commit, out var packageOffset))
                            {
                                if (GitCommitObject.TryGetFromPackageOffset(packageOffset, out var commitObject))
                                {
                                    gitInfo.AuthorDate     = commitObject.AuthorDate;
                                    gitInfo.AuthorEmail    = commitObject.AuthorEmail;
                                    gitInfo.AuthorName     = commitObject.AuthorName;
                                    gitInfo.CommitterDate  = commitObject.CommitterDate;
                                    gitInfo.CommitterEmail = commitObject.CommitterEmail;
                                    gitInfo.CommitterName  = commitObject.CommitterName;
                                    gitInfo.Message        = commitObject.Message;
                                    gitInfo.PgpSignature   = commitObject.PgpSignature;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error loading git information from directory");
            }

            return(gitInfo);
        }