2012-08-15 46 views
0

我一直在试图让代码嗅探器充当svn pre-commit hook,遵循pear的指导。但是,虽然我100%肯定我的代码应该是无效的,我得到没有错误和项目提交没有问题。代码嗅探器SVN提交前钩子

除了遵循梨给出的指导,还有什么需要做的吗?

Link to pear guide on code sniffer as pre-commit hook

我phpcs - svn的预提交的文件:

#!C:\wamp\bin\php\php5.4.3\php.exe 
<?php 
/** 
* A commit hook for SVN. 
* 
* PHP version 5 
* 
* @category PHP 
* @package PHP_CodeSniffer 
* @author Jack Bates <[email protected]> 
* @author Greg Sherwood <[email protected]> 
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600) 
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence 
* @link  http://pear.php.net/package/PHP_CodeSniffer 
*/ 

if (is_file(dirname(__FILE__).'/../CodeSniffer/CLI.php') === true) { 
    include_once dirname(__FILE__).'/../CodeSniffer/CLI.php'; 
} else { 
    include_once 'PHP/CodeSniffer/CLI.php'; 
} 

define('PHP_CODESNIFFER_SVNLOOK', 'C:\Program Files (x86)\VisualSVN Server\bin\svnlook'); 


/** 
* A class to process command line options. 
* 
* @category PHP 
* @package PHP_CodeSniffer 
* @author Jack Bates <[email protected]> 
* @author Greg Sherwood <[email protected]> 
* @copyright 2006-2011 Squiz Pty Ltd (ABN 77 084 670 600) 
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence 
* @version Release: 1.3.6 
* @link  http://pear.php.net/package/PHP_CodeSniffer 
*/ 
class PHP_CodeSniffer_SVN_Hook extends PHP_CodeSniffer_CLI 
{ 


    /** 
    * Get a list of default values for all possible command line arguments. 
    * 
    * @return array 
    */ 
    public function getDefaults() 
    { 
     $defaults = parent::getDefaults(); 

     $defaults['svnArgs'] = array(); 
     return $defaults; 

    }//end getDefaults() 


    /** 
    * Processes an unknown command line argument. 
    * 
    * All unknown args are sent to SVN commands. 
    * 
    * @param string $arg The command line argument. 
    * @param int $pos The position of the argument on the command line. 
    * @param array $values An array of values determined from CLI args. 
    * 
    * @return array The updated CLI values. 
    * @see getCommandLineValues() 
    */ 
    public function processUnknownArgument($arg, $pos, $values) 
    { 
     $values['svnArgs'][] = escapeshellarg($arg); 
     return $values; 

    }//end processUnknownArgument() 


    /** 
    * Runs PHP_CodeSniffer over files are directories. 
    * 
    * @param array $values An array of values determined from CLI args. 
    * 
    * @return int The number of error and warning messages shown. 
    * @see getCommandLineValues() 
    */ 
    public function process($values=array()) 
    { 
     if (empty($values) === true) { 
      $values = parent::getCommandLineValues(); 
     } 

     // Get list of files in this transaction. 
     $command = PHP_CODESNIFFER_SVNLOOK.' changed '.implode(' ', $values['svnArgs']); 
     $handle = popen($command, 'r'); 
     if ($handle === false) { 
      echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; 
      exit(2); 
     } 

     $contents = stream_get_contents($handle); 
     fclose($handle); 

     // Do not check deleted paths. 
     $contents = preg_replace('/^D.*/m', null, $contents); 

     // Drop the four characters representing the action which precede the path on 
     // each line. 
     $contents = preg_replace('/^.{4}/m', null, $contents); 

     $values['standard'] = $this->validateStandard($values['standard']); 
     if (PHP_CodeSniffer::isInstalledStandard($values['standard']) === false) { 
      // They didn't select a valid coding standard, so help them 
      // out by letting them know which standards are installed. 
      echo 'ERROR: the "'.$values['standard'].'" coding standard is not installed. '; 
      $this->printInstalledStandards(); 
      exit(2); 
     } 

     $phpcs = new PHP_CodeSniffer(
      $values['verbosity'], 
      $values['tabWidth'], 
      $values['encoding'] 
     ); 

     // Set file extensions if they were specified. Otherwise, 
     // let PHP_CodeSniffer decide on the defaults. 
     if (empty($values['extensions']) === false) { 
      $phpcs->setAllowedFileExtensions($values['extensions']); 
     } 

     // Set ignore patterns if they were specified. 
     if (empty($values['ignored']) === false) { 
      $phpcs->setIgnorePatterns($values['ignored']); 
     } 

     // Set some convenience member vars. 
     if ($values['errorSeverity'] === null) { 
      $this->errorSeverity = PHPCS_DEFAULT_ERROR_SEV; 
     } else { 
      $this->errorSeverity = $values['errorSeverity']; 
     } 

     if ($values['warningSeverity'] === null) { 
      $this->warningSeverity = PHPCS_DEFAULT_WARN_SEV; 
     } else { 
      $this->warningSeverity = $values['warningSeverity']; 
     } 

     // Initialize PHP_CodeSniffer listeners but don't process any files. 
     $phpcs->setCli($this); 
     $phpcs->process(array(), $values['standard'], $values['sniffs']); 

     // Need double quotes around the following regex beause the vertical whitespace 
     // char is not always treated correctly for whatever reason. 
     foreach (preg_split("/\v|\n/", $contents, -1, PREG_SPLIT_NO_EMPTY) as $path) { 
      // No need to process folders as each changed file is checked. 
      if (substr($path, -1) === '/') { 
       continue; 
      } 

      // We need to check ignore rules ourself because they are 
      // not checked when processing a single file. 
      if ($phpcs->shouldProcessFile($path) === false) { 
       continue; 
      } 

      // Get the contents of each file, as it would be after this transaction. 
      $command = PHP_CODESNIFFER_SVNLOOK.' cat '.implode(' ', $values['svnArgs']).' '.escapeshellarg($path); 
      $handle = popen($command, 'r'); 
      if ($handle === false) { 
       echo 'ERROR: Could not execute "'.$command.'"'.PHP_EOL.PHP_EOL; 
       exit(2); 
      } 

      $contents = stream_get_contents($handle); 
      fclose($handle); 

      $phpcs->processFile($path, $contents); 
     }//end foreach 

     return $this->printErrorReport(
      $phpcs, 
      $values['reports'], 
      $values['showSources'], 
      $values['reportFile'], 
      $values['reportWidth'] 
     ); 

    }//end process() 


