From e7e4da75dddc00b3adb1d23d2ec85c911a91e9ed Mon Sep 17 00:00:00 2001
From: "Gurzhyi, Andrii" <agurzhyi@ebay.com>
Date: Fri, 23 Oct 2015 21:20:50 +0300
Subject: [PATCH] MAGETWO-44443: Grunt less task fails

- Create command for deploy source files of theme
---
 app/code/Magento/Deploy/Model/Filesystem.php  |  10 +-
 .../Console/Command/CssDeployCommand.php      | 241 ------------------
 .../Command/SourceThemeDeployCommand.php      | 173 +++++++++++++
 .../FileGenerator/PublicationDecorator.php    |  20 +-
 .../Console/Command/CssDeployCommandTest.php  | 191 --------------
 app/code/Magento/Developer/etc/di.xml         |  69 ++++-
 app/code/Magento/Translation/etc/di.xml       |   4 +-
 dev/tools/grunt/configs/combo.js              |  10 +-
 8 files changed, 265 insertions(+), 453 deletions(-)
 delete mode 100644 app/code/Magento/Developer/Console/Command/CssDeployCommand.php
 create mode 100644 app/code/Magento/Developer/Console/Command/SourceThemeDeployCommand.php
 delete mode 100644 app/code/Magento/Developer/Test/Unit/Console/Command/CssDeployCommandTest.php

diff --git a/app/code/Magento/Deploy/Model/Filesystem.php b/app/code/Magento/Deploy/Model/Filesystem.php
index 178ad26a2d0..3f695ea4704 100644
--- a/app/code/Magento/Deploy/Model/Filesystem.php
+++ b/app/code/Magento/Deploy/Model/Filesystem.php
@@ -6,11 +6,10 @@
 
 namespace Magento\Deploy\Model;
 
-use Symfony\Component\Console\Output\OutputInterface;
 use Magento\Framework\App\State;
 use Magento\Framework\App\DeploymentConfig\Writer;
 use Magento\Framework\App\Filesystem\DirectoryList;
