Перехватчик кода SVN перед фиксацией

Я пытался заставить сниффер кода действовать как хук предварительной фиксации svn, следуя руководству от груши. Однако, хотя я на 100% уверен, что мой код недействителен, я не получаю ошибок, и проект фиксируется без проблем.

Есть ли что-то еще, что нужно сделать, кроме следования руководству, данному грушей?

Ссылка на руководство по снифферу кода в качестве предварительной -commit hook

Мой файл phpcs-svn-pre-commit:

#!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);
}

?>

И мой файл предварительной фиксации из Subversion:

#!/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, так и в codeniffer, поэтому я в значительной степени просто следую руководствам и запускаю тесты по мере продвижения. Любые советы или подсказки по тому, как заставить это работать, будут оценены :)

ОБНОВЛЕНИЕ

Мне удалось получить некоторые результаты из моего хука svn, однако теперь он показывает список ошибок, основанный на скрипте. Я не знаком с языком сценариев, необходимым для SVN, поэтому понятия не имею, как их решить.

Список ошибок:

REPOS не распознается как внутренняя или внешняя команда

TXN не распознается как внутренняя или внешняя команда

неизвестная команда '/ usr / local / bin / svnlook'

$ SVNLOOK не распознается как внутренняя или внешняя команда


person Björn    schedule 15.08.2012    source источник
comment
Мне кажется, вы отредактировали не тот файл. Перечитайте там документацию, вы пропустили часть того, что вам нужно отредактировать / сделать в системе Windows. Похоже, вы используете систему Windows, не так ли?   -  person hakre    schedule 15.08.2012
comment
Я действительно использую систему Windows, а точнее Windows 7, однако я не могу найти ничего, что упоминало бы окна в руководстве, которое я связал выше. Также я не вижу, есть ли какие-либо другие файлы, есть только один файл phpcs-svn-pre-commit, который находится в C: \ wamp \ bin \ php \ php5.4.3 \ scripts \. То же самое с файлом фиксации mypre, который находится в C: \ repositories \ test \ hooks \, это мой тестовый репозиторий.   -  person Björn    schedule 15.08.2012
comment
Для устранения неполадок создайте ловушку перед фиксацией, которая выводит какое-либо сообщение в STDERR (2) и всегда возвращает существующий код больше 0. Это предотвратит все фиксации. Когда вы заставите это работать (коммиты больше не возможны), вы можете покачиваться с конкретным кодом, в отличие от одного.   -  person hakre    schedule 15.08.2012
comment
См. Здесь некоторые связанные примеры окон (вы видите, они говорят о .bat файлах?) Перехватчик предварительной фиксации Windows для длины комментария Subversion - это всегда хороший шаблон для простого исполняемого командного файла оболочки Windows с перехватом предварительной фиксации.   -  person hakre    schedule 15.08.2012
comment
Я посмотрел на вопрос, который вы указали, и мне удалось заставить работать сценарий, который они там показывают. Я должен отметить, что я работаю с сервером visualSVN, и, похоже, он использует файлы cmd, а не файлы bat для предварительной фиксации. Однако моя текущая проблема теперь оборачивается рядом ошибок.   -  person Björn    schedule 15.08.2012
comment
cmd - это то же самое, что и bat в современной системе Windows, не имеющее ничего общего с visualSVN. У вас есть опыт написания сценариев оболочки Windows?   -  person hakre    schedule 15.08.2012


Ответы (1)


Судя по пути к вашему исполняемому файлу (C:\wamp\bin\php\php5.4.3\php.exe), я предполагаю, что вы работаете на машине с Windows.

Файл pre-commit в вашем вопросе выглядит как сценарий Linux Bash Shell. Синтаксис Bash отличается от синтаксиса командного файла, который вы использовали бы в Windows.

Я предлагаю вам использовать pre-commit.tmpl файл, созданный для машины Windows. Вероятно, они есть в вашей hooks папке. Я использую Linux-машину, поэтому, к сожалению, больше не могу вам помочь в этом поиске ...

Хук pre-commit будет выглядеть так (отрывок взят из Введение в сценарии перехвата Subversion в 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
person andreoliwa    schedule 05.09.2012