public void RecoverAll() { var waitingReceivePacks = new List <ParsedReceivePack>(); foreach (var packDir in recoveryFilePathBuilder.GetPathToPackDirectory()) { foreach (var packFilePath in Directory.GetFiles(packDir)) { using (var fileReader = new StreamReader(packFilePath)) { var packFileData = fileReader.ReadToEnd(); waitingReceivePacks.Add(JsonConvert.DeserializeObject <ParsedReceivePack>(packFileData)); } } } foreach (var pack in waitingReceivePacks.OrderBy(p => p.Timestamp)) { // execute if the pack has been waiting for X amount of time if ((DateTime.Now - pack.Timestamp) >= failedPackWaitTimeBeforeExecution) { // re-parse result file and execute "post" hooks // if result file is no longer there then move on var failedPackResultFilePath = recoveryFilePathBuilder.GetPathToResultFile(pack.PackId, pack.RepositoryName, "receive-pack"); if (File.Exists(failedPackResultFilePath)) { using (var resultFileStream = File.OpenRead(failedPackResultFilePath)) { var failedPackResult = resultFileParser.ParseResult(resultFileStream); ProcessOnePack(pack, failedPackResult); } File.Delete(failedPackResultFilePath); } } } }
public void ExecuteServiceByName(string correlationId, string repositoryName, string serviceName, ExecutionOptions options, System.IO.Stream inStream, System.IO.Stream outStream) { ParsedReceivePack receivedPack = null; if (serviceName == "receive-pack" && inStream.Length > 0) { // PARSING RECEIVE-PACK THAT IS OF THE FOLLOWING FORMAT: // (NEW LINES added for ease of reading) // (LLLL is length of the line (expressed in HEX) until next LLLL value) // // LLLL------ REF LINE -----------\0------- OHTER DATA ----------- // LLLL------ REF LINE ---------------- // ... // ... // 0000PACK------- REST OF PACKAGE -------- // var pktLines = new List <ReceivePackPktLine>(); var buff1 = new byte[1]; var buff4 = new byte[4]; var buff20 = new byte[20]; var buff16K = new byte[1024 * 16]; while (true) { ReadStream(inStream, buff4); var len = Convert.ToInt32(Encoding.UTF8.GetString(buff4), 16); if (len == 0) { break; } len = len - buff4.Length; var accum = new LinkedList <byte>(); while (len > 0) { len -= 1; ReadStream(inStream, buff1); if (buff1[0] == 0) { break; } accum.AddLast(buff1[0]); } if (len > 0) { inStream.Seek(len, SeekOrigin.Current); } var pktLine = Encoding.UTF8.GetString(accum.ToArray()); var pktLineItems = pktLine.Split(' '); var fromCommit = pktLineItems[0]; var toCommit = pktLineItems[1]; var refName = pktLineItems[2]; pktLines.Add(new ReceivePackPktLine(fromCommit, toCommit, refName)); } // parse PACK contents var packCommits = new List <ReceivePackCommit>(); // PACK format // https://www.kernel.org/pub/software/scm/git/docs/technical/pack-format.html // http://schacon.github.io/gitbook/7_the_packfile.html if (inStream.Position < inStream.Length) { ReadStream(inStream, buff4); if (Encoding.UTF8.GetString(buff4) != "PACK") { throw new Exception("Unexpected receive-pack 'PACK' content."); } ReadStream(inStream, buff4); Array.Reverse(buff4); var versionNum = BitConverter.ToInt32(buff4, 0); ReadStream(inStream, buff4); Array.Reverse(buff4); var numObjects = BitConverter.ToInt32(buff4, 0); while (numObjects > 0) { numObjects -= 1; ReadStream(inStream, buff1); var type = (GIT_OBJ_TYPE)((buff1[0] >> 4) & 7); long len = buff1[0] & 15; var shiftAmount = 4; while ((buff1[0] >> 7) == 1) { ReadStream(inStream, buff1); len = len | ((long)(buff1[0] & 127) << shiftAmount); shiftAmount += 7; } if (type == GIT_OBJ_TYPE.OBJ_REF_DELTA) { // read ref name ReadStream(inStream, buff20); } if (type == GIT_OBJ_TYPE.OBJ_OFS_DELTA) { // read negative offset ReadStream(inStream, buff1); while ((buff1[0] >> 7) == 1) { ReadStream(inStream, buff1); } } var origPosition = inStream.Position; long offsetVal = 0; using (var zlibStream = new ZlibStream(inStream, CompressionMode.Decompress, true)) { // read compressed data max 16KB at a time var readRemaining = len; do { var bytesUncompressed = zlibStream.Read(buff16K, 0, buff16K.Length); readRemaining -= bytesUncompressed; } while (readRemaining > 0); if (type == GIT_OBJ_TYPE.OBJ_COMMIT) { var parsedCommit = ParseCommitDetails(buff16K, len); packCommits.Add(parsedCommit); } offsetVal = zlibStream.TotalIn; } // move back position a bit because ZLibStream reads more than needed for inflating inStream.Seek(origPosition + offsetVal, SeekOrigin.Begin); } } // ------------------- var user = HttpContext.Current.User.Username(); receivedPack = new ParsedReceivePack(correlationId, repositoryName, pktLines, user, DateTime.Now, packCommits); inStream.Seek(0, SeekOrigin.Begin); receivePackHandler.PrePackReceive(receivedPack); } GitExecutionResult execResult = null; using (var capturedOutputStream = new MemoryStream()) { gitService.ExecuteServiceByName(correlationId, repositoryName, serviceName, options, inStream, new ReplicatingStream(outStream, capturedOutputStream)); // parse captured output capturedOutputStream.Seek(0, SeekOrigin.Begin); execResult = resultParser.ParseResult(capturedOutputStream); } if (receivedPack != null) { receivePackHandler.PostPackReceive(receivedPack, execResult); } }