zoukankan      html  css  js  c++  java
  • 【C#】纯托管实现一个Git服务端

    【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:      class Program
      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('/')[1];
      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('/')[1];
      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('/')[1];
     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,我不会告诉你这点代码都是抄来的。

          重点是,所有的代码都是托管代码。在Github.com上有个正在发展中的ASP.NET MVC + EF + Sqlite实现的Git服务端(Dudu推荐:用开源 ASP.NET MVC 程序 Bonobo Git Server 搭建 Git 服务器)。经过几天的试用之后觉得比较稳定。重点的重点是此服务端正处在发展初期,你完全可以根据自己需求打造一个最适合自己的Git服务端。PS,此repo的主人最近很活跃。

    用开源 ASP.NET MVC 程序 Bonobo Git Server 搭建 Git 服务器

     

    现在不用Git,都不好意思说自己是程序员。

    当你想用Git,而源代码服务器是Windows系统时,你将面临一个问题:如何在Windows上搭建Git服务器?

    看看这篇文章(Setting up a Msysgit Server with copSSH on Windows)中的配置步骤,你会忘而却步吗?你会感叹“Linux世界的精彩,Windows世界的无奈”?

    但程序员的天性是解决问题并以此为乐。不管生活在哪个世界,解决问题才是王道。于是,有程序员解决了这个问题,用ASP.NET MVC写了一个开源的Git服务器程序——Bonobo Git Server

    Bonobo Git Server基于.NET Framework 4.0+ASP.NET MVC 3开发,数据库用的是SQLite,Git部分用的是GitSharp - Git for .NET and Mono

    运行Bonobo Git Server,只需要IIS+WebDAV(IIS 7.5自带WebDAV, IIS 7.0需要下载安装)。

    下面简单分享一下安装配置步骤,该步骤经过实践检验,我们已经成功部署。

    第一部分 Bonobo Git Server站点的安装与配置

    1. 下载Bonobo Git Server并解压

    下载地址:http://www.chodounsky.net/bonobo-git-server/

    如果想看源代码,请在这里下载:https://github.com/jakubgarfield/Bonobo-Git-Server

    2. 配置一个IIS站点(比如:git.cnblogs.com),指向Bonobo Git Server所在文件夹。

    a) 应用程序池要以.NET Framework 4.0运行。

    b) 要安装ASP.NET MVC3。

    c) 如果服务器用的是X64的Windows,需要下载64位版本的System.Data.SQLite至bin文件夹替换32位版本的。

    3. 通过浏览器访问上一步配置的站点,如下图:

    4. 输入默认用户名admin与密码admin,进入下图页面:

    5. 点击“Global Settings”,设置一下代码库的根目录,并设置好该目录的文件系统权限(需要有写权限):

    6. 点击“Respositories” 》“Create new repository”,创建新的代码库:

    7. 创建好之后,点击代码库的名称,就能查看该代码库的信息,比如最重要的信息——Git Repository Location。

    8. 安装/配置WebDAV

    安装

    1) 如果是IIS 7.5(Windows 7, Windows Server 2008 R2),WebDAV是自带的,只要添加该组件即可。具体配置方法参见 Installing WebDAV on IIS 7.5

    2) 如果是IIS 7.0,需要另外下载安装,请参见 Installing WebDAV on IIS 7.0 。

    配置

    添加一条Authoring Rule:

    到此,Git 服务器站点的基本配置就完成了。

    第二部分 Git客户端简要操作步骤

    现在可以通过Git客户端提交代码了,这里用的是TortoiseGit。

    1. 安装TortoiseGit,下载地址:http://code.google.com/p/tortoisegit/(需要先安装msysgit),VS2010插件可以使用Git Source Control Provider

    2. 在将要放置代码的文件夹点击右键选择"Git Clone",在Url中输入代码库的地址,确定后输入默认用户名与密码,然后就开始Clone...出现如下画面表示Clone成功。

    3. 向这个代码库文件夹添加代码文件,然后通过TortoiseGit的菜单[Git Commint -> "master"...”]提交代码(这个提交只是向本地的代码库提交,并没有提交至服务器,这也是Git与SVN的主要区别之一)。

    4. 通过TortoiseGit > Push 提交至Git服务器。

    第三部分  Git服务器的其他操作

    • 修改管理员密码,通过左侧的 "Users"链接进入用户管理界面进行修改。
    • 添加新用户并授权,管理员无法直创建帐户,需要通过注册页面先注册一个帐户(登录页面右上角有注册链接),然后在用户管理界面将该用户加入Administrator角色。
    • 如果遇到问题,可以查看App_Data中的错误日志文件Bonobo.Git.Server.Errors.log。 
    • 由于是开源程序,有什么不合你意的地方,直接可以修改源代码。

    小结

    轻松搞定,如愿以偿,现在终于可以理直气壮地说,“我是程序员,我用的是Git!”

     
     
     
    标签: Git
  • 相关阅读:
    linux文件属性基础篇
    Linux重定向符号(重点)
    linux---vim和grep
    linux目录文件与系统启动(3)/usr目录、/var目录和/proc目录讲解
    Linux 安装和 连接xshell
    shiro 快速入门详解。
    th 表达式的简单使用。
    springboot 分布式项目,子级项目各自的作用。
    springboot 配置百里香 thymeleaf?
    springboot 配置mybatis 配置mapper.xml
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2987676.html
Copyright © 2011-2022 走看看