]> git.localhorst.tv Git - l2e.git/blob - scripts/issues.php
added script to fetch issues into plaintext files
[l2e.git] / scripts / issues.php
1 #!/usr/bin/env php
2 <?php
3
4 class CSVReader {
5
6         private function __construct() { }
7
8         public static function readFile($file, $enclose = '"', $terminate = ',', $escape = '\\', $pascalEscapes = true, $charset = 'UTF-8') {
9                 return self::readString(file_get_contents($file), $enclose, $terminate, $escape, $pascalEscapes, $charset);
10         }
11
12         public static function readString($string, $enclose = '"', $terminate = ',', $escape = '\\', $pascalEscapes = true, $charset = 'UTF-8') {
13                 $inQuotes = false;
14                 $inEscape = false;
15                 $quoteInQuote = false;
16                 $lastWasCR = false;
17
18                 $len = strlen($string);
19                 $value = '';
20                 $line = array();
21                 $result = new CSVReader();
22
23                 if (empty($string)) {
24                         return $result;
25                 }
26
27                 for ($i = 0; $i < $len; ++$i) {
28                         $c = $string{$i};
29                         if ($inEscape) {
30                                 $value .= $c;
31                                 $inEscape = false;
32                                 continue;
33                         }
34                         if ($c == $escape) {
35                                 $inEscape = true;
36                                 continue;
37                         }
38                         if ($quoteInQuote && $c != $enclose) {
39                                 $quoteInQuote = false;
40                                 $inQuotes = false;
41                         }
42                         if ($lastWasCR && $c != "\n") {
43                                 $lastWasCR = false;
44                                 $line[] = iconv($charset, 'UTF-8//TRANSLIT', $value);
45                                 $result->rows[] = $line;
46                                 $line = array();
47                                 $value = '';
48                         }
49                         if ($c == $enclose) {
50                                 if (!$inQuotes) {
51                                         $inQuotes = true;
52                                 } else if ($pascalEscapes) {
53                                         if ($quoteInQuote) {
54                                                 $quoteInQuote = false;
55                                                 $value .= $enclose;
56                                         } else {
57                                                 $quoteInQuote = true;
58                                         }
59                                 } else {
60                                         $inQuotes = false;
61                                 }
62                                 continue;
63                         }
64                         if ($inQuotes) {
65                                 $value .= $c;
66                                 continue;
67                         }
68                         if ($c == $terminate) {
69                                 $line[] = iconv($charset, 'UTF-8//TRANSLIT', $value);
70                                 $value = '';
71                         } else if ($c == "\r") {
72                                 $lastWasCR = true;
73                         } else if ($c == "\n") {
74                                 $line[] = iconv($charset, 'UTF-8//TRANSLIT', $value);
75                                 $result->rows[] = $line;
76                                 $line = array();
77                                 $value = '';
78                                 $lastWasCR = false;
79                         } else {
80                                 $value .= $c;
81                         }
82                 }
83                 if (!empty($value)) {
84                         $line[] = iconv($charset, 'UTF-8//TRANSLIT', $value);
85                 }
86                 if (!empty($line)) {
87                         $result->rows[] = $line;
88                 }
89                 return $result;
90         }
91
92         public function free() {
93                 $this->rows = array();
94         }
95
96         public function countFields() {
97                 if ($this->rowValid()) {
98                         return count($this->currentRow());
99                 } else if (!empty($this->rows)) {
100                         return count($this->rows[0]);
101                 } else {
102                         return 0;
103                 }
104         }
105
106         public function countRows() {
107                 return count($this->rows);
108         }
109
110         public function getFieldName($columnOffset) {
111                 if (isset($this->names[$columnOffset])) {
112                         return $this->names[$columnOffset];
113                 } else {
114                         throw OutOfBoundsException('cannot determine name for column at offset '.$columnOffset);
115                 }
116         }
117
118         public function next($forSure = false) {
119                 ++$this->rowCursor;
120                 if ($this->rowValid()) {
121                         return true;
122                 } else if ($forSure) {
123                         throw new OutOfBoundsException('there is no next row in this result set');
124                 } else {
125                         return false;
126                 }
127         }
128
129         public function has($columnOffset) {
130                 return $this->rowValid() && array_key_exists($columnOffset, $this->currentRow());
131         }
132
133         public function get($columnOffset) {
134                 if (!isset($this->rows[$this->rowCursor])) {
135                         throw new OutOfBoundsException('cannot get column '.$columnOffset.' of row '.$this->rowCursor.': invalid row');
136                 }
137                 if (!isset($this->rows[$this->rowCursor][$columnOffset])) {
138                         throw new OutOfBoundsException('cannot get column '.$columnOffset.' of row '.$this->rowCursor.': invalid column');
139                 }
140                 return $this->rows[$this->rowCursor][$columnOffset];
141         }
142
143         public function loadColumnNamesFromFirstRow() {
144                 if (isset($this->rows[0])) {
145                         $this->setColumnNames($this->rows[0]);
146                 } else {
147                         throw new RuntimeException('there is no first row');
148                 }
149         }
150
151         public function setColumnNames($names) {
152                 $this->names = $names;
153         }
154
155         public function getNamed($name) {
156                 if (in_array($name, $this->names)) {
157                         return $this->get(array_search($name, $this->names));
158                 } else {
159                         throw new OutOfBoundsException($name.' is not a valid column name');
160                 }
161         }
162
163         public function getNamedInt($name) {
164                 return intval($this->getNamed($name));
165         }
166
167         public function getRowNumber() {
168                 return $this->rowCursor + 1;
169         }
170
171         private function rowValid() {
172                 return $this->rowCursor > -1 && $this->rowCursor < $this->countRows();
173         }
174
175         private function currentRow() {
176                 return $this->rows[$this->rowCursor];
177         }
178
179         private $names = array();
180         private $rows = array();
181         private $rowCursor = -1;
182
183 }
184
185 function writeTicket(CSVReader $csv, $filename) {
186         $file = fopen($filename, 'w');
187         fputs($file, $csv->getNamed('Tracker').' #'.$csv->getnamed('#')
188                         .' - '.$csv->getNamed('Subject').PHP_EOL.PHP_EOL);
189         fputs($file, '  '.str_pad('  Status: '.$csv->getNamed('Status'),   35)
190                         .'    Start date: '.$csv->getNamed('Start date').PHP_EOL);
191         fputs($file, '  '.str_pad('Priority: '.$csv->getNamed('Priority'), 35)
192                         .'      Due date: '.$csv->getNamed('Due date').PHP_EOL);
193         fputs($file, '  '.str_pad('Assignee: '.$csv->getNamed('Assignee'), 35)
194                         .'          Done: '.$csv->getNamed('% Done').'%'.PHP_EOL);
195         fputs($file, '  '.str_pad('Category: '.$csv->getNamed('Category'), 35)
196                         .'Target version: '.$csv->getNamed('Target version').PHP_EOL.PHP_EOL);
197         $description = $csv->getNamed('Description');
198         $description = wordwrap(trim(str_replace(
199                         array("\r\n", "\r", "\n"), array("\n", "\n", PHP_EOL), $description)));
200         fputs($file, $description.PHP_EOL);
201         fclose($file);
202 }
203
204 $dir = dirname(dirname(__FILE__)).'/issues';
205
206 if (!is_dir($dir)) {
207         echo 'creating: ', $dir, PHP_EOL;
208         mkdir($dir);
209 }
210
211 $csv = CSVReader::readFile('http://luke.redirectme.net/redmine/projects/l2e/issues.csv?columns=all&description=1',
212                 '"', ',', '\\', true, 'CP1252');
213 $csv->loadColumnNamesFromFirstRow();
214 $csv->next();
215
216 $ids = array();
217
218 while ($csv->next()) {
219         $ids[] = $csv->getNamed('#');
220         $filename = $csv->getNamed('#').' '.$csv->getNamed('Subject');
221         $filepath = $dir.'/'.$filename;
222         if (!file_exists($filepath)) {
223                 echo 'writing: ', $filename, PHP_EOL;
224                 writeTicket($csv, $filepath);
225                 continue;
226         }
227         $modified = filemtime($filepath);
228         $updated = DateTime::createFromFormat(
229                         'm/d/Y h:i a', // 01/03/2013 05:56 am
230                         $csv->getNamed('Updated'),
231                         new DateTimeZone('Europe/Berlin'))->getTimestamp();
232         if ($updated > ($modified - 60)) {
233                 echo 'updating: ', $filename, PHP_EOL;
234                 writeTicket($csv, $filepath);
235         }
236 }
237
238 $existing = scandir($dir);
239
240 foreach ($existing as $name) {
241         if (!is_file($dir.'/'.$name)) continue;
242         $id = intval($name);
243         if ($id > 0 && !in_array($id, $ids)) {
244                 echo 'removing: ', $name, PHP_EOL;
245                 unlink($dir.'/'.$name);
246         }
247 }
248
249 ?>