-use Magento\Developer\Console\Command\CssDeployCommand;
+use Magento\Developer\Console\Command\SourceThemeDeployCommand;
 
 /**
  * A class to manage Magento modes
@@ -137,9 +136,10 @@ class Filesystem
         $themeLocalePairs = $this->storeView->retrieveThemeLocalePairs();
         foreach ($themeLocalePairs as $themeLocalePair) {
             $theme = $themeLocalePair['theme'] ?: self::DEFAULT_THEME;
-            $cmd = $this->functionCallPath . 'dev:css:deploy less'
-                . ' --' . CssDeployCommand::THEME_OPTION . '="' . $theme . '"'
-                . ' --' . CssDeployCommand::LOCALE_OPTION . '="' . $themeLocalePair['locale'] . '"';
+            $cmd = $this->functionCallPath . 'dev:source_theme:deploy'
+                . ' --' . SourceThemeDeployCommand::TYPE_ARGUMENT . '="less"'
+                . ' --' . SourceThemeDeployCommand::THEME_OPTION . '="' . $theme . '"'
+                . ' --' . SourceThemeDeployCommand::LOCALE_OPTION . '="' . $themeLocalePair['locale'] . '"';
 
             /**
              * @todo build a solution that does not depend on exec
diff --git a/app/code/Magento/Developer/Console/Command/CssDeployCommand.php b/app/code/Magento/Developer/Console/Command/CssDeployCommand.php
deleted file mode 100644
index ac651b633d0..00000000000
--- a/app/code/Magento/Developer/Console/Command/CssDeployCommand.php
+++ /dev/null
@@ -1,241 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Developer\Console\Command;
-
-use Magento\Framework\View\Asset\PreProcessor\Pool;
-use Symfony\Component\Console\Command\Command;
-use Symfony\Component\Console\Input\InputArgument;
-use Symfony\Component\Console\Input\InputOption;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Output\OutputInterface;
-use Magento\Framework\Filesystem;
-use Magento\Framework\View\Asset\Source;
-use Magento\Framework\App\State;
-use Magento\Framework\View\Asset\Repository;
-use Magento\Framework\ObjectManagerInterface;
-use Magento\Framework\App\ObjectManager\ConfigLoader;
-use Magento\Framework\View\Asset\PreProcessor\ChainFactoryInterface;
-use Magento\Framework\App\Filesystem\DirectoryList;
-use Magento\Framework\Validator\Locale;
-
-/**
- * Class CssDeployCommand - collects, processes and publishes source files like LESS or SASS
- * @SuppressWarnings("PMD.CouplingBetweenObjects")
- */
-class CssDeployCommand extends Command
-{
-    /**
-     * Locale option key
-     */
-    const LOCALE_OPTION = 'locale';
-
-    /**
-     * Area option key
-     */
-    const AREA_OPTION = 'area';
-
-    /**
-     * Theme option key
-     */
-    const THEME_OPTION = 'theme';
-
-    /**
-     * Type argument key
-     */
-    const TYPE_ARGUMENT = 'type';
-
-    /**
-     * Files argument key
-     */
-    const FILE_ARGUMENT = 'file';
-
-    /**
-     * @var ObjectManagerInterface
-     */
-    private $objectManager;
-
-    /**
-     * @var Repository
-     */
-    private $assetRepo;
-
-    /**
-     * @var ConfigLoader
-     */
-    private $configLoader;
-
-    /**
-     * @var State
-     */
-    private $state;
-
-    /**
-     * @var Source
-     */
-    private $assetSource;
-
-    /**
-     * @var ChainFactoryInterface
-     */
-    private $chainFactory;
-
-    /**
-     * @var Filesystem
-     */
-    private $filesystem;
-
-    /**
-     * @var Locale
-     */
-    private $validator;
-
-    /**
-     * @var Pool
-     */
-    private $pool;
-
-    /**
-     * Inject dependencies
-     *
-     * @param ObjectManagerInterface $objectManager
-     * @param Repository $assetRepo
-     * @param ConfigLoader $configLoader
-     * @param State $state
-     * @param Source $assetSource
-     * @param ChainFactoryInterface $chainFactory
-     * @param Filesystem $filesystem
-     * @param Locale $validator
-     * @param Pool $pool
-     */
-    public function __construct(
-        ObjectManagerInterface $objectManager,
-        Repository $assetRepo,
-        ConfigLoader $configLoader,
-        State $state,
-        Source $assetSource,
-        ChainFactoryInterface $chainFactory,
-        Filesystem $filesystem,
-        Locale $validator,
-        Pool $pool
-    ) {
-        $this->state = $state;
-        $this->objectManager = $objectManager;
-        $this->configLoader = $configLoader;
-        $this->assetRepo = $assetRepo;
-        $this->assetSource = $assetSource;
-        $this->chainFactory = $chainFactory;
-        $this->filesystem = $filesystem;
-        $this->validator = $validator;
-
-        parent::__construct();
-        $this->pool = $pool;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    protected function configure()
-    {
-        $this->setName('dev:css:deploy')
-            ->setDescription('Collects, processes and publishes source LESS files')
-            ->setDefinition([
-                new InputArgument(
-                    self::TYPE_ARGUMENT,
-                    InputArgument::REQUIRED,
-                    'Type of dynamic stylesheet language: [less]'
-                ),
-                new InputArgument(
-                    self::FILE_ARGUMENT,
-                    InputArgument::IS_ARRAY,
-                    'Files to pre-process (file should be specified without extension)',
-                    ['css/styles-m']
-                ),
-                new InputOption(
-                    self::LOCALE_OPTION,
-                    null,
-                    InputOption::VALUE_REQUIRED,
-                    'Locale',
-                    'en_US'
-                ),
-                new InputOption(
-                    self::AREA_OPTION,
-                    null,
-                    InputOption::VALUE_REQUIRED,
-                    'Area, one of [frontend|adminhtml]',
-                    'frontend'
-                ),
-                new InputOption(
-                    self::THEME_OPTION,
-                    null,
-                    InputOption::VALUE_REQUIRED,
-                    'Theme in format Vendor/theme',
-                    'Magento/blank'
-                ),
-
-            ]);
-
-        parent::configure();
-    }
-
-    /**
-     * {@inheritdoc}
-     * @throws \InvalidArgumentException
-     */
-    protected function execute(InputInterface $input, OutputInterface $output)
-    {
-        $locale = $input->getOption(self::LOCALE_OPTION);
-
-        if (!$this->validator->isValid($locale)) {
-            throw new \InvalidArgumentException(
-                $locale . ' argument has invalid value, please run info:language:list for list of available locales'
-            );
-        }
-
-        $area = $input->getOption(self::AREA_OPTION);
-        $theme = $input->getOption(self::THEME_OPTION);
-
-        $type = $input->getArgument(self::TYPE_ARGUMENT);
-
-        $this->state->setAreaCode($area);
-        $this->objectManager->configure($this->configLoader->load($area));
-
-        foreach ($input->getArgument(self::FILE_ARGUMENT) as $file) {
-            $file .= '.' . $type;
-
-            $output->writeln("<info>Gathering {$file} sources.</info>");
-
-            $asset = $this->assetRepo->createAsset(
-                $file,
-                [
-                    'area' => $area,
-                    'theme' => $theme,
-                    'locale' => $locale,
-                ]
-            );
-
-            $rootDir = $this->filesystem->getDirectoryWrite(DirectoryList::ROOT);
-            $sourceFile = $this->assetSource->findSource($asset);
-            $relativePath = $rootDir->getRelativePath($sourceFile);
-            $content = $rootDir->readFile($relativePath);
-
-            $chain = $this->chainFactory->create(
-                [
-                    'asset'           => $asset,
-                    'origContent'     => $content,
-                    'origContentType' => $asset->getContentType(),
-                    'origAssetPath'   => $relativePath
-                ]
-            );
-
-            $this->pool->process($chain);
-            $targetDir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW);
-            $targetDir->writeFile($chain->getAsset()->getPath(), $chain->getContent());
-
-            $output->writeln('<info>Successfully processed dynamic stylesheet into CSS</info>');
-        }
-    }
-}
diff --git a/app/code/Magento/Developer/Console/Command/SourceThemeDeployCommand.php b/app/code/Magento/Developer/Console/Command/SourceThemeDeployCommand.php
new file mode 100644
index 00000000000..4ae886b3b8d
--- /dev/null
+++ b/app/code/Magento/Developer/Console/Command/SourceThemeDeployCommand.php
@@ -0,0 +1,173 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Developer\Console\Command;
+
+use Magento\Framework\App\State;
+use Magento\Framework\Validator\Locale;
+use Magento\Framework\View\Asset\Repository;
+use Symfony\Component\Console\Command\Command;
+use Magento\Framework\App\View\Asset\Publisher;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Class SourceThemeDeployCommand
+ *
+ * Collects and publishes source files for theme
+ */
+class SourceThemeDeployCommand extends Command
+{
+    /**
+     * Locale option key
+     */
+    const LOCALE_OPTION = 'locale';
+
+    /**
+     * Area option key
+     */
+    const AREA_OPTION = 'area';
+
+    /**
+     * Theme option key
+     */
+    const THEME_OPTION = 'theme';
+
+    /**
+     * Type argument key
+     */
+    const TYPE_ARGUMENT = 'type';
+
+    /**
+     * Files argument key
+     */
+    const FILE_ARGUMENT = 'file';
+
+    /**
+     * @var Locale
+     */
+    private $validator;
+
+    /**
+     * @var Publisher
+     */
+    private $assetPublisher;
+
+    /**
+     * @var Repository
+     */
+    private $assetRepository;
+
+    /**
+     * Constructor
+     *
+     * @param Locale $validator
+     * @param Publisher $assetPublisher
+     * @param Repository $assetRepository
+     */
+    public function __construct(
+        Locale $validator,
+        Publisher $assetPublisher,
+        Repository $assetRepository
+    ) {
+        parent::__construct('dev:source_theme:deploy');
+        $this->validator = $validator;
+        $this->assetPublisher = $assetPublisher;
+        $this->assetRepository = $assetRepository;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        parent::configure();
+        $this->setDescription('Collects and publishes source files for theme.')
+            ->setDefinition([
+                new InputArgument(
+                    self::FILE_ARGUMENT,
+                    InputArgument::IS_ARRAY,
+                    'Files to pre-process (file should be specified without extension)',
+                    ['css/styles-m', 'css/styles-l']
+                ),
+                new InputOption(
+                    self::TYPE_ARGUMENT,
+                    null,
+                    InputOption::VALUE_REQUIRED,
+                    'Type of source files: [less]',
+                    'less'
+                ),
+                new InputOption(
+                    self::LOCALE_OPTION,
+                    null,
+                    InputOption::VALUE_REQUIRED,
+                    'Locale: [en_US]',
+                    'en_US'
+                ),
+                new InputOption(
+                    self::AREA_OPTION,
+                    null,
+                    InputOption::VALUE_REQUIRED,
+                    'Area: [frontend|adminhtml]',
+                    'frontend'
+                ),
+                new InputOption(
+                    self::THEME_OPTION,
+                    null,
+                    InputOption::VALUE_REQUIRED,
+                    'Theme: [Vendor/theme]',
+                    'Magento/luma'
+                ),
+
+            ]);
+    }
+
+    /**
+     * @inheritdoc
+     * @throws \InvalidArgumentException
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $area = $input->getOption(self::AREA_OPTION);
+        $locale = $input->getOption(self::LOCALE_OPTION);
+        $theme = $input->getOption(self::THEME_OPTION);
+        $type = $input->getOption(self::TYPE_ARGUMENT);
+
+        $files = $input->getArgument(self::FILE_ARGUMENT);
+
+        if (!$this->validator->isValid($locale)) {
+            throw new \InvalidArgumentException(
+                $locale . ' argument has invalid value, please run info:language:list for list of available locales'
+            );
+        }
+        $message = sprintf(
+            '<info>Processed Area: %s, Locale: %s, Theme: %s, File type: %s.</info>',
+            $area,
+            $locale,
+            $theme,
+            $type
+        );
+        $output->writeln($message);
+
+        foreach ($files as $file) {
+            $fileInfo = pathinfo($file);
+            $asset = $this->assetRepository->createAsset(
+                $fileInfo['dirname'] . DIRECTORY_SEPARATOR . $fileInfo['basename'] . '.' . $type,
+                [
+                    'area' => $area,
+                    'theme' => $theme,
+                    'locale' => $locale,
+                ]
+            );
+
+            $this->assetPublisher->publish($asset);
+            $output->writeln('<comment>-> ' . $asset->getFilePath() . '</comment>');
+        }
+
+        $output->writeln('<info>Successfully processed stylesheet</info>');
+    }
+}
diff --git a/app/code/Magento/Developer/Model/Css/PreProcessor/FileGenerator/PublicationDecorator.php b/app/code/Magento/Developer/Model/Css/PreProcessor/FileGenerator/PublicationDecorator.php
index 79c47044319..7c14c8f9e1d 100644
--- a/app/code/Magento/Developer/Model/Css/PreProcessor/FileGenerator/PublicationDecorator.php
+++ b/app/code/Magento/Developer/Model/Css/PreProcessor/FileGenerator/PublicationDecorator.php
@@ -5,45 +5,47 @@
  */
 namespace Magento\Developer\Model\Css\PreProcessor\FileGenerator;
 
-use Magento\Framework\Css\PreProcessor\FileGenerator\RelatedGenerator;
 use Magento\Framework\View\Asset\LocalInterface;
+use Magento\Framework\Css\PreProcessor\FileGenerator\RelatedGenerator;
 
 /**
  * Class PublicationDecorator
- * Decorates generator of related assets and publishes them
  *
- * @package Magento\Developer\Model\Less\FileGenerator
+ * Decorates generator of related assets and publishes them
  */
 class PublicationDecorator extends RelatedGenerator
 {
     /**
      * @var \Magento\Framework\App\View\Asset\Publisher
      */
-    private $publisher;
+    private $assetPublisher;
 
     /**
+     * Constructor
+     *
      * @param \Magento\Framework\Filesystem $filesystem
      * @param \Magento\Framework\View\Asset\Repository $assetRepo
      * @param \Magento\Framework\Css\PreProcessor\File\Temporary $temporaryFile
-     * @param \Magento\Framework\App\View\Asset\Publisher $publisher
+     * @param \Magento\Framework\App\View\Asset\Publisher $assetPublisher
      */
     public function __construct(
         \Magento\Framework\Filesystem $filesystem,
         \Magento\Framework\View\Asset\Repository $assetRepo,
         \Magento\Framework\Css\PreProcessor\File\Temporary $temporaryFile,
-        \Magento\Framework\App\View\Asset\Publisher $publisher
+        \Magento\Framework\App\View\Asset\Publisher $assetPublisher
     ) {
         parent::__construct($filesystem, $assetRepo, $temporaryFile);
-        $this->publisher = $publisher;
+        $this->assetPublisher = $assetPublisher;
     }
 
     /**
-     * {inheritdoc}
+     * @inheritdoc
      */
     protected function generateRelatedFile($relatedFileId, LocalInterface $asset)
     {
         $relatedAsset = parent::generateRelatedFile($relatedFileId, $asset);
-        $this->publisher->publish($relatedAsset);
+        $this->assetPublisher->publish($relatedAsset);
+
         return $relatedAsset;
     }
 }
diff --git a/app/code/Magento/Developer/Test/Unit/Console/Command/CssDeployCommandTest.php b/app/code/Magento/Developer/Test/Unit/Console/Command/CssDeployCommandTest.php
deleted file mode 100644
index 0d930989e42..00000000000
--- a/app/code/Magento/Developer/Test/Unit/Console/Command/CssDeployCommandTest.php
+++ /dev/null
@@ -1,191 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Developer\Test\Unit\Console\Command;
-
-use Magento\Framework\Filesystem;
-use Magento\Framework\View\Asset\PreProcessor\Pool;
-use Magento\Framework\View\Asset\Source;
-use Magento\Framework\App\State;
-use Magento\Framework\View\Asset\Repository;
-use Magento\Framework\ObjectManagerInterface;
-use Magento\Framework\App\ObjectManager\ConfigLoader;
-use Magento\Framework\View\Asset\PreProcessor\ChainFactoryInterface;
-use Magento\Developer\Console\Command\CssDeployCommand;
-use Symfony\Component\Console\Tester\CommandTester;
-use Magento\Framework\Validator\Locale;
-
-/**
- * Class CssDeployCommandTest
- */
-class CssDeployCommandTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var CssDeployCommand
-     */
-    private $command;
-
-    /**
-     * @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $objectManager;
-
-    /**
-     * @var Repository|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $assetRepo;
-
-    /**
-     * @var ConfigLoader|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $configLoader;
-
-    /**
-     * @var State|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $state;
-
-    /**
-     * @var Source|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $assetSource;
-
-    /**
-     * @var ChainFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $chainFactory;
-
-    /**
-     * @var Filesystem|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $filesystem;
-
-    /**
-     * @var Locale|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $validator;
-
-    /**
-     * @var Pool|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $poolMock;
-
-    public function setUp()
-    {
-        $this->objectManager = $this->getMockForAbstractClass('Magento\Framework\ObjectManagerInterface');
-        $this->assetRepo = $this->getMock('Magento\Framework\View\Asset\Repository', [], [], '', false);
-        $this->configLoader = $this->getMock('Magento\Framework\App\ObjectManager\ConfigLoader', [], [], '', false);
-        $this->state = $this->getMock('Magento\Framework\App\State', [], [], '', false);
-        $this->assetSource = $this->getMock('Magento\Framework\View\Asset\Source', [], [], '', false);
-        $this->chainFactory = $this->getMockForAbstractClass(
-            'Magento\Framework\View\Asset\PreProcessor\ChainFactoryInterface'
-        );
-        $this->filesystem = $this->getMock('Magento\Framework\Filesystem', [], [], '', false);
-        $this->validator = $this->getMock('Magento\Framework\Validator\Locale', [], [], '', false);
-        $this->poolMock = $this->getMockBuilder('Magento\Framework\View\Asset\PreProcessor\Pool')
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $this->command = new CssDeployCommand(
-            $this->objectManager,
-            $this->assetRepo,
-            $this->configLoader,
-            $this->state,
-            $this->assetSource,
-            $this->chainFactory,
-            $this->filesystem,
-            $this->validator,
-            $this->poolMock
-        );
-    }
-
-    public function testExecute()
-    {
-        $file = 'css/styles-m' . '.less';
-
-        $this->configLoader->expects($this->once())->method('load')->with('frontend')->willReturn([]);
-        $this->objectManager->expects($this->once())->method('configure');
-        $asset = $this->getMockForAbstractClass('Magento\Framework\View\Asset\LocalInterface');
-        $asset->expects($this->once())->method('getContentType')->willReturn('type');
-        $this->assetRepo->expects($this->once())
-            ->method('createAsset')
-            ->with(
-                $file,
-                [
-                    'area' => 'frontend',
-                    'theme' => 'Magento/blank',
-                    'locale' => 'en_US'
-                ]
-            )
-            ->willReturn($asset);
-        $this->assetSource->expects($this->once())->method('findSource')->willReturn('/dev/null');
-
-        $chainMock = $this->getMock('Magento\Framework\View\Asset\PreProcessor\Chain', [], [], '', false);
-        $assetMock = $this->getMockBuilder('Magento\Framework\View\Asset\LocalInterface')
-            ->getMockForAbstractClass();
-
-        $this->chainFactory->expects($this->once())
-            ->method('create')
-            ->with(
-                [
-                    'asset' => $asset,
-                    'origContent' => 'content',
-                    'origContentType' => 'type',
-                    'origAssetPath' => 'relative/path',
-                ]
-            )->willReturn($chainMock);
-
-        $chainMock->expects(self::once())
-            ->method('getAsset')
-            ->willReturn($assetMock);
-
-        $rootDir = $this->getMock('\Magento\Framework\Filesystem\Directory\WriteInterface', [], [], '', false);
-        $this->filesystem->expects($this->at(0))->method('getDirectoryWrite')->willReturn($rootDir);
-        $this->filesystem->expects($this->at(1))->method('getDirectoryWrite')->willReturn(
-            $this->getMock('\Magento\Framework\Filesystem\Directory\WriteInterface', [], [], '', false)
-        );
-        $rootDir->expects($this->atLeastOnce())->method('getRelativePath')->willReturn('relative/path');
-        $rootDir->expects($this->once())->method('readFile')->willReturn('content');
-
-        $this->validator->expects($this->once())->method('isValid')->with('en_US')->willReturn(true);
-
-        $commandTester = new CommandTester($this->command);
-        $commandTester->execute(
-            [
-                'type' => 'less'
-            ]
-        );
-        $this->assertContains(
-            'Successfully processed dynamic stylesheet into CSS',
-            $commandTester->getDisplay()
-        );
-    }
-
-    /**
-     * @expectedException \RuntimeException
-     * @expectedExceptionMessage Not enough arguments
-     */
-    public function testExecuteWithoutParameters()
-    {
-        $commandTester = new CommandTester($this->command);
-        $commandTester->execute([]);
-    }
-
-    /**
-     * @expectedException \InvalidArgumentException
-     * @expectedExceptionMessage WRONG_LOCALE argument has invalid value, please run info:language:list
-     */
-    public function testExecuteWithWrongFormat()
-    {
-        $commandTester = new CommandTester($this->command);
-        $commandTester->execute(
-            [
-                'type' => 'less',
-                '--locale' => 'WRONG_LOCALE'
-            ]
-        );
-    }
-}
diff --git a/app/code/Magento/Developer/etc/di.xml b/app/code/Magento/Developer/etc/di.xml
index a208ec7c5de..25b49f280fd 100644
--- a/app/code/Magento/Developer/etc/di.xml
+++ b/app/code/Magento/Developer/etc/di.xml
@@ -23,11 +23,67 @@
             </argument>
         </arguments>
     </type>
+
+    <virtualType name="AssetMaterializationStrategySourceThemeDeployFactory" type="Magento\Framework\App\View\Asset\MaterializationStrategy\Factory">
+        <arguments>
+            <argument name="strategiesList" xsi:type="array">
+                <item name="symlink" xsi:type="object">Magento\Framework\App\View\Asset\MaterializationStrategy\Symlink</item>
+                <item name="copy" xsi:type="object">Magento\Framework\App\View\Asset\MaterializationStrategy\Copy</item>
+            </argument>
+        </arguments>
+    </virtualType>
+    <virtualType name="AssetPublisherSourceThemeDeploy" type="Magento\Framework\App\View\Asset\Publisher">
+        <arguments>
+            <argument name="materializationStrategyFactory" xsi:type="object">AssetMaterializationStrategySourceThemeDeployFactory</argument>
+        </arguments>
+    </virtualType>
+    <type name="Magento\Developer\Model\Css\PreProcessor\FileGenerator\PublicationDecorator">
+        <arguments>
+            <argument name="assetPublisher" xsi:type="object">AssetPublisherSourceThemeDeploy</argument>
+        </arguments>
+    </type>
+    <virtualType name="PreProcessorInstructionImportSourceThemeDeploy" type="Magento\Framework\Css\PreProcessor\Instruction\Import">
+        <arguments>
+            <argument name="relatedFileGenerator" xsi:type="object">Magento\Developer\Model\Css\PreProcessor\FileGenerator\PublicationDecorator</argument>
+        </arguments>
+    </virtualType>
+    <virtualType name="AssetPreProcessorPoolSourceThemeDeploy" type="Magento\Framework\View\Asset\PreProcessor\Pool">
+        <arguments>
+            <argument name="preprocessors" xsi:type="array">
+                <item name="less" xsi:type="array">
+                    <item name="magento_import" xsi:type="array">
+                        <item name="class" xsi:type="string">Magento\Framework\Css\PreProcessor\Instruction\MagentoImport</item>
+                    </item>
+                    <item name="import" xsi:type="array">
+                        <item name="after" xsi:type="string">magento_import</item>
+                        <item name="class" xsi:type="string">PreProcessorInstructionImportSourceThemeDeploy</item>
+                    </item>
+                </item>
+            </argument>
+        </arguments>
+    </virtualType>
+    <virtualType name="AssetSourceSourceThemeDeploy" type="Magento\Framework\View\Asset\Source">
+        <arguments>
+            <argument name="preProcessorPool" xsi:type="object">AssetPreProcessorPoolSourceThemeDeploy</argument>
+        </arguments>
+    </virtualType>
+    <virtualType name="AssetRepositorySourceThemeDeploy" type="Magento\Framework\View\Asset\Repository">
+        <arguments>
+            <argument name="assetSource" xsi:type="object">AssetSourceSourceThemeDeploy</argument>
+        </arguments>
+    </virtualType>
+    <type name="Magento\Developer\Console\Command\SourceThemeDeployCommand">
+        <arguments>
+            <argument name="assetPublisher" xsi:type="object">AssetPublisherSourceThemeDeploy</argument>
+            <argument name="assetRepository" xsi:type="object">AssetRepositorySourceThemeDeploy</argument>
+        </arguments>
+    </type>
+
     <type name="Magento\Framework\Console\CommandList">
         <arguments>
             <argument name="commands" xsi:type="array">
                 <item name="dev_tests_run" xsi:type="object">Magento\Developer\Console\Command\DevTestsRunCommand</item>
-                <item name="dev_css_deploy" xsi:type="object">Magento\Developer\Console\Command\CssDeployCommand</item>
+                <item name="dev_source_theme_deploy" xsi:type="object">Magento\Developer\Console\Command\SourceThemeDeployCommand</item>
                 <item name="xml_converter" xsi:type="object">Magento\Developer\Console\Command\XmlConverterCommand</item>
             </argument>
         </arguments>
@@ -62,6 +118,11 @@
     <type name="Magento\Framework\View\Asset\PreProcessor\Pool">
         <arguments>
             <argument name="defaultPreprocessor" xsi:type="string">Magento\Framework\View\Asset\PreProcessor\Passthrough</argument>
+        </arguments>
+    </type>
+
+    <virtualType name="AssetPreProcessorPool" type="Magento\Framework\View\Asset\PreProcessor\Pool">
+        <arguments>
             <argument name="preprocessors" xsi:type="array">
                 <item name="less" xsi:type="array">
                     <item name="magento_import" xsi:type="array">
@@ -96,6 +157,12 @@
                 </item>
             </argument>
         </arguments>
+    </virtualType>
+
+    <type name="Magento\Framework\View\Asset\Source">
+        <arguments>
+            <argument name="preProcessorPool" xsi:type="object">AssetPreProcessorPool</argument>
+        </arguments>
     </type>
 
     <type name="Magento\Framework\Css\PreProcessor\Instruction\MagentoImport">
