1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26:
27: require_once 'Varien/Pear/Package.php';
28:
29: class Mage_Adminhtml_Model_Extension extends Varien_Object
30: {
31: protected $_roles;
32:
33: public function getPear()
34: {
35: return Varien_Pear::getInstance();
36: }
37:
38: public function generatePackageXml()
39: {
40: Mage::getSingleton('adminhtml/session')
41: ->setLocalExtensionPackageFormData($this->getData());
42:
43: Varien_Pear::$reloadOnRegistryUpdate = false;
44: $pkg = new Varien_Pear_Package;
45:
46: $pfm = $pkg->getPfm();
47: $pfm->setOptions(array(
48: 'packagedirectory'=>'.',
49: 'baseinstalldir'=>'.',
50: 'simpleoutput'=>true,
51: ));
52:
53: $this->_setPackage($pfm);
54: $this->_setRelease($pfm);
55: $this->_setMaintainers($pfm);
56: $this->_setDependencies($pfm);
57: $this->_setContents($pfm);
58:
59: if (!$pfm->validate(PEAR_VALIDATE_NORMAL)) {
60:
61:
62:
63: $message = $pfm->getValidationWarnings();
64:
65: throw Mage::exception('Mage_Adminhtml', Mage::helper('adminhtml')->__($message[0]['message']));
66:
67: return $this;
68: }
69:
70: $this->setPackageXml($pfm->getDefaultGenerator()->toXml(PEAR_VALIDATE_NORMAL));
71: return $this;
72: }
73:
74: protected function _setPackage($pfm)
75: {
76: $pfm->setPackageType('php');
77: $pfm->setChannel($this->getData('channel'));
78:
79: $pfm->setLicense($this->getData('license'), $this->getData('license_uri'));
80:
81: $pfm->setPackage($this->getData('name'));
82: $pfm->setSummary($this->getData('summary'));
83: $pfm->setDescription($this->getData('description'));
84: }
85:
86: protected function _setRelease($pfm)
87: {
88: $pfm->addRelease();
89: $pfm->setDate(date('Y-m-d'));
90:
91: $pfm->setAPIVersion($this->getData('api_version'));
92: $pfm->setReleaseVersion($this->getData('release_version'));
93: $pfm->setAPIStability($this->getData('api_stability'));
94: $pfm->setReleaseStability($this->getData('release_stability'));
95: $pfm->setNotes($this->getData('notes'));
96: }
97:
98: protected function _setMaintainers($pfm)
99: {
100: $maintainers = $this->getData('maintainers');
101: foreach ($maintainers['role'] as $i=>$role) {
102: if (0===$i) {
103: continue;
104: }
105: $handle = $maintainers['handle'][$i];
106: $name = $maintainers['name'][$i];
107: $email = $maintainers['email'][$i];
108: $active = !empty($maintainers['active'][$i]) ? 'yes' : 'no';
109: $pfm->addMaintainer($role, $handle, $name, $email, $active);
110: }
111: }
112:
113: protected function _setDependencies($pfm)
114: {
115: $pfm->clearDeps();
116: $exclude = $this->getData('depends_php_exclude')!=='' ? explode(',', $this->getData('depends_php_exclude')) : false;
117: $pfm->setPhpDep($this->getData('depends_php_min'), $this->getData('depends_php_max'), $exclude);
118: $pfm->setPearinstallerDep('1.6.2');
119:
120: foreach ($this->getData('depends') as $deptype=>$deps) {
121: foreach ($deps['type'] as $i=>$type) {
122: if (0===$i) {
123: continue;
124: }
125: $name = $deps['name'][$i];
126: $min = !empty($deps['min'][$i]) ? $deps['min'][$i] : false;
127: $max = !empty($deps['max'][$i]) ? $deps['max'][$i] : false;
128: $recommended = !empty($deps['recommended'][$i]) ? $deps['recommended'][$i] : false;
129: $exclude = !empty($deps['exclude'][$i]) ? explode(',', $deps['exclude'][$i]) : false;
130: if ($deptype!=='extension') {
131: $channel = !empty($deps['channel'][$i]) ? $deps['channel'][$i] : 'connect.magentocommerce.com/core';
132: }
133: switch ($deptype) {
134: case 'package':
135: if ($type==='conflicts') {
136: $pfm->addConflictingPackageDepWithChannel(
137: $name, $channel, false, $min, $max, $recommended, $exclude);
138: } else {
139: $pfm->addPackageDepWithChannel(
140: $type, $name, $channel, $min, $max, $recommended, $exclude);
141: }
142: break;
143:
144: case 'subpackage':
145: if ($type==='conflicts') {
146: Mage::throwException(Mage::helper('adminhtml')->__("Subpackage cannot be conflicting."));
147: }
148: $pfm->addSubpackageDepWithChannel(
149: $type, $name, $channel, $min, $max, $recommended, $exclude);
150: break;
151:
152: case 'extension':
153: $pfm->addExtensionDep(
154: $type, $name, $min, $max, $recommended, $exclude);
155: break;
156: }
157: }
158: }
159: }
160:
161: protected function _setContents($pfm)
162: {
163: $baseDir = $this->getRoleDir('mage').DS;
164:
165: $pfm->clearContents();
166: $contents = $this->getData('contents');
167: $usesRoles = array();
168: foreach ($contents['role'] as $i=>$role) {
169: if (0===$i) {
170: continue;
171: }
172:
173: $usesRoles[$role] = 1;
174:
175: $roleDir = $this->getRoleDir($role).DS;
176: $fullPath = $roleDir.$contents['path'][$i];
177:
178: switch ($contents['type'][$i]) {
179: case 'file':
180: if (!is_file($fullPath)) {
181: Mage::throwException(Mage::helper('adminhtml')->__("Invalid file: %s", $fullPath));
182: }
183: $pfm->addFile('/', $contents['path'][$i], array('role'=>$role, 'md5sum'=>md5_file($fullPath)));
184: break;
185:
186: case 'dir':
187: if (!is_dir($fullPath)) {
188: Mage::throwException(Mage::helper('adminhtml')->__("Invalid directory: %s", $fullPath));
189: }
190: $path = $contents['path'][$i];
191: $include = $contents['include'][$i];
192: $ignore = $contents['ignore'][$i];
193: $this->_addDir($pfm, $role, $roleDir, $path, $include, $ignore);
194: break;
195: }
196: }
197:
198: $pearRoles = $this->getRoles();
199:
200: foreach ($usesRoles as $role=>$dummy) {
201: if (empty($pearRoles[$role]['package'])) {
202: continue;
203: }
204: $pfm->addUsesrole($role, $pearRoles[$role]['package']);
205: }
206: }
207:
208: protected function _addDir($pfm, $role, $roleDir, $path, $include, $ignore)
209: {
210: $roleDirLen = strlen($roleDir);
211: $entries = @glob($roleDir.$path.DS."*");
212: if (!empty($entries)) {
213: foreach ($entries as $entry) {
214: $filePath = substr($entry, $roleDirLen);
215: if (!empty($include) && !preg_match($include, $filePath)) {
216: continue;
217: }
218: if (!empty($ignore) && preg_match($ignore, $filePath)) {
219: continue;
220: }
221: if (is_dir($entry)) {
222: $baseName = basename($entry);
223: if ('.'===$baseName || '..'===$baseName) {
224: continue;
225: }
226: $this->_addDir($pfm, $role, $roleDir, $filePath, $include, $ignore);
227: } elseif (is_file($entry)) {
228: $pfm->addFile('/', $filePath, array('role'=>$role, 'md5sum'=>md5_file($entry)));
229: }
230: }
231: }
232: }
233:
234: public function getRoles()
235: {
236: if (!$this->_roles) {
237: $frontend = $this->getPear()->getFrontend();
238: $config = $this->getPear()->getConfig();
239: $pearMage = new PEAR_Command_Mage($frontend, $config);
240: $this->_roles = $pearMage->getRoles();
241: }
242: return $this->_roles;
243: }
244:
245: public function getRoleDir($role)
246: {
247: $roles = $this->getRoles();
248: return Varien_Pear::getInstance()->getConfig()->get($roles[$role]['dir_config']);
249: }
250:
251: public function getMaintainerRoles()
252: {
253: return array(
254: 'lead'=>'Lead',
255: 'developer'=>'Developer',
256: 'contributor'=>'Contributor',
257: 'helper'=>'Helper'
258: );
259: }
260:
261: public function savePackage()
262: {
263: if ($this->getData('file_name') != '') {
264: $fileName = $this->getData('file_name');
265: $this->unsetData('file_name');
266: } else {
267: $fileName = $this->getName();
268: }
269:
270: if (!preg_match('/^[a-z0-9]+[a-z0-9\-\_\.]*([\/\\\\]{1}[a-z0-9]+[a-z0-9\-\_\.]*)*$/i', $fileName)) {
271: return false;
272: }
273:
274: if (!$this->getPackageXml()) {
275: $this->generatePackageXml();
276: }
277: if (!$this->getPackageXml()) {
278: return false;
279: }
280:
281: $pear = Varien_Pear::getInstance();
282: $dir = Mage::getBaseDir('var').DS.'pear';
283: if (!@file_put_contents($dir.DS.'package.xml', $this->getPackageXml())) {
284: return false;
285: }
286:
287: $pkgver = $this->getName().'-'.$this->getReleaseVersion();
288: $this->unsPackageXml();
289: $this->unsRoles();
290: $xml = Mage::helper('core')->assocToXml($this->getData());
291: $xml = new Varien_Simplexml_Element($xml->asXML());
292:
293:
294: $parts = explode(DS, $fileName);
295: array_pop($parts);
296: $newDir = implode(DS, $parts);
297: if ((!empty($newDir)) && (!is_dir($dir . DS . $newDir))) {
298: if (!@mkdir($dir . DS . $newDir, 0777, true)) {
299: return false;
300: }
301: }
302:
303: if (!@file_put_contents($dir . DS . $fileName . '.xml', $xml->asNiceXml())) {
304: return false;
305: }
306:
307: return true;
308: }
309:
310: public function createPackage()
311: {
312: $pear = Varien_Pear::getInstance();
313: $dir = Mage::getBaseDir('var').DS.'pear';
314: if (!Mage::getConfig()->createDirIfNotExists($dir)) {
315: return false;
316: }
317: $curDir = getcwd();
318: chdir($dir);
319: $result = $pear->run('mage-package', array(), array('package.xml'));
320: chdir($curDir);
321: if ($result instanceof PEAR_Error) {
322: return $result;
323: }
324: return true;
325: }
326:
327:
328: public function getStabilityOptions()
329: {
330: return array(
331: 'devel'=>'Development',
332: 'alpha'=>'Alpha',
333: 'beta'=>'Beta',
334: 'stable'=>'Stable',
335: );
336: }
337:
338: public function getKnownChannels()
339: {
340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351:
352: $arr = array(
353: 'connect.magentocommerce.com/core' => 'Magento Core Team',
354: 'connect.magentocommerce.com/community' => 'Magento Community',
355:
356:
357: );
358: return $arr;
359: }
360:
361: public function loadLocal($package, $options=array())
362: {
363: $pear = $this->getPear();
364:
365: $pear->getFrontend()->clear();
366:
367: $result = $pear->run('info', $options, array($package));
368: if ($result instanceof PEAR_Error) {
369: Mage::throwException($result->message);
370: break;
371: }
372:
373: $output = $pear->getOutput();
374: $pkg = new PEAR_PackageFile_v2;
375: $pkg->fromArray($output[0]['output']['raw']);
376:
377: return $pkg;
378: }
379:
380: public function loadRemote($package, $options=array())
381: {
382: $pear = $this->getPear();
383:
384: $pear->getFrontend()->clear();
385:
386: $result = $pear->run('remote-info', $options, array($package));
387: if ($result instanceof PEAR_Error) {
388: Mage::throwException($result->message);
389: break;
390: }
391:
392: $output = $pear->getOutput();
393: $this->setData($output[0]['output']);
394:
395: return $this;
396: }
397: }
398: