[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class PhragmentGetPatchConduitAPIMethod 4 extends PhragmentConduitAPIMethod { 5 6 public function getAPIMethodName() { 7 return 'phragment.getpatch'; 8 } 9 10 public function getMethodStatus() { 11 return self::METHOD_STATUS_UNSTABLE; 12 } 13 14 public function getMethodDescription() { 15 return pht('Retrieve the patches to apply for a given set of files.'); 16 } 17 18 public function defineParamTypes() { 19 return array( 20 'path' => 'required string', 21 'state' => 'required dict<string, string>', 22 ); 23 } 24 25 public function defineReturnType() { 26 return 'nonempty dict'; 27 } 28 29 public function defineErrorTypes() { 30 return array( 31 'ERR_BAD_FRAGMENT' => 'No such fragment exists', 32 ); 33 } 34 35 protected function execute(ConduitAPIRequest $request) { 36 $path = $request->getValue('path'); 37 $state = $request->getValue('state'); 38 // The state is an array mapping file paths to hashes. 39 40 $patches = array(); 41 42 // We need to get all of the mappings (like phragment.getstate) first 43 // so that we can detect deletions and creations of files. 44 $fragment = id(new PhragmentFragmentQuery()) 45 ->setViewer($request->getUser()) 46 ->withPaths(array($path)) 47 ->executeOne(); 48 if ($fragment === null) { 49 throw new ConduitException('ERR_BAD_FRAGMENT'); 50 } 51 52 $mappings = $fragment->getFragmentMappings( 53 $request->getUser(), 54 $fragment->getPath()); 55 56 $file_phids = mpull(mpull($mappings, 'getLatestVersion'), 'getFilePHID'); 57 $files = id(new PhabricatorFileQuery()) 58 ->setViewer($request->getUser()) 59 ->withPHIDs($file_phids) 60 ->execute(); 61 $files = mpull($files, null, 'getPHID'); 62 63 // Scan all of the files that the caller currently has and iterate 64 // over that. 65 foreach ($state as $path => $hash) { 66 // If $mappings[$path] exists, then the user has the file and it's 67 // also a fragment. 68 if (array_key_exists($path, $mappings)) { 69 $file_phid = $mappings[$path]->getLatestVersion()->getFilePHID(); 70 if ($file_phid !== null) { 71 // If the file PHID is present, then we need to check the 72 // hashes to see if they are the same. 73 $hash_caller = strtolower($state[$path]); 74 $hash_current = $files[$file_phid]->getContentHash(); 75 if ($hash_caller === $hash_current) { 76 // The user's version is identical to our version, so 77 // there is no update needed. 78 } else { 79 // The hash differs, and the user needs to update. 80 $patches[] = array( 81 'path' => $path, 82 'fileOld' => null, 83 'fileNew' => $files[$file_phid], 84 'hashOld' => $hash_caller, 85 'hashNew' => $hash_current, 86 'patchURI' => null, 87 ); 88 } 89 } else { 90 // We have a record of this as a file, but there is no file 91 // attached to the latest version, so we consider this to be 92 // a deletion. 93 $patches[] = array( 94 'path' => $path, 95 'fileOld' => null, 96 'fileNew' => null, 97 'hashOld' => $hash_caller, 98 'hashNew' => PhragmentPatchUtil::EMPTY_HASH, 99 'patchURI' => null, 100 ); 101 } 102 } else { 103 // If $mappings[$path] does not exist, then the user has a file, 104 // and we have absolutely no record of it what-so-ever (we haven't 105 // even recorded a deletion). Assuming most applications will store 106 // some form of data near their own files, this is probably a data 107 // file relevant for the application that is not versioned, so we 108 // don't tell the client to do anything with it. 109 } 110 } 111 112 // Check the remaining files that we know about but the caller has 113 // not reported. 114 foreach ($mappings as $path => $child) { 115 if (array_key_exists($path, $state)) { 116 // We have already evaluated this above. 117 } else { 118 $file_phid = $mappings[$path]->getLatestVersion()->getFilePHID(); 119 if ($file_phid !== null) { 120 // If the file PHID is present, then this is a new file that 121 // we know about, but the caller does not. We need to tell 122 // the caller to create the file. 123 $hash_current = $files[$file_phid]->getContentHash(); 124 $patches[] = array( 125 'path' => $path, 126 'fileOld' => null, 127 'fileNew' => $files[$file_phid], 128 'hashOld' => PhragmentPatchUtil::EMPTY_HASH, 129 'hashNew' => $hash_current, 130 'patchURI' => null, 131 ); 132 } else { 133 // We have a record of deleting this file, and the caller hasn't 134 // reported it, so they've probably deleted it in a previous 135 // update. 136 } 137 } 138 } 139 140 // Before we can calculate patches, we need to resolve the old versions 141 // of files so we can draw diffs on them. 142 $hashes = array(); 143 foreach ($patches as $patch) { 144 if ($patch['hashOld'] !== PhragmentPatchUtil::EMPTY_HASH) { 145 $hashes[] = $patch['hashOld']; 146 } 147 } 148 $old_files = array(); 149 if (count($hashes) !== 0) { 150 $old_files = id(new PhabricatorFileQuery()) 151 ->setViewer($request->getUser()) 152 ->withContentHashes($hashes) 153 ->execute(); 154 } 155 $old_files = mpull($old_files, null, 'getContentHash'); 156 foreach ($patches as $key => $patch) { 157 if ($patch['hashOld'] !== PhragmentPatchUtil::EMPTY_HASH) { 158 if (array_key_exists($patch['hashOld'], $old_files)) { 159 $patches[$key]['fileOld'] = $old_files[$patch['hashOld']]; 160 } else { 161 // We either can't see or can't read the old file. 162 $patches[$key]['hashOld'] = PhragmentPatchUtil::EMPTY_HASH; 163 $patches[$key]['fileOld'] = null; 164 } 165 } 166 } 167 168 // Now run through all of the patch entries, calculate the patches 169 // and return the results. 170 foreach ($patches as $key => $patch) { 171 $data = PhragmentPatchUtil::calculatePatch( 172 $patches[$key]['fileOld'], 173 $patches[$key]['fileNew']); 174 unset($patches[$key]['fileOld']); 175 unset($patches[$key]['fileNew']); 176 177 $file = PhabricatorFile::buildFromFileDataOrHash( 178 $data, 179 array( 180 'name' => 'patch.dmp', 181 'ttl' => time() + 60 * 60 * 24, 182 )); 183 $patches[$key]['patchURI'] = $file->getDownloadURI(); 184 } 185 186 return $patches; 187 } 188 189 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |