Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/*
3
 *  $Id$
4
 *
5
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16
 *
17
 * This software consists of voluntary contributions made by many individuals
18
 * and is licensed under the LGPL. For more information please see
19
 * <http://phing.info>.
20
 */
21
 
22
require_once 'phing/Task.php';
23
 
24
  /**
25
  * A Javascript lint task. Checks syntax of Javascript files.
26
  * Javascript lint (http://www.javascriptlint.com) must be in the system path.
27
  * This class is based on Knut Urdalen's PhpLintTask.
28
  *
29
  * @author Stefan Priebsch <stefan.priebsch@e-novative.de>
30
  */
31
  class JslLintTask extends Task
32
  {
33
    protected $file;  // the source file (from xml attribute)
34
    protected $filesets = array(); // all fileset objects assigned to this task
35
 
36
    protected $showWarnings = true;
37
    protected $haltOnFailure = false;
38
    protected $hasErrors = false;
39
    private $badFiles = array();
40
 
41
    /**
42
     * Sets the flag if warnings should be shown
43
     * @param boolean $show
44
     */
45
    public function setShowWarnings($show) {
46
      $this->showWarnings = StringHelper::booleanValue($show);
47
    }
48
 
49
    /**
50
     * The haltonfailure property
51
     * @param boolean $aValue
52
     */
53
    public function setHaltOnFailure($aValue) {
54
      $this->haltOnFailure = $aValue;
55
    }
56
 
57
    /**
58
     * File to be performed syntax check on
59
     * @param PhingFile $file
60
     */
61
    public function setFile(PhingFile $file) {
62
      $this->file = $file;
63
    }
64
 
65
    /**
66
     * Nested creator, creates a FileSet for this task
67
     *
68
     * @return FileSet The created fileset object
69
     */
70
    function createFileSet() {
71
      $num = array_push($this->filesets, new FileSet());
72
      return $this->filesets[$num-1];
73
    }
74
 
75
    /**
76
     * Execute lint check against PhingFile or a FileSet
77
     */
78
    public function main() {
79
      if(!isset($this->file) and count($this->filesets) == 0) {
80
        throw new BuildException("Missing either a nested fileset or attribute 'file' set");
81
      }
82
 
83
      if($this->file instanceof PhingFile) {
84
        $this->lint($this->file->getPath());
85
      } else { // process filesets
86
        $project = $this->getProject();
87
        foreach($this->filesets as $fs) {
88
          $ds = $fs->getDirectoryScanner($project);
89
          $files = $ds->getIncludedFiles();
90
          $dir = $fs->getDir($this->project)->getPath();
91
          foreach($files as $file) {
92
            $this->lint($dir.DIRECTORY_SEPARATOR.$file);
93
          }
94
        }
95
      }
96
 
97
      if ($this->haltOnFailure && $this->hasErrors) throw new BuildException('Syntax error(s) in JS files:' .implode(', ',$this->badFiles));
98
    }
99
 
100
    /**
101
     * Performs the actual syntax check
102
     *
103
     * @param string $file
104
     * @return void
105
     */
106
    protected function lint($file)
107
    {
108
      exec('jsl', $output);
109
      if (!preg_match('/JavaScript\sLint/', implode('', $output))) throw new BuildException('Javascript Lint not found');
110
 
111
      $command = 'jsl -output-format file:__FILE__;line:__LINE__;message:__ERROR__ -process ';
112
 
113
      if(file_exists($file))
114
      {
115
        if(is_readable($file))
116
        {
117
          $messages = array();
118
          exec($command.'"'.$file.'"', $messages);
119
 
120
          $summary = $messages[sizeof($messages) - 1];
121
 
122
          preg_match('/(\d+)\serror/', $summary, $matches);
123
          $errorCount = $matches[1];
124
 
125
          preg_match('/(\d+)\swarning/', $summary, $matches);
126
          $warningCount = $matches[1];
127
 
128
          $errors = array();
129
          $warnings = array();
130
          if ($errorCount > 0 || $warningCount > 0) {
131
            $last = false;
132
            foreach ($messages as $message) {
133
              $matches = array();
134
              if (preg_match('/^(\.*)\^$/', $message)) {
135
                $column = strlen($message);
136
                if ($last == 'error') {
137
                  $errors[count($errors) - 1]['column'] = $column;
138
                } else if ($last == 'warning') {
139
                  $warnings[count($warnings) - 1]['column'] = $column;
140
                }
141
                $last = false;
142
              }
143
              if (!preg_match('/^file:(.+);line:(\d+);message:(.+)$/', $message, $matches)) continue;
144
              $msg = $matches[3];
145
              $data = array('filename' => $matches[1], 'line' => $matches[2], 'message' => $msg);
146
              if (preg_match('/^.*error:.+$/i', $msg)) {
147
                $errors[] = $data;
148
                $last = 'error';
149
              } else if (preg_match('/^.*warning:.+$/i', $msg)) {
150
                $warnings[] = $data;
151
                $last = 'warning';
152
              }
153
            }
154
          }
155
 
156
          if($this->showWarnings && $warningCount > 0)
157
          {
158
            $this->log($file . ': ' . $warningCount . ' warnings detected', Project::MSG_WARN);
159
            foreach ($warnings as $warning) {
160
              $this->log('- line ' . $warning['line'] . (isset($warning['column']) ? ' column ' . $warning['column'] : '') . ': ' . $warning['message'], Project::MSG_WARN);
161
            }
162
          }
163
 
164
          if($errorCount > 0)
165
          {
166
            $this->log($file . ': ' . $errorCount . ' errors detected', Project::MSG_ERR);
167
            foreach ($errors as $error) {
168
              $this->log('- line ' . $error['line'] . (isset($error['column']) ? ' column ' . $error['column'] : '') . ': ' . $error['message'], Project::MSG_ERR);
169
            }
170
            $this->badFiles[] = $file;
171
            $this->hasErrors = true;
172
          } else if (!$this->showWarnings || $warningCount == 0) {
173
            $this->log($file . ': No syntax errors detected', Project::MSG_INFO);
174
          }
175
        } else {
176
          throw new BuildException('Permission denied: '.$file);
177
        }
178
      } else {
179
        throw new BuildException('File not found: '.$file);
180
      }
181
    }
182
  }
183
 
184