public static function importTree($sourcePath, $destinationPath, $options = array())
 {
     $options = array_merge(array('exclude' => array(), 'delete' => true, 'debug' => false), $options);
     // backwords compatibility
     if (isset($options['transferDelete'])) {
         $options['delete'] = (bool) $options['transferDelete'];
         unset($options['transferDelete']);
     }
     // check source
     if (!is_readable($sourcePath)) {
         throw new Exception("Source \"{$sourcePath}\" unreadable");
     }
     if (!empty($options['exclude']) && is_string($options['exclude'])) {
         $options['exclude'] = array($options['exclude']);
     }
     // normalize input paths
     $sourcePath = rtrim($sourcePath, '/');
     if (!$destinationPath || $destinationPath == '/') {
         $destinationPath = null;
     } else {
         $destinationPath = trim($sourcePath, '/');
     }
     // initialize state
     $prefixLen = strlen($sourcePath);
     $collectionsAnalyzed = 0;
     $collectionsDeleted = 0;
     $filesAnalyzed = 0;
     $filesExcluded = 0;
     $filesUpdated = 0;
     $filesDeleted = 0;
     // get complete list of directories existing in destination, build map of local collections
     $destinationCollectionsTree = static::getTree($destinationPath);
     $localDestinationCollectionsMap = array();
     foreach ($destinationCollectionsTree as &$collectionInfo) {
         if ($collectionInfo['Site'] != 'Local') {
             continue;
         }
         if ($collectionInfo['ParentID'] && isset($destinationCollectionsTree[$collectionInfo['ParentID']])) {
             $collectionInfo['_path'] = $destinationCollectionsTree[$collectionInfo['ParentID']]['_path'] . '/' . $collectionInfo['Handle'];
             $localDestinationCollectionsMap[$collectionInfo['_path']] =& $collectionInfo;
         } elseif (!$collectionInfo['ParentID']) {
             $collectionInfo['_path'] = $collectionInfo['Handle'];
         } else {
             $collectionInfo['_path'] = $destinationPath;
         }
     }
     // get complete list of files existing in destination, build map of all by path
     $destinationFilesMap = static::getTreeFilesFromTree($destinationCollectionsTree);
     // configure iterator
     $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($sourcePath, FilesystemIterator::CURRENT_AS_SELF | FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST);
     // iterate through all source files
     foreach ($iterator as $tmpPath => $node) {
         $relPath = substr($tmpPath, $prefixLen);
         $path = $destinationPath ? $destinationPath . $relPath : ltrim($relPath, '/');
         if ($options['debug']) {
             Debug::dump(array('tmpPath' => $tmpPath, 'destPath' => $path), false, 'iterating node');
         }
         if (static::matchesExclude($relPath, $options['exclude'])) {
             $filesExcluded++;
             continue;
         }
         // handle directory
         if ($node->isDir()) {
             SiteCollection::getOrCreatePath($path);
             $collectionsAnalyzed++;
             // erase from destination map
             unset($localDestinationCollectionsMap[$path]);
             continue;
         } else {
             $filesAnalyzed++;
         }
         $existingNode = isset($destinationFilesMap[$path]) ? $destinationFilesMap[$path] : null;
         // calculate hash for incoming file
         $sha1 = sha1_file($node->getRealPath());
         // skip if existing local or remote file matches hash
         if (!$existingNode || $existingNode['SHA1'] != $sha1) {
             if ($options['debug']) {
                 print "Found SHA1 mismatch {$existingNode['SHA1']} != {$sha1}<br>";
             }
             // use lower level create methods to supply already-calculated hash
             $fileRecord = SiteFile::createFromPath($path, null, $existingNode['ID']);
             SiteFile::saveRecordData($fileRecord, fopen($node->getPathname(), 'r'), $sha1);
             $filesUpdated++;
         } elseif ($options['debug']) {
             print "Skipping matching SHA1 to existing file<br>";
         }
         // remove from dest files map
         if ($existingNode) {
             unset($destinationFilesMap[$path]);
         }
     }
     if ($options['delete']) {
         // delete local collections
         foreach ($localDestinationCollectionsMap as $path => $collectionInfo) {
             $relPath = substr($path, strlen($destinationPath));
             // skip excluded paths
             if (static::matchesExclude($relPath, $options['exclude'])) {
                 $filesExcluded++;
                 continue;
             }
             DB::nonQuery('UPDATE `%s` SET Status = "Deleted" WHERE ID = %u', array(SiteCollection::$tableName, $collectionInfo['ID']));
             $collectionsDeleted++;
             #                print("Deleted collection $collectionInfo[ID] at $path<br>");
         }
         // delete files
         foreach ($destinationFilesMap as $path => $fileInfo) {
             // skip remote files
             if ($fileInfo['Site'] != 'Local') {
                 continue;
             }
             $relPath = substr($path, strlen($destinationPath));
             // skip excluded paths
             if (static::matchesExclude($relPath, $options['exclude'])) {
                 $filesExcluded++;
                 continue;
             }
             DB::nonQuery('INSERT INTO `%s` SET CollectionID = %u, Handle = "%s", Status = "Deleted", AuthorID = %u, AncestorID = %u', array(SiteFile::$tableName, $fileInfo['CollectionID'], basename($path), !empty($GLOBALS['Session']) ? $GLOBALS['Session']->PersonID : null, $fileInfo['ID']));
             $filesDeleted++;
             #                print("Deleted file $fileInfo[ID] at $path<br>");
         }
     }
     return array('collectionsAnalyzed' => $collectionsAnalyzed, 'collectionsDeleted' => $collectionsDeleted, 'filesAnalyzed' => $filesAnalyzed, 'filesExcluded' => $filesExcluded, 'filesUpdated' => $filesUpdated, 'filesDeleted' => $filesDeleted);
 }
