徒涉春冰

导航

gitserve:100行代码实现的git服务器

perl实现,依赖以下CPAN模块:Plack、Starman和Plack::App::GitSmartHttp

备注:

 1),可能要设置:git config http.postBuffer 524288000
 2),启动脚本:plackup -s Starman -p 5000 /opt/gitserve.psgi -error-log=/opt/gitserve.log --pid=/opt/gitserve.pid -D
 3) ,stop: kill -TERM `cat /opt/gitserve.pid,reload: kill -HUP`cat /opt/gitserve.pid

4),授权文件: repos段指定git库和授权的group,groups段指定组成员,users段指定用户名和密码。

$ cat authz
[groups]
    postgres = postgres
    test = test, postgres
    boost = boost

[repos]
    boost.git = boost, test

    postgres.git = postgres, test

    test.git = test

[users]
    admin=admin
    postgres=postgres
    test=test
    boost=boost

 

 

代码如下

 

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use diagnostics;
use Carp qw(croak carp confess);

use Plack::Builder;
use Plack::App::GitSmartHttp;
use Plack::App::URLMap;
use Plack::Middleware::Auth::Basic;

my $app = Plack::App::URLMap->new;

my (%repos, %groups, %users);

my $repo_path = "/opt/repos";
my $authz_file = "$repo_path/authz";

load_authz($authz_file);

while (my($reponame, $groupnames) = each %repos) {
    my $git_path = "$reponame";
    my $git_app = Plack::App::GitSmartHttp->new(
        root => "$repo_path/$git_path",
        upload_pack => 1,   # clone
        received_pack => 1, # push
    );

    $git_app = Plack::Middleware::Auth::Basic->wrap(
        $git_app, authenticator => sub {
            my ($auth_user, $auth_password) = @_;

            if (exists $users{$auth_user}) {
                return 0 if $auth_password ne $users{$auth_user};
                # administrator
                return 1 if $auth_user eq 'admin';

                for my $groupname (@$groupnames) {
                    my $group_members = $groups{$groupname};
                    for my $group_member (@$group_members) {
                        if ($auth_user eq $group_member) {
                            return 1;
                        }
                    }
                }
            }
            return 0;
        }
    );

    $app->mount("/$git_path" => $git_app);
}


$app;


sub load_authz {
    my $authz_file = shift @_;

    my $authz_fd;
    eval {
        open $authz_fd, "<$authz_file" or die "open $authz_file: $!\n";
        my $section;
        while (my $line = <$authz_fd>) {
            chomp $line;
            $line =~ s/\s*//gxms;
            next if substr $line, 0, 1 eq '#';
            if ($line =~ m/^\[(\S+)\]$/xms) {
                $section = $1;
                next;
            }
            elsif($line =~ m/^(\S+)=(\S+)$/xms) {
                my $section_key = $1;
                my $section_value = $2;

                if ($section eq "users") {
                    $users{$section_key} = $section_value;
                }
                elsif($section eq "repos") {
                    my (@groups) = split /,/, $section_value;
                    $repos{$section_key} = \@groups;
                }
                elsif($section eq "groups") {
                    my @members = split /,/, $section_value;
                    $groups{$section_key} = \@members;
                }
                else {
                    next;
                }
            }
            else {
                next;
            }
        }
        close $authz_fd;
    };
    croak $@ if $@;
}

 

posted on 2013-05-12 17:12  徒涉春冰  阅读(278)  评论(0编辑  收藏  举报