52037317 发表于 2018-1-14 20:35:34

【C#】纯托管实现一个Git服务端

  有传闻说,这年头不用Git就不是个程序员。传闻归传闻,近些年来Git的发展是如火如荼。除了一些公共的Git平台外,大多的Git服务端都是在Linux上的,Windows的可选方案实在甚少。作为一个.Net码农,当然希望能有个纯托管代码的Git服务端。经过一晚上的学习,用纯托管代码写了个Git服务端供大家参考。
  学习资料:暂无。
  接下来开始码代码。首先加入引用:GitSharp.Core,GitSharp。可以从git://github.com/henon/GitSharp.git获取。然后,
   1:using GitSharp.Core.Transport;  

  

   2:using System;  

  

   3:using System.IO;  

  

   4:using System.Net;  

  

   5:using System.Text;  

  

   6:using System.Text.RegularExpressions;  

  

   7:     

  

   8:namespace SampleGitServer  

  

   9:{  

  

10:   >  

  

11:      {  

  

12:          const string PREFIX = @"http://localhost:2034/";  

  

13:          const string REPOSITORY_PATH = @"F:\Repositories\git-debug-ONLY";  

  

14:     

  

15:          readonly static Regex GetInfoRefsRegex = new Regex(PREFIX + @"\w{3,10}/info/refs\?service=.*");  

  

16:          readonly static Regex GitUploadPackRegex = new Regex(PREFIX + @"\w{3,10}/git-upload-pack");  

  

17:          readonly static Regex GitRecivePackRegex = new Regex(PREFIX + @"\w{3,10}/git-receive-pack");  

  

18:     

  

19:          static void Main(string[] args)  

  

20:          {  

  

21:            var listener = new HttpListener();  

  

22:            listener.Prefixes.Add(PREFIX);  

  

23:     

  

24:            Console.WriteLine("Listening: " + PREFIX);  

  

25:            listener.Start();  

  

26:     

  

27:            while (true)  

  

28:            {  

  

29:                  var context = listener.GetContext();  

  

30:                  var url = context.Request.Url.ToString();  

  

31:     

  

32:                  Console.WriteLine(url);  

  

33:     

  

34:                  if (GetInfoRefsRegex.Match(url).Success)  

  

35:                      GetInfoRefs(context);  

  

36:                  else if (GitUploadPackRegex.Match(url).Success)  

  

37:                      GitUploadPack(context);  

  

38:                  else if (GitRecivePackRegex.Match(url).Success)  

  

39:                      GitRecivePack(context);  

  

40:            }  

  

41:          }  

  

42:     

  

43:          private static void GetInfoRefs(HttpListenerContext context)  

  

44:          {  

  

45:            var Request = context.Request;  

  

46:            var Response = context.Response;  

  

47:            var project = Request.Url.PathAndQuery.Split('/');  

  

48:            var service = Request.QueryString["service"];  

  

49:     

  

50:            var directory = GetDirectoryInfo(project);  

  

51:            if (GitSharp.Repository.IsValid(directory.FullName, true))  

  

52:            {  

  

53:                  Response.StatusCode = 200;  

  

54:                  Response.ContentType = String.Format("application/x-{0}-advertisement", service);  

  

55:                  SetNoCache(Response);  

  

56:     

  

57:                  var sb = new StringBuilder();  

  

58:                  sb.Append(FormatMessage(String.Format("# service={0}\n", service)));  

  

59:                  sb.Append(FlushMessage());  

  

60:                  var bytes = Encoding.ASCII.GetBytes(sb.ToString());  

  

61:                  Response.OutputStream.Write(bytes, 0, bytes.Length);  

  

62:     

  

63:                  using (var repository = new GitSharp.Repository(directory.FullName))  

  

64:                  {  

  

65:                      if (String.Equals("git-receive-pack", service, StringComparison.InvariantCultureIgnoreCase))  

  

66:                      {  

  

67:                        using (var pack = new ReceivePack(repository))  

  

68:                        {  

  

69:                              pack.SendAdvertisedRefs(new RefAdvertiser.PacketLineOutRefAdvertiser(new PacketLineOut(Response.OutputStream)));  

  

70:                        }  

  

71:     

  

72:                      }  

  

73:                      else if (String.Equals("git-upload-pack", service, StringComparison.InvariantCultureIgnoreCase))  

  

74:                      {  

  

75:                        using (var pack = new UploadPack(repository))  

  

76:                        {  

  

77:                              pack.SendAdvertisedRefs(new RefAdvertiser.PacketLineOutRefAdvertiser(new PacketLineOut(Response.OutputStream)));  

  

78:                        }  

  

79:                      }  

  

80:                  }  

  

81:            }  

  

82:            else  

  

83:            {  

  

84:                  Response.StatusCode = 404;  

  

85:            }  

  

86:            Response.Close();  

  

87:          }  

  

88:     

  

89:          private static void GitUploadPack(HttpListenerContext context)  

  

90:          {  

  

91:            var Request = context.Request;  

  

92:            var Response = context.Response;  

  

93:            var project = Request.Url.PathAndQuery.Split('/');  

  

94:     

  

95:            Response.ContentType = "application/x-git-upload-pack-result";  

  

96:            SetNoCache(Response);  

  

97:     

  

98:            var directory = GetDirectoryInfo(project);  

  

99:            if (GitSharp.Repository.IsValid(directory.FullName, true))  

  

100:            {  

  

101:                  using (var repository = new GitSharp.Repository(directory.FullName))  

  

102:                  using (var pack = new UploadPack(repository))  

  

103:                  {  

  

104:                      pack.setBiDirectionalPipe(false);  

  

105:                      pack.Upload(Request.InputStream, Response.OutputStream, Response.OutputStream);  

  

106:                  }  

  

107:            }  

  

108:            else  

  

109:            {  

  

110:                  Response.StatusCode = 404;  

  

111:            }  

  

112:            Response.Close();  

  

113:          }  

  

114:     

  

115:          private static void GitRecivePack(HttpListenerContext context)  

  

116:          {  

  

117:            var Request = context.Request;  

  

118:            var Response = context.Response;  

  

119:            var project = Request.Url.PathAndQuery.Split('/');  

  

120:     

  

121:            Response.ContentType = "application/x-git-receive-pack-result";  

  

122:            SetNoCache(Response);  

  

123:     

  

124:            var directory = GetDirectoryInfo(project);  

  

125:            if (GitSharp.Repository.IsValid(directory.FullName, true))  

  

126:            {  

  

127:                  using (var repository = new GitSharp.Repository(directory.FullName))  

  

128:                  using (var pack = new ReceivePack(repository))  

  

129:                  {  

  

130:                      pack.setBiDirectionalPipe(false);  

  

131:                      pack.receive(Request.InputStream, Response.OutputStream, Response.OutputStream);  

  

132:                  }  

  

133:            }  

  

134:            else  

  

135:            {  

  

136:                  Response.StatusCode = 404;  

  

137:            }  

  

138:            Response.Close();  

  

139:          }  

  

140:     

  

141:          private static String FormatMessage(String input)  

  

142:          {  

  

143:            return (input.Length + 4).ToString("X").PadLeft(4, '0') + input;  

  

144:          }  

  

145:     

  

146:          private static String FlushMessage()  

  

147:          {  

  

148:            return "0000";  

  

149:          }  

  

150:     

  

151:          private static DirectoryInfo GetDirectoryInfo(String project)  

  

152:          {  

  

153:            return new DirectoryInfo(Path.Combine(REPOSITORY_PATH, project));  

  

154:          }  

  

155:     

  

156:          private static void SetNoCache(HttpListenerResponse Response)  

  

157:          {  

  

158:            Response.AddHeader("Expires", "Fri, 01 Jan 1980 00:00:00 GMT");  

  

159:            Response.AddHeader("Pragma", "no-cache");  

  

160:            Response.AddHeader("Cache-Control", "no-cache, max-age=0, must-revalidate");  

  

161:          }  

  

162:      }  

  

163:}  

  好吧,你看完代码会有一种上当的感觉。我必须承认我只是实现了服务端的接口而已。PS,我不会告诉你这点代码都是抄来的。
  重点是,所有的代码都是托管代码。
  

  .Net 托管实现的Git平台可以选择使用Git Candy了,功能比Bonobo更强大,速度更快、更稳定!
  
欢迎你的使用!
  源码在:http://github.com/Aimeast/GitCandy
  演示在:http://gitcandy.com
  Bonobo到GitCandy数据库转换程序:http://gitcandy.com/Repository/Tree/Bonobo2Candy/
页: [1]
查看完整版本: 【C#】纯托管实现一个Git服务端