diff --git a/bin/magento b/bin/magento
index 1cb700def7fa7f3faf073dbd7bb0300892b06332..3fa9221763cf5fca0a09eb4bc6f43d3a5cb22a42 100755
--- a/bin/magento
+++ b/bin/magento
@@ -28,5 +28,5 @@ try {
         echo "\n\n";
         $e = $e->getPrevious();
     }
-    exit(Cli::RETURN_FAILURE);
+    exit(Magento\Framework\Console\Cli::RETURN_FAILURE);
 }
diff --git a/lib/internal/Magento/Framework/Console/Cli.php b/lib/internal/Magento/Framework/Console/Cli.php
index 5a89d0f6b60571680068463df5b78f85951c809c..30242b488b14c3ce838d957a56c431828388bb2a 100644
--- a/lib/internal/Magento/Framework/Console/Cli.php
+++ b/lib/internal/Magento/Framework/Console/Cli.php
@@ -5,102 +5,105 @@
  */
 namespace Magento\Framework\Console;
 
+use Magento\Framework\App\DeploymentConfig;
 use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\App\State;
+use Magento\Framework\Code\Generator\Io;
 use Magento\Framework\Composer\ComposerJsonFinder;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Output\OutputInterface;
-use Symfony\Component\Console\Output\ConsoleOutput;
-use Symfony\Component\Console\Input\ArgvInput;
-use Symfony\Component\Console\Application as SymfonyApplication;
+use Magento\Framework\Exception\FileSystemException;
+use Magento\Setup\Model\ObjectManagerProvider;
+use Symfony\Component\Console;
 use Magento\Framework\App\Bootstrap;
 use Magento\Framework\Filesystem\Driver\File;
 use Magento\Framework\Shell\ComplexParameter;
 use Magento\Setup\Console\CompilerPreparation;
-use \Magento\Framework\App\ProductMetadata;
+use Magento\Framework\App\ProductMetadata;
+use Magento\Framework\ObjectManagerInterface;
+use Zend\ServiceManager\ServiceManager;
 
 /**
- * Magento 2 CLI Application. This is the hood for all command line tools supported by Magento
+ * Magento 2 CLI Application.
+ * This is the hood for all command line tools supported by Magento.
  *
  * {@inheritdoc}
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
-class Cli extends SymfonyApplication
+class Cli extends Console\Application
 {
     /**
-     * Name of input option
+     * Name of input option.
      */
     const INPUT_KEY_BOOTSTRAP = 'bootstrap';
 
-    /**
-     * Cli exit codes
+    /**#@+
+     * Cli exit codes.
      */
     const RETURN_SUCCESS = 0;
     const RETURN_FAILURE = 1;
+    /**#@-*/
 
-    /** @var \Zend\ServiceManager\ServiceManager */
+    /**
+     * Service Manager.
+     *
+     * @var ServiceManager
+     */
     private $serviceManager;
 
     /**
-     * Initialization exception
+     * Initialization exception.
      *
      * @var \Exception
      */
     private $initException;
 
     /**
-     * @param string $name  application name
-     * @param string $version application version
-     * @SuppressWarnings(PHPMD.ExitExpression)
+     * Object Manager.
+     *
+     * @var ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * @param string $name the application name
+     * @param string $version the application version
      */
     public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
     {
         $this->serviceManager = \Zend\Mvc\Application::init(require BP . '/setup/config/application.config.php')
             ->getServiceManager();
-        $generationDirectoryAccess = new GenerationDirectoryAccess($this->serviceManager);
-        if (!$generationDirectoryAccess->check()) {
-            $output = new ConsoleOutput();
-            $output->writeln(
-                '<error>Command line user does not have read and write permissions on var/generation directory.  Please'
-                . ' address this issue before using Magento command line.</error>'
-            );
-            exit(0);
-        }
-        /**
-         * Temporary workaround until the compiler is able to clear the generation directory
-         * @todo remove after MAGETWO-44493 resolved
-         */
-        if (class_exists(CompilerPreparation::class)) {
-            $compilerPreparation = new CompilerPreparation($this->serviceManager, new ArgvInput(), new File());
-            $compilerPreparation->handleCompilerEnvironment();
-        }
+
+        $this->assertCompilerPreparation();
+        $this->initObjectManager();
+        $this->assertGenerationPermissions();
 
         if ($version == 'UNKNOWN') {
-            $directoryList      = new DirectoryList(BP);
+            $directoryList = new DirectoryList(BP);
             $composerJsonFinder = new ComposerJsonFinder($directoryList);
-            $productMetadata    = new ProductMetadata($composerJsonFinder);
+            $productMetadata = new ProductMetadata($composerJsonFinder);
             $version = $productMetadata->getVersion();
         }
+
         parent::__construct($name, $version);
     }
 
     /**
-     * Process an error happened during initialization of commands, if any
+     * {@inheritdoc}
      *
-     * @param InputInterface $input
-     * @param OutputInterface $output
-     * @return int
-     * @throws \Exception
+     * @throws \Exception the exception in case of unexpected error
      */
-    public function doRun(InputInterface $input, OutputInterface $output)
+    public function doRun(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
     {
         $exitCode = parent::doRun($input, $output);
+
         if ($this->initException) {
             $output->writeln(
                 "<error>We're sorry, an error occurred. Try clearing the cache and code generation directories. "
                 . "By default, they are: var/cache, var/di, var/generation, and var/page_cache.</error>"
             );
+
             throw $this->initException;
         }
+
         return $exitCode;
     }
 
@@ -113,46 +116,141 @@ class Cli extends SymfonyApplication
     }
 
     /**
-     * Gets application commands
+     * Gets application commands.
      *
-     * @return array
+     * @return array a list of available application commands
      */
     protected function getApplicationCommands()
     {
         $commands = [];
         try {
-            $bootstrapParam = new ComplexParameter(self::INPUT_KEY_BOOTSTRAP);
-            $params = $bootstrapParam->mergeFromArgv($_SERVER, $_SERVER);
-            $params[Bootstrap::PARAM_REQUIRE_MAINTENANCE] = null;
-            $bootstrap = Bootstrap::create(BP, $params);
-            $objectManager = $bootstrap->getObjectManager();
-            /** @var \Magento\Setup\Model\ObjectManagerProvider $omProvider */
-            $omProvider = $this->serviceManager->get(\Magento\Setup\Model\ObjectManagerProvider::class);
-            $omProvider->setObjectManager($objectManager);
-
             if (class_exists(\Magento\Setup\Console\CommandList::class)) {
                 $setupCommandList = new \Magento\Setup\Console\CommandList($this->serviceManager);
                 $commands = array_merge($commands, $setupCommandList->getCommands());
             }
 
-            if ($objectManager->get(\Magento\Framework\App\DeploymentConfig::class)->isAvailable()) {
-                /** @var \Magento\Framework\Console\CommandListInterface */
-                $commandList = $objectManager->create(\Magento\Framework\Console\CommandListInterface::class);
+            if ($this->objectManager->get(DeploymentConfig::class)->isAvailable()) {
+                /** @var CommandListInterface */
+                $commandList = $this->objectManager->create(CommandListInterface::class);
                 $commands = array_merge($commands, $commandList->getCommands());
             }
 
-            $commands = array_merge($commands, $this->getVendorCommands($objectManager));
+            $commands = array_merge(
+                $commands,
+                $this->getVendorCommands($this->objectManager)
+            );
         } catch (\Exception $e) {
             $this->initException = $e;
         }
+
         return $commands;
     }
 
     /**
-     * Gets vendor commands
+     * Object Manager initialization.
+     *
+     * @return void
+     * @SuppressWarnings(PHPMD.ExitExpression)
+     */
+    private function initObjectManager()
+    {
+        try {
+            $params = (new ComplexParameter(self::INPUT_KEY_BOOTSTRAP))->mergeFromArgv($_SERVER, $_SERVER);
+            $params[Bootstrap::PARAM_REQUIRE_MAINTENANCE] = null;
+
+            $this->objectManager = Bootstrap::create(BP, $params)->getObjectManager();
+
+            /** @var ObjectManagerProvider $omProvider */
+            $omProvider = $this->serviceManager->get(ObjectManagerProvider::class);
+            $omProvider->setObjectManager($this->objectManager);
+        } catch (FileSystemException $exception) {
+            $this->writeGenerationDirectoryReadError();
+
+            exit(static::RETURN_FAILURE);
+        }
+    }
+
+    /**
+     * Checks whether generation directory is read-only.
+     * Depends on the current mode:
+     *      production - application will proceed
+     *      default - application will be terminated
+     *      developer - application will be terminated
+     *
+     * @return void
+     * @SuppressWarnings(PHPMD.ExitExpression)
+     */
+    private function assertGenerationPermissions()
+    {
+        /** @var GenerationDirectoryAccess $generationDirectoryAccess */
+        $generationDirectoryAccess = $this->objectManager->create(
+            GenerationDirectoryAccess::class,
+            ['serviceManager' => $this->serviceManager]
+        );
+        /** @var State $state */
+        $state = $this->objectManager->get(State::class);
+
+        if (
+            $state->getMode() !== State::MODE_PRODUCTION
+            && !$generationDirectoryAccess->check()
+        ) {
+            $this->writeGenerationDirectoryReadError();
+
+            exit(static::RETURN_FAILURE);
+        }
+    }
+
+    /**
+     * Checks whether compiler is being prepared.
+     *
+     * @return void
+     * @SuppressWarnings(PHPMD.ExitExpression)
+     */
+    private function assertCompilerPreparation()
+    {
+        /**
+         * Temporary workaround until the compiler is able to clear the generation directory
+         * @todo remove after MAGETWO-44493 resolved
+         */
+        if (class_exists(CompilerPreparation::class)) {
+            $compilerPreparation = new CompilerPreparation(
+                $this->serviceManager,
+                new Console\Input\ArgvInput(),
+                new File()
+            );
+
+            try {
+                $compilerPreparation->handleCompilerEnvironment();
+            } catch (FileSystemException $e) {
+                $this->writeGenerationDirectoryReadError();
+
+                exit(static::RETURN_FAILURE);
+            }
+        }
+    }
+
+    /**
+     * Writes read error to console.
      *
-     * @param \Magento\Framework\ObjectManagerInterface $objectManager
-     * @return array
+     * @return void
+     */
+    private function writeGenerationDirectoryReadError()
+    {
+        $output = new Console\Output\ConsoleOutput();
+        $output->writeln(
+            '<error>'
+            . 'Command line user does not have read and write permissions on ' . Io::DEFAULT_DIRECTORY . ' directory. '
+            . 'Please address this issue before using Magento command line.'
+            . '</error>'
+        );
+    }
+
+    /**
+     * Retrieves vendor commands.
+     *
+     * @param ObjectManagerInterface $objectManager the object manager
+     *
+     * @return array an array with external commands
      */
     protected function getVendorCommands($objectManager)
     {
@@ -165,6 +263,7 @@ class Cli extends SymfonyApplication
                 );
             }
         }