    /** 
    * Prints out the usage information for this script. 
    * 
    * @return void 
    */ 
    public function printUsage() 
    { 
     parent::printUsage(); 

     echo PHP_EOL; 
     echo ' Each additional argument is passed to the `svnlook changed ...`'.PHP_EOL; 
     echo ' and `svnlook cat ...` commands. The report is printed on standard output,'.PHP_EOL; 
     echo ' however Subversion displays only standard error to the user, so in a'.PHP_EOL; 
     echo ' pre-commit hook, this script should be invoked as follows:'.PHP_EOL; 
     echo PHP_EOL; 
     echo ' '.basename($_SERVER['argv'][0]).' ... "$REPOS" -t "$TXN" >&2 || exit 1'.PHP_EOL; 

    }//end printUsage() 


}//end class 

$phpcs = new PHP_CodeSniffer_SVN_Hook(); 
$phpcs->checkRequirements(); 

$numErrors = $phpcs->process(); 
if ($numErrors !== 0) { 
    exit(1); 
} 

?> 

而且从颠覆我的预提交的文件:

#!/bin/sh 

# PRE-COMMIT HOOK 
# 
# The pre-commit hook is invoked before a Subversion txn is 
# committed. Subversion runs this hook by invoking a program 
# (script, executable, binary, etc.) named 'pre-commit' (for which 
# this file is a template), with the following ordered arguments: 
# 
# [1] REPOS-PATH (the path to this repository) 
# [2] TXN-NAME  (the name of the txn about to be committed) 
# 
# [STDIN] LOCK-TOKENS ** the lock tokens are passed via STDIN. 
# 
# If STDIN contains the line "LOCK-TOKENS:\n" (the "\n" denotes a 
# single newline), the lines following it are the lock tokens for 
# this commit. The end of the list is marked by a line containing 
# only a newline character. 
# 
# Each lock token line consists of a URI-escaped path, followed 
# by the separator character '|', followed by the lock token string, 
# followed by a newline. 
# 
# The default working directory for the invocation is undefined, so 
# the program should set one explicitly if it cares. 
# 
# If the hook program exits with success, the txn is committed; but 
# if it exits with failure (non-zero), the txn is aborted, no commit 
# takes place, and STDERR is returned to the client. The hook 
# program can use the 'svnlook' utility to help it examine the txn. 
# 
# On a Unix system, the normal procedure is to have 'pre-commit' 
# invoke other programs to do the real work, though it may do the 
# work itself too. 
# 
# *** NOTE: THE HOOK PROGRAM MUST NOT MODIFY THE TXN, EXCEPT *** 
# *** FOR REVISION PROPERTIES (like svn:log or svn:author). *** 
# 
# This is why we recommend using the read-only 'svnlook' utility. 
# In the future, Subversion may enforce the rule that pre-commit 
# hooks should not modify the versioned data in txns, or else come 
# up with a mechanism to make it safe to do so (by informing the 
# committing client of the changes). However, right now neither 
# mechanism is implemented, so hook writers just have to be careful. 
# 
# Note that 'pre-commit' must be executable by the user(s) who will 
# invoke it (typically the user httpd runs as), and that user must 
# have filesystem-level permission to access the repository. 
# 
# On a Windows system, you should name the hook program 
# 'pre-commit.bat' or 'pre-commit.exe', 
# but the basic idea is the same. 
# 
# The hook program typically does not inherit the environment of 
# its parent process. For example, a common problem is for the 
# PATH environment variable to not be set to its usual value, so 
# that subprograms fail to launch unless invoked via absolute path. 
# If you're having unexpected problems with a hook program, the 
# culprit may be unusual (or missing) environment variables. 
# 
# Here is an example hook script, for a Unix /bin/sh interpreter. 
# For more examples and pre-written hooks, see those in 
# the Subversion repository at 
# http://svn.apache.org/repos/asf/subversion/trunk/tools/hook-scripts/ and 
# http://svn.apache.org/repos/asf/subversion/trunk/contrib/hook-scripts/ 


