Browse Source

folder sync shell

euromark 13 years ago
parent
commit
c61a69eb8f
1 changed files with 205 additions and 0 deletions
  1. 205 0
      Console/Command/FolderSyncShell.php

+ 205 - 0
Console/Command/FolderSyncShell.php

@@ -0,0 +1,205 @@
+<?php
+App::uses('Folder', 'Utility');
+App::uses('File', 'Utility');
+App::uses('AppShell', 'Console/Command');
+
+/**
+ * Folder Sync Shell to update all files from location a with new files from location b
+ *
+ * @version 1.0
+ * @cakephp 2.x
+ * @author Mark Scherer
+ * @license MIT
+ * 2012-07-18 ms
+ */
+class FolderSyncShell extends AppShell {
+
+	public $sourceFolder = null;
+
+	public $targetFolder = null;
+
+	public $files = 0;
+
+	public $missing = array();
+
+	public $updatedFiles = 0;
+
+	public $removedFiles = 0;
+
+	public $excludes = array('.git', '.svn');
+
+	/**
+	 * main
+	 *
+	 * @return void
+	 * 2012-07-18 ms
+	 */
+	public function main() {
+		$this->help();
+	}
+
+	/**
+	 * main
+	 *
+	 * @return void
+	 * 2012-07-18 ms
+	 */
+	public function update() {
+		$this->sourceFolder = $this->params['source'];
+		if (empty($this->sourceFolder)) {
+			$this->sourceFolder = APP;
+			if (!empty($this->params['plugin'])) {
+				$this->sourceFolder = CakePlugin::path($this->params['plugin']);
+			}
+		}
+		if ($this->sourceFolder) {
+			$this->sourceFolder = realpath($this->sourceFolder);
+		}
+		if (!empty($this->params['target'])) {
+			$this->targetFolder = realpath($this->params['target']);
+		}
+		if (!$this->sourceFolder || !is_dir($this->sourceFolder)) {
+			$this->error('Folder not exists', 'Please specify a valid source folder');
+		}
+		if (!$this->targetFolder || !is_dir($this->targetFolder)) {
+			$this->error('Folder not exists', 'Please specify a valid target folder');
+		}
+
+		$this->out('From: '.$this->sourceFolder);
+		$this->out('To: '.$this->targetFolder);
+
+		$excludes = $this->excludes;
+		$this->_sync($this->sourceFolder, $this->targetFolder, $excludes);
+
+		$this->out(__('Files: %s', $this->files));
+		$this->out();
+
+		if (!empty($this->missing)) {
+			$this->out(__('%s missing files', count($this->missing)));
+			foreach ($this->missing as $missing) {
+				$this->out('- '.$missing);
+			}
+			$this->out();
+		}
+
+		if ($this->updatedFiles) {
+			$this->out(__('%s target files updated', $this->updatedFiles));
+		}
+		if ($this->removedFiles) {
+			$this->out(__('%s source files removed', $this->removedFiles));
+		}
+		if (!$this->updatedFiles && !$this->removedFiles) {
+			$this->out('(nothing to do)');
+		}
+	}
+
+
+	protected function _sync($from, $to, $excludes = array()) {
+		$Folder = new Folder($to);
+		$content = $Folder->read(true, true, true);
+		foreach ($content[0] as $folder) {
+			$targetFolder = $folder;
+			$folder = str_replace($this->targetFolder, '', $targetFolder);
+			$sourceFolder = $this->sourceFolder . $folder;
+			$this->_sync($sourceFolder, $targetFolder, $excludes);
+		}
+		foreach ($content[1] as $file) {
+			$targetFile = $file;
+			$file = str_replace($this->targetFolder, '', $targetFile);
+			$sourceFile = $this->sourceFolder . $file;
+			$this->updateFile($targetFile, $sourceFile, $file);
+		}
+	}
+
+	/**
+	 * @param target
+	 * @param source - does not have to exists
+	 * @return void;
+	 */
+	protected function updateFile($target, $source, $name = null) {
+		if (!empty($this->params['verbose'])) {
+			if (!$name) {
+				$name = $target;
+			}
+			$this->out('- '.$name);
+		}
+		$this->files++;
+
+		$sourceExists = file_exists($source);
+		if (!$sourceExists && !empty($this->params['remove'])) {
+			if (empty($this->params['dry-run']) && !unlink($target)) {
+				throw new InternalErrorException('no rights');
+			}
+			$this->missing[] = $name;
+			$this->removedFiles++;
+			return;
+		} elseif (!$sourceExists) {
+			$this->missing[] = $name;
+			return;
+		}
+		if (sha1(file_get_contents($source)) === sha1(file_get_contents($target))) {
+			return;
+		}
+		if (empty($this->params['dry-run']) && !copy($source, $target)) {
+			throw new InternalErrorException('no rights');
+		}
+		$this->updatedFiles++;
+	}
+
+
+	public function help() {
+		$head  = __("Usage: cake FolderSync <command>") . "\n";
+		$head .= "-----------------------------------------------\n";
+		$head .= __("Commands:") . "\n\n";
+
+		$head .= "\t" . 'update' . "\n\n";
+		//$head .= "\t" . 'update' . "\n\n";
+
+		$this->out($head);
+	}
+
+	public function getOptionParser() {
+		$subcommandParser = array(
+			'options' => array(
+				'source'=> array(
+					'short' => 's',
+					'help' => __d('cake_console', 'source - defaults to app'),
+					'default' => '',
+				),
+				'target'=> array(
+					'short' => 't',
+					'help' => __d('cake_console', 'target - required'),
+					'default' => '',
+				),
+				'plugin' => array(
+					'short' => 'p',
+					'help' => __d('cake_console', 'The plugin folder - can only be used with app as source'),
+					'default' => '',
+				),
+				'remove' => array(
+					'short' => 'r',
+					'help' => __d('cake_console', 'Remove files if source is non-existent'),
+					'boolean' => true
+				),
+				'dry-run'=> array(
+					'short' => 'd',
+					'help' => __d('cake_console', 'Dry run the update, no files will actually be modified.'),
+					'boolean' => true
+				),
+				'log'=> array(
+					'short' => 'l',
+					'help' => __d('cake_console', 'Log all ouput to file log.txt in TMP dir'),
+					'boolean' => true
+				),
+			)
+		);
+
+		return parent::getOptionParser()
+			->description(__d('cake_console', "..."))
+			->addSubcommand('update', array(
+				'help' => __d('cake_console', 'Update'),
+				'parser' => $subcommandParser
+			));
+	}
+
+}