rework everything; add emacs output mode
[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->loadParameters();
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         $sql = file_get_contents($filename);
70         if (trim($sql) == '') {
71             $this->renderer->displayError('SQL file empty', '', 0, 0);
72             return false;
73         }
74
75         $parser = new \SqlParser\Parser($sql);
76         if (count($parser->errors) == 0) {
77             $this->renderer->finishOk();
78             return true;
79         }
80
81         $lines = array(1 => 0);
82         $pos = -1;
83         $line = 1;
84         while (false !== $pos = strpos($sql, "\n", ++$pos)) {
85             $lines[++$line] = $pos;
86         }
87
88         foreach ($parser->errors as $error) {
89             /* @var SqlParser\Exceptions\ParserException $error) */
90             reset($lines);
91             $line = 1;
92             while (next($lines) && $error->token->position >= current($lines)) {
93                 ++$line;
94             }
95             $col = $error->token->position - $lines[$line];
96
97             $this->renderer->displayError(
98                 $error->getMessage(),
99                 //FIXME: ->token or ->value?
100                 $error->token->token,
101                 $line,
102                 $col
103             );
104         }
105
106         return false;
107     }
108
109     /**
110      * Load parameters for the CLI option parser.
111      *
112      * @return \Console_CommandLine CLI option parser
113      */
114     protected function loadParameters()
115     {
116         $parser = new \Console_CommandLine();
117         $parser->description = 'php-sqllint';
118         $parser->version = '0.0.1';
119
120         $parser->addOption(
121             'renderer',
122             array(
123                 'short_name'  => '-r',
124                 'long_name'   => '--renderer',
125                 'description' => 'Output mode',
126                 'action'      => 'StoreString',
127                 'choices'     => array(
128                     'emacs',
129                     'text',
130                 ),
131                 'default'     => 'text',
132                 'add_list_option' => true,
133             )
134         );
135
136         $parser->addArgument(
137             'sql_files',
138             array(
139                 'multiple' => true
140             )
141         );
142
143         return $parser;
144     }
145
146     /**
147      * Let the CLI option parser parse the options.
148      *
149      * @param object $parser Option parser
150      *
151      * @return array Array of file names
152      */
153     protected function parseParameters(\Console_CommandLine $parser)
154     {
155         try {
156             $result = $parser->parse();
157
158             $rendClass = '\\phpsqllint\\Renderer_'
159                 . ucfirst($result->options['renderer']);
160             $this->renderer = new $rendClass();
161
162             foreach ($result->args['sql_files'] as $filename) {
163                 if (!file_exists($filename)) {
164                     throw new \Exception('File does not exist: ' . $filename);
165                 }
166                 if (!is_file($filename)) {
167                     throw new \Exception('Not a file: ' . $filename);
168                 }
169             }
170
171             return $result->args['sql_files'];
172         } catch (\Exception $exc) {
173             $parser->displayError($exc->getMessage());
174         }
175     }
176
177 }
178 ?>