diff --git a/apps/files/appinfo/info.xml b/apps/files/appinfo/info.xml index 34800378537ead29daf6456563038a43dc3bbbe4..390d645e2a44bac66a9bb7483976d3cc1bb47e7f 100644 --- a/apps/files/appinfo/info.xml +++ b/apps/files/appinfo/info.xml @@ -4,8 +4,8 @@ <name>Files</name> <description>File Management</description> <licence>AGPL</licence> - <author>Robin Appelman</author> - <require>4.93</require> + <author>Robin Appelman, Vincent Petry</author> + <requiremin>4.93</requiremin> <shipped>true</shipped> <standalone/> <default_enable/> diff --git a/apps/files_encryption/appinfo/info.xml b/apps/files_encryption/appinfo/info.xml index 15a09a29f51da5b99edfb72bae10fa2b53fc3644..b11272f63e7a2bde47baafecb3bb086882d74fb6 100644 --- a/apps/files_encryption/appinfo/info.xml +++ b/apps/files_encryption/appinfo/info.xml @@ -5,7 +5,7 @@ <description>The ownCloud files encryption system provides server side-encryption. After the app is enabled you need to re-login to initialize your encryption keys. Please note that server side encryption requires that the ownCloud server admin can be trusted. The main purpose of this app is the encryption of files that are stored on externally mounted storages.</description> <licence>AGPL</licence> <author>Sam Tuke, Bjoern Schiessle, Florin Peter</author> - <require>4</require> + <requiremin>4</requiremin> <shipped>true</shipped> <documentation> <user>http://doc.owncloud.org/server/6.0/user_manual/files/encryption.html</user> diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml index 0542b7b10a7afe831d0b917b9daf284949ab08f5..2698706c09084ba431a97e3c4e9afbc41c780e29 100644 --- a/apps/files_external/appinfo/info.xml +++ b/apps/files_external/appinfo/info.xml @@ -4,8 +4,8 @@ <name>External storage support</name> <description>Mount external storage sources</description> <licence>AGPL</licence> - <author>Robin Appelman, Michael Gapczynski</author> - <require>4.93</require> + <author>Robin Appelman, Michael Gapczynski, Vincent Petry</author> + <requiremin>4.93</requiremin> <shipped>true</shipped> <types> <filesystem/> diff --git a/apps/files_sharing/appinfo/info.xml b/apps/files_sharing/appinfo/info.xml index 9b42c1e17b5a8ff757517a2f79e845f2e841aff3..077433a53abc814586bf78f73f1f7b47eae33217 100644 --- a/apps/files_sharing/appinfo/info.xml +++ b/apps/files_sharing/appinfo/info.xml @@ -4,8 +4,8 @@ <name>Share Files</name> <description>File sharing between users</description> <licence>AGPL</licence> - <author>Michael Gapczynski</author> - <require>4.93</require> + <author>Michael Gapczynski, Bjoern Schiessle</author> + <requiremin>4.93</requiremin> <shipped>true</shipped> <default_enable/> <types> diff --git a/apps/files_trashbin/appinfo/info.xml b/apps/files_trashbin/appinfo/info.xml index 2cc7d9a7ac3a0fc2779f0ca32811260df2a72888..860d6b1242a8b023f0792a452153c4d8fe2abaa1 100644 --- a/apps/files_trashbin/appinfo/info.xml +++ b/apps/files_trashbin/appinfo/info.xml @@ -19,7 +19,7 @@ <licence>AGPL</licence> <author>Bjoern Schiessle</author> <shipped>true</shipped> - <require>4.9</require> + <requiremin>4.9</requiremin> <default_enable/> <types> <filesystem/> diff --git a/apps/files_versions/appinfo/info.xml b/apps/files_versions/appinfo/info.xml index a735caee945c3fd8cd5d3d98aa2db474b6397fe2..5d536638fe849a1ea347f7bd9873258a7563967d 100644 --- a/apps/files_versions/appinfo/info.xml +++ b/apps/files_versions/appinfo/info.xml @@ -3,8 +3,8 @@ <id>files_versions</id> <name>Versions</name> <licence>AGPL</licence> - <author>Frank Karlitschek</author> - <require>4.93</require> + <author>Frank Karlitschek, Bjoern Schiessle</author> + <requiremin>4.93</requiremin> <shipped>true</shipped> <description> ownCloud supports simple version control for files. The versioning app diff --git a/apps/user_ldap/appinfo/info.xml b/apps/user_ldap/appinfo/info.xml index e4a4375a737fed5eaf489e7e9013ad9e6d8ab96f..b70f0c543559c0722e8e0c9bc108cbdcf0b7c2f8 100644 --- a/apps/user_ldap/appinfo/info.xml +++ b/apps/user_ldap/appinfo/info.xml @@ -9,7 +9,7 @@ </description> <licence>AGPL</licence> <author>Dominik Schmidt and Arthur Schiwon</author> - <require>4.93</require> + <requiremin>4.93</requiremin> <shipped>true</shipped> <types> <authentication/> diff --git a/apps/user_webdavauth/appinfo/info.xml b/apps/user_webdavauth/appinfo/info.xml index 20c5909cc12ed3937cf5db1980e67cd8bd07aa6f..16e6942505bd19a359d99dbe0ff92847d35a8cd8 100755 --- a/apps/user_webdavauth/appinfo/info.xml +++ b/apps/user_webdavauth/appinfo/info.xml @@ -7,7 +7,7 @@ This app is not compatible with the LDAP user and group backend.</description> <licence>AGPL</licence> <author>Frank Karlitschek</author> - <require>4.93</require> + <requiremin>4.93</requiremin> <shipped>true</shipped> <types> <authentication/> diff --git a/lib/private/app.php b/lib/private/app.php index 575cc9f41af67b0b83095b86ed2cfea3bae95eb7..50065197eb4ef395df2f8d68f55b38fde37e32f6 100644 --- a/lib/private/app.php +++ b/lib/private/app.php @@ -231,7 +231,7 @@ class OC_App{ // check if the app is compatible with this version of ownCloud $info=OC_App::getAppInfo($app); $version=OC_Util::getVersion(); - if(!isset($info['require']) or !self::isAppVersionCompatible($version, $info['require'])) { + if(!self::isAppCompatible($version, $info)) { throw new \Exception( $l->t("App \"%s\" can't be installed because it is not compatible with this version of ownCloud.", array($info['name']) @@ -898,7 +898,7 @@ class OC_App{ foreach($apps as $app) { // check if the app is compatible with this version of ownCloud $info = OC_App::getAppInfo($app); - if(!isset($info['require']) or !self::isAppVersionCompatible($version, $info['require'])) { + if(!self::isAppCompatible($version, $info)) { OC_Log::write('core', 'App "'.$info['name'].'" ('.$app.') can\'t be used because it is' .' not compatible with this version of ownCloud', @@ -909,38 +909,78 @@ class OC_App{ } } + /** + * Ajust the number of version parts of $version1 to match + * the number of version parts of $version2. + * + * @param string $version1 version to adjust + * @param string $version2 version to take the number of parts from + * @return string shortened $version1 + */ + private static function adjustVersionParts($version1, $version2) { + $version1 = explode('.', $version1); + $version2 = explode('.', $version2); + // reduce $version1 to match the number of parts in $version2 + while (count($version1) > count($version2)) { + array_pop($version1); + } + // if $version1 does not have enough parts, add some + while (count($version1) < count($version2)) { + $version1[] = '0'; + } + return implode('.', $version1); + } /** - * Compares the app version with the owncloud version to see if the app - * requires a newer version than the currently active one - * @param array $owncloudVersions array with 3 entries: major minor bugfix - * @param string $appRequired the required version from the xml - * major.minor.bugfix + * Check whether the current ownCloud version matches the given + * application's version requirements. + * + * The comparison is made based on the number of parts that the + * app info version has. For example for ownCloud 6.0.3 if the + * app info version is expecting version 6.0, the comparison is + * made on the first two parts of the ownCloud version. + * This means that it's possible to specify "requiremin" => 6 + * and "requiremax" => 6 and it will still match ownCloud 6.0.3. + * + * @param string $ocVersion ownCloud version to check against + * @param array $appInfo app info (from xml) + * * @return boolean true if compatible, otherwise false */ - public static function isAppVersionCompatible($owncloudVersions, $appRequired){ - $appVersions = explode('.', $appRequired); + public static function isAppCompatible($ocVersion, $appInfo){ + $requireMin = ''; + $requireMax = ''; + if (isset($appInfo['requiremin'])) { + $requireMin = $appInfo['requiremin']; + } else if (isset($appInfo['require'])) { + $requireMin = $appInfo['require']; + } - for($i=0; $i<count($appVersions); $i++){ - $appVersion = (int) $appVersions[$i]; + if (isset($appInfo['requiremax'])) { + $requireMax = $appInfo['requiremax']; + } - if(isset($owncloudVersions[$i])){ - $owncloudVersion = $owncloudVersions[$i]; - } else { - $owncloudVersion = 0; - } + if (is_array($ocVersion)) { + $ocVersion = implode('.', $ocVersion); + } - if($owncloudVersion < $appVersion){ - return false; - } elseif ($owncloudVersion > $appVersion) { - return true; - } + if (!empty($requireMin) + && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<') + ) { + + return false; + } + + if (!empty($requireMax) + && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>') + ) { + + return false; } return true; } - /** * get the installed version of all apps */ diff --git a/lib/private/installer.php b/lib/private/installer.php index 667c05c9c1608076e960d5440dd673bcb381425b..3bddfa6a3b73b671a97185242056704e09b49902 100644 --- a/lib/private/installer.php +++ b/lib/private/installer.php @@ -133,10 +133,7 @@ class OC_Installer{ } // check if the app is compatible with this version of ownCloud - if( - !isset($info['require']) - or !OC_App::isAppVersionCompatible(OC_Util::getVersion(), $info['require']) - ) { + if(!OC_App::isAppCompatible(OC_Util::getVersion(), $info)) { OC_Helper::rmdirr($extractDir); throw new \Exception($l->t("App can't be installed because it is not compatible with this version of ownCloud")); } diff --git a/tests/lib/app.php b/tests/lib/app.php index 683820cabb6fdd76c1e374d87d06ebff8a0919ba..e2b578fe6b9185d2223d5a075bf7c4415085e65b 100644 --- a/tests/lib/app.php +++ b/tests/lib/app.php @@ -1,6 +1,7 @@ <?php /** * Copyright (c) 2012 Bernhard Posselt <dev@bernhard-posselt.com> + * Copyright (c) 2014 Vincent Petry <pvince81@owncloud.com> * This file is licensed under the Affero General Public License version 3 or * later. * See the COPYING-README file. @@ -8,75 +9,218 @@ class Test_App extends PHPUnit_Framework_TestCase { - - public function testIsAppVersionCompatibleSingleOCNumber(){ - $oc = array(4); - $app = '4.0'; - - $this->assertTrue(OC_App::isAppVersionCompatible($oc, $app)); - } - - - public function testIsAppVersionCompatibleMultipleOCNumber(){ - $oc = array(4, 3, 1); - $app = '4.3'; - - $this->assertTrue(OC_App::isAppVersionCompatible($oc, $app)); - } - - - public function testIsAppVersionCompatibleSingleNumber(){ - $oc = array(4); - $app = '4'; - - $this->assertTrue(OC_App::isAppVersionCompatible($oc, $app)); - } - - - public function testIsAppVersionCompatibleSingleAppNumber(){ - $oc = array(4, 3); - $app = '4'; - - $this->assertTrue(OC_App::isAppVersionCompatible($oc, $app)); - } - - - public function testIsAppVersionCompatibleComplex(){ - $oc = array(5, 0, 0); - $app = '4.5.1'; - - $this->assertTrue(OC_App::isAppVersionCompatible($oc, $app)); - } - - - public function testIsAppVersionCompatibleShouldFail(){ - $oc = array(4, 3, 1); - $app = '4.3.2'; - - $this->assertFalse(OC_App::isAppVersionCompatible($oc, $app)); + function appVersionsProvider() { + return array( + // exact match + array( + '6.0.0.0', + array( + 'requiremin' => '6.0', + 'requiremax' => '6.0', + ), + true + ), + // in-between match + array( + '6.0.0.0', + array( + 'requiremin' => '5.0', + 'requiremax' => '7.0', + ), + true + ), + // app too old + array( + '6.0.0.0', + array( + 'requiremin' => '5.0', + 'requiremax' => '5.0', + ), + false + ), + // app too new + array( + '5.0.0.0', + array( + 'requiremin' => '6.0', + 'requiremax' => '6.0', + ), + false + ), + // only min specified + array( + '6.0.0.0', + array( + 'requiremin' => '6.0', + ), + true + ), + // only min specified fail + array( + '5.0.0.0', + array( + 'requiremin' => '6.0', + ), + false + ), + // only min specified legacy + array( + '6.0.0.0', + array( + 'require' => '6.0', + ), + true + ), + // only min specified legacy fail + array( + '4.0.0.0', + array( + 'require' => '6.0', + ), + false + ), + // only max specified + array( + '5.0.0.0', + array( + 'requiremax' => '6.0', + ), + true + ), + // only max specified fail + array( + '7.0.0.0', + array( + 'requiremax' => '6.0', + ), + false + ), + // variations of versions + // single OC number + array( + '4', + array( + 'require' => '4.0', + ), + true + ), + // multiple OC number + array( + '4.3.1', + array( + 'require' => '4.3', + ), + true + ), + // single app number + array( + '4', + array( + 'require' => '4', + ), + true + ), + // single app number fail + array( + '4.3', + array( + 'require' => '5', + ), + false + ), + // complex + array( + '5.0.0', + array( + 'require' => '4.5.1', + ), + true + ), + // complex fail + array( + '4.3.1', + array( + 'require' => '4.3.2', + ), + false + ), + // two numbers + array( + '4.3.1', + array( + 'require' => '4.4', + ), + false + ), + // one number fail + array( + '4.3.1', + array( + 'require' => '5', + ), + false + ), + // pre-alpha app + array( + '5.0.3', + array( + 'require' => '4.93', + ), + true + ), + // pre-alpha OC + array( + '6.90.0.2', + array( + 'require' => '6.90', + ), + true + ), + // pre-alpha OC max + array( + '6.90.0.2', + array( + 'requiremax' => '7', + ), + true + ), + // expect same major number match + array( + '5.0.3', + array( + 'require' => '5', + ), + true + ), + // expect same major number match + array( + '5.0.3', + array( + 'requiremax' => '5', + ), + true + ), + ); } - public function testIsAppVersionCompatibleShouldFailTwoVersionNumbers(){ - $oc = array(4, 3, 1); - $app = '4.4'; - - $this->assertFalse(OC_App::isAppVersionCompatible($oc, $app)); - } - - - public function testIsAppVersionCompatibleShouldWorkForPreAlpha(){ - $oc = array(5, 0, 3); - $app = '4.93'; - - $this->assertTrue(OC_App::isAppVersionCompatible($oc, $app)); + /** + * @dataProvider appVersionsProvider + */ + public function testIsAppCompatible($ocVersion, $appInfo, $expectedResult) { + $this->assertEquals($expectedResult, OC_App::isAppCompatible($ocVersion, $appInfo)); } - - public function testIsAppVersionCompatibleShouldFailOneVersionNumbers(){ - $oc = array(4, 3, 1); - $app = '5'; - - $this->assertFalse(OC_App::isAppVersionCompatible($oc, $app)); + /** + * Test that the isAppCompatible method also supports passing an array + * as $ocVersion + */ + public function testIsAppCompatibleWithArray() { + $ocVersion = array(6); + $appInfo = array( + 'requiremin' => '6', + 'requiremax' => '6', + ); + $this->assertTrue(OC_App::isAppCompatible($ocVersion, $appInfo)); } /**