├── README.md ├── app └── code │ └── Inchoo │ └── Helloworld │ ├── Block │ └── Helloworld.php │ ├── Controller │ └── Index │ │ └── Index.php │ ├── etc │ ├── frontend │ │ └── routes.xml │ └── module.xml │ ├── registration.php │ └── view │ └── frontend │ ├── layout │ └── helloworld_index_index.xml │ └── templates │ └── helloworld.phtml ├── composer.json ├── composer.lock ├── phpserver ├── .htaccess ├── README.md └── router.php └── update ├── .gitignore ├── .htaccess ├── README.md ├── app ├── .htaccess ├── bootstrap.php └── code │ └── Magento │ └── Update │ ├── Backup.php │ ├── Backup │ └── BackupInfo.php │ ├── CronReadinessCheck.php │ ├── ExcludeFilter.php │ ├── MaintenanceMode.php │ ├── Queue.php │ ├── Queue │ ├── AbstractJob.php │ ├── JobBackup.php │ ├── JobComponentUninstall.php │ ├── JobFactory.php │ ├── JobMaintenanceMode.php │ ├── JobRemoveBackups.php │ ├── JobRollback.php │ ├── JobUpdate.php │ ├── Reader.php │ └── Writer.php │ ├── Rollback.php │ ├── Status.php │ ├── Test │ └── Unit │ │ ├── Queue │ │ ├── AbstractJobTest.php │ │ └── JobFactoryTest.php │ │ ├── QueueTest.php │ │ └── _files │ │ └── update_queue_valid.json │ ├── etc │ └── backup_blacklist.txt │ └── view │ └── templates │ └── status.phtml ├── composer.json ├── composer.lock ├── cron.php ├── dev ├── .htaccess ├── shell │ └── cron.sh └── tests │ └── integration │ └── testsuite │ └── Magento │ └── Update │ ├── CronReadinessCheckTest.php │ ├── CronTest.php │ ├── MaintenanceModeTest.php │ ├── Queue │ ├── JobBackupTest.php │ ├── JobComponentUninstallTest.php │ ├── JobRemoveBackupsTest.php │ ├── JobRollbackTest.php │ ├── JobUpdateTest.php │ ├── ReaderTest.php │ └── WriterTest.php │ ├── RollbackTest.php │ ├── StatusCheckTest.php │ ├── StatusTest.php │ └── _files │ ├── composer.json │ ├── update_queue_invalid.json │ ├── update_queue_valid.json │ └── update_status.txt ├── index.php ├── pub ├── .htaccess ├── css │ └── setup.css ├── favicon.ico ├── fonts │ ├── icons │ │ ├── icons.eot │ │ ├── icons.svg │ │ ├── icons.ttf │ │ ├── icons.woff │ │ ├── icons.woff2 │ │ └── selection.json │ └── opensans │ │ ├── bold │ │ ├── opensans-700.eot │ │ ├── opensans-700.svg │ │ ├── opensans-700.ttf │ │ ├── opensans-700.woff │ │ └── opensans-700.woff2 │ │ ├── light │ │ ├── opensans-300.eot │ │ ├── opensans-300.svg │ │ ├── opensans-300.ttf │ │ ├── opensans-300.woff │ │ └── opensans-300.woff2 │ │ ├── regular │ │ ├── opensans-400.eot │ │ ├── opensans-400.svg │ │ ├── opensans-400.ttf │ │ ├── opensans-400.woff │ │ └── opensans-400.woff2 │ │ └── semibold │ │ ├── opensans-600.eot │ │ ├── opensans-600.svg │ │ ├── opensans-600.ttf │ │ ├── opensans-600.woff │ │ └── opensans-600.woff2 ├── images │ ├── ajax-loader.gif │ ├── arrows-bg.svg │ ├── favicon │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ └── favicon.ico │ ├── loader-2.gif │ ├── logo.svg │ ├── magento-icon.svg │ └── magento-logo.svg └── js │ ├── lib │ ├── angular-ng-storage │ │ └── angular-ng-storage.min.js │ ├── angular │ │ ├── angular.js │ │ ├── angular.min.js │ │ └── angular.min.js.map │ └── jquery.js │ └── status.js └── var └── .htaccess /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/magento/magento2.svg?branch=master)](https://travis-ci.org/magento/magento2) 2 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/magento/magento2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 3 |

Welcome

4 | Welcome to Magento 2 installation! We're glad you chose to install Magento 2, a cutting edge, feature-rich eCommerce solution that gets results. 5 | 6 | The installation instructions that used to be here are now published on our GitHub site. Use the information on this page to get started or go directly to the guide. 7 | 8 |

New to Magento? Need some help?

9 | If you're not sure about the following, you probably need a little help before you start installing the Magento software: 10 | 11 | * Is the Magento software installed already? 12 | * What's a terminal, command prompt, or Secure Shell (ssh)? 13 | * Where's my Magento server and how do I access it? 14 | * What's PHP? 15 | * What's Apache? 16 | * What's MySQL? 17 | 18 |

Step 1: Verify your prerequisites

19 | 20 | Use the following table to verify you have the correct prerequisites to install the Magento software. 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
PrerequisiteHow to checkFor more information
Apache 2.2 or 2.4Ubuntu: apache2 -v
32 | CentOS: httpd -v
Apache
PHP 5.5.x or 5.6.xphp -vPHP Ubuntu
PHP CentOS
MySQL 5.6.xmysql -u [root user name] -pMySQL
46 | 47 |

Step 2: Prepare to install

48 | 49 | After verifying your prerequisites, perform the following tasks in order to prepare to install the Magento software. 50 | 51 | 1. Install Composer 52 | 2. Clone the Magento repository 53 | 54 |

Step 3: Install and verify the installation

55 | 56 | 1. Update installation dependencies 57 | 2. Install Magento: 58 | * Install Magento software using the web interface 59 | * Install Magento software using the command line 60 | 2. Verify the installation 61 | 62 |

Contributing to the Magento 2 code base

63 | Contributions can take the form of new components or features, changes to existing features, tests, documentation (such as developer guides, user guides, examples, or specifications), bug fixes, optimizations, or just good suggestions. 64 | 65 | To learn about how to make a contribution, click [here][1]. 66 | 67 | To learn about issues, click [here][2]. To open an issue, click [here][3]. 68 | 69 | To suggest documentation improvements, click [here][4]. 70 | 71 | [1]: 72 | [2]: 73 | [3]: 74 | [4]: 75 | # magento_helloworld 76 | -------------------------------------------------------------------------------- /app/code/Inchoo/Helloworld/Block/Helloworld.php: -------------------------------------------------------------------------------- 1 | _resultPageFactory = $resultPageFactory; 14 | parent::__construct($context); 15 | } 16 | 17 | public function execute() 18 | { 19 | $resultPage = $this->_resultPageFactory->create(); 20 | return $resultPage; 21 | } 22 | } -------------------------------------------------------------------------------- /app/code/Inchoo/Helloworld/etc/frontend/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/code/Inchoo/Helloworld/etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/code/Inchoo/Helloworld/registration.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/code/Inchoo/Helloworld/view/frontend/templates/helloworld.phtml: -------------------------------------------------------------------------------- 1 |

getHelloWorldTxt(); ?>

-------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "magento/project-community-edition", 3 | "description": "eCommerce Platform for Growth (Community Edition)", 4 | "type": "project", 5 | "version": "2.0.4", 6 | "license": [ 7 | "OSL-3.0", 8 | "AFL-3.0" 9 | ], 10 | "repositories": [ 11 | { 12 | "type": "composer", 13 | "url": "https://repo.magento.com/" 14 | } 15 | ], 16 | "require": { 17 | "magento/product-community-edition": "2.0.4", 18 | "composer/composer": "@alpha" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "4.1.0", 22 | "squizlabs/php_codesniffer": "1.5.3", 23 | "phpmd/phpmd": "2.3.*", 24 | "pdepend/pdepend": "2.2.2", 25 | "sjparkinson/static-review": "~4.1", 26 | "fabpot/php-cs-fixer": "~1.2", 27 | "lusitanian/oauth": "~0.3 <=0.7.0" 28 | }, 29 | "config": { 30 | "use-include-path": true 31 | }, 32 | "autoload": { 33 | "psr-4": { 34 | "Magento\\Framework\\": "lib/internal/Magento/Framework/", 35 | "Magento\\Setup\\": "setup/src/Magento/Setup/", 36 | "Magento\\": "app/code/Magento/" 37 | }, 38 | "psr-0": { 39 | "": "app/code/" 40 | }, 41 | "files": [ 42 | "app/etc/NonComposerComponentRegistration.php" 43 | ] 44 | }, 45 | "autoload-dev": { 46 | "psr-4": { 47 | "Magento\\Sniffs\\": "dev/tests/static/framework/Magento/Sniffs/", 48 | "Magento\\Tools\\": "dev/tools/Magento/Tools/", 49 | "Magento\\Tools\\Sanity\\": "dev/build/publication/sanity/Magento/Tools/Sanity/", 50 | "Magento\\TestFramework\\Inspection\\": "dev/tests/static/framework/Magento/TestFramework/Inspection/", 51 | "Magento\\TestFramework\\Utility\\": "dev/tests/static/framework/Magento/TestFramework/Utility/" 52 | } 53 | }, 54 | "minimum-stability": "alpha", 55 | "prefer-stable": true, 56 | "extra": { 57 | "magento-force": "override" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /phpserver/.htaccess: -------------------------------------------------------------------------------- 1 | Order deny,allow 2 | Deny from all 3 | -------------------------------------------------------------------------------- /phpserver/README.md: -------------------------------------------------------------------------------- 1 | PHP Built-in webserver 2 | ====================== 3 | 4 | php has a Built-in webserver since version 5.4 5 | https://secure.php.net/manual/en/features.commandline.webserver.php 6 | 7 | As many applications and frameworks rely on rewrites on webserver side, 8 | the same as Magento does, it offers an argument for a router script. 9 | Either the script returns false which means, it should try to deliver the file 10 | as usual via file system lookup, or it executes the specific php scripts via include. 11 | 12 | Example: 13 | requests to `/static/frontend/Magento/blank/en_US/mage/calendar.css` should deliver the file if it exists, or execute `/static.php` if not. 14 | 15 | Without a router script, that is not possible via the php built-in server. 16 | 17 | ### How to use it 18 | 19 | example usage: ```php -S 127.0.0.41:8082 -t ./pub/ ./phpserver/router.php``` 20 | 21 | ### What exactly the script does 22 | 23 | first we have an low level `$debug` closure, for the case you need to debug execution. 24 | 25 | If the request path starts with index.php, get.php, static.php, we return to normal request flow. 26 | If we notice a favicon.ico request, the same. 27 | 28 | Then rewrite paths for `pub/errors/default/` by removing the `pub/` part. (was at least needed for older versions) 29 | 30 | Request starting with `media/`, `opt/`, `static/` test if the file exists. 31 | If Yes, then handle it, if not "forward" `static` to `static.php` and `media` to `get.php` 32 | 33 | If none of the rules matched, return 404. 34 | You may instead include the index.php, if 404 should be handled by Magento or you want 35 | urls without `index.php/`. 36 | -------------------------------------------------------------------------------- /phpserver/router.php: -------------------------------------------------------------------------------- 1 | '.PHP_EOL; 33 | }; 34 | 35 | /** 36 | * Caution, this is very experimental stuff 37 | * no guarantee for working result 38 | * has tons of potential big security holes 39 | */ 40 | 41 | if (php_sapi_name() === 'cli-server') { 42 | 43 | $debug($_SERVER["REQUEST_URI"]); 44 | if (preg_match('/^\/(index|get|static)\.php(\/)?/', $_SERVER["REQUEST_URI"])) { 45 | return false; // serve the requested resource as-is. 46 | } 47 | 48 | $path = pathinfo($_SERVER["SCRIPT_FILENAME"]); 49 | $url = pathinfo(substr($_SERVER["REQUEST_URI"], 1)); 50 | $route = parse_url(substr($_SERVER["REQUEST_URI"], 1))["path"]; 51 | 52 | $debug($path); 53 | $debug($route); 54 | 55 | if ($path["basename"] == 'favicon.ico') { 56 | return false; 57 | } 58 | 59 | $debug($route); 60 | $debug(strpos($route, 'errors/default/css/')); 61 | 62 | if (strpos($route, 'pub/errors/default/') === 0) { 63 | $route = preg_replace('#pub/errors/default/#', 'errors/default/', $route, 1); 64 | } 65 | 66 | $debug($route); 67 | 68 | if ( 69 | strpos($route, 'media/') === 0 || 70 | strpos($route, 'opt/') === 0 || 71 | strpos($route, 'static/') === 0 || 72 | strpos($route, 'errors/default/css/') === 0 || 73 | strpos($route, 'errors/default/images/') === 0 74 | ) { 75 | $magentoPackagePubDir = __DIR__."/../pub"; 76 | 77 | $file = $magentoPackagePubDir.'/'.$route; 78 | $debug($file); 79 | if (file_exists($file)) { 80 | $debug('file exists'); 81 | return false; 82 | } else { 83 | $debug('file does not exist'); 84 | if (strpos($route, 'static/') === 0) { 85 | $route = preg_replace('#static/#', '', $route, 1); 86 | $_GET['resource'] = $route; 87 | include($magentoPackagePubDir.'/static.php'); 88 | exit; 89 | } elseif (strpos($route, 'media/') === 0) { 90 | include($magentoPackagePubDir.'/get.php'); 91 | exit; 92 | } 93 | } 94 | } 95 | 96 | header('HTTP/1.0 404 Not Found'); 97 | } 98 | -------------------------------------------------------------------------------- /update/.gitignore: -------------------------------------------------------------------------------- 1 | /var/* 2 | !/var/.htaccess 3 | /vendor 4 | /.buildpath 5 | /.cache 6 | /.metadata 7 | /.project 8 | /.settings 9 | atlassian* 10 | /.idea 11 | /.gitattributes -------------------------------------------------------------------------------- /update/.htaccess: -------------------------------------------------------------------------------- 1 | Order deny,allow 2 | Deny from all 3 | 4 | 5 | Allow from all 6 | 7 | -------------------------------------------------------------------------------- /update/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/README.md -------------------------------------------------------------------------------- /update/app/.htaccess: -------------------------------------------------------------------------------- 1 | Order deny,allow 2 | Deny from all 3 | 4 | -------------------------------------------------------------------------------- /update/app/bootstrap.php: -------------------------------------------------------------------------------- 1 | backupInfo = $backupInfo ? $backupInfo : new BackupInfo(); 36 | $this->status = $status ? $status : new Status(); 37 | } 38 | 39 | /** 40 | * Create backup archive using unix zip tool. 41 | * 42 | * @return $this 43 | * @throws \RuntimeException 44 | */ 45 | public function execute() 46 | { 47 | $backupFilePath = $this->backupInfo->getBackupPath() . $this->backupInfo->generateBackupFilename(); 48 | $command = $this->buildShellCommand($backupFilePath); 49 | $this->status->add(sprintf('Creating backup archive "%s" ...', $backupFilePath)); 50 | exec($command, $output, $return); 51 | if ($return) { 52 | throw new \RuntimeException( 53 | sprintf('Cannot create backup with command "%s": %s', $command, implode("\n", $output)) 54 | ); 55 | } 56 | $this->status->add(sprintf('Backup archive "%s" has been created.', $backupFilePath)); 57 | return $this; 58 | } 59 | 60 | /** 61 | * Construct shell command for creating backup archive. 62 | * 63 | * @param string $backupFilePath 64 | * @return string 65 | */ 66 | protected function buildShellCommand($backupFilePath) 67 | { 68 | $excludedElements = ''; 69 | foreach ($this->backupInfo->getBlacklist() as $excludedElement) { 70 | $elementPath = $excludedElement; 71 | $fullPath = $this->backupInfo->getArchivedDirectory() . '/' . $elementPath; 72 | $excludedElements .= is_dir($fullPath) ? $elementPath . '\* ' : $elementPath . ' '; 73 | } 74 | $changeDirectoryCommand = sprintf("cd %s", $this->backupInfo->getArchivedDirectory()); 75 | $zipCommand = sprintf("zip -r %s . -x %s", $backupFilePath, $excludedElements); 76 | return $changeDirectoryCommand . ' && ' . $zipCommand; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Backup/BackupInfo.php: -------------------------------------------------------------------------------- 1 | blacklistFilePath = $blacklistFilePath ? $blacklistFilePath : __DIR__ . '/../etc/backup_blacklist.txt'; 40 | } 41 | 42 | /** 43 | * Generate backup filename based on current timestamp. 44 | * 45 | * @return string 46 | */ 47 | public function generateBackupFilename() 48 | { 49 | $currentDate = gmdate('Y-m-d-H-i-s', time()); 50 | return 'backup-' . $currentDate . '.zip'; 51 | } 52 | 53 | /** 54 | * Return files/directories, which need to be excluded from backup 55 | * 56 | * @throws \RuntimeException 57 | * @return string[] 58 | */ 59 | public function getBlacklist() 60 | { 61 | if (null === $this->blacklist) { 62 | $blacklistContent = file_get_contents($this->blacklistFilePath); 63 | if ($blacklistContent === FALSE) { 64 | throw new \RuntimeException('Could not read the blacklist file: ' . $this->blacklistFilePath); 65 | } 66 | /** Ignore commented and empty lines */ 67 | $blacklistArray = explode("\n", $blacklistContent); 68 | $blacklistArray = array_filter( 69 | $blacklistArray, 70 | function ($value) { 71 | $value = trim($value); 72 | return (empty($value) || strpos($value, '#') === 0) ? false : true; 73 | } 74 | ); 75 | $this->blacklist = $blacklistArray; 76 | } 77 | return $this->blacklist; 78 | } 79 | 80 | /** 81 | * Return path to a directory, which need to be archived 82 | * 83 | * @return string 84 | */ 85 | public function getArchivedDirectory() 86 | { 87 | return MAGENTO_BP; 88 | } 89 | 90 | /** 91 | * Return path, where backup have to be saved 92 | * 93 | * @return string 94 | */ 95 | public function getBackupPath() 96 | { 97 | return BACKUP_DIR; 98 | } 99 | 100 | /** 101 | * Returns list of backup file paths 102 | * 103 | * @return array 104 | */ 105 | public function getBackupFilePaths() 106 | { 107 | $timeStamp = $this->getLastBackupFileTimestamp(); 108 | $backupTypes = [self::BACKUP_CODE, self::BACKUP_MEDIA]; 109 | $backupPaths = []; 110 | foreach ($backupTypes as $backupType) { 111 | $fileName = BACKUP_DIR . $timeStamp . '_filesystem_' . $backupType .'.tgz'; 112 | if (!file_exists($fileName)) { 113 | $backupPaths['error'][] = 'Backup file does not exist for "' . $backupType . '"'; 114 | } else { 115 | $backupPaths[$backupType]['filename'] = $fileName; 116 | $backupPaths[$backupType]['type'] = 'rollback'; 117 | } 118 | } 119 | $fileName = BACKUP_DIR . $timeStamp .'_' . self::BACKUP_DB .'.gz'; 120 | if (!file_exists($fileName)) { 121 | $backupPaths['error'][] = 'Backup file does not exist for "' . self::BACKUP_DB . '"'; 122 | } else { 123 | $backupPaths[self::BACKUP_DB]['filename'] = $fileName; 124 | $backupPaths[self::BACKUP_DB]['type'] = 'setup:rollback'; 125 | } 126 | return $backupPaths; 127 | } 128 | 129 | /** 130 | * Find the timestamp of the last backup file from backup directory. 131 | * 132 | * @throws \RuntimeException 133 | * @return string 134 | */ 135 | private function getLastBackupFileTimestamp() 136 | { 137 | $allFileList = scandir(BACKUP_DIR, SCANDIR_SORT_DESCENDING); 138 | $backupFileName = ''; 139 | 140 | if (isset($allFileList) && !empty($allFileList)) { 141 | $backupFileName = explode('_', $allFileList[0])[0]; 142 | } 143 | 144 | if (empty($backupFileName)) { 145 | throw new \RuntimeException('Backup directory is empty'); 146 | } 147 | return $backupFileName; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/CronReadinessCheck.php: -------------------------------------------------------------------------------- 1 | []]; 36 | $success = true; 37 | 38 | $nonWritablePaths = $this->checkPermissionsRecursively(); 39 | 40 | if (!empty($nonWritablePaths)) { 41 | $resultJsonRawData[self::KEY_READINESS_CHECKS][self::KEY_FILE_PERMISSIONS_VERIFIED] = false; 42 | $resultJsonRawData[self::KEY_READINESS_CHECKS][self::KEY_ERROR] = 43 | 'Found non-writable path(s):
' . implode('
', $nonWritablePaths); 44 | $success = false; 45 | } else { 46 | $resultJsonRawData[self::KEY_READINESS_CHECKS][self::KEY_FILE_PERMISSIONS_VERIFIED] = true; 47 | } 48 | 49 | if (file_exists(MAGENTO_BP . '/var/' . self::CRON_JOB_STATUS_FILE)) { 50 | $jsonData = json_decode(file_get_contents(MAGENTO_BP . '/var/' . self::CRON_JOB_STATUS_FILE), true); 51 | if (isset($jsonData[self::KEY_CURRENT_TIMESTAMP])) { 52 | $resultJsonRawData[self::KEY_LAST_TIMESTAMP] = $jsonData[self::KEY_CURRENT_TIMESTAMP]; 53 | } 54 | } 55 | $resultJsonRawData[self::KEY_CURRENT_TIMESTAMP] = time(); 56 | 57 | $resultJson = json_encode($resultJsonRawData, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); 58 | file_put_contents(MAGENTO_BP . '/var/' . self::CRON_JOB_STATUS_FILE, $resultJson); 59 | 60 | return $success; 61 | } 62 | 63 | /** 64 | * Check file permissions recursively 65 | * 66 | * @return string[] 67 | */ 68 | private function checkPermissionsRecursively() 69 | { 70 | $nonWritablePaths = []; 71 | $filesystemIterator = new \RecursiveIteratorIterator( 72 | new \RecursiveDirectoryIterator(MAGENTO_BP), 73 | \RecursiveIteratorIterator::SELF_FIRST 74 | ); 75 | $filesystemIterator = new ExcludeFilter( 76 | $filesystemIterator, 77 | [ 78 | MAGENTO_BP . '/update', 79 | MAGENTO_BP . '/var/session', 80 | '.git', 81 | '.idea' 82 | ] 83 | ); 84 | foreach ($filesystemIterator as $item) { 85 | $path = $item->__toString(); 86 | if (!is_writable($path)) { 87 | $nonWritablePaths[] = $path; 88 | } 89 | } 90 | return $nonWritablePaths; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/ExcludeFilter.php: -------------------------------------------------------------------------------- 1 | _filters = $filters; 31 | } 32 | 33 | /** 34 | * Check whether the current element of the iterator is acceptable 35 | * 36 | * @return bool 37 | */ 38 | public function accept() 39 | { 40 | $current = str_replace('\\', '/', $this->current()->__toString()); 41 | $currentFilename = str_replace('\\', '/', $this->current()->getFilename()); 42 | 43 | if ($currentFilename == '.' || $currentFilename == '..') { 44 | return false; 45 | } 46 | 47 | foreach ($this->_filters as $filter) { 48 | $filter = str_replace('\\', '/', $filter); 49 | if (false !== strpos($current, $filter)) { 50 | return false; 51 | } 52 | } 53 | 54 | return true; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/MaintenanceMode.php: -------------------------------------------------------------------------------- 1 | flagFile = $flagFile ? $flagFile : MAGENTO_BP . '/var/.maintenance.flag'; 44 | $this->ipFile = $ipFile ? $ipFile : MAGENTO_BP . '/var/.maintenance.ip'; 45 | $this->status = $status ? $status : new Status(); 46 | } 47 | 48 | /** 49 | * Check whether Magento maintenance mode is on. 50 | * 51 | * @return bool 52 | */ 53 | public function isOn() 54 | { 55 | return file_exists($this->flagFile); 56 | } 57 | 58 | /** 59 | * Set maintenance mode. 60 | * 61 | * @param bool $isOn 62 | * @return $this 63 | * @throws \RuntimeException 64 | */ 65 | public function set($isOn) 66 | { 67 | if ($isOn) { 68 | if (touch($this->flagFile)) { 69 | $this->status->add("Magento maintenance mode is enabled."); 70 | } else { 71 | throw new \RuntimeException("Magento maintenance mode cannot be enabled."); 72 | } 73 | } else if (file_exists($this->flagFile)) { 74 | if (file_exists($this->ipFile)) { 75 | /** Maintenance mode should not be unset from updater application if it was set manually by the admin */ 76 | $this->status->add( 77 | "Magento maintenance mode was not disabled. It can be disabled form the Magento Backend." 78 | ); 79 | } else if (unlink($this->flagFile)) { 80 | $this->status->add("Magento maintenance mode is disabled."); 81 | } else { 82 | throw new \RuntimeException("Magento maintenance mode cannot be disabled."); 83 | } 84 | } 85 | return $this; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Queue.php: -------------------------------------------------------------------------------- 1 | reader = $reader ? $reader : new Reader(); 52 | $this->writer = $writer ? $writer : new Writer(); 53 | $this->jobFactory = $jobFactory ? $jobFactory : new JobFactory(); 54 | } 55 | 56 | /** 57 | * Peek at job queue 58 | * 59 | * @throws \RuntimeException 60 | * @return array 61 | */ 62 | public function peek() 63 | { 64 | $queue = json_decode($this->reader->read(), true); 65 | if (!is_array($queue)) { 66 | return []; 67 | } 68 | if (isset($queue[self::KEY_JOBS]) && is_array($queue[self::KEY_JOBS])) { 69 | $this->validateJobDeclaration($queue[self::KEY_JOBS][0]); 70 | return $queue[self::KEY_JOBS][0]; 71 | } else { 72 | throw new \RuntimeException(sprintf('"%s" field is missing or is not an array.', self::KEY_JOBS)); 73 | } 74 | } 75 | 76 | /** 77 | * Pop job queue. 78 | * 79 | * @return AbstractJob 80 | * @throws \RuntimeException 81 | */ 82 | public function popQueuedJob() 83 | { 84 | $job = null; 85 | $queue = json_decode($this->reader->read(), true); 86 | if (!is_array($queue)) { 87 | return $job; 88 | } 89 | if (isset($queue[self::KEY_JOBS]) && is_array($queue[self::KEY_JOBS])) { 90 | $this->validateJobDeclaration($queue[self::KEY_JOBS][0]); 91 | $job = $this->jobFactory->create( 92 | $queue[self::KEY_JOBS][0][self::KEY_JOB_NAME], 93 | $queue[self::KEY_JOBS][0][self::KEY_JOB_PARAMS] 94 | ); 95 | array_shift($queue[self::KEY_JOBS]); 96 | if (empty($queue[self::KEY_JOBS])) { 97 | $this->writer->write(''); 98 | } else { 99 | $this->writer->write(json_encode($queue, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES )); 100 | } 101 | } else { 102 | throw new \RuntimeException(sprintf('"%s" field is missing or is not an array.', self::KEY_JOBS)); 103 | } 104 | return $job; 105 | } 106 | 107 | /** 108 | * Check if queue is empty 109 | * 110 | * @return bool 111 | */ 112 | public function isEmpty() 113 | { 114 | $queue = json_decode($this->reader->read(), true); 115 | return empty($queue); 116 | } 117 | 118 | /** 119 | * @param array $jobs 120 | * @return void 121 | */ 122 | public function addJobs(array $jobs) 123 | { 124 | foreach ($jobs as $job) { 125 | $this->validateJobDeclaration($job); 126 | $queue = json_decode($this->reader->read(), true); 127 | $queue[self::KEY_JOBS][] = $job; 128 | $this->writer->write(json_encode($queue, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES )); 129 | } 130 | } 131 | 132 | /** 133 | * @return void 134 | */ 135 | public function clear() 136 | { 137 | $this->writer->write(''); 138 | } 139 | 140 | /** 141 | * Make sure job declaration is correct. 142 | * 143 | * @param object $job 144 | * @throws \RuntimeException 145 | */ 146 | protected function validateJobDeclaration($job) 147 | { 148 | $requiredFields = [self::KEY_JOB_NAME, self::KEY_JOB_PARAMS]; 149 | foreach ($requiredFields as $field) { 150 | if (!isset($job[$field])) { 151 | throw new \RuntimeException(sprintf('"%s" field is missing for one or more jobs.', $field)); 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Queue/AbstractJob.php: -------------------------------------------------------------------------------- 1 | name = $name; 48 | $this->params = $params; 49 | $this->status = $status ? $status : new Status(); 50 | $this->maintenanceMode = $maintenanceMode ? $maintenanceMode : new MaintenanceMode(); 51 | } 52 | 53 | /** 54 | * Get job name. 55 | * 56 | * @return string 57 | */ 58 | public function getName() 59 | { 60 | return $this->name; 61 | } 62 | 63 | /** 64 | * Get string representation of a job. 65 | * 66 | * @return string 67 | */ 68 | public function __toString() 69 | { 70 | return $this->name . ' ' . json_encode($this->params, JSON_UNESCAPED_SLASHES ); 71 | } 72 | 73 | /** 74 | * Execute job. 75 | * 76 | * @return $this 77 | * @throws \RuntimeException 78 | */ 79 | abstract public function execute(); 80 | } 81 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Queue/JobBackup.php: -------------------------------------------------------------------------------- 1 | backup = new Backup($backupInfo); 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | */ 46 | public function execute() 47 | { 48 | $this->backup->execute(); 49 | return $this; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Queue/JobComponentUninstall.php: -------------------------------------------------------------------------------- 1 | queue = $queue ? $queue : new Queue(); 49 | 50 | $this->composerApp = $composerApp ? $composerApp : 51 | new MagentoComposerApplication( 52 | MAGENTO_BP . '/var/composer_home', 53 | $composerPath 54 | ); 55 | } 56 | 57 | /** 58 | * {@inheritdoc} 59 | */ 60 | public function execute() 61 | { 62 | try { 63 | $this->status->add('Starting composer remove...'); 64 | if (isset($this->params['components'])) { 65 | $packages = []; 66 | foreach ($this->params['components'] as $compObj) { 67 | $packages[] = $compObj['name']; 68 | } 69 | $this->status->add( 70 | $this->composerApp->runComposerCommand( 71 | ['command' => 'remove', 'packages' => $packages, '--no-update' => true] 72 | ) 73 | ); 74 | } else { 75 | throw new \RuntimeException('Cannot find component to uninstall'); 76 | } 77 | $this->status->add($this->composerApp->runComposerCommand(['command' => 'update'])); 78 | $this->status->add('Composer remove completed successfully'); 79 | $this->queue->addJobs( 80 | [['name' => \Magento\Update\Queue\JobFactory::NAME_MAINTENANCE_MODE, 'params' => ['enable' => false]]] 81 | ); 82 | } catch (\Exception $e) { 83 | $this->status->setUpdateError(true); 84 | throw new \RuntimeException(sprintf('Could not complete %s successfully: %s', $this, $e->getMessage())); 85 | } 86 | return $this; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Queue/JobFactory.php: -------------------------------------------------------------------------------- 1 | params['enable'] == true) { 34 | $this->maintenanceMode->set(true); 35 | } else { 36 | $this->maintenanceMode->set(false); 37 | } 38 | } catch (\Exception $e) { 39 | 40 | } 41 | return $this; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Queue/JobRemoveBackups.php: -------------------------------------------------------------------------------- 1 | params[self::BACKUPS_FILE_NAMES])) { 23 | $filesToDelete = $this->params[self::BACKUPS_FILE_NAMES]; 24 | } 25 | if ($this->maintenanceMode->isOn() || $this->status->isUpdateError()) { 26 | throw new \RuntimeException("Cannot remove backup archives while setup is in progress."); 27 | } 28 | foreach ($filesToDelete as $archivePath) { 29 | if (file_exists($archivePath) && unlink($archivePath)) { 30 | $this->status->add(sprintf('"%s" was deleted successfully.', $archivePath)); 31 | } else { 32 | throw new \RuntimeException(sprintf('Could not delete backup archive "%s"', $archivePath)); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Queue/JobRollback.php: -------------------------------------------------------------------------------- 1 | params[self::BACKUP_FILE_NAME]) ? null : $this->params[self::BACKUP_FILE_NAME]; 25 | $rollBack->execute($backupFileName); 26 | return $this; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Queue/JobUpdate.php: -------------------------------------------------------------------------------- 1 | queue = $queue ? $queue : new Queue(); 66 | $this->backup = $backup ? $backup : new Backup(); 67 | $this->rollback = $rollback ? $rollback : new Rollback(); 68 | 69 | $vendorPath = MAGENTO_BP . '/' . (include (MAGENTO_BP . '/app/etc/vendor_path.php')); 70 | $composerPath = $vendorPath . '/../composer.json'; 71 | $composerPath = realpath($composerPath); 72 | 73 | $this->composerApp = $composerApp ? $composerApp : 74 | new MagentoComposerApplication( 75 | MAGENTO_BP . '/var/composer_home', 76 | $composerPath 77 | ); 78 | } 79 | 80 | /** 81 | * {@inheritdoc} 82 | */ 83 | public function execute() 84 | { 85 | try { 86 | $this->status->add('Starting composer update...'); 87 | if (isset($this->params['components'])) { 88 | $packages = []; 89 | foreach ($this->params['components'] as $compObj) { 90 | $packages[] = implode(' ', $compObj); 91 | } 92 | foreach ($packages as $package) { 93 | if (strpos($package, 'magento/product-enterprise-edition') !== false) { 94 | $this->composerApp->runComposerCommand( 95 | [ 96 | 'command' => 'remove', 97 | 'packages' => ['magento/product-community-edition'], 98 | '--no-update' => true 99 | ] 100 | ); 101 | } 102 | } 103 | $this->status->add( 104 | $this->composerApp->runComposerCommand( 105 | ['command' => 'require', 'packages' => $packages, '--no-update' => true] 106 | ) 107 | ); 108 | } else { 109 | throw new \RuntimeException('Cannot find component to update'); 110 | } 111 | $this->status->add($this->composerApp->runComposerCommand(['command' => 'update'])); 112 | $this->status->add('Composer update completed successfully'); 113 | $this->createSetupUpgradeTasks(); 114 | } catch (\Exception $e) { 115 | $this->status->setUpdateError(true); 116 | throw new \RuntimeException(sprintf('Could not complete %s successfully: %s', $this, $e->getMessage())); 117 | } 118 | return $this; 119 | } 120 | 121 | /** 122 | * Create setup:upgrade task for setup application cron 123 | * 124 | * @return void 125 | */ 126 | private function createSetupUpgradeTasks() 127 | { 128 | $jobs = [['name' => 'setup:upgrade', 'params' => []]]; 129 | $this->queue->addJobs($jobs); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Queue/Reader.php: -------------------------------------------------------------------------------- 1 | queueFilePath = $queueFilePath ? $queueFilePath : MAGENTO_BP . '/var/.update_queue.json'; 27 | } 28 | 29 | /** 30 | * Read Magento updater application jobs queue as a JSON string. 31 | * 32 | * @return string Queue file content (valid JSON string) 33 | * @throws \RuntimeException 34 | */ 35 | public function read() 36 | { 37 | $queue = ''; 38 | if (!file_exists($this->queueFilePath)) { 39 | return $queue; 40 | } 41 | $queueFileContent = file_get_contents($this->queueFilePath); 42 | if ($queueFileContent) { 43 | json_decode($queueFileContent); 44 | if (json_last_error() !== JSON_ERROR_NONE) { 45 | throw new \RuntimeException(sprintf('Content of "%s" must be a valid JSON.', $this->queueFilePath)); 46 | } 47 | $queue = $queueFileContent; 48 | } 49 | return $queue; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Queue/Writer.php: -------------------------------------------------------------------------------- 1 | queueFilePath)) { 20 | // empty string is used to clear the job queue 21 | if ($data != '') { 22 | json_decode($data); 23 | if (json_last_error() !== JSON_ERROR_NONE) { 24 | throw new \RuntimeException(sprintf('Content to write must be a valid JSON.')); 25 | } 26 | } 27 | return file_put_contents($this->queueFilePath, $data); 28 | } 29 | return false; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Rollback.php: -------------------------------------------------------------------------------- 1 | backupFileDir = $backupFileDir ? $backupFileDir : BACKUP_DIR; 46 | $this->restoreTargetDir = $restoreTargetDir ? $restoreTargetDir : MAGENTO_BP; 47 | $this->status = $status ? $status : new Status(); 48 | $this->backupInfo = $backupInfo ? $backupInfo : new BackupInfo(); 49 | } 50 | 51 | /** 52 | * Restore Magento code from the backup archive. 53 | * 54 | * Rollback to the code/media version stored in the specified backup archive. 55 | * 56 | * @param string $backupFilePath 57 | * @return void 58 | */ 59 | public function execute($backupFilePath) 60 | { 61 | $this->status->add(sprintf('Restoring archive from "%s" ...', $backupFilePath)); 62 | $this->unzipArchive($backupFilePath); 63 | } 64 | 65 | /** 66 | * Unzip specified archive 67 | * 68 | * @param string $backupFilePath 69 | * @throws \RuntimeException 70 | * @return $this 71 | */ 72 | private function unzipArchive($backupFilePath) 73 | { 74 | $phar = new \PharData($backupFilePath); 75 | $tarFile = str_replace('.tgz', '.tar', $backupFilePath); 76 | if (@file_exists($tarFile)) { 77 | @unlink($tarFile); 78 | } 79 | $phar->decompress(); 80 | $tar = new \PharData($tarFile); 81 | 82 | if (strpos($backupFilePath, BackupInfo::BACKUP_MEDIA) > 0 ) { 83 | $this->deleteDirectory($this->restoreTargetDir . '/pub/media'); 84 | } elseif (strpos($backupFilePath, BackupInfo::BACKUP_CODE) > 0 ) { 85 | $blackListFolders = $this->backupInfo->getBlacklist(); 86 | $exclusions = []; 87 | foreach ($blackListFolders as $blackListFolder) { 88 | $exclusions[] = $this->restoreTargetDir . '/' . $blackListFolder; 89 | } 90 | try { 91 | $this->deleteDirectory($this->restoreTargetDir, $exclusions); 92 | } catch (\Exception $e) { 93 | $this->status->setUpdateError(); 94 | $this->status->add('Error during rollback ' . $e->getMessage()); 95 | } 96 | } else { 97 | $this->status->setUpdateError(); 98 | $this->status->add('Invalid backup type'); 99 | } 100 | $tar->extractTo($this->restoreTargetDir , null, true); 101 | @unlink($tarFile); 102 | 103 | //TODO Temporary solution, can be removed when MAGETWO-38589 is fixed. 104 | if (strpos($backupFilePath, BackupInfo::BACKUP_MEDIA) > 0 ) { 105 | $iterator = new \RecursiveIteratorIterator( 106 | new \RecursiveDirectoryIterator($this->restoreTargetDir . '/pub/media'), 107 | \RecursiveIteratorIterator::SELF_FIRST 108 | ); 109 | foreach($iterator as $item) { 110 | @chmod($item, 0777); 111 | } 112 | } elseif (strpos($backupFilePath, BackupInfo::BACKUP_CODE) > 0 ) { 113 | $iterator = new \RecursiveIteratorIterator( 114 | new \RecursiveDirectoryIterator($this->restoreTargetDir), 115 | \RecursiveIteratorIterator::SELF_FIRST 116 | ); 117 | foreach($iterator as $item) { 118 | @chmod($item, 0755); 119 | } 120 | $writeAccessFolders = ['/pub/media', '/pub/static', '/var']; 121 | foreach ($writeAccessFolders as $folder) { 122 | if (file_exists($this->restoreTargetDir . $folder)) { 123 | $iterator = new \RecursiveIteratorIterator( 124 | new \RecursiveDirectoryIterator($this->restoreTargetDir . $folder), 125 | \RecursiveIteratorIterator::SELF_FIRST 126 | ); 127 | foreach($iterator as $item) { 128 | @chmod($item, 0777); 129 | } 130 | } 131 | } 132 | } 133 | //TODO Till here 134 | } 135 | 136 | /** 137 | * Recursively remove files and directories 138 | * 139 | * @param string $dir 140 | * @param array $exclude 141 | * @return bool 142 | */ 143 | private function deleteDirectory($dir, $exclude = []) { 144 | 145 | $filesystemIterator = new \RecursiveIteratorIterator( 146 | new \RecursiveDirectoryIterator($dir), 147 | \RecursiveIteratorIterator::CHILD_FIRST 148 | ); 149 | 150 | $iterator = new ExcludeFilter($filesystemIterator, $exclude); 151 | 152 | foreach ($iterator as $item) { 153 | $itemToBeDeleted = $item->__toString(); 154 | if ($item->isDir()) { 155 | rmdir($itemToBeDeleted); 156 | } else { 157 | unlink($itemToBeDeleted); 158 | } 159 | } 160 | 161 | // If $dir is empty with no child items, iterator will not be valid. 162 | // See http://php.net/manual/en/directoryiterator.valid.php 163 | if (is_dir($dir) && !(new \FilesystemIterator($dir))->valid()) { 164 | rmdir($dir); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Status.php: -------------------------------------------------------------------------------- 1 | statusFilePath = $statusFilePath ? $statusFilePath : MAGENTO_BP . '/var/.update_status.txt'; 62 | $this->logFilePath = $logFilePath ? $logFilePath : MAGENTO_BP . '/var/update_status.log'; 63 | $this->updateInProgressFlagFilePath = $updateInProgressFlagFilePath 64 | ? $updateInProgressFlagFilePath 65 | : MAGENTO_BP . '/var/.update_in_progress.flag'; 66 | $this->updateErrorFlagFilePath = $updateErrorFlagFilePath 67 | ? $updateErrorFlagFilePath 68 | : MAGENTO_BP . '/var/.update_error.flag'; 69 | } 70 | 71 | /** 72 | * Get current updater application status. 73 | * 74 | * @return string 75 | */ 76 | public function get() 77 | { 78 | if (file_exists($this->statusFilePath)) { 79 | return file_get_contents($this->statusFilePath); 80 | } 81 | return ''; 82 | } 83 | 84 | /** 85 | * Add status update. 86 | * 87 | * Add information to a temporary file which is used for status display on a web page and to a permanent status log. 88 | * 89 | * @param string $text 90 | * @return $this 91 | * @throws \RuntimeException 92 | */ 93 | public function add($text) 94 | { 95 | $currentUtcTime = '[' . date('Y-m-d H:i:s T', time()) . '] '; 96 | $text = $currentUtcTime . $text; 97 | $this->writeMessageToFile($text, $this->logFilePath); 98 | $this->writeMessageToFile($text, $this->statusFilePath); 99 | return $this; 100 | } 101 | 102 | /** 103 | * Add status update to show progress 104 | * 105 | * @param string $text 106 | * @return $this 107 | * @throws \RuntimeException 108 | */ 109 | public function addWithoutNewLine($text) 110 | { 111 | $this->writeMessageToFile($text, $this->logFilePath, false); 112 | $this->writeMessageToFile($text, $this->statusFilePath, false); 113 | return $this; 114 | } 115 | 116 | /** 117 | * Write status information to the file. 118 | * 119 | * @param string $text 120 | * @param string $filePath 121 | * @param bool $newline 122 | * @return $this 123 | * @throws \RuntimeException 124 | */ 125 | protected function writeMessageToFile($text, $filePath, $newline = true) 126 | { 127 | $isNewFile = !file_exists($filePath); 128 | if (!$isNewFile && file_get_contents($filePath)) { 129 | $text = $newline ? PHP_EOL . "{$text}" :"{$text}"; 130 | } 131 | if (false === file_put_contents($filePath, $text, FILE_APPEND)) { 132 | throw new \RuntimeException(sprintf('Cannot add status information to "%s"', $filePath)); 133 | } 134 | if ($isNewFile) { 135 | chmod($filePath, 0777); 136 | } 137 | return $this; 138 | } 139 | 140 | /** 141 | * Clear current status text. 142 | * 143 | * Note that this method does not clear status information from the permanent status log. 144 | * 145 | * @return $this 146 | * @throws \RuntimeException 147 | */ 148 | public function clear() 149 | { 150 | if (!file_exists($this->statusFilePath)) { 151 | return $this; 152 | } else if (false === file_put_contents($this->statusFilePath, '')) { 153 | throw new \RuntimeException(sprintf('Cannot clear status information from "%s"', $this->statusFilePath)); 154 | } 155 | return $this; 156 | } 157 | 158 | /** 159 | * Check if updater application is running. 160 | * 161 | * @return bool 162 | */ 163 | public function isUpdateInProgress() 164 | { 165 | return file_exists($this->updateInProgressFlagFilePath); 166 | } 167 | 168 | /** 169 | * Set current updater app status: true if update is in progress, false otherwise. 170 | * 171 | * @param bool $isInProgress 172 | * @return $this 173 | */ 174 | public function setUpdateInProgress($isInProgress = true) 175 | { 176 | return $this->setFlagValue($this->updateInProgressFlagFilePath, $isInProgress); 177 | } 178 | 179 | /** 180 | * Check if error has occurred during updater application execution. 181 | * 182 | * @return bool 183 | */ 184 | public function isUpdateError() 185 | { 186 | return file_exists($this->updateErrorFlagFilePath); 187 | } 188 | 189 | /** 190 | * Set current updater app status: true if error occurred during update app execution, false otherwise. 191 | * 192 | * @param bool $isErrorOccurred 193 | * @return $this 194 | */ 195 | public function setUpdateError($isErrorOccurred = true) 196 | { 197 | return $this->setFlagValue($this->updateErrorFlagFilePath, $isErrorOccurred); 198 | } 199 | 200 | /** 201 | * Create flag in case when value is set to 'true', remove it if value is set to 'false'. 202 | * 203 | * @param string $pathToFlagFile 204 | * @param bool $value 205 | * @throws \RuntimeException 206 | * @return $this 207 | */ 208 | protected function setFlagValue($pathToFlagFile, $value) 209 | { 210 | if ($value) { 211 | $updateInProgressFlagFile = fopen($pathToFlagFile, 'w'); 212 | if (!$updateInProgressFlagFile) { 213 | throw new \RuntimeException(sprintf('"%s" cannot be created.', $pathToFlagFile)); 214 | } 215 | fclose($updateInProgressFlagFile); 216 | } else if (file_exists($pathToFlagFile)) { 217 | unlink($pathToFlagFile); 218 | } 219 | return $this; 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Test/Unit/Queue/AbstractJobTest.php: -------------------------------------------------------------------------------- 1 | '/Users/john/archive.zip', 'sourceDirectory' => '/Users/john/Magento'] 16 | ); 17 | $this->assertEquals( 18 | 'backup {"targetArchivePath":"/Users/john/archive.zip","sourceDirectory":"/Users/john/Magento"}', 19 | (string)$job 20 | ); 21 | } 22 | } -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Test/Unit/Queue/JobFactoryTest.php: -------------------------------------------------------------------------------- 1 | jobFactory = new JobFactory(); 21 | } 22 | 23 | /** 24 | * @dataProvider createProvider 25 | */ 26 | public function testCreate($jobName, $expectedJobClass) 27 | { 28 | $job = $this->jobFactory->create($jobName, []); 29 | $this->assertInstanceOf($expectedJobClass, $job); 30 | } 31 | 32 | public function createProvider() 33 | { 34 | return [ 35 | 'Update Job' => [JobFactory::NAME_UPDATE, '\Magento\Update\Queue\JobUpdate'], 36 | 'Backup Job' => [JobFactory::NAME_BACKUP, '\Magento\Update\Queue\JobBackup'], 37 | 'Rollback Job' => [JobFactory::NAME_ROLLBACK, '\Magento\Update\Queue\JobRollback'], 38 | 'Remove backups Job' => [JobFactory::NAME_REMOVE_BACKUPS, '\Magento\Update\Queue\JobRemoveBackups'], 39 | 'Uninstall Job' => [JobFactory::NAME_UNINSTALL, '\Magento\Update\Queue\JobComponentUninstall'], 40 | ]; 41 | } 42 | 43 | public function testCreateInvalidJob() 44 | { 45 | $this->setExpectedException( 46 | '\RuntimeException', 47 | '"invalid" job is not supported.' 48 | ); 49 | $this->jobFactory->create('invalid', []); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Test/Unit/QueueTest.php: -------------------------------------------------------------------------------- 1 | reader = $this->getMock('Magento\Update\Queue\Reader', [], [], '', false); 35 | $this->writer = $this->getMock('Magento\Update\Queue\Writer', [], [], '', false); 36 | $this->jobFactory = $this->getMock('Magento\Update\Queue\JobFactory', [], [], '', false); 37 | $this->queue = new Queue($this->reader, $this->writer, $this->jobFactory); 38 | } 39 | 40 | public function testPeek() 41 | { 42 | $this->reader->expects($this->once()) 43 | ->method('read') 44 | ->willReturn('{"jobs": [{"name": "job A", "params" : []}, {"name": "job B", "params" : []}]}'); 45 | $this->assertEquals(['name' => 'job A', 'params' => []], $this->queue->peek()); 46 | } 47 | 48 | public function testPeekEmpty() 49 | { 50 | $this->reader->expects($this->once()) 51 | ->method('read') 52 | ->willReturn(''); 53 | $this->assertEquals([], $this->queue->peek()); 54 | } 55 | 56 | /** 57 | * @expectedException \RuntimeException 58 | * @expectedExceptionMessage "params" field is missing for one or more jobs 59 | */ 60 | public function testPeekException() 61 | { 62 | $this->reader->expects($this->once()) 63 | ->method('read') 64 | ->willReturn('{"jobs": [{"name": "job A"}, {"name": "job B"}]}'); 65 | $this->queue->peek(); 66 | } 67 | 68 | /** 69 | * @expectedException \RuntimeException 70 | * @expectedExceptionMessage "jobs" field is missing or is not an array 71 | */ 72 | public function testPeekExceptionNoJobsKey() 73 | { 74 | $this->reader->expects($this->once()) 75 | ->method('read') 76 | ->willReturn('{"foo": "bar"}'); 77 | $this->queue->peek(); 78 | } 79 | 80 | public function testPopQueuedJob() 81 | { 82 | $this->reader->expects($this->once()) 83 | ->method('read') 84 | ->willReturn('{"jobs": [{"name": "job A", "params" : []}, {"name": "job B", "params" : []}]}'); 85 | $job = $this->getMockForAbstractClass('Magento\Update\Queue\AbstractJob', [], '', false); 86 | $this->jobFactory->expects($this->once())->method('create')->with('job A', [])->willReturn($job); 87 | $rawData = ['jobs' => [['name' => 'job B', 'params' => []]]]; 88 | $this->writer->expects($this->once())->method('write')->with(json_encode($rawData, JSON_PRETTY_PRINT)); 89 | $this->assertEquals($job, $this->queue->popQueuedJob()); 90 | } 91 | 92 | public function testPopQueuedJobEmptyAfter() 93 | { 94 | $this->reader->expects($this->once()) 95 | ->method('read') 96 | ->willReturn('{"jobs": [{"name": "job A", "params" : []}]}'); 97 | $job = $this->getMockForAbstractClass('Magento\Update\Queue\AbstractJob', [], '', false); 98 | $this->jobFactory->expects($this->once())->method('create')->with('job A', [])->willReturn($job); 99 | $this->writer->expects($this->once())->method('write')->with(''); 100 | $this->assertEquals($job, $this->queue->popQueuedJob()); 101 | } 102 | 103 | /** 104 | * @expectedException \RuntimeException 105 | * @expectedExceptionMessage "params" field is missing for one or more jobs 106 | */ 107 | public function testPopQueuedJobException() 108 | { 109 | $this->reader->expects($this->once()) 110 | ->method('read') 111 | ->willReturn('{"jobs": [{"name": "job A"}, {"name": "job B"}]}'); 112 | $this->writer->expects($this->never())->method('write'); 113 | $this->queue->popQueuedJob(); 114 | } 115 | 116 | /** 117 | * @expectedException \RuntimeException 118 | * @expectedExceptionMessage "jobs" field is missing or is not an array 119 | */ 120 | public function testPopQueuedJobExceptionNoJobsKey() 121 | { 122 | $this->reader->expects($this->once()) 123 | ->method('read') 124 | ->willReturn('{"foo": "bar"}'); 125 | $this->writer->expects($this->never())->method('write'); 126 | $this->queue->popQueuedJob(); 127 | } 128 | 129 | public function testAddJobs() 130 | { 131 | $queue = ['jobs' => []]; 132 | $this->reader->expects($this->at(0))->method('read')->willReturn(''); 133 | $queue['jobs'][] = ['name' => 'job A', 'params' => []]; 134 | $this->writer->expects($this->at(0)) 135 | ->method('write') 136 | ->with(json_encode($queue, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); 137 | $this->reader->expects($this->at(1)) 138 | ->method('read') 139 | ->willReturn(json_encode($queue, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); 140 | $queue['jobs'][] = ['name' => 'job B', 'params' => []]; 141 | $this->writer->expects($this->at(1)) 142 | ->method('write') 143 | ->with(json_encode($queue, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); 144 | $this->queue->addJobs([['name' => 'job A', 'params' => []], ['name' => 'job B', 'params' => []]]); 145 | } 146 | 147 | /** 148 | * @expectedException \RuntimeException 149 | * @expectedExceptionMessage field is missing for one or more jobs 150 | */ 151 | public function testAddJobsInvalidJobs() 152 | { 153 | $this->queue->addJobs([['no_name' => 'no job', 'no_params' => []]]); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/Test/Unit/_files/update_queue_valid.json: -------------------------------------------------------------------------------- 1 | { 2 | "jobs": [ 3 | { 4 | "name": "backup", 5 | "params": {} 6 | }, 7 | { 8 | "name": "rollback", 9 | "params": { 10 | "backup_file_name": "/full/path/to/archive.zip" 11 | } 12 | }, 13 | { 14 | "name": "remove_backups", 15 | "params": { 16 | "backups_file_names": [ 17 | "/full/path/to/archive1.zip", 18 | "/full/path/to/archive2.zip" 19 | ] 20 | } 21 | }, 22 | { 23 | "name": "update", 24 | "params": { 25 | "components": [ 26 | { 27 | "name": "packageName1", 28 | "version": "1.0.0" 29 | }, 30 | { 31 | "name": "packageName2", 32 | "version": "2.0.0" 33 | } 34 | ] 35 | } 36 | }, 37 | { 38 | "name": "uninstall", 39 | "params": { 40 | "components": [ 41 | { 42 | "name": "packageName3", 43 | "version": "3.0.0" 44 | }, 45 | { 46 | "name": "packageName4", 47 | "version": "4.0.0" 48 | } 49 | ] 50 | } 51 | } 52 | ], 53 | "ignored_field": "" 54 | } -------------------------------------------------------------------------------- /update/app/code/Magento/Update/etc/backup_blacklist.txt: -------------------------------------------------------------------------------- 1 | # The list contains the paths relative to the directory that is archived 2 | var 3 | pub/static 4 | update 5 | pub/media 6 | .git 7 | .svn 8 | node_modules 9 | .grunt 10 | .idea 11 | -------------------------------------------------------------------------------- /update/app/code/Magento/Update/view/templates/status.phtml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Magento Updater 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 52 |
53 |
54 |
55 | 62 |
63 |
64 |
65 | 85 |
86 |
87 |
88 |
89 |
90 |

91 |
92 | 93 |
94 |
95 |
96 |

97 | Error in Update! 98 |
99 | Please refer to documentation Doc link to perform manual rollback. 100 |

101 |

102 | To attempt automatic rollback, please click the "Rollback" button. 103 |

104 | 107 |
108 |
109 |
110 | 113 |
114 |
115 |
116 |
117 |
118 |
119 | Rollback has been performed. Please check console log for more detail. 120 | 123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | 132 | -------------------------------------------------------------------------------- /update/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "magento/updater", 3 | "description": "Magento Updater", 4 | "type": "project", 5 | "version": "10.0.0", 6 | "license": [ 7 | "OSL-3.0", 8 | "AFL-3.0" 9 | ], 10 | "repositories": [ 11 | { 12 | "type": "composer", 13 | "url": "https://repo.magento.com/" 14 | } 15 | ], 16 | "require": { 17 | "php": "~5.5.0|~5.6.0|~7.0.0", 18 | "composer/composer": "1.0.0-beta1", 19 | "magento/composer": "~1.0.0", 20 | "symfony/console": "~2.3 <2.7" 21 | }, 22 | "autoload": { 23 | "psr-4": { 24 | "Magento\\": "app/code/Magento/" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /update/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "a14703fd85fe4cbc06792a443c7b852e", 8 | "content-hash": "f36b1156480403ca022e20effd0c8bbd", 9 | "packages": [ 10 | { 11 | "name": "composer/composer", 12 | "version": "1.0.0-beta1", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/composer/composer.git", 16 | "reference": "5cb2b522637a941d608c58bd522f3b2a7bda4a1c" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/composer/composer/zipball/5cb2b522637a941d608c58bd522f3b2a7bda4a1c", 21 | "reference": "5cb2b522637a941d608c58bd522f3b2a7bda4a1c", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "composer/semver": "^1.0", 26 | "composer/spdx-licenses": "^1.0", 27 | "justinrainbow/json-schema": "^1.6", 28 | "php": "^5.3.2 || ^7.0", 29 | "seld/cli-prompt": "^1.0", 30 | "seld/jsonlint": "^1.4", 31 | "seld/phar-utils": "^1.0", 32 | "symfony/console": "^2.5 || ^3.0", 33 | "symfony/filesystem": "^2.5 || ^3.0", 34 | "symfony/finder": "^2.2 || ^3.0", 35 | "symfony/process": "^2.1 || ^3.0" 36 | }, 37 | "require-dev": { 38 | "phpunit/phpunit": "^4.5 || ^5.0.5", 39 | "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" 40 | }, 41 | "suggest": { 42 | "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", 43 | "ext-zip": "Enabling the zip extension allows you to unzip archives", 44 | "ext-zlib": "Allow gzip compression of HTTP requests" 45 | }, 46 | "bin": [ 47 | "bin/composer" 48 | ], 49 | "type": "library", 50 | "extra": { 51 | "branch-alias": { 52 | "dev-master": "1.0-dev" 53 | } 54 | }, 55 | "autoload": { 56 | "psr-4": { 57 | "Composer\\": "src/Composer" 58 | } 59 | }, 60 | "notification-url": "https://packagist.org/downloads/", 61 | "license": [ 62 | "MIT" 63 | ], 64 | "authors": [ 65 | { 66 | "name": "Nils Adermann", 67 | "email": "naderman@naderman.de", 68 | "homepage": "http://www.naderman.de" 69 | }, 70 | { 71 | "name": "Jordi Boggiano", 72 | "email": "j.boggiano@seld.be", 73 | "homepage": "http://seld.be" 74 | } 75 | ], 76 | "description": "Composer helps you declare, manage and install dependencies of PHP projects, ensuring you have the right stack everywhere.", 77 | "homepage": "https://getcomposer.org/", 78 | "keywords": [ 79 | "autoload", 80 | "dependency", 81 | "package" 82 | ], 83 | "time": "2016-03-03 15:15:10" 84 | }, 85 | { 86 | "name": "composer/semver", 87 | "version": "1.3.0", 88 | "source": { 89 | "type": "git", 90 | "url": "https://github.com/composer/semver.git", 91 | "reference": "df4463baa9f44fe6cf0a6da4fde2934d4c0a2747" 92 | }, 93 | "dist": { 94 | "type": "zip", 95 | "url": "https://api.github.com/repos/composer/semver/zipball/df4463baa9f44fe6cf0a6da4fde2934d4c0a2747", 96 | "reference": "df4463baa9f44fe6cf0a6da4fde2934d4c0a2747", 97 | "shasum": "" 98 | }, 99 | "require": { 100 | "php": "^5.3.2 || ^7.0" 101 | }, 102 | "require-dev": { 103 | "phpunit/phpunit": "^4.5 || ^5.0.5", 104 | "phpunit/phpunit-mock-objects": "2.3.0 || ^3.0" 105 | }, 106 | "type": "library", 107 | "extra": { 108 | "branch-alias": { 109 | "dev-master": "1.x-dev" 110 | } 111 | }, 112 | "autoload": { 113 | "psr-4": { 114 | "Composer\\Semver\\": "src" 115 | } 116 | }, 117 | "notification-url": "https://packagist.org/downloads/", 118 | "license": [ 119 | "MIT" 120 | ], 121 | "authors": [ 122 | { 123 | "name": "Nils Adermann", 124 | "email": "naderman@naderman.de", 125 | "homepage": "http://www.naderman.de" 126 | }, 127 | { 128 | "name": "Jordi Boggiano", 129 | "email": "j.boggiano@seld.be", 130 | "homepage": "http://seld.be" 131 | }, 132 | { 133 | "name": "Rob Bast", 134 | "email": "rob.bast@gmail.com", 135 | "homepage": "http://robbast.nl" 136 | } 137 | ], 138 | "description": "Semver library that offers utilities, version constraint parsing and validation.", 139 | "keywords": [ 140 | "semantic", 141 | "semver", 142 | "validation", 143 | "versioning" 144 | ], 145 | "time": "2016-02-25 22:23:39" 146 | }, 147 | { 148 | "name": "composer/spdx-licenses", 149 | "version": "1.1.2", 150 | "source": { 151 | "type": "git", 152 | "url": "https://github.com/composer/spdx-licenses.git", 153 | "reference": "9e1c3926bb0842812967213d7c92827bc5883671" 154 | }, 155 | "dist": { 156 | "type": "zip", 157 | "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/9e1c3926bb0842812967213d7c92827bc5883671", 158 | "reference": "9e1c3926bb0842812967213d7c92827bc5883671", 159 | "shasum": "" 160 | }, 161 | "require": { 162 | "php": ">=5.3.2" 163 | }, 164 | "require-dev": { 165 | "phpunit/phpunit": "~4.5", 166 | "phpunit/phpunit-mock-objects": "~2.3" 167 | }, 168 | "type": "library", 169 | "extra": { 170 | "branch-alias": { 171 | "dev-master": "1.x-dev" 172 | } 173 | }, 174 | "autoload": { 175 | "psr-4": { 176 | "Composer\\Spdx\\": "src" 177 | } 178 | }, 179 | "notification-url": "https://packagist.org/downloads/", 180 | "license": [ 181 | "MIT" 182 | ], 183 | "authors": [ 184 | { 185 | "name": "Nils Adermann", 186 | "email": "naderman@naderman.de", 187 | "homepage": "http://www.naderman.de" 188 | }, 189 | { 190 | "name": "Jordi Boggiano", 191 | "email": "j.boggiano@seld.be", 192 | "homepage": "http://seld.be" 193 | }, 194 | { 195 | "name": "Rob Bast", 196 | "email": "rob.bast@gmail.com", 197 | "homepage": "http://robbast.nl" 198 | } 199 | ], 200 | "description": "SPDX licenses list and validation library.", 201 | "keywords": [ 202 | "license", 203 | "spdx", 204 | "validator" 205 | ], 206 | "time": "2015-10-05 11:27:42" 207 | }, 208 | { 209 | "name": "justinrainbow/json-schema", 210 | "version": "1.6.1", 211 | "source": { 212 | "type": "git", 213 | "url": "https://github.com/justinrainbow/json-schema.git", 214 | "reference": "cc84765fb7317f6b07bd8ac78364747f95b86341" 215 | }, 216 | "dist": { 217 | "type": "zip", 218 | "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/cc84765fb7317f6b07bd8ac78364747f95b86341", 219 | "reference": "cc84765fb7317f6b07bd8ac78364747f95b86341", 220 | "shasum": "" 221 | }, 222 | "require": { 223 | "php": ">=5.3.29" 224 | }, 225 | "require-dev": { 226 | "json-schema/json-schema-test-suite": "1.1.0", 227 | "phpdocumentor/phpdocumentor": "~2", 228 | "phpunit/phpunit": "~3.7" 229 | }, 230 | "bin": [ 231 | "bin/validate-json" 232 | ], 233 | "type": "library", 234 | "extra": { 235 | "branch-alias": { 236 | "dev-master": "1.6.x-dev" 237 | } 238 | }, 239 | "autoload": { 240 | "psr-4": { 241 | "JsonSchema\\": "src/JsonSchema/" 242 | } 243 | }, 244 | "notification-url": "https://packagist.org/downloads/", 245 | "license": [ 246 | "BSD-3-Clause" 247 | ], 248 | "authors": [ 249 | { 250 | "name": "Bruno Prieto Reis", 251 | "email": "bruno.p.reis@gmail.com" 252 | }, 253 | { 254 | "name": "Justin Rainbow", 255 | "email": "justin.rainbow@gmail.com" 256 | }, 257 | { 258 | "name": "Igor Wiedler", 259 | "email": "igor@wiedler.ch" 260 | }, 261 | { 262 | "name": "Robert Schönthal", 263 | "email": "seroscho@googlemail.com" 264 | } 265 | ], 266 | "description": "A library to validate a json schema.", 267 | "homepage": "https://github.com/justinrainbow/json-schema", 268 | "keywords": [ 269 | "json", 270 | "schema" 271 | ], 272 | "time": "2016-01-25 15:43:01" 273 | }, 274 | { 275 | "name": "magento/composer", 276 | "version": "1.0.3", 277 | "source": { 278 | "type": "git", 279 | "url": "https://github.com/magento/composer.git", 280 | "reference": "b53f7c8a037860b467083e94de7c17cfd323e365" 281 | }, 282 | "dist": { 283 | "type": "zip", 284 | "url": "https://api.github.com/repos/magento/composer/zipball/b53f7c8a037860b467083e94de7c17cfd323e365", 285 | "reference": "b53f7c8a037860b467083e94de7c17cfd323e365", 286 | "shasum": "" 287 | }, 288 | "require": { 289 | "composer/composer": "1.0.0-beta1", 290 | "php": "~5.5.0|~5.6.0|~7.0.0", 291 | "symfony/console": "~2.3 <2.7" 292 | }, 293 | "require-dev": { 294 | "phpunit/phpunit": "4.1.0" 295 | }, 296 | "type": "library", 297 | "autoload": { 298 | "psr-4": { 299 | "Magento\\Composer\\": "src" 300 | } 301 | }, 302 | "notification-url": "https://packagist.org/downloads/", 303 | "license": [ 304 | "OSL-3.0", 305 | "AFL-3.0" 306 | ], 307 | "description": "Magento composer library helps to instantiate Composer application and run composer commands.", 308 | "time": "2016-03-08 20:50:51" 309 | }, 310 | { 311 | "name": "seld/cli-prompt", 312 | "version": "1.0.1", 313 | "source": { 314 | "type": "git", 315 | "url": "https://github.com/Seldaek/cli-prompt.git", 316 | "reference": "b27db1514f7d7bb7a366ad95d4eb2b17140a0691" 317 | }, 318 | "dist": { 319 | "type": "zip", 320 | "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/b27db1514f7d7bb7a366ad95d4eb2b17140a0691", 321 | "reference": "b27db1514f7d7bb7a366ad95d4eb2b17140a0691", 322 | "shasum": "" 323 | }, 324 | "require": { 325 | "php": ">=5.3" 326 | }, 327 | "type": "library", 328 | "extra": { 329 | "branch-alias": { 330 | "dev-master": "1.x-dev" 331 | } 332 | }, 333 | "autoload": { 334 | "psr-4": { 335 | "Seld\\CliPrompt\\": "src/" 336 | } 337 | }, 338 | "notification-url": "https://packagist.org/downloads/", 339 | "license": [ 340 | "MIT" 341 | ], 342 | "authors": [ 343 | { 344 | "name": "Jordi Boggiano", 345 | "email": "j.boggiano@seld.be" 346 | } 347 | ], 348 | "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type", 349 | "keywords": [ 350 | "cli", 351 | "console", 352 | "hidden", 353 | "input", 354 | "prompt" 355 | ], 356 | "time": "2016-01-09 17:55:27" 357 | }, 358 | { 359 | "name": "seld/jsonlint", 360 | "version": "1.4.0", 361 | "source": { 362 | "type": "git", 363 | "url": "https://github.com/Seldaek/jsonlint.git", 364 | "reference": "66834d3e3566bb5798db7294619388786ae99394" 365 | }, 366 | "dist": { 367 | "type": "zip", 368 | "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/66834d3e3566bb5798db7294619388786ae99394", 369 | "reference": "66834d3e3566bb5798db7294619388786ae99394", 370 | "shasum": "" 371 | }, 372 | "require": { 373 | "php": "^5.3 || ^7.0" 374 | }, 375 | "bin": [ 376 | "bin/jsonlint" 377 | ], 378 | "type": "library", 379 | "autoload": { 380 | "psr-4": { 381 | "Seld\\JsonLint\\": "src/Seld/JsonLint/" 382 | } 383 | }, 384 | "notification-url": "https://packagist.org/downloads/", 385 | "license": [ 386 | "MIT" 387 | ], 388 | "authors": [ 389 | { 390 | "name": "Jordi Boggiano", 391 | "email": "j.boggiano@seld.be", 392 | "homepage": "http://seld.be" 393 | } 394 | ], 395 | "description": "JSON Linter", 396 | "keywords": [ 397 | "json", 398 | "linter", 399 | "parser", 400 | "validator" 401 | ], 402 | "time": "2015-11-21 02:21:41" 403 | }, 404 | { 405 | "name": "seld/phar-utils", 406 | "version": "1.0.1", 407 | "source": { 408 | "type": "git", 409 | "url": "https://github.com/Seldaek/phar-utils.git", 410 | "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a" 411 | }, 412 | "dist": { 413 | "type": "zip", 414 | "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/7009b5139491975ef6486545a39f3e6dad5ac30a", 415 | "reference": "7009b5139491975ef6486545a39f3e6dad5ac30a", 416 | "shasum": "" 417 | }, 418 | "require": { 419 | "php": ">=5.3" 420 | }, 421 | "type": "library", 422 | "extra": { 423 | "branch-alias": { 424 | "dev-master": "1.x-dev" 425 | } 426 | }, 427 | "autoload": { 428 | "psr-4": { 429 | "Seld\\PharUtils\\": "src/" 430 | } 431 | }, 432 | "notification-url": "https://packagist.org/downloads/", 433 | "license": [ 434 | "MIT" 435 | ], 436 | "authors": [ 437 | { 438 | "name": "Jordi Boggiano", 439 | "email": "j.boggiano@seld.be" 440 | } 441 | ], 442 | "description": "PHAR file format utilities, for when PHP phars you up", 443 | "keywords": [ 444 | "phra" 445 | ], 446 | "time": "2015-10-13 18:44:15" 447 | }, 448 | { 449 | "name": "symfony/console", 450 | "version": "v2.6.13", 451 | "target-dir": "Symfony/Component/Console", 452 | "source": { 453 | "type": "git", 454 | "url": "https://github.com/symfony/console.git", 455 | "reference": "0e5e18ae09d3f5c06367759be940e9ed3f568359" 456 | }, 457 | "dist": { 458 | "type": "zip", 459 | "url": "https://api.github.com/repos/symfony/console/zipball/0e5e18ae09d3f5c06367759be940e9ed3f568359", 460 | "reference": "0e5e18ae09d3f5c06367759be940e9ed3f568359", 461 | "shasum": "" 462 | }, 463 | "require": { 464 | "php": ">=5.3.3" 465 | }, 466 | "require-dev": { 467 | "psr/log": "~1.0", 468 | "symfony/event-dispatcher": "~2.1", 469 | "symfony/phpunit-bridge": "~2.7", 470 | "symfony/process": "~2.1" 471 | }, 472 | "suggest": { 473 | "psr/log": "For using the console logger", 474 | "symfony/event-dispatcher": "", 475 | "symfony/process": "" 476 | }, 477 | "type": "library", 478 | "extra": { 479 | "branch-alias": { 480 | "dev-master": "2.6-dev" 481 | } 482 | }, 483 | "autoload": { 484 | "psr-0": { 485 | "Symfony\\Component\\Console\\": "" 486 | } 487 | }, 488 | "notification-url": "https://packagist.org/downloads/", 489 | "license": [ 490 | "MIT" 491 | ], 492 | "authors": [ 493 | { 494 | "name": "Fabien Potencier", 495 | "email": "fabien@symfony.com" 496 | }, 497 | { 498 | "name": "Symfony Community", 499 | "homepage": "https://symfony.com/contributors" 500 | } 501 | ], 502 | "description": "Symfony Console Component", 503 | "homepage": "https://symfony.com", 504 | "time": "2015-07-26 09:08:40" 505 | }, 506 | { 507 | "name": "symfony/filesystem", 508 | "version": "v3.0.3", 509 | "source": { 510 | "type": "git", 511 | "url": "https://github.com/symfony/filesystem.git", 512 | "reference": "23ae8f9648d0a7fe94a47c8e20e5bf37c489a451" 513 | }, 514 | "dist": { 515 | "type": "zip", 516 | "url": "https://api.github.com/repos/symfony/filesystem/zipball/23ae8f9648d0a7fe94a47c8e20e5bf37c489a451", 517 | "reference": "23ae8f9648d0a7fe94a47c8e20e5bf37c489a451", 518 | "shasum": "" 519 | }, 520 | "require": { 521 | "php": ">=5.5.9" 522 | }, 523 | "type": "library", 524 | "extra": { 525 | "branch-alias": { 526 | "dev-master": "3.0-dev" 527 | } 528 | }, 529 | "autoload": { 530 | "psr-4": { 531 | "Symfony\\Component\\Filesystem\\": "" 532 | }, 533 | "exclude-from-classmap": [ 534 | "/Tests/" 535 | ] 536 | }, 537 | "notification-url": "https://packagist.org/downloads/", 538 | "license": [ 539 | "MIT" 540 | ], 541 | "authors": [ 542 | { 543 | "name": "Fabien Potencier", 544 | "email": "fabien@symfony.com" 545 | }, 546 | { 547 | "name": "Symfony Community", 548 | "homepage": "https://symfony.com/contributors" 549 | } 550 | ], 551 | "description": "Symfony Filesystem Component", 552 | "homepage": "https://symfony.com", 553 | "time": "2016-02-23 15:16:06" 554 | }, 555 | { 556 | "name": "symfony/finder", 557 | "version": "v3.0.3", 558 | "source": { 559 | "type": "git", 560 | "url": "https://github.com/symfony/finder.git", 561 | "reference": "623bda0abd9aa29e529c8e9c08b3b84171914723" 562 | }, 563 | "dist": { 564 | "type": "zip", 565 | "url": "https://api.github.com/repos/symfony/finder/zipball/623bda0abd9aa29e529c8e9c08b3b84171914723", 566 | "reference": "623bda0abd9aa29e529c8e9c08b3b84171914723", 567 | "shasum": "" 568 | }, 569 | "require": { 570 | "php": ">=5.5.9" 571 | }, 572 | "type": "library", 573 | "extra": { 574 | "branch-alias": { 575 | "dev-master": "3.0-dev" 576 | } 577 | }, 578 | "autoload": { 579 | "psr-4": { 580 | "Symfony\\Component\\Finder\\": "" 581 | }, 582 | "exclude-from-classmap": [ 583 | "/Tests/" 584 | ] 585 | }, 586 | "notification-url": "https://packagist.org/downloads/", 587 | "license": [ 588 | "MIT" 589 | ], 590 | "authors": [ 591 | { 592 | "name": "Fabien Potencier", 593 | "email": "fabien@symfony.com" 594 | }, 595 | { 596 | "name": "Symfony Community", 597 | "homepage": "https://symfony.com/contributors" 598 | } 599 | ], 600 | "description": "Symfony Finder Component", 601 | "homepage": "https://symfony.com", 602 | "time": "2016-01-27 05:14:46" 603 | }, 604 | { 605 | "name": "symfony/process", 606 | "version": "v3.0.3", 607 | "source": { 608 | "type": "git", 609 | "url": "https://github.com/symfony/process.git", 610 | "reference": "dfecef47506179db2501430e732adbf3793099c8" 611 | }, 612 | "dist": { 613 | "type": "zip", 614 | "url": "https://api.github.com/repos/symfony/process/zipball/dfecef47506179db2501430e732adbf3793099c8", 615 | "reference": "dfecef47506179db2501430e732adbf3793099c8", 616 | "shasum": "" 617 | }, 618 | "require": { 619 | "php": ">=5.5.9" 620 | }, 621 | "type": "library", 622 | "extra": { 623 | "branch-alias": { 624 | "dev-master": "3.0-dev" 625 | } 626 | }, 627 | "autoload": { 628 | "psr-4": { 629 | "Symfony\\Component\\Process\\": "" 630 | }, 631 | "exclude-from-classmap": [ 632 | "/Tests/" 633 | ] 634 | }, 635 | "notification-url": "https://packagist.org/downloads/", 636 | "license": [ 637 | "MIT" 638 | ], 639 | "authors": [ 640 | { 641 | "name": "Fabien Potencier", 642 | "email": "fabien@symfony.com" 643 | }, 644 | { 645 | "name": "Symfony Community", 646 | "homepage": "https://symfony.com/contributors" 647 | } 648 | ], 649 | "description": "Symfony Process Component", 650 | "homepage": "https://symfony.com", 651 | "time": "2016-02-02 13:44:19" 652 | } 653 | ], 654 | "packages-dev": [], 655 | "aliases": [], 656 | "minimum-stability": "stable", 657 | "stability-flags": { 658 | "composer/composer": 10 659 | }, 660 | "prefer-stable": false, 661 | "prefer-lowest": false, 662 | "platform": { 663 | "php": "~5.5.0|~5.6.0|~7.0.0" 664 | }, 665 | "platform-dev": [] 666 | } 667 | -------------------------------------------------------------------------------- /update/cron.php: -------------------------------------------------------------------------------- 1 | runReadinessCheck()) { 13 | exit('Cron readiness check failed'); 14 | } 15 | 16 | if ($status->isUpdateInProgress()) { 17 | exit('Cron is already in progress...'); 18 | } 19 | 20 | if ($status->isUpdateError()) { 21 | exit('There was an error in previous Updater jobs...'); 22 | } 23 | 24 | $backupDirectory = BACKUP_DIR; 25 | if (!file_exists($backupDirectory)) { 26 | if (!mkdir($backupDirectory)) { 27 | $status->add(sprintf('Backup directory "%s" cannot be created.', $backupDirectory)); 28 | exit(); 29 | } 30 | chmod($backupDirectory, 0770); 31 | } 32 | 33 | try { 34 | $status->setUpdateInProgress(); 35 | } catch (\RuntimeException $e) { 36 | $status->add($e->getMessage()); 37 | exit(); 38 | } 39 | 40 | $jobQueue = new \Magento\Update\Queue(); 41 | 42 | try { 43 | while (!empty($jobQueue->peek()) && 44 | strpos($jobQueue->peek()[\Magento\Update\Queue::KEY_JOB_NAME], 'setup:') === false 45 | ) { 46 | $job = $jobQueue->popQueuedJob(); 47 | $status->add( 48 | sprintf('Job "%s" has been started', $job) 49 | ); 50 | try { 51 | $job->execute(); 52 | $status->add(sprintf('Job "%s" has successfully completed', $job)); 53 | } catch (\Exception $e) { 54 | $status->setUpdateError(); 55 | $status->add( 56 | sprintf('An error occurred while executing job "%s": %s', $job, $e->getMessage()) 57 | ); 58 | $status->setUpdateInProgress(false); 59 | }; 60 | } 61 | } catch (\Exception $e) { 62 | $status->setUpdateError(); 63 | $status->add($e->getMessage()); 64 | } finally { 65 | $status->setUpdateInProgress(false); 66 | } 67 | -------------------------------------------------------------------------------- /update/dev/.htaccess: -------------------------------------------------------------------------------- 1 | Order deny,allow 2 | Deny from all 3 | 4 | -------------------------------------------------------------------------------- /update/dev/shell/cron.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright © 2016 Magento. All rights reserved. 3 | # See COPYING.txt for license details. 4 | 5 | CRONSCRIPT="cron.php" 6 | INSTALLDIR=`echo $0 | sed 's/cron\.sh//g'`"../../" 7 | 8 | PHP_BIN=`which php` 9 | if ! ps auxwww | grep " $CRONSCRIPT" | grep -v grep | grep -v cron.sh 1>/dev/null 2>/dev/null ; then 10 | $PHP_BIN "$INSTALLDIR""$CRONSCRIPT" & 11 | fi 12 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/CronReadinessCheckTest.php: -------------------------------------------------------------------------------- 1 | assertFalse($cronReadinessCheck->runReadinessCheck()); 22 | $file = fopen(__DIR__ . '/_files/readiness_check', 'r'); 23 | $data = fread($file, filesize(__DIR__ . '/_files/readiness_check')); 24 | $json = json_decode($data, true); 25 | $expected = [ 26 | CronReadinessCheck::KEY_READINESS_CHECKS => [ 27 | CronReadinessCheck::KEY_FILE_PERMISSIONS_VERIFIED => false, 28 | ], 29 | CronReadinessCheck::KEY_LAST_TIMESTAMP => 150, 30 | CronReadinessCheck::KEY_CURRENT_TIMESTAMP => 200, 31 | ]; 32 | $errorMessage = $json[CronReadinessCheck::KEY_READINESS_CHECKS]['error']; 33 | unset($json[CronReadinessCheck::KEY_READINESS_CHECKS]['error']); 34 | $this->assertEquals($expected, $json); 35 | $this->assertContains('Found non-writable path(s):
', $errorMessage); 36 | } 37 | 38 | public function testRunReadinessCheck() 39 | { 40 | $cronReadinessCheck = new CronReadinessCheck(); 41 | self::$writable = true; 42 | $this->assertTrue($cronReadinessCheck->runReadinessCheck()); 43 | $file = fopen(__DIR__ . '/_files/readiness_check', 'r'); 44 | $data = fread($file, filesize(__DIR__ . '/_files/readiness_check')); 45 | $json = json_decode($data, true); 46 | $expected = [ 47 | CronReadinessCheck::KEY_READINESS_CHECKS => [CronReadinessCheck::KEY_FILE_PERMISSIONS_VERIFIED => true], 48 | CronReadinessCheck::KEY_LAST_TIMESTAMP => 150, 49 | CronReadinessCheck::KEY_CURRENT_TIMESTAMP => 200, 50 | ]; 51 | sort($expected); 52 | sort($json); 53 | $this->assertEquals($expected, $json); 54 | } 55 | } 56 | 57 | function time() 58 | { 59 | return 200; 60 | } 61 | 62 | function file_put_contents($filename, $data) 63 | { 64 | $file = fopen(__DIR__ . '/_files/readiness_check', 'w+'); 65 | fwrite($file, $data); 66 | fclose($file); 67 | } 68 | 69 | function file_exists($filename) 70 | { 71 | return true; 72 | } 73 | 74 | function file_get_contents() 75 | { 76 | return json_encode([CronReadinessCheck::KEY_CURRENT_TIMESTAMP => 150]); 77 | } 78 | 79 | function is_writable() 80 | { 81 | return CronReadinessCheckTest::$writable; 82 | } 83 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/CronTest.php: -------------------------------------------------------------------------------- 1 | backupPath = TESTS_TEMP_DIR . '/var/backup'; 44 | if (!is_dir($this->backupPath)) { 45 | mkdir($this->backupPath, 0777, true); 46 | } 47 | 48 | $this->cronScript = UPDATER_BP . '/cron.php'; 49 | $this->backupToRollback = $this->backupPath . '/BackupToRollback.zip'; 50 | $this->backupToRemoveA = $this->backupPath . '/BackupToRemoveA.zip'; 51 | $this->backupToRemoveB = $this->backupPath . '/BackupToRemoveB.zip'; 52 | $this->status = new \Magento\Update\Status(); 53 | 54 | file_put_contents($this->backupToRollback, 'w'); 55 | file_put_contents($this->backupToRemoveA, 'w'); 56 | file_put_contents($this->backupToRemoveB, 'w'); 57 | } 58 | 59 | protected function tearDown() 60 | { 61 | $this->status->setUpdateInProgress(false); 62 | $this->status->setUpdateError(false); 63 | if (file_exists($this->backupToRollback)) { 64 | unlink($this->backupToRollback); 65 | } 66 | if (file_exists($this->backupToRemoveA)) { 67 | unlink($this->backupToRemoveA); 68 | } 69 | if (file_exists($this->backupToRemoveB)) { 70 | unlink($this->backupToRemoveB); 71 | } 72 | array_map('unlink', glob($this->backupPath . '/*.zip')); 73 | if (is_dir($this->backupPath)) { 74 | rmdir($this->backupPath); 75 | rmdir(TESTS_TEMP_DIR . '/var'); 76 | } 77 | if (file_exists(MAGENTO_BP . '/var/.update_queue.json')) { 78 | file_put_contents(MAGENTO_BP . '/var/.update_queue.json', ''); 79 | } 80 | } 81 | 82 | public function testUpdateInProgress() 83 | { 84 | $this->status->setUpdateInProgress(); 85 | $actualResponse = shell_exec('php -f ' . $this->cronScript); 86 | $this->assertEquals('Cron is already in progress...', $actualResponse); 87 | } 88 | 89 | public function testValidQueue() 90 | { 91 | $this->assertTrue(file_exists($this->backupToRollback)); 92 | $this->assertTrue(file_exists($this->backupToRemoveA)); 93 | $this->assertTrue(file_exists($this->backupToRemoveB)); 94 | 95 | file_put_contents(MAGENTO_BP . '/var/.update_queue.json', 96 | '{ 97 | "jobs": [ 98 | { 99 | "name": "remove_backups", 100 | "params": { 101 | "backups_file_names": [ 102 | "' . $this->backupToRemoveA . '", 103 | "' . $this->backupToRemoveB . '" 104 | ] 105 | } 106 | } 107 | ], 108 | "ignored_field": "" 109 | }'); 110 | shell_exec('php -f ' . $this->cronScript); 111 | 112 | $jobStatus = $this->status->get(); 113 | // verify removals 114 | $this->assertNotContains('An error occurred while executing job ""', $jobStatus); 115 | $this->assertContains('Job "remove_backups {"backups_file_names":["' . 116 | $this->backupToRemoveA . '","' . $this->backupToRemoveB . 117 | '"]}" has successfully completed', $jobStatus); 118 | $this->assertFalse(file_exists($this->backupToRemoveA)); 119 | $this->assertFalse(file_exists($this->backupToRemoveB)); 120 | } 121 | 122 | /** 123 | * Test invalid queue file 124 | * 125 | * @expectedException /RuntimeException 126 | * @expectedExceptionMessage RuntimeException: Missing job params "params" field is missing for one or more jobs 127 | */ 128 | public function testInvalidQueue() 129 | { 130 | file_put_contents(MAGENTO_BP . '/var/.update_queue.json', 131 | '{ 132 | "jobs": [ 133 | { 134 | "name": "backup" 135 | } 136 | ], 137 | "ignored_field": "" 138 | }'); 139 | shell_exec('php -f ' . $this->cronScript); 140 | $jobStatus = $this->status->get(); 141 | $this->assertContains('"params" field is missing for one or more jobs', $jobStatus); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/MaintenanceModeTest.php: -------------------------------------------------------------------------------- 1 | flagFile = TESTS_TEMP_DIR . '/.maintenance.flag'; 32 | $this->ipFile = TESTS_TEMP_DIR . '/.maintenance.ip'; 33 | } 34 | 35 | protected function setUp() 36 | { 37 | $this->maintenanceMode = new \Magento\Update\MaintenanceMode($this->flagFile, $this->ipFile); 38 | if (file_exists($this->flagFile)) { 39 | unlink($this->flagFile); 40 | } 41 | if (file_exists($this->ipFile)) { 42 | unlink($this->ipFile); 43 | } 44 | } 45 | 46 | protected function tearDown() 47 | { 48 | if (file_exists($this->flagFile)) { 49 | unlink($this->flagFile); 50 | } 51 | if (file_exists($this->ipFile)) { 52 | unlink($this->ipFile); 53 | } 54 | } 55 | 56 | public function testFlow() 57 | { 58 | $this->assertFalse($this->maintenanceMode->isOn()); 59 | 60 | /** Successfully set maintenance mode */ 61 | $this->maintenanceMode->set(true); 62 | $this->assertTrue($this->maintenanceMode->isOn()); 63 | 64 | /** Successfully disable maintenance mode */ 65 | $this->maintenanceMode->set(false); 66 | $this->assertFalse($this->maintenanceMode->isOn()); 67 | 68 | /** Test case when maintenance mode cannot be disabled from the updater application */ 69 | $this->maintenanceMode->set(true); 70 | file_put_contents($this->ipFile, ''); 71 | $this->maintenanceMode->set(false); 72 | $this->assertTrue($this->maintenanceMode->isOn()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/Queue/JobBackupTest.php: -------------------------------------------------------------------------------- 1 | backupFilename = uniqid('test_backup') . '.zip'; 25 | $this->backupPath = TESTS_TEMP_DIR . '/backup/'; 26 | if (!is_dir($this->backupPath)) { 27 | mkdir($this->backupPath); 28 | } 29 | } 30 | 31 | protected function tearDown() 32 | { 33 | if (is_dir($this->backupPath)) { 34 | rmdir($this->backupPath); 35 | } 36 | if (file_exists(TESTS_TEMP_DIR . '/maintenanceMode.flag')) { 37 | unlink(TESTS_TEMP_DIR . '/maintenanceMode.flag'); 38 | } 39 | if (file_exists(TESTS_TEMP_DIR . '/maintenanceAddress.flag')) { 40 | unlink(TESTS_TEMP_DIR . '/maintenanceAddress.flag'); 41 | } 42 | parent::tearDown(); 43 | } 44 | 45 | public function testArchive() 46 | { 47 | if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { 48 | $this->markTestSkipped(); 49 | } 50 | $jobName = 'Backup'; 51 | $jobStatus = new \Magento\Update\Status(); 52 | $jobStatus->clear(); 53 | 54 | $backupInfo = $this->getMockBuilder('Magento\Update\Backup\BackupInfo') 55 | ->disableOriginalConstructor() 56 | ->getMock(); 57 | $backupInfo->expects($this->any()) 58 | ->method('generateBackupFilename') 59 | ->willReturn($this->backupFilename); 60 | $backupInfo->expects($this->any()) 61 | ->method('getArchivedDirectory') 62 | ->willReturn(UPDATER_BP); 63 | $backupInfo->expects($this->any()) 64 | ->method('getBlacklist') 65 | ->willReturn(['var/backup', 'vendor', 'app/code']); 66 | $backupInfo->expects($this->any()) 67 | ->method('getBackupPath') 68 | ->willReturn($this->backupPath); 69 | 70 | $maintenanceMode = new MaintenanceMode( 71 | TESTS_TEMP_DIR . '/maintenanceMode.flag', 72 | TESTS_TEMP_DIR . '/maintenanceAddress.flag' 73 | ); 74 | $jobBackup = new \Magento\Update\Queue\JobBackup($jobName, [], $jobStatus, $maintenanceMode, $backupInfo); 75 | $this->dirList = scandir($this->backupPath); 76 | 77 | $jobBackup->execute(); 78 | 79 | $tmpFiles = array_diff(scandir($this->backupPath), $this->dirList); 80 | $actualBackupFile = array_pop($tmpFiles); 81 | $this->assertEquals($this->backupFilename, $actualBackupFile); 82 | 83 | $actualJobStatus = $jobStatus->get(); 84 | $fullBackupFileName = $this->backupPath . $this->backupFilename; 85 | $this->assertContains(sprintf('Creating backup archive "%s" ...', $fullBackupFileName), $actualJobStatus); 86 | $this->assertContains(sprintf('Backup archive "%s" has been created.', $fullBackupFileName), $actualJobStatus); 87 | 88 | if (file_exists($this->backupPath . $actualBackupFile)) { 89 | unlink($this->backupPath . $actualBackupFile); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/Queue/JobComponentUninstallTest.php: -------------------------------------------------------------------------------- 1 | status = $this->getMock('Magento\Update\Status', [], [], '', false); 24 | $this->composerApp = $this->getMock('Magento\Composer\MagentoComposerApplication', [], [], '', false); 25 | } 26 | 27 | public function testExecute() 28 | { 29 | $om = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); 30 | $jobComponentUninstall = $om->create( 31 | 'Magento\Update\Queue\JobComponentUninstall', 32 | [ 33 | 'composerApp' => $this->composerApp, 34 | 'status' => $this->status, 35 | 'params' => ['components' => [['name' => 'vendor/package']]], 36 | 'name' => 'component:uninstall', 37 | ] 38 | ); 39 | $this->status->expects($this->atLeastOnce())->method('add'); 40 | $this->composerApp->expects($this->at(0)) 41 | ->method('runComposerCommand') 42 | ->with(['command' => 'remove', 'packages' => ['vendor/package'], '--no-update' => true]) 43 | ->willReturn('Success'); 44 | $this->composerApp->expects($this->at(1)) 45 | ->method('runComposerCommand') 46 | ->with(['command' => 'update']) 47 | ->willReturn('Success'); 48 | $jobComponentUninstall->execute(); 49 | } 50 | 51 | /** 52 | * @expectedException \RuntimeException 53 | * @expectedExceptionMessage Cannot find component to uninstall 54 | */ 55 | public function testExecuteNoComponent() 56 | { 57 | $om = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); 58 | $jobComponentUninstall = $om->create( 59 | 'Magento\Update\Queue\JobComponentUninstall', 60 | [ 61 | 'composerApp' => $this->composerApp, 62 | 'status' => $this->status, 63 | 'params' => [], 64 | 'name' => 'component:uninstall', 65 | ] 66 | ); 67 | $this->composerApp->expects($this->never())->method('runComposerCommand'); 68 | $jobComponentUninstall->execute(); 69 | } 70 | 71 | /** 72 | * @expectedException \RuntimeException 73 | * @expectedExceptionMessage Exception 74 | */ 75 | public function testExecuteException() 76 | { 77 | $om = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); 78 | $jobComponentUninstall = $om->create( 79 | 'Magento\Update\Queue\JobComponentUninstall', 80 | [ 81 | 'composerApp' => $this->composerApp, 82 | 'status' => $this->status, 83 | 'params' => ['components' => [['name' => 'vendor/package']]], 84 | 'name' => 'component:uninstall' 85 | ] 86 | ); 87 | $this->status->expects($this->atLeastOnce())->method('add'); 88 | $this->composerApp->expects($this->at(0)) 89 | ->method('runComposerCommand') 90 | ->with(['command' => 'remove', 'packages' => ['vendor/package'], '--no-update' => true]) 91 | ->willReturn('Success'); 92 | $this->composerApp->expects($this->at(1)) 93 | ->method('runComposerCommand') 94 | ->with(['command' => 'update']) 95 | ->will($this->throwException(new \Exception('Exception'))); 96 | $this->status->expects($this->once())->method('setUpdateError')->with(true); 97 | $jobComponentUninstall->execute(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/Queue/JobRemoveBackupsTest.php: -------------------------------------------------------------------------------- 1 | backupFilenameA = uniqid('test_backupA') . '.zip'; 43 | $this->backupFilenameB = uniqid('test_backupB') . '.zip'; 44 | $this->backupFilenameC = uniqid('test_backupC') . '.zip'; 45 | $this->backupPath = TESTS_TEMP_DIR . '/backup/'; 46 | if (!is_dir($this->backupPath)) { 47 | mkdir($this->backupPath); 48 | } 49 | $this->maintenanceFlagFilePath = TESTS_TEMP_DIR . '/.maintenance.flag'; 50 | $this->maintenanceAddressFlag = $this->maintenanceAddressFlag; 51 | $this->updateErrorFlagFilePath = TESTS_TEMP_DIR . '/.update_error.flag'; 52 | } 53 | 54 | protected function tearDown() 55 | { 56 | parent::tearDown(); 57 | if (file_exists($this->backupPath . $this->backupFilenameA)) { 58 | unlink($this->backupPath . $this->backupFilenameA); 59 | } 60 | if (file_exists($this->backupPath . $this->backupFilenameB)) { 61 | unlink($this->backupPath . $this->backupFilenameB); 62 | } 63 | if (file_exists($this->backupPath . $this->backupFilenameC)) { 64 | unlink($this->backupPath . $this->backupFilenameC); 65 | } 66 | if (is_dir($this->backupPath)) { 67 | rmdir($this->backupPath); 68 | } 69 | if (file_exists($this->maintenanceFlagFilePath)) { 70 | unlink($this->maintenanceFlagFilePath); 71 | } 72 | if (file_exists($this->updateErrorFlagFilePath)) { 73 | unlink($this->updateErrorFlagFilePath); 74 | } 75 | } 76 | 77 | /** 78 | * @param bool $isMaintenanceModeOn 79 | * @param bool $isUpdaterError 80 | * @dataProvider flagFileDataProvider 81 | * @expectedException \RuntimeException 82 | * @expectedExceptionMessage Cannot remove backup archives while setup is in progress. 83 | */ 84 | public function testExecuteFlag($isMaintenanceModeOn, $isUpdaterError) 85 | { 86 | /** @var \Magento\Update\MaintenanceMode $maintenanceModeMock */ 87 | $maintenanceModeMock = $this->getMockBuilder('Magento\Update\MaintenanceMode') 88 | ->disableOriginalConstructor() 89 | ->getMock(); 90 | $maintenanceModeMock->expects($this->any())->method('isOn')->willReturn($isMaintenanceModeOn); 91 | /** @var \Magento\Update\Status $statusMock */ 92 | $statusMock = $this->getMockBuilder('Magento\Update\Status') 93 | ->disableOriginalConstructor() 94 | ->getMock(); 95 | $statusMock->expects($this->any())->method('isUpdateError')->willReturn($isUpdaterError); 96 | $this->jobRemoveBackup = new \Magento\Update\Queue\JobRemoveBackups( 97 | 'remove_backups', 98 | [$this->backupPath . $this->backupFilenameA], 99 | $statusMock, 100 | $maintenanceModeMock 101 | ); 102 | $this->jobRemoveBackup->execute(); 103 | } 104 | 105 | public function flagFileDataProvider() 106 | { 107 | return [ 108 | "Updater error" => [false, true], 109 | "Maintenance mode on" => [true, true] 110 | ]; 111 | } 112 | 113 | /** 114 | * @expectedException \RuntimeException 115 | * @expectedExceptionMessage Could not delete backup archive 116 | */ 117 | public function testExecuteInvalidBackupFile() 118 | { 119 | $maintenanceMode = new \Magento\Update\MaintenanceMode( 120 | $this->maintenanceFlagFilePath, 121 | $this->maintenanceAddressFlag 122 | ); 123 | $this->jobRemoveBackup = new \Magento\Update\Queue\JobRemoveBackups( 124 | 'remove_backups', 125 | ['backups_file_names' => [$this->backupPath . 'no-such-file.zip']], 126 | new Status(), 127 | $maintenanceMode 128 | ); 129 | $this->jobRemoveBackup->execute(); 130 | } 131 | 132 | public function testExecuteSingle() 133 | { 134 | if (!file_exists($this->backupPath . $this->backupFilenameA)) { 135 | file_put_contents($this->backupPath . $this->backupFilenameA, ''); 136 | } 137 | $maintenanceMode = new \Magento\Update\MaintenanceMode( 138 | $this->maintenanceFlagFilePath, 139 | $this->maintenanceAddressFlag 140 | ); 141 | $this->jobRemoveBackup = new \Magento\Update\Queue\JobRemoveBackups( 142 | 'remove_backups', 143 | ['backups_file_names' => [$this->backupPath . $this->backupFilenameA]], 144 | new \Magento\Update\Status(), 145 | $maintenanceMode 146 | ); 147 | $this->jobRemoveBackup->execute(); 148 | $this->assertFalse(file_exists($this->backupPath . $this->backupFilenameA)); 149 | } 150 | 151 | public function testExecuteMultiple() 152 | { 153 | if (!file_exists($this->backupPath . $this->backupFilenameA)) { 154 | file_put_contents($this->backupPath . $this->backupFilenameA, ''); 155 | } 156 | if (!file_exists($this->backupPath . $this->backupFilenameB)) { 157 | file_put_contents($this->backupPath . $this->backupFilenameB, ''); 158 | } 159 | if (!file_exists($this->backupPath . $this->backupFilenameC)) { 160 | file_put_contents($this->backupPath . $this->backupFilenameC, ''); 161 | } 162 | $maintenanceMode = new \Magento\Update\MaintenanceMode( 163 | $this->maintenanceFlagFilePath, 164 | $this->maintenanceAddressFlag 165 | ); 166 | $this->jobRemoveBackup = new \Magento\Update\Queue\JobRemoveBackups( 167 | 'remove_backups', 168 | [ 169 | 'backups_file_names' => [ 170 | $this->backupPath . $this->backupFilenameA, 171 | $this->backupPath . $this->backupFilenameB 172 | ] 173 | ], 174 | new \Magento\Update\Status(), 175 | $maintenanceMode 176 | ); 177 | $this->jobRemoveBackup->execute(); 178 | $this->assertFalse(file_exists($this->backupPath . $this->backupFilenameA)); 179 | $this->assertFalse(file_exists($this->backupPath . $this->backupFilenameB)); 180 | $this->assertTrue(file_exists($this->backupPath . $this->backupFilenameC)); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/Queue/JobRollbackTest.php: -------------------------------------------------------------------------------- 1 | maintenanceFlagFilePath = TESTS_TEMP_DIR . '/.maintenance.flag'; 20 | $this->updateErrorFlagFilePath = TESTS_TEMP_DIR . '/.update_error.flag'; 21 | } 22 | 23 | protected function tearDown() 24 | { 25 | parent::tearDown(); 26 | if (file_exists($this->maintenanceFlagFilePath)) { 27 | unlink($this->maintenanceFlagFilePath); 28 | } 29 | if (file_exists($this->updateErrorFlagFilePath)) { 30 | unlink($this->updateErrorFlagFilePath); 31 | } 32 | } 33 | 34 | public function testManualRollbackBackupFileUnavailable() 35 | { 36 | $backupFileName = UPDATER_BP . '/dev/tests/integration/testsuite/Magento/Update/_files/backup/' . 'fake.zip'; 37 | $maintenanceMode = new \Magento\Update\MaintenanceMode( 38 | $this->maintenanceFlagFilePath, 39 | $this->updateErrorFlagFilePath 40 | ); 41 | $jobRollback = new \Magento\Update\Queue\JobRollback( 42 | 'rollback', 43 | ['backup_file_name' => $backupFileName], 44 | new \Magento\Update\Status(), 45 | $maintenanceMode 46 | ); 47 | $this->setExpectedException('RuntimeException', sprintf('"%s" backup file does not exist.', $backupFileName)); 48 | $jobRollback->execute(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/Queue/JobUpdateTest.php: -------------------------------------------------------------------------------- 1 | status = $this->getMock('Magento\Update\Status', [], [], '', false); 29 | $this->composerApp = $this->getMock('Magento\Composer\MagentoComposerApplication', [], [], '', false); 30 | $this->queue = $this->getMock('Magento\Update\Queue', [], [], '', false); 31 | 32 | } 33 | 34 | public function testExecute() 35 | { 36 | $om = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); 37 | $jobUpdate = $om->create( 38 | 'Magento\Update\Queue\JobUpdate', 39 | [ 40 | 'composerApp' => $this->composerApp, 41 | 'status' => $this->status, 42 | 'params' => ['components' => [['name' => 'vendor/package', 'version' => '1.0']]], 43 | 'queue' => $this->queue, 44 | 'name' => 'setup:upgrade', 45 | ] 46 | ); 47 | $this->status->expects($this->atLeastOnce())->method('add'); 48 | $this->composerApp->expects($this->at(0)) 49 | ->method('runComposerCommand') 50 | ->with(['command' => 'require', 'packages' => ['vendor/package 1.0'], '--no-update' => true]) 51 | ->willReturn('Success'); 52 | $this->composerApp->expects($this->at(1)) 53 | ->method('runComposerCommand') 54 | ->with(['command' => 'update']) 55 | ->willReturn('Success'); 56 | $this->queue->expects($this->once())->method('addJobs')->with([['name' => 'setup:upgrade', 'params' => []]]); 57 | $jobUpdate->execute(); 58 | } 59 | 60 | /** 61 | * @expectedException \RuntimeException 62 | * @expectedExceptionMessage Cannot find component to update 63 | */ 64 | public function testExecuteNoRequire() 65 | { 66 | $om = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); 67 | $jobUpdate = $om->create( 68 | 'Magento\Update\Queue\JobUpdate', 69 | [ 70 | 'composerApp' => $this->composerApp, 71 | 'status' => $this->status, 72 | 'params' => [], 73 | 'queue' => $this->queue, 74 | 'name' => 'setup:upgrade', 75 | ] 76 | ); 77 | $this->composerApp->expects($this->never())->method('runComposerCommand'); 78 | $this->queue->expects($this->never())->method('addJobs'); 79 | $jobUpdate->execute(); 80 | } 81 | 82 | /** 83 | * @expectedException \RuntimeException 84 | * @expectedExceptionMessage Exception 85 | */ 86 | public function testExecuteException() 87 | { 88 | $om = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); 89 | $jobUpdate = $om->create( 90 | 'Magento\Update\Queue\JobUpdate', 91 | [ 92 | 'composerApp' => $this->composerApp, 93 | 'status' => $this->status, 94 | 'params' => ['components' => [['name' => 'vendor/package', 'version' => '1.0']]], 95 | 'queue' => $this->queue, 96 | 'name' => 'setup:upgrade', 97 | ] 98 | ); 99 | $this->status->expects($this->atLeastOnce())->method('add'); 100 | $this->composerApp->expects($this->at(0)) 101 | ->method('runComposerCommand') 102 | ->with(['command' => 'require', 'packages' => ['vendor/package 1.0'], '--no-update' => true]) 103 | ->willReturn('Success'); 104 | $this->composerApp->expects($this->at(1)) 105 | ->method('runComposerCommand') 106 | ->with(['command' => 'update']) 107 | ->will($this->throwException(new \Exception('Exception'))); 108 | $this->status->expects($this->once())->method('setUpdateError')->with(true); 109 | $jobUpdate->execute(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/Queue/ReaderTest.php: -------------------------------------------------------------------------------- 1 | validQueueFilePath = __DIR__ . '/../_files/update_queue_valid.json'; 34 | $this->invalidQueueFilePath = __DIR__ . '/../_files/update_queue_invalid.json'; 35 | $this->tmpQueueFilePath = TESTS_TEMP_DIR . '/update_queue_valid.json'; 36 | 37 | /** Prepare temporary queue file which can be modified */ 38 | $queueFileContent = file_get_contents($this->validQueueFilePath); 39 | file_put_contents($this->tmpQueueFilePath, $queueFileContent); 40 | /** Make sure it was created */ 41 | $this->assertEquals($queueFileContent, file_get_contents($this->tmpQueueFilePath), "Precondition failed."); 42 | } 43 | 44 | protected function tearDown() 45 | { 46 | parent::tearDown(); 47 | if (file_exists($this->tmpQueueFilePath)) { 48 | unlink($this->tmpQueueFilePath); 49 | } 50 | } 51 | 52 | public function testRead() 53 | { 54 | $reader = new \Magento\Update\Queue\Reader($this->validQueueFilePath); 55 | $actualQueueFileContent = $reader->read(); 56 | $expectedQueueFileContent = file_get_contents($this->validQueueFilePath); 57 | $this->assertEquals($expectedQueueFileContent, $actualQueueFileContent); 58 | } 59 | 60 | public function testReadFileDoesNotExist() 61 | { 62 | $invalidFilePath = 'invalidpath'; 63 | $reader = new \Magento\Update\Queue\Reader($invalidFilePath); 64 | $actualQueueFileContent = $reader->read(); 65 | $expectedQueueFileContent = ''; 66 | $this->assertEquals($expectedQueueFileContent, $actualQueueFileContent); 67 | } 68 | 69 | public function testReadInvalidFileFormat() 70 | { 71 | $reader = new \Magento\Update\Queue\Reader($this->invalidQueueFilePath); 72 | $this->setExpectedException( 73 | '\RuntimeException', 74 | "Content of \"{$this->invalidQueueFilePath}\" must be a valid JSON." 75 | ); 76 | $reader->read(); 77 | } 78 | } -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/Queue/WriterTest.php: -------------------------------------------------------------------------------- 1 | validQueueFilePath); 13 | $writer->write('{"jobs": []}'); 14 | $expectedQueueFileContent = file_get_contents($this->validQueueFilePath); 15 | $this->assertEquals($expectedQueueFileContent, $writer->read()); 16 | } 17 | 18 | /** 19 | * @expectedException \RuntimeException 20 | * @expectedExceptionMessage Content to write must be a valid JSON. 21 | */ 22 | public function testWriteInvalidJson() 23 | { 24 | $writer = new \Magento\Update\Queue\Writer($this->validQueueFilePath); 25 | $writer->write('invalid json string'); 26 | } 27 | 28 | public function testWriteFileDoesNotExist() 29 | { 30 | $invalidFilePath = 'invalidpath'; 31 | $writer = new \Magento\Update\Queue\Writer($invalidFilePath); 32 | $this->assertFalse($writer->write('{jobs: []}')); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/RollbackTest.php: -------------------------------------------------------------------------------- 1 | backupPath = UPDATER_BP . '/dev/tests/integration/testsuite/Magento/Update/_files/backup/'; 49 | $this->archivedDir = UPDATER_BP . '/dev/tests/integration/testsuite/Magento/Update/_files/archived/'; 50 | $this->excludedDir = UPDATER_BP . '/dev/tests/integration/testsuite/Magento/Update/_files/archived/excluded/'; 51 | 52 | if (!is_dir($this->backupPath)) { 53 | mkdir($this->backupPath); 54 | } 55 | if (!is_dir($this->archivedDir)) { 56 | mkdir($this->archivedDir); 57 | } 58 | if (!is_dir($this->excludedDir)) { 59 | mkdir($this->excludedDir); 60 | } 61 | 62 | $this->backupFileName = $this->backupPath . '/../' . uniqid() . '_code.tar'; 63 | $this->backupFile = new \PharData($this->backupFileName); 64 | $this->backupInfo = $this->getMock('Magento\Update\Backup\BackupInfo', [], [], '', false); 65 | $this->rollBack = new \Magento\Update\Rollback($this->backupPath, $this->archivedDir, null, $this->backupInfo); 66 | } 67 | 68 | protected function tearDown() 69 | { 70 | parent::tearDown(); 71 | $this->autoRollbackHelper(2); 72 | if (file_exists($this->backupFileName)) { 73 | unlink($this->backupFileName); 74 | } 75 | $gtzFile = str_replace('tar', 'tgz', $this->backupFileName); 76 | if (file_exists($gtzFile)) { 77 | unlink($gtzFile); 78 | } 79 | 80 | rmdir($this->backupPath); 81 | rmdir($this->excludedDir); 82 | rmdir($this->archivedDir); 83 | } 84 | 85 | /** 86 | * @expectedException \UnexpectedValueException 87 | */ 88 | public function testAutoRollbackBackupFileUnavailable() 89 | { 90 | $this->rollBack->execute('someInvalidfile'); 91 | } 92 | 93 | public function testAutoRollback() 94 | { 95 | // Setup 96 | $this->autoRollbackHelper(); 97 | 98 | $this->backupFile->buildFromDirectory($this->archivedDir); 99 | $this->backupFile->addEmptyDir("testDirectory"); 100 | $this->backupFile->compress(\Phar::GZ, '.tgz'); 101 | 102 | $newFile = $this->backupPath . '/' . uniqid() . '_code.tgz'; 103 | copy($this->backupFileName, $newFile); 104 | if (file_exists($this->backupFileName)) { 105 | unset($this->backupFile); 106 | unlink($this->backupFileName); 107 | } 108 | $gtzFile = str_replace('tar', 'tgz', $this->backupFileName); 109 | if (file_exists($gtzFile)) { 110 | unlink($gtzFile); 111 | } 112 | $this->backupFileName = $newFile; 113 | 114 | // Change the contents of a.txt 115 | $this->autoRollbackHelper(1); 116 | $this->assertEquals('foo changed', file_get_contents($this->archivedDir . 'a.txt')); 117 | 118 | $this->backupInfo->expects($this->once())->method('getBlacklist')->willReturn(['excluded']); 119 | // Rollback process 120 | $this->rollBack->execute($this->backupFileName); 121 | 122 | // Assert that the contents of a.txt has been restored properly 123 | $this->assertEquals('foo', file_get_contents($this->archivedDir . 'a.txt')); 124 | } 125 | 126 | /** 127 | * Helper to create simple files 128 | * 129 | * @param int $flag 130 | */ 131 | protected function autoRollbackHelper($flag = 0) 132 | { 133 | $fileA = 'a.txt'; 134 | $fileB = 'b.txt'; 135 | $fileC = 'c.txt'; 136 | 137 | if ($flag === 0) { 138 | file_put_contents($this->archivedDir . $fileA, 'foo'); 139 | file_put_contents($this->archivedDir . $fileB, 'bar'); 140 | file_put_contents($this->archivedDir . $fileC, 'baz'); 141 | } elseif ($flag === 1) { 142 | file_put_contents($this->archivedDir . $fileA, 'foo changed'); 143 | } elseif ($flag === 2) { 144 | if (file_exists($this->archivedDir . $fileA)) { 145 | unlink($this->archivedDir . $fileA); 146 | } 147 | if (file_exists($this->archivedDir . $fileB)) { 148 | unlink($this->archivedDir . $fileB); 149 | } 150 | if (file_exists($this->archivedDir . $fileC)) { 151 | unlink($this->archivedDir . $fileC); 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/StatusCheckTest.php: -------------------------------------------------------------------------------- 1 | indexScript = UPDATER_BP . '/index.php'; 30 | $this->status = new \Magento\Update\Status(); 31 | $this->status->clear(); 32 | $this->uniqueMessage = 'Test Message' . uniqid(); 33 | } 34 | 35 | protected function tearDown() 36 | { 37 | $this->status->clear(); 38 | unset($this->uniqueMessage); 39 | } 40 | 41 | /** 42 | * @param bool $isInProgress 43 | * @param string $statusMessage 44 | * @dataProvider progressStatusDataProvider 45 | */ 46 | public function testStatusCheck($isInProgress, $statusMessage) 47 | { 48 | $this->status->add($this->uniqueMessage); 49 | $this->status->setUpdateInProgress($isInProgress); 50 | $actualResponse = $this->getResponse(); 51 | 52 | $this->assertContains($this->uniqueMessage, $actualResponse); 53 | $this->assertContains($statusMessage, $actualResponse); 54 | } 55 | 56 | /** 57 | * @param bool $isInProgress 58 | * @dataProvider progressStatusDataProvider 59 | */ 60 | public function testStatusCheckAjax($isInProgress) 61 | { 62 | $this->status->add($this->uniqueMessage); 63 | $this->status->setUpdateInProgress($isInProgress); 64 | $actualResponse = json_decode($this->getResponse(self::REQUEST_TYPE_AJAX), true); 65 | 66 | $this->assertInternalType('array', $actualResponse); 67 | $this->assertArrayHasKey('statusMessage', $actualResponse); 68 | $this->assertArrayHasKey('isUpdateInProgress', $actualResponse); 69 | $this->assertContains($this->uniqueMessage, $actualResponse['statusMessage']); 70 | $this->assertEquals($isInProgress, $actualResponse['isUpdateInProgress']); 71 | } 72 | 73 | /** 74 | * @return array 75 | */ 76 | public function progressStatusDataProvider() 77 | { 78 | return [ 79 | 'isRunning' => [ 80 | 'isInProgress' => true, 81 | 'statusMessage' => 'Update application is running' 82 | ], 83 | 'isNotRunning' => [ 84 | 'isInProgress' => false, 85 | 'statusMessage' => 'Update application is not running' 86 | ], 87 | ]; 88 | } 89 | 90 | /** 91 | * Return response of index.php, according to the request type 92 | * 93 | * @param string|null $requestType 94 | * @return string 95 | */ 96 | protected function getResponse($requestType = null) 97 | { 98 | if ($requestType === self::REQUEST_TYPE_AJAX) { 99 | $_SERVER['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest'; 100 | } 101 | ob_start(); 102 | include $this->indexScript; 103 | $response = ob_get_contents(); 104 | ob_end_clean(); 105 | unset($_SERVER['HTTP_X_REQUESTED_WITH']); 106 | return $response; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/StatusTest.php: -------------------------------------------------------------------------------- 1 | statusFilePath = __DIR__ . '/_files/update_status.txt'; 44 | $this->tmpStatusFilePath = TESTS_TEMP_DIR . '/update_status.txt'; 45 | $this->tmpStatusLogFilePath = TESTS_TEMP_DIR . '/update_status.log'; 46 | $this->updateInProgressFlagFilePath = TESTS_TEMP_DIR . '/update_in_progress.flag'; 47 | $this->updateErrorFlagFilePath = TESTS_TEMP_DIR . '/update_error.flag'; 48 | 49 | $statusFileContent = file_get_contents($this->statusFilePath); 50 | /** Prepare temporary status file which can be modified */ 51 | file_put_contents($this->tmpStatusFilePath, $statusFileContent); 52 | /** Make sure it was created */ 53 | $this->assertEquals($statusFileContent, file_get_contents($this->tmpStatusFilePath), "Precondition failed."); 54 | 55 | file_put_contents($this->tmpStatusLogFilePath, $statusFileContent); 56 | $this->assertEquals($statusFileContent, file_get_contents($this->tmpStatusLogFilePath), "Precondition failed."); 57 | } 58 | 59 | protected function tearDown() 60 | { 61 | parent::tearDown(); 62 | if (file_exists($this->tmpStatusFilePath)) { 63 | unlink($this->tmpStatusFilePath); 64 | } 65 | if (file_exists($this->tmpStatusLogFilePath)) { 66 | unlink($this->tmpStatusLogFilePath); 67 | } 68 | if (file_exists($this->updateInProgressFlagFilePath)) { 69 | unlink($this->updateInProgressFlagFilePath); 70 | } 71 | if (file_exists($this->updateErrorFlagFilePath)) { 72 | unlink($this->updateErrorFlagFilePath); 73 | } 74 | } 75 | 76 | public function testGet() 77 | { 78 | $status = new \Magento\Update\Status($this->statusFilePath); 79 | $actualStatusText = $status->get(); 80 | /** Ensure that actual status text is correct */ 81 | $statusArray = file_get_contents($this->statusFilePath); 82 | $this->assertEquals($statusArray, $actualStatusText); 83 | } 84 | 85 | public function testGetFileDoesNotExixt() 86 | { 87 | $status = new \Magento\Update\Status('invalid_file_path'); 88 | $this->assertEquals('', $status->get()); 89 | } 90 | 91 | public function testGetEmptyFile() 92 | { 93 | file_put_contents($this->tmpStatusFilePath, ''); 94 | $status = new \Magento\Update\Status($this->tmpStatusFilePath); 95 | $this->assertEquals('', $status->get()); 96 | } 97 | 98 | public function testAdd() 99 | { 100 | $originalStatus = file_get_contents($this->tmpStatusFilePath); 101 | $status = new \Magento\Update\Status($this->tmpStatusFilePath, $this->tmpStatusLogFilePath); 102 | 103 | $firstUpdate = <<add($firstUpdate); 108 | $textAfterFirstUpdate = "$originalStatus\n{$firstUpdate}"; 109 | $this->verifyAddedStatus($textAfterFirstUpdate, $this->tmpStatusFilePath, 1); 110 | $this->verifyAddedStatus($textAfterFirstUpdate, $this->tmpStatusLogFilePath, 1); 111 | 112 | $secondUpdate = <<assertInstanceOf('Magento\Update\Status', $status->add($secondUpdate)); 119 | $textAfterSecondUpdate = "{$originalStatus}\n{$firstUpdate}\n{$secondUpdate}"; 120 | $this->verifyAddedStatus($textAfterSecondUpdate, $this->tmpStatusFilePath, 2); 121 | $this->verifyAddedStatus($textAfterSecondUpdate, $this->tmpStatusLogFilePath, 2); 122 | } 123 | 124 | public function testAddToNotExistingFile() 125 | { 126 | unlink($this->tmpStatusFilePath); 127 | $this->assertFalse(file_exists($this->tmpStatusFilePath), "Precondition failed."); 128 | 129 | $status = new \Magento\Update\Status($this->tmpStatusFilePath); 130 | $statusUpdate = <<add($statusUpdate, $this->tmpStatusFilePath); 135 | $this->verifyAddedStatus($statusUpdate, $this->tmpStatusFilePath, 1); 136 | } 137 | 138 | public function testClear() 139 | { 140 | $originalLogFileContent = file_get_contents($this->tmpStatusLogFilePath); 141 | $status = new \Magento\Update\Status($this->tmpStatusFilePath, $this->tmpStatusLogFilePath); 142 | $this->assertInstanceOf('Magento\Update\Status', $status->clear()); 143 | $this->assertEquals('', file_get_contents($this->tmpStatusFilePath)); 144 | $this->assertEquals($originalLogFileContent, file_get_contents($this->tmpStatusLogFilePath)); 145 | } 146 | 147 | public function testClearNotExistingFile() 148 | { 149 | unlink($this->tmpStatusFilePath); 150 | $this->assertFalse(file_exists($this->tmpStatusFilePath), "Precondition failed."); 151 | 152 | $status = new \Magento\Update\Status($this->tmpStatusFilePath); 153 | $this->assertInstanceOf('Magento\Update\Status', $status->clear()); 154 | $this->assertFalse(file_exists($this->tmpStatusFilePath)); 155 | } 156 | 157 | public function testIsUpdateInProgress() 158 | { 159 | $status = new \Magento\Update\Status( 160 | $this->tmpStatusFilePath, 161 | $this->tmpStatusLogFilePath, 162 | $this->updateInProgressFlagFilePath 163 | ); 164 | $this->assertFalse($status->isUpdateInProgress()); 165 | 166 | $this->assertInstanceOf('Magento\Update\Status', $status->setUpdateInProgress()); 167 | $this->assertTrue($status->isUpdateInProgress()); 168 | 169 | $this->assertInstanceOf('Magento\Update\Status', $status->setUpdateInProgress(false)); 170 | $this->assertFalse($status->isUpdateInProgress()); 171 | 172 | $this->assertInstanceOf('Magento\Update\Status', $status->setUpdateInProgress(true)); 173 | $this->assertTrue($status->isUpdateInProgress()); 174 | } 175 | 176 | public function testIsUpdateError() 177 | { 178 | $status = new \Magento\Update\Status( 179 | $this->tmpStatusFilePath, 180 | $this->tmpStatusLogFilePath, 181 | $this->updateInProgressFlagFilePath, 182 | $this->updateErrorFlagFilePath 183 | ); 184 | $this->assertFalse($status->isUpdateError()); 185 | 186 | $this->assertInstanceOf('Magento\Update\Status', $status->setUpdateError()); 187 | $this->assertTrue($status->isUpdateError()); 188 | 189 | $this->assertInstanceOf('Magento\Update\Status', $status->setUpdateError(false)); 190 | $this->assertFalse($status->isUpdateError()); 191 | 192 | $this->assertInstanceOf('Magento\Update\Status', $status->setUpdateError(true)); 193 | $this->assertTrue($status->isUpdateError()); 194 | } 195 | 196 | /** 197 | * @param string $expectedTextAfterUpdate 198 | * @param string $filePath 199 | * @param int $expectedNumberOfTimeEntries 200 | */ 201 | protected function verifyAddedStatus($expectedTextAfterUpdate, $filePath, $expectedNumberOfTimeEntries) 202 | { 203 | $actualStatusText = file_get_contents($filePath); 204 | /** Make sure that number of current date/time entries matches expected value */ 205 | preg_match_all('/\[.*?\]\s/', $actualStatusText, $matches); 206 | $this->assertCount(1, $matches); 207 | $this->assertCount($expectedNumberOfTimeEntries, $matches[0]); 208 | 209 | /** Eliminate current date/time entries from the actual status content before text comparison */ 210 | $actualStatusText = preg_replace('/\[.*?\]\s/', '', $actualStatusText); 211 | $this->assertEquals($expectedTextAfterUpdate, $actualStatusText); 212 | } 213 | } -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/_files/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "magento/updater", 3 | "description": "Test composer.json", 4 | "type": "project", 5 | "version": "0.74.0-beta2", 6 | "license": [ 7 | "OSL-3.0", 8 | "AFL-3.0" 9 | ], 10 | "require": { 11 | "php": "~5.5.0|~5.6.0|~7.0.0", 12 | "magento/product-community-edition": "0.74.0-beta12" 13 | }, 14 | "require-dev": { 15 | "phpunit/phpunit": "4.1.0" 16 | }, 17 | "replace": { 18 | "magento/module-admin-notification": "self.version" 19 | }, 20 | "autoload": { 21 | "psr-4": { 22 | "Magento\\": "app/code/Magento/" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/_files/update_queue_invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "jobs": [ 3 | { 4 | "name": "backup", 5 | "params": {} 6 | }, 7 | { 8 | "name": "rollback", 9 | "params": { 10 | "backup_file_name": "/full/path/to/archive.zip" 11 | } 12 | }, 13 | { 14 | "name": "remove_backups", 15 | "params": { 16 | "backups_file_names": [ 17 | "/full/path/to/archive1.zip", 18 | "/full/path/to/archive2.zip" 19 | ] 20 | } 21 | }, 22 | { 23 | "name": "update", 24 | "params": { 25 | "require": [ 26 | { 27 | "name": "packageName1", 28 | "version": "1.0.0" 29 | }, 30 | { 31 | "name": "packageName2", 32 | "version": "2.0.0" 33 | } 34 | ] 35 | } 36 | }, 37 | { 38 | "name": "uninstall", 39 | "params": { 40 | "components": [ 41 | { 42 | "name": "packageName3" 43 | }, 44 | { 45 | "name": "packageName4" 46 | } 47 | ] 48 | } 49 | } 50 | ], 51 | "ignored_field": '' 52 | } 53 | -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/_files/update_queue_valid.json: -------------------------------------------------------------------------------- 1 | { 2 | "jobs": [ 3 | { 4 | "name": "backup", 5 | "params": {} 6 | }, 7 | { 8 | "name": "rollback", 9 | "params": { 10 | "backup_file_name": "/full/path/to/archive.zip" 11 | } 12 | }, 13 | { 14 | "name": "remove_backups", 15 | "params": { 16 | "backups_file_names": [ 17 | "/full/path/to/archive1.zip", 18 | "/full/path/to/archive2.zip" 19 | ] 20 | } 21 | }, 22 | { 23 | "name": "update", 24 | "params": { 25 | "components": [ 26 | { 27 | "name": "packageName1", 28 | "version": "1.0.0" 29 | }, 30 | { 31 | "name": "packageName2", 32 | "version": "2.0.0" 33 | } 34 | ] 35 | } 36 | }, 37 | { 38 | "name": "uninstall", 39 | "params": { 40 | "components": [ 41 | { 42 | "name": "packageName3", 43 | "version": "9.0.0" 44 | }, 45 | { 46 | "name": "packageName4", 47 | "version": "7.0.0" 48 | } 49 | ] 50 | } 51 | } 52 | ], 53 | "ignored_field": "" 54 | } -------------------------------------------------------------------------------- /update/dev/tests/integration/testsuite/Magento/Update/_files/update_status.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. 2 | Aenean massa. 3 | Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. 4 | Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. 5 | Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. 6 | In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. 7 | Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. 8 | Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. 9 | Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. 10 | Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. 11 | Nam eget dui. Etiam rhoncus. 12 | 13 | Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum. 14 | 15 | 16 | Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. 17 | Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, -------------------------------------------------------------------------------- /update/index.php: -------------------------------------------------------------------------------- 1 | isUpdateInProgress(); 21 | $statusMessage = ''; 22 | $statusMessage .= $status->get(); 23 | $statusMessage = str_replace("\n", "
", $statusMessage); 24 | $queue = new \Magento\Update\Queue(); 25 | $pending = !$status->isUpdateInProgress() && !$queue->isEmpty() && !$status->isUpdateError(); 26 | 27 | if (isset($_SERVER['PATH_INFO']) && !empty($_SERVER['PATH_INFO'])) { 28 | if($_SERVER['PATH_INFO'] === '/rollback' && file_exists(MAGENTO_BP . '/var/.update_error.flag')) { 29 | try { 30 | $queue->clear(); 31 | $backupInfo = new \Magento\Update\Backup\BackupInfo(); 32 | 33 | $backupPaths = $backupInfo->getBackupFilePaths(); 34 | if (isset($backupPaths['error'])) { 35 | $status->add('WARNING: There is a problem with backup files! Performing rollback from these' 36 | . ' files may cause the Magento application to be unstable'); 37 | foreach ($backupPaths['error'] as $error) { 38 | $status->add($error); 39 | } 40 | unset($backupPaths['error']); 41 | } 42 | 43 | foreach (array_values($backupPaths) as $backupPath) { 44 | $queue->addJobs( 45 | ['jobs' => 46 | [ 47 | 'name' => $backupPath['type'], 48 | 'params'=> ['backup_file_name' => $backupPath['filename']] 49 | ] 50 | ] 51 | ); 52 | } 53 | 54 | $status->setUpdateError(false); 55 | } catch (\Exception $e) { 56 | $status->setUpdateError(true); 57 | $status->add('Error in Rollback:' . $e->getMessage()); 58 | } 59 | } elseif ($_SERVER['PATH_INFO'] === '/status') { 60 | $complete = !$status->isUpdateInProgress() && $queue->isEmpty() && !$status->isUpdateError(); 61 | if ($complete) { 62 | $status->clear(); 63 | } 64 | echo json_encode( 65 | [ 66 | 'statusMessage' => $statusMessage, 67 | 'isUpdateInProgress' => $isUpdateInProgress, 68 | 'complete' => $complete, 69 | 'error' => $status->isUpdateError(), 70 | 'pending' => $pending, 71 | ] 72 | ); 73 | } 74 | } else { 75 | if (!file_exists(MAGENTO_BP . '/app/etc/config.php') || !file_exists(MAGENTO_BP . '/app/etc/env.php')) { 76 | header('Location: ../setup'); 77 | die(); 78 | } 79 | $type = 'default'; 80 | $titles = []; 81 | $defaultHeaderTitle = 'Magento Updater'; 82 | if (file_exists(MAGENTO_BP . '/var/.type.json')) { 83 | $typeFlag = json_decode(file_get_contents(MAGENTO_BP . '/var/.type.json'), true); 84 | $headerTitle = isset($typeFlag['headerTitle']) ? $typeFlag['headerTitle'] : $defaultHeaderTitle; 85 | $titles = $typeFlag['titles']; 86 | } else { 87 | $headerTitle = $defaultHeaderTitle; 88 | } 89 | include __DIR__ . '/app/code/Magento/Update/view/templates/status.phtml'; 90 | } 91 | -------------------------------------------------------------------------------- /update/pub/.htaccess: -------------------------------------------------------------------------------- 1 | Allow from all 2 | 3 | 4 | ############################################ 5 | ## prevent clickjacking 6 | Header set X-Frame-Options SAMEORIGIN 7 | 8 | -------------------------------------------------------------------------------- /update/pub/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/favicon.ico -------------------------------------------------------------------------------- /update/pub/fonts/icons/icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/icons/icons.eot -------------------------------------------------------------------------------- /update/pub/fonts/icons/icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /update/pub/fonts/icons/icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/icons/icons.ttf -------------------------------------------------------------------------------- /update/pub/fonts/icons/icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/icons/icons.woff -------------------------------------------------------------------------------- /update/pub/fonts/icons/icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/icons/icons.woff2 -------------------------------------------------------------------------------- /update/pub/fonts/opensans/bold/opensans-700.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/bold/opensans-700.eot -------------------------------------------------------------------------------- /update/pub/fonts/opensans/bold/opensans-700.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/bold/opensans-700.ttf -------------------------------------------------------------------------------- /update/pub/fonts/opensans/bold/opensans-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/bold/opensans-700.woff -------------------------------------------------------------------------------- /update/pub/fonts/opensans/bold/opensans-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/bold/opensans-700.woff2 -------------------------------------------------------------------------------- /update/pub/fonts/opensans/light/opensans-300.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/light/opensans-300.eot -------------------------------------------------------------------------------- /update/pub/fonts/opensans/light/opensans-300.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/light/opensans-300.ttf -------------------------------------------------------------------------------- /update/pub/fonts/opensans/light/opensans-300.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/light/opensans-300.woff -------------------------------------------------------------------------------- /update/pub/fonts/opensans/light/opensans-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/light/opensans-300.woff2 -------------------------------------------------------------------------------- /update/pub/fonts/opensans/regular/opensans-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/regular/opensans-400.eot -------------------------------------------------------------------------------- /update/pub/fonts/opensans/regular/opensans-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/regular/opensans-400.ttf -------------------------------------------------------------------------------- /update/pub/fonts/opensans/regular/opensans-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/regular/opensans-400.woff -------------------------------------------------------------------------------- /update/pub/fonts/opensans/regular/opensans-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/regular/opensans-400.woff2 -------------------------------------------------------------------------------- /update/pub/fonts/opensans/semibold/opensans-600.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/semibold/opensans-600.eot -------------------------------------------------------------------------------- /update/pub/fonts/opensans/semibold/opensans-600.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/semibold/opensans-600.ttf -------------------------------------------------------------------------------- /update/pub/fonts/opensans/semibold/opensans-600.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/semibold/opensans-600.woff -------------------------------------------------------------------------------- /update/pub/fonts/opensans/semibold/opensans-600.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/fonts/opensans/semibold/opensans-600.woff2 -------------------------------------------------------------------------------- /update/pub/images/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/images/ajax-loader.gif -------------------------------------------------------------------------------- /update/pub/images/arrows-bg.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /update/pub/images/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/images/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /update/pub/images/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/images/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /update/pub/images/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/images/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /update/pub/images/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/images/favicon/favicon.ico -------------------------------------------------------------------------------- /update/pub/images/loader-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saedyousef/magento_helloworld/00e4a7f0a6cea4483cd2891a026623cd8b96f3ca/update/pub/images/loader-2.gif -------------------------------------------------------------------------------- /update/pub/images/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /update/pub/images/magento-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /update/pub/images/magento-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /update/pub/js/lib/angular-ng-storage/angular-ng-storage.min.js: -------------------------------------------------------------------------------- 1 | /*! ngStorage 0.3.0 | Copyright (c) 2013 Gias Kay Lee | MIT License */"use strict";!function(){function a(a){return["$rootScope","$window",function(b,c){for(var d,e,f,g=c[a]||(console.warn("This browser does not support Web Storage!"),{}),h={$default:function(a){for(var b in a)angular.isDefined(h[b])||(h[b]=a[b]);return h},$reset:function(a){for(var b in h)"$"===b[0]||delete h[b];return h.$default(a)}},i=0;i