diff --git a/app/code/Magento/Translation/etc/di.xml b/app/code/Magento/Translation/etc/di.xml
index 05c7f766a45..7d2ec64b604 100644
--- a/app/code/Magento/Translation/etc/di.xml
+++ b/app/code/Magento/Translation/etc/di.xml
@@ -64,7 +64,7 @@
         </arguments>
     </type>
 
-    <type name="Magento\Framework\View\Asset\PreProcessor\Pool">
+    <virtualType name="AssetPreProcessorPool">
         <arguments>
             <argument name="preprocessors" xsi:type="array">
                 <item name="js" xsi:type="array">
@@ -79,7 +79,7 @@
                 </item>
             </argument>
         </arguments>
-    </type>
+    </virtualType>
 
     <type name="Magento\Framework\Console\CommandList">
         <arguments>
diff --git a/dev/tools/grunt/configs/combo.js b/dev/tools/grunt/configs/combo.js
index cd3484eee78..f86a47261b8 100644
--- a/dev/tools/grunt/configs/combo.js
+++ b/dev/tools/grunt/configs/combo.js
@@ -16,10 +16,12 @@ module.exports = {
         var cmdPlus = /^win/.test(process.platform) ? ' & ' : ' && ',
             command = 'grunt --force clean:' + themeName + cmdPlus;
 
-        command = command + 'php bin/magento dev:css:deploy ' + theme[themeName].dsl + ' ' + theme[themeName].files.join(' ') +
-        ' --locale=' + theme[themeName].locale +
-        ' --area=' + theme[themeName].area +
-        ' --theme=' + theme[themeName].name;
+        command = command + 'php bin/magento dev:source_theme:deploy ' +
+            theme[themeName].files.join(' ') +
+            ' --type=less' +
+            ' --locale=' + theme[themeName].locale +
+            ' --area=' + theme[themeName].area +
+            ' --theme=' + theme[themeName].name;
 
         return command;
     },
-- 
GitLab