1<?php 2/** 3 * Poldek Plugin: query poldek for package info 4 * 5 * Add poldek tags to dokuwiki 6 * 7 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 8 * @author Elan Ruusamäe <glen@delfi.ee> 9 */ 10// must be run within Dokuwiki 11if(!defined('DOKU_INC')) die(); 12 13/** 14 * All DokuWiki plugins to extend the parser/rendering mechanism 15 * need to inherit from this class 16 * 17 * @author Elan Ruusamäe <glen@delfi.ee> 18 */ 19class helper_plugin_poldek extends DokuWiki_Plugin { 20 /* 21 * Path to package list cache file 22 * Filled by sync() method. 23 * @var string $cache 24 */ 25 private $cache; 26 27 /** 28 * Update poldek indexes for active repos 29 * Save down list of packages. 30 * 31 * We create two cache objects, one for updating indexes, which is mtime based 32 * And other for package list, which depends on index file. 33 * And each page depends on the package list file 34 * 35 * Without force, cache is attempted to be used, even if it's stale 36 * 37 * Called by ls command, or from cron 38 */ 39 public function sync($force = false) { 40 // do this once per request 41 if ($this->cache) { 42 return; 43 } 44 45 global $conf; 46 47 $idx_cache = new cache($this->getPluginName(), '.idx'); 48 $pkg_cache = new cache($this->getPluginName(), '.txt'); 49 $cache_exists = file_exists($pkg_cache->cache); 50 51 // check poldek indexes 52 if (!$cache_exists || !$idx_cache->useCache(array('age' => $conf['locktime'], 'files' => getConfigFiles('main')))) { 53 54 // cache is ok, if it exists and is not empty and does not contain errors 55 $cache_ok = $cache_exists && filesize($pkg_cache->cache) && !preg_grep('/^error:/', file($pkg_cache->cache)); 56 57 // without force update indexes only if cache is missing 58 if ($force || !$cache_exists) { 59 $lines = $this->exec("--up"); 60 // process output, if we find "Writing ..." line, means we should update ls output as well 61 // Writing /root/.poldek-cache/[...]/packages.ndir.gz... 62 // Index patches size too big 63 // Retrieving whole index ... 64 if (!$cache_exists || !$cache_ok || preg_grep('/^(Writing|Retrieving whole index) /', $lines)) { 65 $idx_cache->storeCache(time()); 66 } else { 67 // freshen timestamp or we keep updating indexes if index 68 // is older than locktime 69 touch($idx_cache->cache); 70 if ($force) { 71 // sleep, so packages cache be newer 72 sleep(1); 73 } 74 // touch also package file, not to trigger it's update 75 touch($pkg_cache->cache); 76 clearstatcache(); 77 } 78 } 79 } 80 81 // do not update listing, if cache exists and not in cron mode 82 if (($force || !$cache_exists) && !$pkg_cache->useCache(array('files' => array($idx_cache->cache)))) { 83 $lines = $this->shcmd("ls", $rc); 84 // write cache, unless there was an error 85 if (!$rc) { 86 $pkg_cache->storeCache(join("\n", $lines)); 87 } 88 } 89 90 $this->cache = $pkg_cache->cache; 91 } 92 93 public function ls($package) { 94 static $cache; 95 96 if (!$cache) { 97 $cache = array(); 98 99 // regexp matching is slow. 100 // cache this for cases having more than one instance of our plugin on page 101 foreach (file($this->getCache()) as $line) { 102 if (preg_match('/^(?P<name>.+)-(?P<version>[^-]+)-(?P<release>[^-]+)\.(?P<arch>[^.]+)$/', $line, $m)) { 103 $cache[$m['name']] = $line; 104 } elseif (preg_match('/error: (?P<name>.+): no such package or directory/', $line, $m)) { 105 $cache[$m['name']] = $line; 106 } 107 } 108 } 109 110 if (isset($cache[$package])) { 111 return $cache[$package]; 112 } 113 114 return "error: $package: no such package"; 115 } 116 117 /** 118 * Get filename for package list 119 * It ensures that cache file is created, if missing 120 */ 121 public function getCache() { 122 $this->sync(); 123 return $this->cache; 124 } 125 126 /** 127 * Run command in poldek 128 */ 129 private function shcmd($cmd, &$rc = null) { 130 return $this->exec('-q -Q --shcmd='.escapeshellarg($cmd), $rc); 131 } 132 133 /** 134 * Run poldek with configured repositories and cachedir 135 * Setups proxies if needed 136 */ 137 private function exec($cmd, &$rc = null) { 138 global $conf; 139 $cachedir = $conf['cachedir'].'/'.$this->getPluginName(); 140 141 // base poldek command 142 $poldek = 'exec poldek --skip-installed --cachedir=' . escapeshellarg($cachedir); 143 144 $poldek_conf = DOKU_CONF . 'poldek.conf'; 145 if (file_exists($poldek_conf)) { 146 $poldek .= ' --conf '.escapeshellarg($poldek_conf); 147 } 148 149 $repos = $this->getConf('repos'); 150 foreach (explode(',', $repos) as $repo) { 151 $poldek .= ' --sn '.escapeshellarg(trim($repo)); 152 } 153 154 // proxies setup 155 $http_proxy = $this->getConf('http_proxy'); 156 if ($http_proxy) { 157 $poldek .= ' -O '.escapeshellarg("proxy=http: {$http_proxy}"); 158 } 159 $ftp_proxy = $this->getConf('ftp_proxy'); 160 if ($ftp_proxy) { 161 $poldek.= ' -O '.escapeshellarg("proxy=ftp: {$ftp_proxy}"); 162 } 163 164 $poldek .= " $cmd"; 165 166 exec($poldek, $lines, $rc); 167 return $lines; 168 } 169} 170 171//Setup VIM: ex: noet ts=4 enc=utf-8 : 172