Exemple #2
0
foreach ($repoCfg['trees'] as $srcPath => $treeOptions) {
    if (is_string($treeOptions)) {
        $treeOptions = array('path' => $treeOptions);
    }
    if (!is_string($srcPath)) {
        $srcPath = $treeOptions['path'];
    } elseif (!$treeOptions['path']) {
        $treeOptions['path'] = $srcPath;
    }
    $treeOptions['exclude'][] = '#(^|/)\\.git(/|$)#';
    if (is_file($treeOptions['path'])) {
        $sha1 = sha1_file($treeOptions['path']);
        $existingNode = Site::resolvePath($srcPath);
        if (!$existingNode || $existingNode->SHA1 != $sha1) {
            $fileRecord = SiteFile::createFromPath($srcPath, null, $existingNode ? $existingNode->ID : null);
            SiteFile::saveRecordData($fileRecord, fopen($treeOptions['path'], 'r'), $sha1);
            Benchmark::mark("importing file {$srcPath} from {$treeOptions['path']}");
        } else {
            Benchmark::mark("skipped unchanged file {$srcPath} from {$treeOptions['path']}");
        }
    } else {
        $cachedFiles = Emergence_FS::cacheTree($srcPath);
        Benchmark::mark("precached {$srcPath}: " . $cachedFiles);
        $exportResult = Emergence_FS::importTree($treeOptions['path'], $srcPath, $treeOptions);
        Benchmark::mark("importing directory {$srcPath} from {$treeOptions['path']}: " . http_build_query($exportResult));
    }
}
// commit changes
#$repo->git('add --all');
#
#$repo->git(sprintf(
 public static function handleImportRequest()
 {
     // get repo
     if (empty($_REQUEST['repo'])) {
         die('Parameter "repo" required');
     }
     $repoName = $_REQUEST['repo'];
     if (!array_key_exists($repoName, Git::$repositories)) {
         die("Repo '{$repoName}' is not defined in Git::\$repositories");
     }
     $repoCfg = Git::$repositories[$repoName];
     // start the process
     set_time_limit(0);
     Benchmark::startLive();
     Benchmark::mark("configured request: repoName={$repoName}");
     // get paths
     $repoPath = "{$_SERVER['SITE_ROOT']}/site-data/git/{$repoName}";
     // check if there is an existing repo
     if (!is_dir("{$repoPath}/.git")) {
         die("{$repoPath} does not contain .git");
     }
     // get repo
     chdir($repoPath);
     // sync trees
     foreach ($repoCfg['trees'] as $srcPath => $treeOptions) {
         if (is_string($treeOptions)) {
             $treeOptions = array('path' => $treeOptions);
         }
         if (!is_string($srcPath)) {
             $srcPath = $treeOptions['path'];
         } elseif (!$treeOptions['path']) {
             $treeOptions['path'] = $srcPath;
         }
         if (is_string($treeOptions['exclude'])) {
             $treeOptions['exclude'] = array($treeOptions['exclude']);
         }
         $treeOptions['exclude'][] = '#(^|/)\\.git(/|$)#';
         $treeOptions['dataPath'] = false;
         try {
             if (is_file($treeOptions['path'])) {
                 $sha1 = sha1_file($treeOptions['path']);
                 $existingNode = Site::resolvePath($srcPath);
                 if (!$existingNode || $existingNode->SHA1 != $sha1) {
                     $fileRecord = SiteFile::createFromPath($srcPath, null, $existingNode ? $existingNode->ID : null);
                     SiteFile::saveRecordData($fileRecord, fopen($treeOptions['path'], 'r'), $sha1);
                     Benchmark::mark("importing file {$srcPath} from {$treeOptions['path']}");
                 } else {
                     Benchmark::mark("skipped unchanged file {$srcPath} from {$treeOptions['path']}");
                 }
             } else {
                 $exportResult = Emergence_FS::importTree($treeOptions['path'], $srcPath, $treeOptions);
                 Benchmark::mark("importing directory {$srcPath} from {$treeOptions['path']}: " . http_build_query($exportResult));
             }
         } catch (Exception $e) {
             Benchmark::mark("failed to import directory {$srcPath} from {$treeOptions['path']}: " . $e->getMessage());
         }
     }
 }