5e4f6388435a2d0e3610e30441ef052c97bbd706
[php-sqllint.git] / src / phpsqllint / Cli.php
1 <?php
2 /**
3  * Part of php-sqllint
4  *
5  * PHP version 5
6  *
7  * @category Tools
8  * @package  PHP-SQLlint
9  * @author   Christian Weiske <cweiske@cweiske.de>
10  * @license  http://www.gnu.org/licenses/agpl.html GNU AGPL v3
11  * @link     http://cweiske.de/php-sqllint.htm
12  */
13 namespace phpsqllint;
14 use SqlParser\Parser;
15
16 require_once 'Console/CommandLine.php';
17
18 /**
19  * Command line interface
20  *
21  * @category Tools
22  * @package  PHP-SQLlint
23  * @author   Christian Weiske <cweiske@cweiske.de>
24  * @license  http://www.gnu.org/licenses/agpl.html GNU AGPL v3
25  * @link     http://www.emacswiki.org/emacs/CreatingYourOwnCompileErrorRegexp
26  */
27 class Cli
28 {
29     protected $renderer;
30
31     /**
32      * Start processing.
33      *
34      * @return void
35      */
36     public function run()
37     {
38         try {
39             $parser = $this->loadOptionParser();
40             $files  = $this->parseParameters($parser);
41
42             $allfine = true;
43             foreach ($files as $filename) {
44                 $allfine &= $this->checkFile($filename);
45             }
46
47             if ($allfine == true) {
48                 exit(0);
49             } else {
50                 exit(10);
51             }
52         } catch (\Exception $e) {
53             echo 'Error: ' . $e->getMessage() . "\n";
54             exit(1);
55         }
56     }
57
58     /**
59      * Check a .sql file for syntax errors
60      *
61      * @param string $filename File path
62      *
63      * @return boolean True if there were no errors, false if there were some
64      */
65     public function checkFile($filename)
66     {
67         $this->renderer->startRendering($filename);
68
69         if ($filename == '-') {
70             $sql = file_get_contents('php://stdin');
71         } else {
72             $sql = file_get_contents($filename);
73         }
74         if (trim($sql) == '') {
75             $this->renderer->displayError('SQL file empty', '', 0, 0);
76             return false;
77         }
78
79         $parser = new \SqlParser\Parser($sql);
80         if (count($parser->errors) == 0) {
81             $this->renderer->finishOk();
82             return true;
83         }
84
85         $lines = array(1 => 0);
86         $pos = -1;
87         $line = 1;
88         while (false !== $pos = strpos($sql, "\n", ++$pos)) {
89             $lines[++$line] = $pos;
90         }
91
92         foreach ($parser->errors as $error) {
93             /* @var SqlParser\Exceptions\ParserException $error) */
94             reset($lines);
95             $line = 1;
96             while (next($lines) && $error->token->position >= current($lines)) {
97                 ++$line;
98             }
99             $col = $error->token->position - $lines[$line];
100
101             $this->renderer->displayError(
102                 $error->getMessage(),
103                 //FIXME: ->token or ->value?
104                 $error->token->token,
105                 $line,
106                 $col
107             );
108         }
109
110         return false;
111     }
112
113     /**
114      * Load parameters for the CLI option parser.
115      *
116      * @return \Console_CommandLine CLI option parser
117      */
118     protected function loadOptionParser()
119     {
120         $parser = new \Console_CommandLine();
121         $parser->description = 'php-sqllint';
122         $parser->version = '0.0.2';
123         $parser->avoid_reading_stdin = true;
124
125         $parser->addOption(
126             'renderer',
127             array(
128                 'short_name'  => '-r',
129                 'long_name'   => '--renderer',
130                 'description' => 'Output mode',
131                 'action'      => 'StoreString',
132                 'choices'     => array(
133                     'emacs',
134                     'text',
135                 ),
136                 'default'     => 'text',
137                 'add_list_option' => true,
138             )
139         );
140
141         $parser->addArgument(
142             'sql_files',
143             array(
144                 'description' => 'SQL files, "-" for stdin',
145                 'multiple'    => true
146             )
147         );
148
149         return $parser;
150     }
151
152     /**
153      * Let the CLI option parser parse the options.
154      *
155      * @param object $parser Option parser
156      *
157      * @return array Array of file names
158      */
159     protected function parseParameters(\Console_CommandLine $parser)
160     {
161         try {
162             $result = $parser->parse();
163
164             $rendClass = '\\phpsqllint\\Renderer_'
165                 . ucfirst($result->options['renderer']);
166             $this->renderer = new $rendClass();
167
168             foreach ($result->args['sql_files'] as $filename) {
169                 if ($filename == '-') {
170                     continue;
171                 }
172                 if (!file_exists($filename)) {
173                     throw new \Exception('File does not exist: ' . $filename);
174                 }
175                 if (!is_file($filename)) {
176                     throw new \Exception('Not a file: ' . $filename);
177                 }
178             }
179
180             return $result->args['sql_files'];
181         } catch (\Exception $exc) {
182             $parser->displayError($exc->getMessage());
183         }
184     }
185
186 }
187 ?>