protected function execute(InputInterface $input, OutputInterface $output)
 {
     $files = $input->getArgument('files');
     if (!$files) {
         $files = array(getcwd());
     }
     $iterator = new RecursiveSourcesIterator($files);
     if (!$input->getOption('dotfiles')) {
         $iterator = new DotfilesFilter($iterator);
     }
     $scanner = new TreeScanner($output);
     $scanner->scanTree($iterator);
     $strings = $scanner->getStrings();
     $output->writeln("<info>{$strings->count()} translatable strings detected</info>");
     $locales = new CsvFilter(new \RecursiveIteratorIterator($iterator));
     $csvCount = iterator_count($locales);
     $output->writeln("<info>{$csvCount} CSV file(s) found</info>");
     /* @var $locale SourceFileInfo */
     foreach ($locales as $locale) {
         $csv = new Strings();
         $csv->fromCsvFile($locale->getPathname());
         $add = $strings->subtract($csv);
         $delete = $csv->subtract($strings);
         if ($add->count() || $delete->count()) {
             $output->writeln("<info>Adding {$add->count()} strings to and removing {$delete->count()} strings from {$locale->getRelativePathname()}</info>");
             $csv->merge($add)->subtract($delete)->toCsvFile($locale->getPathname());
         }
     }
 }
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $changed = $this->getChangedFiles($input->getArgument('before'), $input->getArgument('after'));
     if (!$changed) {
         $output->writeln('<info>Cannot detect any difference</info>');
         return;
     }
     $before = $this->getFiles($input->getArgument('before'));
     $after = $this->getFiles($input->getArgument('after'));
     // attempt to prioritise changed files and quit early if safe
     if ($before instanceof \ArrayAccess && $after instanceof \ArrayAccess) {
         // keys of both should be paths relative to repo
         $beforeScanner = new TreeScanner($output);
         $afterScanner = new TreeScanner($output);
         foreach ($changed as $filename) {
             if (isset($before[$filename])) {
                 $beforeScanner->scanFile($before[$filename]);
                 unset($before[$filename]);
             }
             if (isset($after[$filename])) {
                 $afterScanner->scanFile($after[$filename]);
                 unset($after[$filename]);
             }
         }
         // strings are ArrayObjects so comparison is easy
         if ($beforeScanner->getStrings() == $afterScanner->getStrings()) {
             $output->writeln('<info>Cannot detect significant difference in changed files</info>');
             return;
         }
         if ($output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE) {
             $output->writeln('<comment>Immediate files show a significant difference</comment>');
         }
         // continue with rest of project files
         $beforeScanner->scanTree($before);
         $beforeStrings = $beforeScanner->getStrings();
         $afterScanner->scanTree($after);
         $afterStrings = $afterScanner->getStrings();
     } else {
         $beforeStrings = $this->getStrings($before, $output);
         $afterStrings = $this->getStrings($after, $output);
     }
     $add = $afterStrings->subtract($beforeStrings);
     $delete = $beforeStrings->subtract($afterStrings);
     if ($output->getVerbosity() === OutputInterface::VERBOSITY_NORMAL) {
         $output->writeln("<info>{$add->count()} strings to be added and {$delete->count()} to be removed</info>");
     } else {
         $output->writeln('<info>Add the following:</info>');
         $output->writeln($add->toCsvArray());
         $output->writeln('<info>Remove the following:</info>');
         $output->writeln($delete->toCsvArray());
     }
     if (!$add->count() && !$delete->count()) {
         // nothing to do
         return;
     }
     // if update-dir is null, realpath defaults to cwd
     $updateDir = realpath($input->getOption('update-dir'));
     $dir = new RecursiveSourcesIterator(array($updateDir));
     $locales = new CsvFilter(new \RecursiveIteratorIterator($dir));
     $csvCount = iterator_count($locales);
     $output->writeln("<info>{$csvCount} CSV file(s) found</info>");
     /* @var $locale SourceFileInfo */
     foreach ($locales as $locale) {
         $csv = new Strings();
         $csv->fromCsvFile($locale->getPathname());
         // careful to not overwrite good translations
         $csvAdd = $add->subtract($csv);
         // count deletions which actually have an effect
         $csvDel = $delete->subtract($csv);
         if ($csvAdd->count() || $csvDel->count()) {
             $output->writeln("<info>Adding {$csvAdd->count()} strings to and removing {$csvDel->count()} strings from {$locale->getRelativePathname()}</info>");
             $csv->merge($csvAdd)->subtract($csvDel)->toCsvFile($locale->getPathname());
             exec('git add ' . escapeshellarg($locale->getPathname()));
         }
     }
 }