[ Index ]

PHP Cross Reference of PHK Manager

title

Body

[close]

/PHK/Build/PSF/ -> Parser.php (source)

   1  <?php
   2  //=============================================================================
   3  //
   4  // Copyright Francois Laupretre <phk@tekwire.net>
   5  //
   6  //   Licensed under the Apache License, Version 2.0 (the "License");
   7  //   you may not use this file except in compliance with the License.
   8  //   You may obtain a copy of the License at
   9  //
  10  //       http://www.apache.org/licenses/LICENSE-2.0
  11  //
  12  //   Unless required by applicable law or agreed to in writing, software
  13  //   distributed under the License is distributed on an "AS IS" BASIS,
  14  //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15  //   See the License for the specific language governing permissions and
  16  //   limitations under the License.
  17  //
  18  //=============================================================================
  19  /**
  20  * @copyright Francois Laupretre <phk@tekwire.net>
  21  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, V 2.0
  22  * @category PHK
  23  * @package PHK
  24  *///==========================================================================
  25  
  26  namespace PHK\Build\PSF {
  27  
  28  if (!class_exists('PHK\Build\PSF\Parser',false))
  29  {
  30  //=============================================================================
  31  /**
  32  * The PSF parser
  33  *
  34  * API status: Private
  35  * Included in the PHK PHP runtime: No
  36  * Implemented in the extension: No
  37  *///==========================================================================
  38  
  39  class Parser
  40  {
  41  private $path; // PSF absolute path
  42  
  43  private $vars;    // Variables
  44  
  45  private $line_nb;
  46  
  47  //---------
  48  
  49  private function __construct($path,$vars)
  50  {
  51  $this->path=$path;
  52  $this->vars=$vars;
  53  }
  54  
  55  //---- \Exception with file name and line number
  56  // Can be called recursively. So, we decorate the message only once
  57  
  58  private function sendError($msg)
  59  {
  60  if (($msg!='') && ($msg{0}=='>')) throw new \Exception($msg);
  61  else throw new \Exception('> '.$this->path.'(line '.$this->line_nb.') : '.$msg);
  62  }
  63  
  64  //---- Read a line with continuation '\' and strip comments (#) + trim()
  65  //---- Returns false on EOF
  66  
  67  private function getLine($fp)
  68  {
  69  $line='';
  70  
  71  while (true)
  72      {
  73      $this->line_nb++;
  74      if (($line1=fgets($fp))===false) // EOF
  75          {
  76          if ($line=='') return null;
  77          else $this->sendError('Unexpected EOF'); // If it was a continuation
  78          }
  79      if (($pos=strpos($line1,'#'))!==false)    // Remove comments
  80          $line1=substr($line1,0,$pos);
  81      $line1=trim($line1);
  82      if ($line1=='') continue;
  83  
  84      if ($line1[strlen($line1)-1]=='\\')    // Continued on next line
  85          {
  86          $cont=true;
  87          $line1=substr($line1,0,-1);    // Remove \ at EOL
  88          $line .=' '; // As we trim every line, add a space for continuation
  89          }
  90      else $cont=false;
  91      $line .= $line1;
  92      if ($cont) continue;
  93      //-- Variables substitution
  94  
  95      while (($pos=strpos($line,'$('))!==false) // always search the whole line
  96          {
  97          $pos2=strpos($line,')',$pos);
  98          if ($pos2==($pos+2)) $this->sendError('Empty variable');
  99          if ($pos2===false) $this->sendError('No variable end');
 100          $var=substr($line,$pos+2,$pos2-($pos+2));
 101          $val=$this->getVar($var);
 102          $line=substr_replace($line,$val,$pos,$pos2+1-$pos);
 103          }
 104  
 105      //-- Convert tabs to space, Remove leading/trailing blanks, and suppress
 106      //-- multiple spaces
 107  
 108      $line=preg_replace('/\s+/',' ',str_replace('    ',' ',trim($line)));
 109  
 110      if ($line!='') break;    // Skip empty lines
 111      }
 112  return $line;
 113  }
 114  
 115  //---------
 116  
 117  private function getVar($name)
 118  {
 119  if (isset($this->vars[$name])) return $this->vars[$name];
 120  if (($val=getenv($name))!==false) return $val;
 121  $this->sendError($name.': reference to undefined variable');
 122  }
 123  
 124  //---------
 125  
 126  private function setVar($name,$value)
 127  {
 128  $this->vars[$name]=$value;
 129  }
 130  
 131  //---------
 132  // On entry, $phk is a \PHK\Build\Creator object
 133  
 134  public function applyTo($phk)
 135  {
 136  if (!($phk instanceof \PHK\Build\Creator))
 137      throw new \Exception('Object must be \PHK\Build\Creator');
 138  
 139  if (!($fp=fopen($this->path,'rb',false)))
 140      throw new \Exception($this->path.': Cannot open');
 141      
 142  $this->line_nb=0;
 143  
 144  try {
 145  while (!is_null($line=$this->getLine($fp)))
 146      {
 147      if ($line{0}==='%') break;    // Next block found
 148      $op=new CmdOptions;
 149      $words=explode(' ',$line);
 150      if (!count($words)) throw new \Exception('No command');
 151      $command=strtolower(array_shift($words));
 152      switch($command)
 153          {
 154          case 'add':    // add [-t <target-path>] [-b <target-base>] [-C <dir>]
 155                      //   [-c <compression-scheme>] <source1> [<source2>...]
 156              
 157              $op->parseAll($words);
 158              if (count($words)==0)
 159                  throw new \Exception('Usage: add [options] <path1> [<path2> ...]');
 160              $base_dir=\Phool\File::combinePath(dirname($this->path)
 161                  ,$op->option('directory'));
 162              foreach($words as $spath)
 163                  {
 164                  $spath=rtrim($spath,'/');    // Beware of trailing '/'
 165                  if (is_null($target=$op->option('target-path')))
 166                      {
 167                      if (\Phool\File::isAbsolutePath($spath))
 168                          throw new \Exception("$spath: Arg must be a relative path");
 169                      $tbase=$op->option('target-base');
 170                      if (is_null($tbase)) $tbase='';
 171                      $target=$tbase.'/'.$spath;
 172                      }
 173                  $sapath=\Phool\File::combinePath($base_dir,$spath);
 174                  $phk->ftree()->mergeIntoFileTree($target,$sapath,$op->options());
 175                  }
 176              break;
 177  
 178          case 'modify':
 179              $op->parseAll($words);
 180              if (count($words)==0)
 181                  throw new \Exception('Usage: modify [options] <path1> [<path2> ...]');
 182              foreach($words as $tpath)
 183                  $phk->ftree()->modify($tpath,$op->options());
 184              break;
 185  
 186          case 'mount':
 187              if (count($words)!=2)
 188                  throw new \Exception('Usage: mount <phk-path> <var-name>');
 189              list($path,$mnt_var)=$words;
 190              $mnt=\PHK\Mgr::mount($path,\PHK::NO_MOUNT_SCRIPT);
 191              $this->setVar($mnt_var,'phk://'.$mnt);
 192              break;
 193  
 194          case 'remove':    // remove <path> [<path>...]
 195              if (count($words)==0)
 196                  throw new \Exception('Usage: remove <path1> [<path2> ...]');
 197              foreach($words as $tpath) $phk->ftree()->remove(trim($tpath,'/'));
 198              break;
 199  
 200          case 'set':
 201              if (count($words) < 1)
 202                  throw new \Exception('Usage: set <var-name> [value]');
 203              $var=array_shift($words);
 204              $this->setVar($var,implode(' ',$words));
 205              break;
 206  
 207          case 'section':        //-- Undocumented
 208              $op->parseAll($words);
 209              if (count($words)!=2)
 210                  throw new \Exception('Usage: section [-C <dir>] <name> <path>');
 211              list($name,$path)=$words;
 212              $phk->addSection($name,\Phool\File::readFile($path));
 213              break;
 214              
 215          default:
 216              $this->sendError($command.': Unknown command');
 217          }
 218      }
 219  } catch (\Exception $e) { $this->sendError($e->getMessage()); }
 220  
 221  if (!is_null($line)) // If we met a '%'
 222      {
 223      // Get package options (metainfo)
 224      // Default syntax: YAML
 225  
 226      $op=new MetaOptions;
 227  
 228      $args=explode(' ',$line);
 229      $op->parseAll($args);
 230  
 231      $data='';
 232      while (($line=fgets($fp))!==false) $data .= $line;
 233  
 234      switch(strtolower($op->option('syntax')))
 235          {
 236          case 'yaml':
 237              $options=\Symfony\Component\Yaml\Yaml::parse($data);
 238              break;
 239  
 240          case 'json':
 241              $json=new Services_JSON();
 242              $options=$json->decode($data);
 243              unset($json);
 244              break;
 245  
 246          case 'php':
 247              $options=\PHK\Stream\Backend::_includeString("<?php\n".$data."\n?>");
 248              break;
 249  
 250          default:
 251              throw new \Exception("$syntax: Unknown options syntax");
 252          }
 253  
 254      if (!(is_array($options)))
 255          throw new \Exception('Options block should define an array');
 256      $phk->setOptions($options);
 257      }
 258  
 259  fclose($fp);
 260  }
 261  
 262  //---------
 263  // Build a new PHK package from a PSF file
 264  
 265  public static function build($phk_path,$psf_path,$vars)
 266  {
 267  //-- Create empty output object
 268  
 269  $phk_path=\Phool\File::mkAbsolutePath($phk_path);
 270  $mnt=\PHK\Mgr::mount($phk_path,\PHK::IS_CREATOR);
 271  $phk=\PHK\Mgr::instance($mnt);
 272  
 273  if (is_null($psf_path)) // Compute PSF path from PHK path
 274      {
 275      $base=basename($phk_path);
 276      $dotpos=strrpos($base,'.');
 277      if ($dotpos===false) $base=$base.'.psf';
 278      else $base=substr_replace($base,'.psf',$dotpos);
 279      $psf_path=dirname($phk_path).'/'.$base;
 280      }
 281  else    // Make PSF path absolute
 282      {
 283      $psf_path=\Phool\File::mkAbsolutePath($psf_path);
 284      }
 285  
 286  //-- Interpret PSF
 287  
 288  $psf=new self($psf_path,$vars);
 289  $psf->applyTo($phk);
 290  
 291  //-- Dump to file
 292  
 293  $phk->dump();
 294  }
 295  
 296  //---
 297  } // End of class
 298  //===========================================================================
 299  } // End of class_exists
 300  //===========================================================================
 301  } // End of namespace
 302  //===========================================================================
 303  ?>


Generated: Thu Jun 4 18:33:15 2015 Cross-referenced by PHPXref 0.7.1