linux subdivision ying gai ke yi le ba

源代码在线查看: commit-access-control.pl.in

软件大小: 10313 K
上传用户: zhangyuntong
关键词: subdivision linux ying gai
下载地址: 免注册下载 普通下载 VIP

相关代码

				#!/usr/bin/env perl
				
				# ====================================================================
				# commit-access-control.pl: check if the user that submitted the
				# transaction TXN-NAME has the appropriate rights to perform the
				# commit in repository REPOS using the permissions listed in the
				# configuration file CONF_FILE.
				#
				# $HeadURL: http://svn.collab.net/repos/svn/branches/1.1.x/tools/hook-scripts/commit-access-control.pl.in $
				# $LastChangedDate: 2004-06-14 13:29:22 -0700 (Mon, 14 Jun 2004) $
				# $LastChangedBy: breser $
				# $LastChangedRevision: 9986 $
				#
				# Usage: commit-access-control.pl REPOS TXN-NAME CONF_FILE
				#    
				# ====================================================================
				# Copyright (c) 2000-2004 CollabNet.  All rights reserved.
				#
				# This software is licensed as described in the file COPYING, which
				# you should have received as part of this distribution.  The terms
				# are also available at http://subversion.tigris.org/license-1.html.
				# If newer versions of this license are posted there, you may use a
				# newer version instead, at your option.
				#
				# This software consists of voluntary contributions made by many
				# individuals.  For exact contribution history, see the revision
				# history and logs, available at http://subversion.tigris.org/.
				# ====================================================================
				
				# Turn on warnings the best way depending on the Perl version.
				BEGIN {
				  if ( $] >= 5.006_000)
				    { require warnings; import warnings; }                      
				  else  
				    { $^W = 1; }               
				}           
				
				use strict;
				use Carp;
				use Config::IniFiles 2.27;
				
				######################################################################
				# Configuration section.
				
				# Svnlook path.
				my $svnlook = "@SVN_BINDIR@/svnlook";
				
				# Since the path to svnlook depends upon the local installation
				# preferences, check that the required program exists to insure that
				# the administrator has set up the script properly.
				{
				  my $ok = 1;
				  foreach my $program ($svnlook)
				    {
				      if (-e $program)
				        {
				          unless (-x $program)
				            {
				              warn "$0: required program `$program' is not executable, ",
				                   "edit $0.\n";
				              $ok = 0;
				            }
				        }
				      else
				        {
				          warn "$0: required program `$program' does not exist, edit $0.\n";
				          $ok = 0;
				        }
				    }
				  exit 1 unless $ok;
				}
				
				######################################################################
				# Initial setup/command-line handling.
				
				&usage unless @ARGV == 3;
				
				my $repos        = shift;
				my $txn          = shift;
				my $cfg_filename = shift;
				
				unless (-e $repos)
				  {
				    &usage("$0: repository directory `$repos' does not exist.");
				  }
				unless (-d $repos)
				  {
				    &usage("$0: repository directory `$repos' is not a directory.");
				  }
				unless (-e $cfg_filename)
				  {
				    &usage("$0: configuration file `$cfg_filename' does not exist.");
				  }
				unless (-r $cfg_filename)
				  {
				    &usage("$0: configuration file `$cfg_filename' is not readable.");
				  }
				
				# Define two constant subroutines to stand for read-only or read-write
				# access to the repository.
				sub ACCESS_READ_ONLY  () { 'read-only' }
				sub ACCESS_READ_WRITE () { 'read-write' }
				
				######################################################################
				# Load the configuration file and validate it.
				my $cfg = Config::IniFiles->new(-file => $cfg_filename);
				unless ($cfg)
				  {
				    die "$0: error in loading configuration file `$cfg_filename'",
				         @Config::IniFiles::errors ? ":\n@Config::IniFiles::errors\n"
				                                   : ".\n";
				  }
				
				# Go through each section of the configuration file, validate that
				# each section has the required parameters and complain about unknown
				# parameters.  Compile any regular expressions.
				my @sections = $cfg->Sections;
				{
				  my $ok = 1;
				  foreach my $section (@sections)
				    {
				      # First check for any unknown parameters.
				      foreach my $param ($cfg->Parameters($section))
				        {
				          next if $param eq 'match';
				          next if $param eq 'users';
				          next if $param eq 'access';
				          warn "$0: config file `$cfg_filename' section `$section' parameter ",
				               "`$param' is being ignored.\n";
				          $cfg->delval($section, $param);
				        }
				
				      my $access = $cfg->val($section, 'access');
				      if (defined $access)
				        {
				          unless ($access eq ACCESS_READ_ONLY or $access eq ACCESS_READ_WRITE)
				            {
				              warn "$0: config file `$cfg_filename' section `$section' sets ",
				                "`access' to illegal value `$access'.\n";
				              $ok = 0;
				            }
				        }
				      else
				        {
				          warn "$0: config file `$cfg_filename' section `$section' does ",
				            "not set `access' parameter.\n";
				          $ok = 0;
				        }
				
				      my $match_regex = $cfg->val($section, 'match');
				      if (defined $match_regex)
				        {
				          # To help users that automatically write regular expressions
				          # that match the beginning of absolute paths using ^/,
				          # remove the / character because subversion paths, while
				          # they start at the root level, do not begin with a /.
				          $match_regex =~ s#^\^/#^#;
				
				          my $match_re;
				          eval { $match_re = qr/$match_regex/ };
				          if ($@)
				            {
				              warn "$0: config file `$cfg_filename' section `$section' ",
				                   "`match' regex `$match_regex' does not compile:\n$@\n";
				              $ok = 0;
				            }
				          else
				            {
				              $cfg->newval($section, 'match_re', $match_re);
				            }
				        }
				      else
				        {
				          warn "$0: config file `$cfg_filename' section `$section' does ",
				               "not set `match' parameter.\n";
				          $ok = 0;
				        }
				    }
				  exit 1 unless $ok;
				}
				
				######################################################################
				# Harvest data using svnlook.
				
				# Change into /tmp so that svnlook diff can create its .svnlook
				# directory.
				my $tmp_dir = '/tmp';
				chdir($tmp_dir)
				  or die "$0: cannot chdir `$tmp_dir': $!\n";
				
				# Get the author from svnlook.
				my @svnlooklines = &read_from_process($svnlook, 'author', $repos, '-t', $txn);
				my $author = shift @svnlooklines;
				unless (length $author)
				  {
				    die "$0: txn `$txn' has no author.\n";
				  }
				
				# Figure out what directories have changed using svnlook..
				my @dirs_changed = &read_from_process($svnlook, 'dirs-changed', $repos,
				                                      '-t', $txn);
				
				# Lose the trailing slash in the directory names if one exists, except
				# in the case of '/'.
				my $rootchanged = 0;
				for (my $i=0; $i				  {
				    if ($dirs_changed[$i] eq '/')
				      {
				        $rootchanged = 1;
				      }
				    else
				      {
				        $dirs_changed[$i] =~ s#^(.+)[/\\]$#$1#;
				      }
				  }
				
				# Figure out what files have changed using svnlook.
				my @files_changed;
				foreach my $line (&read_from_process($svnlook, 'changed', $repos, '-t', $txn))
				  {
				    # Split the line up into the modification code and path, ignoring
				    # property modifications.
				    if ($line =~ /^..  (.*)$/)
				      {
				        push(@files_changed, $1);
				      }
				  }
				
				# Create the list of all modified paths.
				my @changed = (@dirs_changed, @files_changed);
				
				# There should always be at least one changed path.  If there are
				# none, then there maybe something fishy going on, so just exit now
				# indicating that the commit should not proceed.
				unless (@changed)
				  {
				    die "$0: no changed paths found in txn `$txn'.\n";
				  }
				
				######################################################################
				# Populate the permissions table.
				
				# Set a hash keeping track of the access rights to each path.  Because
				# this is an access control script, set the default permissions to
				# read-only.
				my %permissions;
				foreach my $path (@changed)
				  {
				    $permissions{$path} = ACCESS_READ_ONLY;
				  }
				
				foreach my $section (@sections)
				  {
				    # Decide if this section should be used.  It should be used if
				    # there are no users listed at all for this section, or if there
				    # are users listed and the author is one of them.
				    my $use_this_section;
				
				    # If there are any users listed, then check if the author of this
				    # commit is listed in the list.  If not, then delete the section,
				    # because it won't apply.
				    #
				    # The configuration file can list users like this on multiple
				    # lines:
				    #   users = joe@mysite.com betty@mysite.com
				    #   users = bob@yoursite.com
				
				    # Because of the way Config::IniFiles works, check if there are
				    # any users at all with the scalar return from val() and if there,
				    # then get the array value to get all users.
				    my $users = $cfg->val($section, 'users');
				    if (defined $users and length $users)
				      {
				        my $match_user = 0;
				        foreach my $entry ($cfg->val($section, 'users'))
				          {
				            unless ($match_user)
				              {
				                foreach my $user (split(' ', $entry))
				                  {
				                    if ($author eq $user)
				                      {
				                        $match_user = 1;
				                        last;
				                      }
				                  }
				              }
				          }
				
				        $use_this_section = $match_user;
				      }
				    else
				      {
				        $use_this_section = 1;
				      }
				
				    next unless $use_this_section;
				
				    # Go through each modified path and match it to the regular
				    # expression and set the access right if the regular expression
				    # matches.
				    my $access   = $cfg->val($section, 'access');
				    my $match_re = $cfg->val($section, 'match_re');
				    foreach my $path (@changed)
				      {
				        $permissions{$path} = $access if $path =~ $match_re;
				      }
				  }
				
				# Go through all the modified paths and see if any permissions are
				# read-only.  If so, then fail the commit.
				my @failed_paths;
				foreach my $path (@changed)
				  {
				    if ($permissions{$path} ne ACCESS_READ_WRITE)
				      {
				        push(@failed_paths, $path);
				      }
				  }
				
				if (@failed_paths)
				  {
				    warn "$0: user `$author' does not have permission to commit to ",
				         @failed_paths > 1 ? "these paths:\n  " : "this path:\n  ",
				         join("\n  ", @failed_paths), "\n"; 
				    exit 1;
				  }
				else
				  {
				    exit 0;
				  }
				
				sub usage
				{
				  warn "@_\n" if @_;
				  die "usage: $0 REPOS TXN-NAME CONF_FILE\n";
				}
				
				sub safe_read_from_pipe
				{
				  unless (@_)
				    {
				      croak "$0: safe_read_from_pipe passed no arguments.\n";
				    }
				  print "Running @_\n";
				  my $pid = open(SAFE_READ, '-|');
				  unless (defined $pid)
				    {
				      die "$0: cannot fork: $!\n";
				    }
				  unless ($pid)
				    {
				      open(STDERR, ">&STDOUT")
				        or die "$0: cannot dup STDOUT: $!\n";
				      exec(@_)
				        or die "$0: cannot exec `@_': $!\n";
				    }
				  my @output;
				  while ()
				    {
				      chomp;
				      push(@output, $_);
				    }
				  close(SAFE_READ);
				  my $result = $?;
				  my $exit   = $result >> 8;
				  my $signal = $result & 127;
				  my $cd     = $result & 128 ? "with core dump" : "";
				  if ($signal or $cd)
				    {
				      warn "$0: pipe from `@_' failed $cd: exit=$exit signal=$signal\n";
				    }
				  if (wantarray)
				    {
				      return ($result, @output);
				    }
				  else
				    {
				      return $result;
				    }
				}
				
				sub read_from_process
				  {
				  unless (@_)
				    {
				      croak "$0: read_from_process passed no arguments.\n";
				    }
				  my ($status, @output) = &safe_read_from_pipe(@_);
				  if ($status)
				    {
				      if (@output)
				        {
				          die "$0: `@_' failed with this output:\n", join("\n", @output), "\n";
				        }
				      else
				        {
				          die "$0: `@_' failed with no output.\n";
				        }
				    }
				  else
				    {
				      return @output;
				    }
				}
							

相关资源