REPOS="$1" 
TXN="$2" 

# Make sure that the log message contains some text. 
SVNLOOK=/usr/local/bin/svnlook 
$SVNLOOK log -t "$TXN" "$REPOS" | \ 
    grep "[a-zA-Z0-9]" > /dev/null || exit 1 

# Check that the author of this commit has the rights to perform 
# the commit on the files and directories being modified. 
commit-access-control.pl "$REPOS" "$TXN" commit-access-control.cfg || exit 1 

C:\wamp\bin\php\php5.4.3\scripts\phpcs-svn-pre-commit "$REPOS" -t "$TXN" >&2 || exit 1 

# All checks passed, so allow the commit. 
exit 0 

我是很新的这两个SVN和codesniffer,所以我几乎只是遵循指南和运行测试,因为我走了。在得到这个工作的任何意见或建议可以理解的:)

UPDATE

我设法得到了一些成果了我SVN挂钩的,现在却显示了基于脚本错误的列表。我不熟悉SVN所需的脚本语言,所以我不知道如何解决这些问题。错误的

列表:

REPOS不被识别为内部或外部命令

TXN不被识别为内部或外部命令

未知命令 '的/ usr/local/bin中/ svnlook的'

$ svnlook的不被识别为内部或外部命令

+0

在我看来你编辑了错误的文件。重新阅读那里的文档,你忽略了你必须在Windows系统上编辑/执行的部分。看起来你正在使用Windows系统,对吧? – hakre 2012-08-15 09:21:43

+0

我确实使用Windows系统,Windows 7是精确的,但我真的找不到任何提及上面链接的指南上的窗口。另外我不知道如何有任何其他文件,只有一个phpcs-svn-pre-commit文件位于C:\ wamp \ bin \ php \ php5.4.3 \ scripts \。与mypre commit文件相同,位于C:\ repositories \ test \ hooks \上,这是我的测试库。 – 2012-08-15 09:36:10

+0

对于故障排除,创建一个预先提交挂钩,它向STDERR(2)输出一些消息,并始终返回大于0的存在代码。这将阻止所有提交。当你得到这个工作(不再有可能),你可以用具体的代码来摆动。 – hakre 2012-08-15 09:38:17

回答

1

从您的可执行文件的路径来看( C:\wamp\bin\php\php5.4.3\php.exe),我假设你正在使用Windows机器。

您问题中的pre-commit文件看起来像Linux Bash Shell脚本。 Bash与您在Windows下使用的批处理文件有不同的语法。

我建议你使用为Windows机器制作的pre-commit.tmpl文件。 您可能在hooks文件夹中有这些文件。 我使用的是Linux,所以很遗憾,我不能帮助您进一步此搜索上...

pre-commit钩看起来像这样(从An Introduction to Subversion Hook Scripts on Windows采取摘录):

@echo off 
:: Stops commits that don't include a log message of at least 6 characters. 
@echo off 

setlocal 

rem Subversion sends through the repository path and transaction id 
set REPOS=%1 
set TXN=%2 

svnlook log %REPOS% -t %TXN% | findstr ...... > nul 
if %errorlevel% gtr 0 (goto err) else exit 0 

:err 
echo --------------------------------------------------------------------------- 1>&2 
echo Your commit has been blocked because it didn't include a log message. 1>&2 
echo Do the commit again, this time with a log message that describes your changes. 1>&2 
echo --------------------------------------------------------------------------- 1>&2 
exit 1