+
         return $commands;
     }
 }
diff --git a/setup/src/Magento/Setup/Console/CompilerPreparation.php b/setup/src/Magento/Setup/Console/CompilerPreparation.php
index df32f9b018a0f2bbb8103ae9556c8863d17ff286..e986749ee6efb04a26aa73ddbd59fb933cc003a2 100644
--- a/setup/src/Magento/Setup/Console/CompilerPreparation.php
+++ b/setup/src/Magento/Setup/Console/CompilerPreparation.php
@@ -1,49 +1,62 @@
 <?php
-/***
+/**
  * Copyright © 2013-2017 Magento, Inc. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\Setup\Console;
 
-
 use Magento\Framework\App\Bootstrap;
 use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Console\GenerationDirectoryAccess;
+use Magento\Framework\Exception\FileSystemException;
 use Magento\Framework\Filesystem\Driver\File;
+use Magento\Framework\Phrase;
 use Magento\Setup\Console\Command\DiCompileCommand;
 use Magento\Setup\Mvc\Bootstrap\InitParamListener;
 use Symfony\Component\Console\Input\ArgvInput;
+use Zend\ServiceManager\ServiceManager;
 
 class CompilerPreparation
 {
-    /** @var \Zend\ServiceManager\ServiceManager */
+    /**
+     * @var ServiceManager
+     */
     private $serviceManager;
 
-    /** @var ArgvInput */
+    /**
+     * @var ArgvInput
+     */
     private $input;
 
-    /** @var File */
+    /**
+     * @var File
+     */
     private $filesystemDriver;
 
     /**
-     * @param \Zend\ServiceManager\ServiceManager $serviceManager
+     * @var GenerationDirectoryAccess
+     */
+    private $generationDirectoryAccess;
+
+    /**
+     * @param ServiceManager $serviceManager
      * @param ArgvInput $input
      * @param File $filesystemDriver
      */
     public function __construct(
-        \Zend\ServiceManager\ServiceManager $serviceManager,
-        \Symfony\Component\Console\Input\ArgvInput $input,
-        \Magento\Framework\Filesystem\Driver\File $filesystemDriver
+        ServiceManager $serviceManager,
+        ArgvInput $input,
+        File $filesystemDriver
     ) {
-        $this->serviceManager   = $serviceManager;
-        $this->input            = $input;
+        $this->serviceManager = $serviceManager;
+        $this->input = $input;
         $this->filesystemDriver = $filesystemDriver;
     }
 
     /**
-     * Determine whether a CLI command is for compilation, and if so, clear the directory
+     * Determine whether a CLI command is for compilation, and if so, clear the directory.
      *
-     * @throws \Magento\Framework\Exception\FileSystemException
+     * @throws FileSystemException if generation directory is read-only
      * @return void
      */
     public function handleCompilerEnvironment()
@@ -63,10 +76,30 @@ class CompilerPreparation
         $compileDirList[] = $directoryList->getPath(DirectoryList::GENERATION);
         $compileDirList[] = $directoryList->getPath(DirectoryList::DI);
 
+        if (!$this->getGenerationDirectoryAccess()->check()) {
+            throw new FileSystemException(
+                new Phrase('Generation directory can not be written.')
+            );
+        }
+
         foreach ($compileDirList as $compileDir) {
             if ($this->filesystemDriver->isExists($compileDir)) {
                 $this->filesystemDriver->deleteDirectory($compileDir);
             }
         }
     }
+
+    /**
+     * Retrieves generation directory access checker.
+     *
+     * @return GenerationDirectoryAccess the generation directory access checker
+     */
+    private function getGenerationDirectoryAccess()
+    {
+        if (null === $this->generationDirectoryAccess) {
+            $this->generationDirectoryAccess = new GenerationDirectoryAccess($this->serviceManager);
+        }
+
+        return $this->generationDirectoryAccess;
+    }
 }
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/CompilerPreparationTest.php b/setup/src/Magento/Setup/Test/Unit/Console/CompilerPreparationTest.php
index 813cb5dccc98f7ac7d34b0fdc28ff7769070bbaf..93118211062eddac065cdfe4b75bcb8f310421f3 100644
--- a/setup/src/Magento/Setup/Test/Unit/Console/CompilerPreparationTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Console/CompilerPreparationTest.php
@@ -1,48 +1,69 @@
 <?php
-/***
+/**
  * Copyright © 2013-2017 Magento, Inc. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\Setup\Test\Unit\Console;
 
-
+use Magento\Framework\Console\GenerationDirectoryAccess;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 use Magento\Setup\Console\Command\DiCompileCommand;
 use Magento\Setup\Mvc\Bootstrap\InitParamListener;
+use Magento\Framework\Filesystem\Driver\File;
 use Symfony\Component\Console\Input\ArgvInput;
+use Zend\ServiceManager\ServiceManager;
+use Magento\Setup\Console\CompilerPreparation;
+use PHPUnit_Framework_MockObject_MockObject as Mock;
 
 class CompilerPreparationTest extends \PHPUnit_Framework_TestCase
 {
-    /** @var \Magento\Setup\Console\CompilerPreparation */
+    /**
+     * @var CompilerPreparation|Mock
+     */
     private $model;
 
-    /** @var \Zend\ServiceManager\ServiceManager | \PHPUnit_Framework_MockObject_MockObject */
+    /**
+     * @var ServiceManager|Mock
+     */
     private $serviceManagerMock;
 
-    /** @var \Symfony\Component\Console\Input\ArgvInput | \PHPUnit_Framework_MockObject_MockObject */
+    /**
+     * @var ArgvInput|Mock
+     */
     private $inputMock;
 
-    /** @var \Magento\Framework\Filesystem\Driver\File | \PHPUnit_Framework_MockObject_MockObject */
+    /**
+     * @var File|Mock
+     */
     private $filesystemDriverMock;
 
