diff --git a/application/Espo/Core/ExtensionManager.php b/application/Espo/Core/ExtensionManager.php
index f3c35baf7a..8613b3a958 100644
--- a/application/Espo/Core/ExtensionManager.php
+++ b/application/Espo/Core/ExtensionManager.php
@@ -28,7 +28,6 @@ class ExtensionManager extends Upgrades\Base
protected $params = array(
'packagePath' => 'data/upload/extensions',
-
'backupPath' => 'data/.backup/extensions',
'scriptNames' => array(
diff --git a/application/Espo/Core/UpgradeManager.php b/application/Espo/Core/UpgradeManager.php
index adae1d87f3..3e805b5b52 100644
--- a/application/Espo/Core/UpgradeManager.php
+++ b/application/Espo/Core/UpgradeManager.php
@@ -30,6 +30,7 @@ class UpgradeManager extends Upgrades\Base
protected $params = array(
'packagePath' => 'data/upload/upgrades',
+ 'backupPath' => 'data/.backup/upgrades',
'scriptNames' => array(
'before' => 'BeforeUpgrade',
diff --git a/application/Espo/Core/Upgrades/Actions/Base.php b/application/Espo/Core/Upgrades/Actions/Base.php
index 52e7f7ad0a..2b0f530910 100644
--- a/application/Espo/Core/Upgrades/Actions/Base.php
+++ b/application/Espo/Core/Upgrades/Actions/Base.php
@@ -304,7 +304,7 @@ abstract class Base
/**
* Get a list of files defined in manifest.json
*
- * @return [type] [description]
+ * @return array
*/
protected function getDeleteFileList()
{
@@ -352,6 +352,18 @@ abstract class Base
return $this->data['fileList'];
}
+ protected function getRestoreFileList()
+ {
+ if (!isset($this->data['restoreFileList'])) {
+ $backupPath = $this->getPath('backupPath');
+ $backupFilePath = Util::concatPath($backupPath, self::FILES);
+
+ $this->data['restoreFileList'] = $this->getFileManager()->getFileList($backupFilePath, true, '', true, true);
+ }
+
+ return $this->data['restoreFileList'];
+ }
+
protected function copy($sourcePath, $destPath, $recursively = false, array $fileList = null, $copyOnlyFiles = false)
{
try {
@@ -506,4 +518,23 @@ abstract class Base
{
return $this->getContainer()->get('dataManager')->clearCache();
}
+
+ protected function checkIsWritable()
+ {
+ $fullFileList = array_merge($this->getDeleteFileList(), $this->getCopyFileList());
+
+ $result = $this->getFileManager()->isWritableList($fullFileList);
+ if (!$result) {
+ $permissionDeniedList = $this->getFileManager()->getLastPermissionDeniedList();
+ throw new Error("Permission denied in
". implode(",
", $permissionDeniedList));
+ }
+ }
+
+ protected function backupExistingFiles()
+ {
+ $fullFileList = array_merge($this->getDeleteFileList(), $this->getCopyFileList());
+
+ $backupPath = $this->getPath('backupPath');
+ return $this->copy('', array($backupPath, self::FILES), false, $fullFileList);
+ }
}
\ No newline at end of file
diff --git a/application/Espo/Core/Upgrades/Actions/Base/Install.php b/application/Espo/Core/Upgrades/Actions/Base/Install.php
index 7a0f9dd93a..4d27ba9b87 100644
--- a/application/Espo/Core/Upgrades/Actions/Base/Install.php
+++ b/application/Espo/Core/Upgrades/Actions/Base/Install.php
@@ -23,6 +23,7 @@
namespace Espo\Core\Upgrades\Actions\Base;
use Espo\Core\Exceptions\Error;
+use Espo\Core\Utils\Util;
class Install extends \Espo\Core\Upgrades\Actions\Base
{
@@ -58,15 +59,15 @@ class Install extends \Espo\Core\Upgrades\Actions\Base
$this->isAcceptable();
}
- $this->beforeRunAction();
+ //check permissions copied and deleted files
+ $this->checkIsWritable();
+
+ $this->backupExistingFiles();
/* run before install script */
$this->runScript('before');
- /* remove files defined in a manifest */
- if (!$this->deleteFiles()) {
- $this->throwErrorAndRemovePackage('Permission denied to delete files.');
- }
+ $this->beforeRunAction();
/* copy files from directory "Files" to EspoCRM files */
if (!$this->copyFiles()) {
@@ -74,15 +75,18 @@ class Install extends \Espo\Core\Upgrades\Actions\Base
}
$this->isCopied = true;
+ /* remove files defined in a manifest */
+ $this->deleteFiles();
+
if (!$this->systemRebuild()) {
$this->throwErrorAndRemovePackage('Error occurred while EspoCRM rebuild.');
}
+ $this->afterRunAction();
+
/* run before install script */
$this->runScript('after');
- $this->afterRunAction();
-
$this->clearCache();
/* delete unziped files */
@@ -93,15 +97,25 @@ class Install extends \Espo\Core\Upgrades\Actions\Base
protected function restoreFiles()
{
- $backupPath = $this->getPath('backupPath');
-
- $res = true;
- if ($this->isCopied) {
- $res &= $this->copy(array($backupPath, self::FILES), '', true);
- $GLOBALS['log']->info('Restore: copy back');
+ if (!$this->isCopied) {
+ return;
}
- $res &= $this->getFileManager()->removeInDir($backupPath, true);
+ $GLOBALS['log']->info('Installer: Restore previous files.');
+
+ $backupPath = $this->getPath('backupPath');
+ $backupFilePath = Util::concatPath($backupPath, self::FILES);
+
+ $backupFileList = $this->getRestoreFileList();
+ $copyFileList = $this->getCopyFileList();
+ $deleteFileList = array_diff($copyFileList, $backupFileList);
+
+ $res = $this->copy($backupFilePath, '', true);
+ $res &= $this->getFileManager()->remove($deleteFileList, null, true);
+
+ if ($res) {
+ $this->getFileManager()->removeInDir($backupPath, true);
+ }
return $res;
}
diff --git a/application/Espo/Core/Upgrades/Actions/Base/Uninstall.php b/application/Espo/Core/Upgrades/Actions/Base/Uninstall.php
index 5c84377eb8..722e0e9287 100644
--- a/application/Espo/Core/Upgrades/Actions/Base/Uninstall.php
+++ b/application/Espo/Core/Upgrades/Actions/Base/Uninstall.php
@@ -37,34 +37,36 @@ class Uninstall extends \Espo\Core\Upgrades\Actions\Base
$this->setProcessId($processId);
- $this->beforeRunAction();
+ $this->checkIsWritable();
/* run before install script */
$this->runScript('beforeUninstall');
+ $this->beforeRunAction();
+
$backupPath = $this->getPath('backupPath');
if (file_exists($backupPath)) {
- /* remove extension files, saved in fileList */
- if (!$this->deleteFiles(true)) {
- throw new Error('Permission denied to delete files.');
- }
-
/* copy core files */
if (!$this->copyFiles()) {
- throw new Error('Cannot copy files.');
+ throw new $this->throwErrorAndRemovePackage('Cannot copy files.');
+ }
+
+ /* remove extension files, saved in fileList */
+ if (!$this->deleteFiles(true)) {
+ throw new $this->throwErrorAndRemovePackage('Permission denied to delete files.');
}
}
if (!$this->systemRebuild()) {
- throw new Error('Error occurred while EspoCRM rebuild.');
+ throw new $this->throwErrorAndRemovePackage('Error occurred while EspoCRM rebuild.');
}
+ $this->afterRunAction();
+
/* run before install script */
$this->runScript('afterUninstall');
- $this->afterRunAction();
-
$this->clearCache();
/* delete backup files */
@@ -73,12 +75,6 @@ class Uninstall extends \Espo\Core\Upgrades\Actions\Base
$GLOBALS['log']->debug('Uninstallation process ['.$processId.']: end run.');
}
- protected function getDeleteFileList()
- {
- $extensionEntity = $this->getExtensionEntity();
- return $extensionEntity->get('fileList');
- }
-
protected function restoreFiles()
{
$packagePath = $this->getPath('packagePath');
@@ -131,4 +127,41 @@ class Uninstall extends \Espo\Core\Upgrades\Actions\Base
throw new Error($errorMessage);
}
+ protected function getCopyFileList()
+ {
+ if (!isset($this->data['fileList'])) {
+ $backupPath = $this->getPath('backupPath');
+ $filesPath = Util::concatPath($backupPath, self::FILES);
+
+ $this->data['fileList'] = $this->getFileManager()->getFileList($filesPath, true, '', true, true);
+ }
+
+ return $this->data['fileList'];
+ }
+
+ protected function getRestoreFileList()
+ {
+ if (!isset($this->data['restoreFileList'])) {
+ $packagePath = $this->getPackagePath();
+ $filesPath = Util::concatPath($packagePath, self::FILES);
+
+ if (!file_exists($filesPath)) {
+ $this->unzipArchive($packagePath);
+ }
+
+ $this->data['restoreFileList'] = $this->getFileManager()->getFileList($filesPath, true, '', true, true);
+ }
+
+ return $this->data['restoreFileList'];
+ }
+
+ protected function getDeleteFileList()
+ {
+ $packageFileList = $this->getRestoreFileList();
+ $backupFileList = $this->getCopyFileList();
+
+ $deleteFileList = array_diff($packageFileList, $backupFileList);
+
+ return $deleteFileList;
+ }
}
diff --git a/application/Espo/Core/Upgrades/Actions/Extension/Install.php b/application/Espo/Core/Upgrades/Actions/Extension/Install.php
index dff99f54a0..1fb605cd8a 100644
--- a/application/Espo/Core/Upgrades/Actions/Extension/Install.php
+++ b/application/Espo/Core/Upgrades/Actions/Extension/Install.php
@@ -37,8 +37,6 @@ class Install extends \Espo\Core\Upgrades\Actions\Base\Install
$this->uninstallExtension();
$this->deleteExtension();
}
-
- $this->copyExistingFiles();
}
protected function afterRunAction()
@@ -51,12 +49,11 @@ class Install extends \Espo\Core\Upgrades\Actions\Base\Install
*
* @return bool
*/
- protected function copyExistingFiles()
+ protected function backupExistingFiles()
{
- $fileList = $this->getCopyFileList();
- $backupPath = $this->getPath('backupPath');
+ parent::backupExistingFiles();
- $res = $this->copy('', array($backupPath, self::FILES), false, $fileList);
+ $backupPath = $this->getPath('backupPath');
/** copy scripts files */
$packagePath = $this->getPackagePath();
@@ -65,19 +62,6 @@ class Install extends \Espo\Core\Upgrades\Actions\Base\Install
return $res;
}
- protected function restoreFiles()
- {
- $res = true;
- if ($this->isCopied) {
- $extensionFileList = $this->getCopyFileList();
- $res &= $this->getFileManager()->remove($extensionFileList);
- }
-
- $res &= parent::restoreFiles();
-
- return $res;
- }
-
protected function isNew()
{
$extensionEntity = $this->getExtensionEntity();
diff --git a/application/Espo/Core/Upgrades/Actions/Extension/Uninstall.php b/application/Espo/Core/Upgrades/Actions/Extension/Uninstall.php
index 41745c0979..d68fe183d2 100644
--- a/application/Espo/Core/Upgrades/Actions/Extension/Uninstall.php
+++ b/application/Espo/Core/Upgrades/Actions/Extension/Uninstall.php
@@ -68,4 +68,14 @@ class Uninstall extends \Espo\Core\Upgrades\Actions\Base\Uninstall
$extensionEntity->set('isInstalled', false);
$this->getEntityManager()->saveEntity($extensionEntity);
}
+
+ protected function getRestoreFileList()
+ {
+ if (!isset($this->data['restoreFileList'])) {
+ $extensionEntity = $this->getExtensionEntity();
+ $this->data['restoreFileList'] = $extensionEntity->get('fileList');
+ }
+
+ return $this->data['restoreFileList'];
+ }
}
\ No newline at end of file
diff --git a/application/Espo/Core/Upgrades/Actions/Upgrade/Install.php b/application/Espo/Core/Upgrades/Actions/Upgrade/Install.php
index 5d3b69a8c5..407ff85733 100644
--- a/application/Espo/Core/Upgrades/Actions/Upgrade/Install.php
+++ b/application/Espo/Core/Upgrades/Actions/Upgrade/Install.php
@@ -24,17 +24,12 @@ namespace Espo\Core\Upgrades\Actions\Upgrade;
class Install extends \Espo\Core\Upgrades\Actions\Base\Install
{
- protected function systemRebuild()
+ protected function afterRunAction()
{
$manifest = $this->getManifest();
- $res = $this->getConfig()->set('version', $manifest['version']);
- if (method_exists($this->getConfig(), 'save')) {
- $res = $this->getConfig()->save();
- }
- $res &= parent::systemRebuild();
-
- return $res;
+ $this->getConfig()->set('version', $manifest['version']);
+ $this->getConfig()->save();
}
/**
diff --git a/application/Espo/Core/Utils/File/Manager.php b/application/Espo/Core/Utils/File/Manager.php
index e0cb8f4576..391ffabef6 100644
--- a/application/Espo/Core/Utils/File/Manager.php
+++ b/application/Espo/Core/Utils/File/Manager.php
@@ -29,6 +29,8 @@ class Manager
{
private $permission;
+ private $permissionDeniedList = array();
+
public function __construct(\Espo\Core\Utils\Config $config = null)
{
$params = null;
@@ -774,5 +776,73 @@ return '.var_export($content, true).';
?>';
}
+ /**
+ * Check if $paths are writable. Permission denied list are defined in getLastPermissionDeniedList()
+ *
+ * @param array $paths
+ *
+ * @return boolean
+ */
+ public function isWritableList(array $paths)
+ {
+ $permissionDeniedList = array();
+
+ $result = true;
+ foreach ($paths as $path) {
+ $rowResult = $this->isWritable($path);
+ if (!$rowResult) {
+ $permissionDeniedList[] = $path;
+ }
+ $result &= $rowResult;
+ }
+
+ if (!empty($permissionDeniedList)) {
+ $this->permissionDeniedList = $this->getPermissionUtils()->arrangePermissionList($permissionDeniedList);
+ }
+
+ return (bool) $result;
+ }
+
+ /**
+ * Get last permission denied list
+ *
+ * @return array
+ */
+ public function getLastPermissionDeniedList()
+ {
+ return $this->permissionDeniedList;
+ }
+
+ /**
+ * Check if $path is writable
+ *
+ * @param string | array $path
+ *
+ * @return boolean
+ */
+ public function isWritable($path)
+ {
+ $existFile = $this->getExistsPath($path);
+
+ return is_writable($existFile);
+ }
+
+ /**
+ * Get exists path. Ex. if check /var/www/espocrm/custom/someFile.php and this file doesn't extist, result will be /var/www/espocrm/custom
+ *
+ * @param string | array $path
+ *
+ * @return string
+ */
+ protected function getExistsPath($path)
+ {
+ $fullPath = $this->concatPaths($path);
+
+ if (!file_exists($fullPath)) {
+ $fullPath = $this->getExistsPath($fullPath, PATHINFO_DIRNAME);
+ }
+
+ return $fullPath;
+ }
}