Index: trunk/extensions/SwiftMedia/TODO |
— | — | @@ -0,0 +1,11 @@ |
| 2 | +4) Of course, append() and appendFinish() need to be implemented. |
| 3 | +5) The Upload seems to take more time than I expect, but that could be a function of generating the six thumbnails. |
| 4 | +6) There's no 404 handler to generate missing thumbnails. |
| 5 | +7) There's no support for remote thumbnailing. |
| 6 | +8) Test cases (but of course that could be done until the cows come home). |
| 7 | +9) Read through the code and look for anything which is insane. |
| 8 | +10) Remove directory from $wgLocalFileRepo, to make sure that there's no references to it. Ditto for wgDeletedDirectory and deletedDir. |
| 9 | +11) Determine what to do about the one remaining core change needed for Swift. |
| 10 | +12) Implement repo->freeTemp() - needed by several extensions and UploadFromStash. |
| 11 | +13) Do we need $wgLocalRepo->ThumbUrl to be configurable given that the Python middleware presumes it? |
| 12 | + |
Index: trunk/extensions/SwiftMedia/copyover |
— | — | @@ -2,6 +2,6 @@ |
3 | 3 | |
4 | 4 | scp rnelson@ersch.wikimedia.org:/var/www/LocalSettings.php . |
5 | 5 | scp rnelson@alsted.wikimedia.org:/etc/swift/proxy-server.conf . |
6 | | -scp rnelson@ersch.wikimedia.org:/var/www/extensions/SwiftMedia/{SwiftMedia.body.php,SwiftMedia.i18n.php,SwiftMedia.php} . |
| 6 | +scp rnelson@ersch.wikimedia.org:/var/www/extensions/SwiftMedia/{SwiftMedia.body.php,SwiftMedia.i18n.php,SwiftMedia.php,TODO} . |
7 | 7 | scp rnelson@alsted.wikimedia.org:/usr/local/lib/python2.6/dist-packages/wmf/{client.py,__init__.py,rewrite.py} wmf/ |
8 | 8 | perl -pi -e "s/'key' => '.*'/'key' => 'secret'/" LocalSettings.php |
Index: trunk/extensions/SwiftMedia/SwiftMedia.body.php |
— | — | @@ -53,28 +53,28 @@ |
54 | 54 | #$deleted; # Bitfield akin to rev_deleted |
55 | 55 | /**#@-*/ |
56 | 56 | |
57 | | - /** |
58 | | - * Create a LocalFile from a title |
59 | | - * Do not call this except from inside a repo class. |
60 | | - * |
61 | | - * Note: $unused param is only here to avoid an E_STRICT |
62 | | - */ |
63 | | - static function newFromTitle( $title, $repo, $unused = null ) { |
| 57 | + /** |
| 58 | + * Create a LocalFile from a title |
| 59 | + * Do not call this except from inside a repo class. |
| 60 | + * |
| 61 | + * Note: $unused param is only here to avoid an E_STRICT |
| 62 | + */ |
| 63 | + static function newFromTitle( $title, $repo, $unused = null ) { |
64 | 64 | if ( empty($title) ) { return null; } |
65 | | - return new self( $title, $repo ); |
66 | | - } |
| 65 | + return new self( $title, $repo ); |
| 66 | + } |
67 | 67 | |
68 | | - /** |
69 | | - * Create a LocalFile from a title |
70 | | - * Do not call this except from inside a repo class. |
71 | | - */ |
72 | | - static function newFromRow( $row, $repo ) { |
73 | | - $title = Title::makeTitle( NS_FILE, $row->img_name ); |
74 | | - $file = new self( $title, $repo ); |
75 | | - $file->loadFromRow( $row ); |
| 68 | + /** |
| 69 | + * Create a LocalFile from a title |
| 70 | + * Do not call this except from inside a repo class. |
| 71 | + */ |
| 72 | + static function newFromRow( $row, $repo ) { |
| 73 | + $title = Title::makeTitle( NS_FILE, $row->img_name ); |
| 74 | + $file = new self( $title, $repo ); |
| 75 | + $file->loadFromRow( $row ); |
76 | 76 | |
77 | | - return $file; |
78 | | - } |
| 77 | + return $file; |
| 78 | + } |
79 | 79 | |
80 | 80 | /** |
81 | 81 | * Constructor. |
— | — | @@ -82,7 +82,7 @@ |
83 | 83 | */ |
84 | 84 | function __construct( $title, $repo ) { |
85 | 85 | if ( !is_object( $title ) ) { |
86 | | - throw new MWException( __CLASS__ . ' constructor given bogus title.' ); |
| 86 | + throw new MWException( __CLASS__ . " constructor given bogus title." ); |
87 | 87 | } |
88 | 88 | |
89 | 89 | parent::__construct( $title, $repo ); |
— | — | @@ -229,7 +229,7 @@ |
230 | 230 | |
231 | 231 | // Sanity check prefix once |
232 | 232 | if ( substr( key( $array ), 0, $prefixLength ) !== $prefix ) { |
233 | | - throw new MWException( __METHOD__ . ': incorrect $prefix parameter' ); |
| 233 | + throw new MWException( __METHOD__ . ": incorrect $prefix parameter" ); |
234 | 234 | } |
235 | 235 | |
236 | 236 | $decoded = array(); |
— | — | @@ -412,19 +412,23 @@ |
413 | 413 | $this->temp_path = tempnam( wfTempDir(), 'swift_in_' ); |
414 | 414 | |
415 | 415 | /* Fetch the image out of Swift */ |
416 | | - $auth = new CF_Authentication($this->repo->swiftuser, $this->repo->key, NULL, $this->repo->authurl); |
417 | | - $auth->authenticate(); |
418 | | - $conn = new CF_Connection($auth); |
419 | | - $cont = $conn->get_container($container); |
| 416 | + $conn = $this->repo->connect(); |
| 417 | + $cont = $this->repo->get_container($conn,$container); |
420 | 418 | |
421 | 419 | try { |
422 | 420 | $obj = $cont->get_object($rel); |
423 | 421 | } catch (NoSuchObjectException $e) { |
424 | | - throw new MWException( 'Unable to open original file at $container/$rel'); |
| 422 | + throw new MWException( "Unable to open original file at $container/$rel"); |
425 | 423 | } |
426 | | - // FIXME we need to do a try here, but let's see how it fails first. |
| 424 | + |
427 | 425 | wfDebug( __METHOD__ . " writing to " . $this->temp_path . "\n"); |
428 | | - $obj->save_to_filename( $this->temp_path); |
| 426 | + try { |
| 427 | + $obj->save_to_filename( $this->temp_path); |
| 428 | + } catch (IOException $e) { |
| 429 | + throw new MWException( __METHOD__ . ": error opening '$e'" ); |
| 430 | + } catch (InvalidResponseException $e) { |
| 431 | + throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
| 432 | + } |
429 | 433 | |
430 | 434 | return $this->temp_path; |
431 | 435 | } |
— | — | @@ -598,13 +602,11 @@ |
599 | 603 | $thumb = $this->handler->doTransform( $this, $thumbTemp, $thumbUrl, $params ); |
600 | 604 | |
601 | 605 | // Store the thumbnail into Swift, but in the thumb version of the container. |
602 | | - $auth = new CF_Authentication($this->repo->swiftuser, $this->repo->key, NULL, $this->repo->authurl); |
603 | | - $auth->authenticate(); |
604 | | - $conn = new CF_Connection($auth); |
605 | | - $container = $conn->get_container($this->repo->container . "%2Fthumb"); |
606 | 606 | wfDebug( __METHOD__ . "Creating thumb " . $this->getRel() . "/" . $thumbName . "\n"); |
607 | | - $obj = $container->create_object($this->getRel() . "/" . $thumbName); |
608 | | - $thumbRel = $obj->load_from_filename($thumbTemp); |
| 607 | + $conn = $this->repo->connect(); |
| 608 | + $container = $this->repo->get_container($conn,$this->repo->container . "%2Fthumb"); |
| 609 | + $this->repo->write_swift_object( $thumbTemp, $container, $this->getRel() . "/" . $thumbName); |
| 610 | + // php-cloudfiles throws exceptions, so failure never gets here. |
609 | 611 | |
610 | 612 | // Clean up temporary data. |
611 | 613 | unlink($thumbTemp); |
— | — | @@ -621,13 +623,13 @@ |
622 | 624 | * Upgrading directly from 1.4 to 1.8/SwiftMedia is not supported. |
623 | 625 | */ |
624 | 626 | function migrateThumbFile( $thumbName ) { |
625 | | - throw new MWException( __METHOD__.': not implemented' ); |
| 627 | + throw new MWException( __METHOD__.": not implemented" ); |
626 | 628 | } |
627 | 629 | /** |
628 | 630 | * Get the public root directory of the repository. |
629 | 631 | */ |
630 | 632 | function getRootDirectory() { |
631 | | - throw new MWException( __METHOD__.': not implemented' ); |
| 633 | + throw new MWException( __METHOD__.": not implemented" ); |
632 | 634 | } |
633 | 635 | |
634 | 636 | |
— | — | @@ -642,12 +644,9 @@ |
643 | 645 | $this->load(); |
644 | 646 | |
645 | 647 | $prefix = $this->getRel(); |
646 | | - $auth = new CF_Authentication($this->repo->swiftuser, $this->repo->key, NULL, $this->repo->authurl); |
647 | | - $auth->authenticate(); |
648 | | - $conn = new CF_Connection($auth); |
649 | | - $container = $conn->get_container($this->repo->container . "%2Fthumb"); |
| 648 | + $conn = $this->repo->connect(); |
| 649 | + $container = $this->repo->get_container($conn,$this->repo->container . "%2Fthumb"); |
650 | 650 | $files = $container->list_objects(0, NULL, $prefix); |
651 | | - wfDebug( __METHOD__ . var_export($files, true) . "\n"); |
652 | 651 | return $files; |
653 | 652 | } |
654 | 653 | |
— | — | @@ -698,10 +697,8 @@ |
699 | 698 | $files = $this->getThumbnails(); |
700 | 699 | $urls = array(); |
701 | 700 | |
702 | | - $auth = new CF_Authentication($this->repo->swiftuser, $this->repo->key, NULL, $this->repo->authurl); |
703 | | - $auth->authenticate(); |
704 | | - $conn = new CF_Connection($auth); |
705 | | - $container = $conn->get_container($this->repo->container . "%2Fthumb"); |
| 701 | + $conn = $this->repo->connect(); |
| 702 | + $container = $this->repo->get_container($conn,$this->repo->container . "%2Fthumb"); |
706 | 703 | foreach ( $files as $file ) { |
707 | 704 | // I have no idea how to implement this given that we don't have paths in Swift |
708 | 705 | // Only remove files not in the $wgExcludeFromThumbnailPurge configuration variable |
— | — | @@ -711,9 +708,7 @@ |
712 | 709 | //} |
713 | 710 | |
714 | 711 | $urls[] = $this->getThumbUrl($file); |
715 | | - # Check that the base file name is part of the thumb name |
716 | | - # This is a basic sanity check to avoid erasing unrelated directories |
717 | | - $container->delete_object($file); |
| 712 | + $this->repo->swift_delete($container, $file); |
718 | 713 | } |
719 | 714 | |
720 | 715 | // Purge the squid |
— | — | @@ -829,7 +824,6 @@ |
830 | 825 | /** getRel inherited */ |
831 | 826 | /** getUrlRel inherited */ |
832 | 827 | /** getArchiveRel inherited */ |
833 | | - /** getThumbRel inherited */ |
834 | 828 | /** getArchiveUrl inherited */ |
835 | 829 | /** getThumbUrl inherited */ |
836 | 830 | /** getArchiveVirtualUrl inherited */ |
— | — | @@ -1171,7 +1165,7 @@ |
1172 | 1166 | foreach ( $result as $row ) { |
1173 | 1167 | $batch->addOld( $row->oi_archive_name ); |
1174 | 1168 | } |
1175 | | - //wfDebug(__METHOD__ . var_export($batch, true) . "\n"); |
| 1169 | + //wfDebug(__METHOD__ . " deleting these files: " . var_export($batch, true) . "\n"); |
1176 | 1170 | $status = $batch->execute(); |
1177 | 1171 | |
1178 | 1172 | if ( $status->ok ) { |
— | — | @@ -2242,24 +2236,111 @@ |
2243 | 2237 | */ |
2244 | 2238 | |
2245 | 2239 | class SwiftRepo extends LocalRepo { |
2246 | | - var $fileFactory = array( 'SwiftFile', 'newFromTitle' ); |
2247 | | - var $fileFactoryKey = array( 'SwiftFile', 'newFromKey' ); |
2248 | | - var $fileFromRowFactory = array( 'SwiftFile', 'newFromRow' ); |
2249 | | - var $oldFileFactory = array( 'OldSwiftFile', 'newFromTitle' ); |
2250 | | - var $oldFileFactoryKey = array( 'OldSwiftFile', 'newFromKey' ); |
2251 | | - var $oldFileFromRowFactory = array( 'OldSwiftFile', 'newFromRow' ); |
| 2240 | + var $fileFactory = array( 'SwiftFile', 'newFromTitle' ); |
| 2241 | + var $fileFactoryKey = array( 'SwiftFile', 'newFromKey' ); |
| 2242 | + var $fileFromRowFactory = array( 'SwiftFile', 'newFromRow' ); |
| 2243 | + var $oldFileFactory = array( 'OldSwiftFile', 'newFromTitle' ); |
| 2244 | + var $oldFileFactoryKey = array( 'OldSwiftFile', 'newFromKey' ); |
| 2245 | + var $oldFileFromRowFactory = array( 'OldSwiftFile', 'newFromRow' ); |
2252 | 2246 | |
2253 | 2247 | function __construct( $info ) { |
2254 | | - parent::__construct( $info ); |
| 2248 | + FileRepo::__construct( $info ); |
2255 | 2249 | |
2256 | 2250 | // Required settings |
2257 | | - $this->key= $info['key']; |
| 2251 | + $this->url = $info['url']; |
| 2252 | + |
| 2253 | + // Optional settings |
| 2254 | + $this->hashLevels = isset( $info['hashLevels'] ) ? $info['hashLevels'] : 2; |
| 2255 | + $this->deletedHashLevels = isset( $info['deletedHashLevels'] ) ? |
| 2256 | + $info['deletedHashLevels'] : $this->hashLevels; |
| 2257 | + |
| 2258 | + if ( isset( $info['thumbUrl'] ) ) { |
| 2259 | + $this->thumbUrl = $info['thumbUrl']; |
| 2260 | + } else { |
| 2261 | + $this->thumbUrl = "{$this->url}/thumb"; |
| 2262 | + } |
| 2263 | + |
| 2264 | + // Required settings |
2258 | 2265 | $this->swiftuser= $info['user']; |
| 2266 | + $this->swiftkey= $info['key']; |
2259 | 2267 | $this->authurl= $info['authurl']; |
2260 | 2268 | $this->container= $info['container']; |
2261 | 2269 | } |
2262 | 2270 | |
2263 | 2271 | /** |
| 2272 | + * Get a connection to the swift proxy. |
| 2273 | + * |
| 2274 | + * @return CF_Connection |
| 2275 | + */ |
| 2276 | + function connect() { |
| 2277 | + $auth = new CF_Authentication($this->swiftuser, $this->swiftkey, NULL, $this->authurl); |
| 2278 | + try { |
| 2279 | + $auth->authenticate(); |
| 2280 | + } catch (AuthenticationException $e) { |
| 2281 | + throw new MWException( "We can't authenticate ourselves." ); |
| 2282 | + } catch (InvalidResponseException $e) { |
| 2283 | + throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
| 2284 | + } |
| 2285 | + return new CF_Connection($auth); |
| 2286 | + } |
| 2287 | + |
| 2288 | + /** |
| 2289 | + * Given a connection and container name, return the container. |
| 2290 | + * We KNOW the container should exist, so puke if it doesn't. |
| 2291 | + * |
| 2292 | + * @return CF_Container |
| 2293 | + */ |
| 2294 | + function get_container($conn, $cont) { |
| 2295 | + try { |
| 2296 | + return $conn->get_container($cont); |
| 2297 | + } catch (NoSuchContainerException $e) { |
| 2298 | + throw new MWException( "A container we thought existed, doesn't." ); |
| 2299 | + } catch (InvalidResponseException $e) { |
| 2300 | + throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
| 2301 | + } |
| 2302 | + } |
| 2303 | + |
| 2304 | + /** |
| 2305 | + * Given a filename, container, and object name, write the file into the object. |
| 2306 | + * None of these error conditions are recoverable by the user, so we just dump |
| 2307 | + * an Internal Error on them. |
| 2308 | + * |
| 2309 | + * @return CF_Container |
| 2310 | + */ |
| 2311 | + function write_swift_object( $srcPath, $dstc, $dstRel) { |
| 2312 | + try { |
| 2313 | + $obj = $dstc->create_object($dstRel); |
| 2314 | + $obj->load_from_filename( $srcPath, True); |
| 2315 | + } catch (SyntaxException $e) { |
| 2316 | + throw new MWException( "missing required parameters" ); |
| 2317 | + } catch (BadContentTypeException $e) { |
| 2318 | + throw new MWException( "No Content-Type was/could be set" ); |
| 2319 | + } catch (InvalidResponseException $e) { |
| 2320 | + throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
| 2321 | + } catch (IOException $e) { |
| 2322 | + throw new MWException( "error opening file '$e'" ); |
| 2323 | + } |
| 2324 | + } |
| 2325 | + |
| 2326 | + /** |
| 2327 | + * Given a container and object name, delete the object. |
| 2328 | + * None of these error conditions are recoverable by the user, so we just dump |
| 2329 | + * an Internal Error on them. |
| 2330 | + * |
| 2331 | + */ |
| 2332 | + function swift_delete( $container, $rel ) { |
| 2333 | + try { |
| 2334 | + $container->delete_object($rel); |
| 2335 | + } catch (SyntaxException $e) { |
| 2336 | + throw new MWException( "Swift object name not well-formed: '$e'" ); |
| 2337 | + } catch (NoSuchObjectException $e) { |
| 2338 | + throw new MWException( "Swift object we are trying to delete does not exist: '$e'" ); |
| 2339 | + } catch (InvalidResponseException $e) { |
| 2340 | + throw new MWException( "unexpected response '$e'" ); |
| 2341 | + } |
| 2342 | + } |
| 2343 | + |
| 2344 | + /** |
2264 | 2345 | * Store a batch of files |
2265 | 2346 | * |
2266 | 2347 | * @param $triplets Array: (src,zone,dest) triplets as per store() |
— | — | @@ -2268,6 +2349,7 @@ |
2269 | 2350 | * self::OVERWRITE Overwrite an existing destination file instead of failing |
2270 | 2351 | * self::OVERWRITE_SAME Overwrite the file if the destination exists and has the |
2271 | 2352 | * same contents as the source |
| 2353 | + * @return $status |
2272 | 2354 | */ |
2273 | 2355 | function storeBatch( $triplets, $flags = 0 ) { |
2274 | 2356 | wfDebug( __METHOD__ . ': Storing ' . count( $triplets ) . |
— | — | @@ -2279,7 +2361,7 @@ |
2280 | 2362 | list( $srcPath, $dstZone, $dstRel ) = $triplet; |
2281 | 2363 | |
2282 | 2364 | if ( !$this->validateFilename( $dstRel ) ) { |
2283 | | - throw new MWException( 'Validation error in $dstRel' ); |
| 2365 | + throw new MWException( "Validation error in $dstRel" ); |
2284 | 2366 | } |
2285 | 2367 | |
2286 | 2368 | // Check overwriting |
— | — | @@ -2304,17 +2386,14 @@ |
2305 | 2387 | } |
2306 | 2388 | |
2307 | 2389 | // Execute the store operation for each triplet |
2308 | | - $auth = new CF_Authentication($this->swiftuser, $this->key, NULL, $this->authurl); |
2309 | | - $auth->authenticate(); |
2310 | | - $conn = new CF_Connection($auth); |
| 2390 | + $conn = $this->connect(); |
2311 | 2391 | |
2312 | 2392 | foreach ( $triplets as $i => $triplet ) { |
2313 | 2393 | list( $srcPath, $dstZone, $dstRel ) = $triplet; |
2314 | 2394 | |
2315 | | - // Create the destination object. |
| 2395 | + // Point to the container. |
2316 | 2396 | $dstContainer = $this->getZoneContainer( $dstZone ); |
2317 | | - $dstc = $conn->get_container($dstContainer); |
2318 | | - $obj = $dstc->create_object($dstRel); |
| 2397 | + $dstc = $this->get_container($conn, $dstContainer); |
2319 | 2398 | |
2320 | 2399 | $good = true; |
2321 | 2400 | |
— | — | @@ -2322,34 +2401,17 @@ |
2323 | 2402 | if (self::isVirtualUrl( $srcPath )) { |
2324 | 2403 | $src = $this->resolveVirtualUrl( $srcPath ); |
2325 | 2404 | list ($srcContainer, $srcRel) = $src; |
| 2405 | + $srcc = $this->get_container($conn, $srcContainer); |
2326 | 2406 | |
2327 | | - $obj->content_type = "text/plain"; |
2328 | | - $obj->write("."); |
2329 | | - |
2330 | | - // FIXME: not sure if we need to re-open it, but let's not take any chances. |
2331 | | - $obj = $dstc->get_object($dstRel); |
2332 | | - // FIXME: errors are returned as exceptions. |
2333 | | - $obj->copy("$srcContainer/$srcRel"); |
2334 | | - if (0) { // handle exceptions |
2335 | | - $status->error( 'filecopyerror', $srcPath, $dstPath ); |
2336 | | - $good = false; |
2337 | | - } |
| 2407 | + $this->swiftcopy($srcc, $srcRel, $dstc, $dstRel); |
2338 | 2408 | if ( $flags & self::DELETE_SOURCE ) { |
2339 | | - $srcc = $conn->get_container($srcContainer); |
2340 | | - // FIXME: handle exceptions. |
2341 | | - $srcc->delete_object($srcRel); |
2342 | | - if (0) { // handle exceptions. |
2343 | | - $status->error( 'filerenameerror', $srcPath, $dstPath ); |
2344 | | - $good = false; |
2345 | | - } |
| 2409 | + $this->swift_delete( $srcc, $srcRel ); |
2346 | 2410 | } |
2347 | 2411 | } else { |
2348 | | - // write an ordinary file into Swift. |
2349 | | - $obj->load_from_filename( $srcPath, True); |
2350 | | - // $status->error( 'filecopyerror', $srcPath, $dstRel ); |
2351 | | - // $good = false; |
| 2412 | + $this->write_swift_object( $srcPath, $dstc, $dstRel); |
| 2413 | + // php-cloudfiles throws exceptions, so failure never gets here. |
2352 | 2414 | if ( $flags & self::DELETE_SOURCE ) { |
2353 | | - delete ( $srcPath ); |
| 2415 | + unlink ( $srcPath ); |
2354 | 2416 | } |
2355 | 2417 | } |
2356 | 2418 | |
— | — | @@ -2392,10 +2454,10 @@ |
2393 | 2455 | } |
2394 | 2456 | |
2395 | 2457 | function append( $srcPath, $toAppendPath, $flags = 0 ){ |
2396 | | - throw new MWException( __METHOD__.': Not yet implemented.' ); |
| 2458 | + throw new MWException( __METHOD__.": Not yet implemented." ); |
2397 | 2459 | } |
2398 | 2460 | function appendFinish( $toAppendPath ){ |
2399 | | - throw new MWException( __METHOD__.': Not yet implemented.' ); |
| 2461 | + throw new MWException( __METHOD__.": Not yet implemented." ); |
2400 | 2462 | } |
2401 | 2463 | |
2402 | 2464 | /** |
— | — | @@ -2427,8 +2489,8 @@ |
2428 | 2490 | } |
2429 | 2491 | |
2430 | 2492 | |
2431 | | - function newFromArchiveName( $title, $archiveName ) { |
2432 | | - return OldSwiftFile::newFromArchiveName( $title, $this, $archiveName ); |
| 2493 | + function newFromArchiveName( $title, $archiveName ) { |
| 2494 | + return OldSwiftFile::newFromArchiveName( $title, $this, $archiveName ); |
2433 | 2495 | } |
2434 | 2496 | |
2435 | 2497 | /** |
— | — | @@ -2442,21 +2504,18 @@ |
2443 | 2505 | function fileExistsBatch( $files, $flags = 0 ) { |
2444 | 2506 | if ($flags != self::FILES_ONLY) { |
2445 | 2507 | // we ONLY support when $flags & self::FILES_ONLY is set! |
2446 | | - throw new MWException( 'Swift Media Store doesn\'t have directories'); |
| 2508 | + throw new MWException( "Swift Media Store doesn't have directories"); |
2447 | 2509 | } |
2448 | | - wfDebug( __METHOD__ . var_export($files, true) . " " . $flags. "\n"); |
2449 | 2510 | $result = array(); |
2450 | | - $auth = new CF_Authentication($this->swiftuser, $this->key, NULL, $this->authurl); |
2451 | | - $auth->authenticate(); |
2452 | | - $conn = new CF_Connection($auth); |
2453 | | - $container = $conn->get_container($this->container); |
| 2511 | + $conn = $this->connect(); |
2454 | 2512 | |
2455 | 2513 | foreach ( $files as $key => $file ) { |
2456 | | - if ( self::isVirtualUrl( $file ) ) { |
2457 | | - $rvu = $this->resolveVirtualUrl( $file ); |
2458 | | - list ($cont, $rel) = $rvu; |
2459 | | - $container = $conn->get_container($cont); |
| 2514 | + if ( !self::isVirtualUrl( $file ) ) { |
| 2515 | + throw new MWException( __METHOD__ . " requires a virtual URL, not '$file'"); |
2460 | 2516 | } |
| 2517 | + $rvu = $this->resolveVirtualUrl( $file ); |
| 2518 | + list ($cont, $rel) = $rvu; |
| 2519 | + $container = $this->get_container($conn,$cont); |
2461 | 2520 | try { |
2462 | 2521 | $obj = $container->get_object($rel); |
2463 | 2522 | $result[$key] = true; |
— | — | @@ -2469,36 +2528,53 @@ |
2470 | 2529 | } |
2471 | 2530 | |
2472 | 2531 | |
2473 | | - function getFileProps( $virtualUrl ) { |
2474 | | - wfDebug( __METHOD__ . " $virtualUrl\n" ); |
2475 | | - return parent::getFileProps( $virtualUrl ); |
2476 | | - } |
| 2532 | + // FIXME: do we really need to reject empty titles? |
2477 | 2533 | function newFile( $title, $time = false ) { |
2478 | 2534 | if ( empty($title) ) { return null; } |
2479 | | - //wfDebug( __METHOD__ . " $title, $time " . var_export($this->fileFactory, true) ."\n" ); |
2480 | | - $f = parent::newFile( $title, $time ); |
2481 | | - return $f; |
| 2535 | + return parent::newFile( $title, $time ); |
2482 | 2536 | } |
2483 | | - function findFile( $title, $options = array() ) { |
2484 | | - //wfDebug( __METHOD__ . " finding $title" . var_export($options, true) . "\n" ); |
2485 | | - $found = parent::findFile( $title, $options ); |
2486 | | - //wfDebug( __METHOD__ . " found " . var_export($found, true) . "\n" ); |
2487 | | - return $found; |
2488 | | - } |
2489 | 2537 | |
2490 | | - function swiftcopy($container, $srcRel, $archiveRel ) { |
2491 | | - // Note the assumption that we're not doing cross-container copies. |
2492 | | - // |
| 2538 | + /** |
| 2539 | + * Copy a file from one place to another place in the same container |
| 2540 | + * @param $srcContainer CF_Container |
| 2541 | + * @param $srcRel String: relative path to the source file. |
| 2542 | + * @param $dstContainer CF_Container |
| 2543 | + * @param $dstRel String: relative path to the destination. |
| 2544 | + */ |
| 2545 | + function swiftcopy($srcContainer, $srcRel, $dstContainer, $dstRel ) { |
2493 | 2546 | // The destination must exist already. |
2494 | | - $obj = $container->create_object($archiveRel); |
| 2547 | + $obj = $dstContainer->create_object($dstRel); |
2495 | 2548 | $obj->content_type = "text/plain"; |
2496 | | - $obj->write("."); |
2497 | | - // FIXME: not sure if we need to re-open it, but let's not take any chances. |
2498 | | - $obj = $container->get_object($archiveRel); |
2499 | | - // Errors are returned as exceptions. |
2500 | | - wfDebug( __METHOD__ . " copying to $archiveRel from " . $container->name . "/" . $srcRel . "\n"); |
2501 | | - $success = $obj->copy($container->name . "/" . $srcRel); |
2502 | | - return $success; |
| 2549 | + |
| 2550 | + try { |
| 2551 | + $obj->write("."); |
| 2552 | + } catch (SyntaxException $e ) { |
| 2553 | + throw new MWException( "Write failed: $e" ); |
| 2554 | + } catch (BadContentTypeException $e ) { |
| 2555 | + throw new MWException( "Missing Content-Type: $e" ); |
| 2556 | + } catch (MisMatchedChecksumException $e ) { |
| 2557 | + throw new MWException( __METHOD__ . "should not happen: '$e'" ); |
| 2558 | + } catch (InvalidResponseException $e ) { |
| 2559 | + throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
| 2560 | + } |
| 2561 | + |
| 2562 | + try { |
| 2563 | + $obj = $dstContainer->get_object($dstRel); |
| 2564 | + } catch (NoSuchObjectException $e) { |
| 2565 | + throw new MWException( "The object we just created does not exist: " . $dstContainer->name . "/$dstRel: $e" ); |
| 2566 | + } |
| 2567 | + |
| 2568 | + wfDebug( __METHOD__ . " copying to " . $dstContainer->name . "/" . $dstRel . " from " . $srcContainer->name . "/" . $srcRel . "\n"); |
| 2569 | + |
| 2570 | + try { |
| 2571 | + $obj->copy($srcContainer->name . "/" . $srcRel); |
| 2572 | + } catch (SyntaxException $e ) { |
| 2573 | + throw new MWException( "Source file does not exist: " . $srcContainer->name . "/$srcRel: $e" ); |
| 2574 | + } catch (MisMatchedChecksumException $e ) { |
| 2575 | + throw new MWException( "Checksums do not match: $e" ); |
| 2576 | + } catch (InvalidResponseException $e ) { |
| 2577 | + throw new MWException( __METHOD__ . "unexpected response '$e'" ); |
| 2578 | + } |
2503 | 2579 | } |
2504 | 2580 | |
2505 | 2581 | /** |
— | — | @@ -2508,13 +2584,8 @@ |
2509 | 2585 | * that the source files should be deleted if possible |
2510 | 2586 | */ |
2511 | 2587 | function publishBatch( $triplets, $flags = 0 ) { |
2512 | | - $auth = new CF_Authentication($this->swiftuser, $this->key, NULL, $this->authurl); |
2513 | | - $auth->authenticate(); |
2514 | | - $conn = new CF_Connection($auth); |
2515 | | - $container = $conn->get_container($this->container); |
2516 | | - #wfDebug( "Number of Objects: " . $container->object_count . "\n" ); |
2517 | | - #wfDebug( "Bytes stored in container: " . $container->bytes_used . "\n" ); |
2518 | | - #wfDebug( "Object: " . var_export($pic, true) . "\n" ); |
| 2588 | + $conn = $this->connect(); |
| 2589 | + $container = $this->get_container($conn,$this->container); |
2519 | 2590 | |
2520 | 2591 | # paranoia |
2521 | 2592 | $status = $this->newGood( array() ); |
— | — | @@ -2522,10 +2593,10 @@ |
2523 | 2594 | list( $srcPath, $dstRel, $archiveRel ) = $triplet; |
2524 | 2595 | |
2525 | 2596 | if ( !$this->validateFilename( $dstRel ) ) { |
2526 | | - throw new MWException( 'Validation error in $dstRel' ); |
| 2597 | + throw new MWException( "Validation error in $dstRel" ); |
2527 | 2598 | } |
2528 | 2599 | if ( !$this->validateFilename( $archiveRel ) ) { |
2529 | | - throw new MWException( 'Validation error in $archiveRel' ); |
| 2600 | + throw new MWException( "Validation error in $archiveRel" ); |
2530 | 2601 | } |
2531 | 2602 | if ( !is_file( $srcPath ) ) { |
2532 | 2603 | // Make a list of files that don't exist for return to the caller |
— | — | @@ -2547,35 +2618,19 @@ |
2548 | 2619 | $pic = NULL; |
2549 | 2620 | } |
2550 | 2621 | if( $pic ) { |
2551 | | - // this shouldn't fail, but we'll catch it anyway. |
2552 | | - try { |
2553 | | - $success = $this->swiftcopy($container, $dstRel, $archiveRel ); |
2554 | | - } catch (NoSuchObjectException $e) { |
2555 | | - $success = false; |
2556 | | - } |
2557 | | - |
2558 | | - if( !$success ) { |
2559 | | - $status->error( 'filerenameerror',$dstRel, $archiveRel ); |
2560 | | - $status->failCount++; |
2561 | | - continue; |
2562 | | - } else { |
2563 | | - wfDebug(__METHOD__.": moved file $dstRel to $archiveRel\n"); |
2564 | | - } |
| 2622 | + $this->swiftcopy($container, $dstRel, $container, $archiveRel ); |
| 2623 | + wfDebug(__METHOD__.": moved file $dstRel to $archiveRel\n"); |
2565 | 2624 | $status->value[$i] = 'archived'; |
2566 | 2625 | } else { |
2567 | 2626 | $status->value[$i] = 'new'; |
2568 | 2627 | } |
2569 | 2628 | |
2570 | 2629 | $good = true; |
2571 | | - // FIXME: how does this return failure?? |
2572 | | - $obj = $container->create_object($dstRel); |
2573 | | - // FIXME: we need to do a try here |
2574 | | - $obj->load_from_filename( $srcPath, True); |
2575 | | - // $status->error( 'filecopyerror', $srcPath, $dstRel ); |
2576 | | - // $good = false; |
2577 | | - //if ( $flags & self::DELETE_SOURCE ) { |
2578 | | - // delete ( $srcPath ); |
2579 | | - //} |
| 2630 | + $this->write_swift_object( $srcPath, $container, $dstRel); |
| 2631 | + // php-cloudfiles throws exceptions, so failure never gets here. |
| 2632 | + if ( $flags & self::DELETE_SOURCE ) { |
| 2633 | + unlink ( $srcPath ); |
| 2634 | + } |
2580 | 2635 | |
2581 | 2636 | if ( $good ) { |
2582 | 2637 | $status->successCount++; |
— | — | @@ -2595,9 +2650,7 @@ |
2596 | 2651 | * @param $pairs array List of files to delete |
2597 | 2652 | */ |
2598 | 2653 | function cleanupBatch( $files ) { |
2599 | | - $auth = new CF_Authentication($this->swiftuser, $this->key, NULL, $this->authurl); |
2600 | | - $auth->authenticate(); |
2601 | | - $conn = new CF_Connection($auth); |
| 2654 | + $conn = $this->connect(); |
2602 | 2655 | foreach ( $files as $file ) { |
2603 | 2656 | if ( is_array( $file ) ) { |
2604 | 2657 | // This is a pair, extract it |
— | — | @@ -2609,13 +2662,13 @@ |
2610 | 2663 | list( $cont, $rel) = $path; |
2611 | 2664 | } else { |
2612 | 2665 | // FIXME: This is a full file name |
2613 | | - throw new MWException( __METHOD__.': $file needs an unlink()' ); |
| 2666 | + throw new MWException( __METHOD__.": $file needs an unlink()" ); |
2614 | 2667 | } |
2615 | 2668 | } |
2616 | 2669 | |
2617 | 2670 | wfDebug( __METHOD__.": $cont/$rel\n" ); |
2618 | | - $container = $conn->get_container($cont); |
2619 | | - $container->delete_object($rel); |
| 2671 | + $container = $this->get_container($conn,$cont); |
| 2672 | + $this->swift_delete( $container, $rel ); |
2620 | 2673 | } |
2621 | 2674 | } |
2622 | 2675 | |
— | — | @@ -2627,11 +2680,9 @@ |
2628 | 2681 | * @return FileRepoStatus |
2629 | 2682 | */ |
2630 | 2683 | function cleanupDeletedBatch( $storageKeys ) { |
2631 | | - $auth = new CF_Authentication($this->swiftuser, $this->key, NULL, $this->authurl); |
2632 | | - $auth->authenticate(); |
2633 | | - $conn = new CF_Connection($auth); |
| 2684 | + $conn = $this->connect(); |
2634 | 2685 | $cont = $this->getZoneContainer( 'deleted' ); |
2635 | | - $container = $conn->get_container($cont); |
| 2686 | + $container = $this->get_container($conn,$cont); |
2636 | 2687 | |
2637 | 2688 | $dbw = $this->getMasterDB(); |
2638 | 2689 | $status = $this->newGood(); |
— | — | @@ -2655,11 +2706,7 @@ |
2656 | 2707 | } |
2657 | 2708 | if ( !$inuse ) { |
2658 | 2709 | wfDebug( __METHOD__ . ": deleting $key\n" ); |
2659 | | - $container->delete_object($rel); |
2660 | | - if ( 0 ) { |
2661 | | - $status->error( 'undelete-cleanup-error', $rel ); |
2662 | | - $status->failCount++; |
2663 | | - } |
| 2710 | + $this->swift_delete( $container, $rel ); |
2664 | 2711 | } else { |
2665 | 2712 | wfDebug( __METHOD__ . ": $key still in use\n" ); |
2666 | 2713 | $status->successCount++; |
— | — | @@ -2673,7 +2720,7 @@ |
2674 | 2721 | * Makes no sense in our context -- don't let anybody call it. |
2675 | 2722 | */ |
2676 | 2723 | function getZonePath( $zone ) { |
2677 | | - throw new MWException( __METHOD__.': not implemented' ); |
| 2724 | + throw new MWException( __METHOD__.": not implemented" ); |
2678 | 2725 | } |
2679 | 2726 | |
2680 | 2727 | /** |
— | — | @@ -2698,7 +2745,7 @@ |
2699 | 2746 | */ |
2700 | 2747 | function resolveVirtualUrl( $url ) { |
2701 | 2748 | if ( substr( $url, 0, 9 ) != 'mwrepo://' ) { |
2702 | | - throw new MWException( __METHOD__.': unknown protoocl' ); |
| 2749 | + throw new MWException( __METHOD__.": unknown protocol" ); |
2703 | 2750 | } |
2704 | 2751 | |
2705 | 2752 | $bits = explode( '/', substr( $url, 9 ), 3 ); |
— | — | @@ -2938,30 +2985,6 @@ |
2939 | 2986 | |
2940 | 2987 | |
2941 | 2988 | class Junkyjunk { |
2942 | | - function __construct( $info ) { |
2943 | | - parent::__construct( $info ); |
2944 | | - |
2945 | | - // Required settings |
2946 | | - $this->directory = $info['directory']; |
2947 | | - $this->url = $info['url']; |
2948 | | - |
2949 | | - // Optional settings |
2950 | | - $this->hashLevels = isset( $info['hashLevels'] ) ? $info['hashLevels'] : 2; |
2951 | | - $this->deletedHashLevels = isset( $info['deletedHashLevels'] ) ? |
2952 | | - $info['deletedHashLevels'] : $this->hashLevels; |
2953 | | - $this->fileMode = isset( $info['fileMode'] ) ? $info['fileMode'] : 0644; |
2954 | | - if ( isset( $info['thumbDir'] ) ) { |
2955 | | - $this->thumbDir = $info['thumbDir']; |
2956 | | - } else { |
2957 | | - $this->thumbDir = "{$this->directory}/thumb"; |
2958 | | - } |
2959 | | - if ( isset( $info['thumbUrl'] ) ) { |
2960 | | - $this->thumbUrl = $info['thumbUrl']; |
2961 | | - } else { |
2962 | | - $this->thumbUrl = "{$this->url}/thumb"; |
2963 | | - } |
2964 | | - } |
2965 | | - |
2966 | 2989 | function append( $srcPath, $toAppendPath, $flags = 0 ) { |
2967 | 2990 | $status = $this->newGood(); |
2968 | 2991 | |