+    /**
+     * @var GenerationDirectoryAccess|Mock
+     */
+    private $generationDirectoryAccessMock;
+
     public function setUp()
     {
-        $this->serviceManagerMock = $this->getMockBuilder(\Zend\ServiceManager\ServiceManager::class)
+        $this->serviceManagerMock = $this->getMockBuilder(ServiceManager::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->inputMock = $this->getMockBuilder(ArgvInput::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->inputMock = $this->getMockBuilder(\Symfony\Component\Console\Input\ArgvInput::class)
+        $this->filesystemDriverMock = $this->getMockBuilder(File::class)
             ->disableOriginalConstructor()
             ->getMock();
-        $this->filesystemDriverMock = $this->getMockBuilder(\Magento\Framework\Filesystem\Driver\File::class)
+        $this->generationDirectoryAccessMock = $this->getMockBuilder(GenerationDirectoryAccess::class)
             ->disableOriginalConstructor()
             ->getMock();
+
         $this->model = (new ObjectManager($this))->getObject(
-            \Magento\Setup\Console\CompilerPreparation::class,
+            CompilerPreparation::class,
             [
                 'serviceManager' => $this->serviceManagerMock,
                 'input' => $this->inputMock,
-                'filesystemDriver' => $this->filesystemDriverMock
+                'filesystemDriver' => $this->filesystemDriverMock,
+                'generationDirectoryAccess' => $this->generationDirectoryAccessMock,
             ]
         );
     }
@@ -56,21 +77,31 @@ class CompilerPreparationTest extends \PHPUnit_Framework_TestCase
      */
     public function testClearGenerationDirWhenNeeded($commandName, $isCompileCommand, $isHelpOption, $dirExists = false)
     {
-        $this->inputMock->expects($this->once())->method('getFirstArgument')->willReturn($commandName);
+        $this->inputMock->expects($this->once())
+            ->method('getFirstArgument')
+            ->willReturn($commandName);
         $this->inputMock->expects($this->atLeastOnce())
             ->method('hasParameterOption')
-            ->with(
-                $this->logicalOr('--help', '-h')
-            )->willReturn($isHelpOption);
+            ->with($this->logicalOr('--help', '-h'))
+            ->willReturn($isHelpOption);
+
         if ($isCompileCommand && !$isHelpOption) {
             $this->filesystemDriverMock->expects($this->exactly(2))
                 ->method('isExists')
                 ->willReturn($dirExists);
-            $this->filesystemDriverMock->expects($this->exactly(((int)$dirExists) * 2))->method('deleteDirectory');
+            $this->filesystemDriverMock->expects($this->exactly(((int)$dirExists) * 2))
+                ->method('deleteDirectory');
         } else {
-            $this->filesystemDriverMock->expects($this->never())->method('isExists');
-            $this->filesystemDriverMock->expects($this->never())->method('deleteDirectory');
+            $this->filesystemDriverMock->expects($this->never())
+                ->method('isExists');
+            $this->filesystemDriverMock->expects($this->never())
+                ->method('deleteDirectory');
         }
+
+        $this->generationDirectoryAccessMock->expects($this->any())
+            ->method('check')
+            ->willReturn(true);
+
         $this->model->handleCompilerEnvironment();
     }
 
@@ -108,10 +139,6 @@ class CompilerPreparationTest extends \PHPUnit_Framework_TestCase
         $customGenerationDirectory = '/custom/generated/code/directory';
         $defaultDiDirectory = '/custom/di/directory';
         $mageInitParams = ['MAGE_DIRS' => ['generation' => ['path' => $customGenerationDirectory]]];
-
-        $this->inputMock->expects($this->once())
-            ->method('getFirstArgument')
-            ->willReturn(DiCompileCommand::NAME);
         $dirValueMap = [
             [
                 $customGenerationDirectory,
@@ -122,16 +149,24 @@ class CompilerPreparationTest extends \PHPUnit_Framework_TestCase
                 true
             ]
         ];
-        // Filesystem mock
-        $this->filesystemDriverMock->expects($this->exactly(2))->method('isExists')->willReturn(true);
+
+        $this->inputMock->expects($this->once())
+            ->method('getFirstArgument')
+            ->willReturn(DiCompileCommand::NAME);
+        $this->filesystemDriverMock->expects($this->exactly(2))
+            ->method('isExists')
+            ->willReturn(true);
         $this->filesystemDriverMock->expects($this->exactly(2))
             ->method('deleteDirectory')
-            ->will($this->returnValueMap($dirValueMap));
-
+            ->willReturnMap($dirValueMap);
         $this->serviceManagerMock->expects($this->once())
             ->method('get')
             ->with(InitParamListener::BOOTSTRAP_PARAM)
             ->willReturn($mageInitParams);
+        $this->generationDirectoryAccessMock->expects($this->once())
+            ->method('check')
+            ->willReturn(true);
+
         $this->model->handleCompilerEnvironment();
     }
 
@@ -139,10 +174,6 @@ class CompilerPreparationTest extends \PHPUnit_Framework_TestCase
     {
         $customGenerationDirectory = '/custom/generated/code/directory';
         $customDiDirectory = '/custom/di/directory';
-        
-        $this->inputMock->expects($this->once())
-            ->method('getFirstArgument')
-            ->willReturn(DiCompileCommand::NAME);
         $dirResultMap = [
             [
                 $this->logicalNot($this->equalTo($customGenerationDirectory)),
@@ -154,10 +185,18 @@ class CompilerPreparationTest extends \PHPUnit_Framework_TestCase
             ]
         ];
 
-        $this->filesystemDriverMock->expects($this->exactly(2))->method('isExists')->willReturn(true);
+        $this->inputMock->expects($this->once())
+            ->method('getFirstArgument')
+            ->willReturn(DiCompileCommand::NAME);
+        $this->filesystemDriverMock->expects($this->exactly(2))
+            ->method('isExists')
+            ->willReturn(true);
         $this->filesystemDriverMock->expects($this->exactly(2))
             ->method('deleteDirectory')
-            ->will($this->returnValueMap($dirResultMap));
+            ->willReturnMap($dirResultMap);
+        $this->generationDirectoryAccessMock->expects($this->once())
+            ->method('check')
+            ->willReturn(true);
 
         $this->model->handleCompilerEnvironment();
     }