r22492 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r22491‎ | r22492 | r22493 >
Date:00:50, 28 May 2007
Author:tstarling
Status:old
Tags:
Comment:
Migrated maintenance scripts cleanupImages.php, rebuildImages.php and importImages.php. Fixed some issues with OldLocalFile. Broke upgrade1_5.php.
Modified paths:
  • /branches/filerepo-work/phase3/includes/AutoLoader.php (modified) (history)
  • /branches/filerepo-work/phase3/includes/filerepo/FSRepo.php (modified) (history)
  • /branches/filerepo-work/phase3/includes/filerepo/LocalFile.php (modified) (history)
  • /branches/filerepo-work/phase3/includes/filerepo/LocalRepo.php (modified) (history)
  • /branches/filerepo-work/phase3/includes/filerepo/OldLocalFile.php (modified) (history)
  • /branches/filerepo-work/phase3/includes/filerepo/UnregisteredLocalFile.php (modified) (history)
  • /branches/filerepo-work/phase3/maintenance/FiveUpgrade.inc (modified) (history)
  • /branches/filerepo-work/phase3/maintenance/cleanupImages.php (modified) (history)
  • /branches/filerepo-work/phase3/maintenance/importImages.inc.php (modified) (history)
  • /branches/filerepo-work/phase3/maintenance/importImages.php (modified) (history)
  • /branches/filerepo-work/phase3/maintenance/rebuildImages.php (modified) (history)

Diff [purge]

Index: branches/filerepo-work/phase3/maintenance/importImages.php
@@ -42,56 +42,40 @@
4343 $license = isset( $options['license'] ) ? $options['license'] : '';
4444
4545 # Batch "upload" operation
 46+ global $wgUploadDirectory;
4647 foreach( $files as $file ) {
47 -
4848 $base = wfBaseName( $file );
4949
5050 # Validate a title
5151 $title = Title::makeTitleSafe( NS_IMAGE, $base );
52 - if( is_object( $title ) ) {
 52+ if( !is_object( $title ) ) {
 53+ echo( "{$base} could not be imported; a valid title cannot be produced\n" );
 54+ continue;
 55+ }
5356
54 - # Check existence
55 - $image = new Image( $title );
56 - if( !$image->exists() ) {
 57+ # Check existence
 58+ $image = wfLocalFile( $title );
 59+ if( $image->exists() ) {
 60+ echo( "{$base} could not be imported; a file with this name exists in the wiki\n" );
 61+ continue;
 62+ }
5763
58 - global $wgUploadDirectory;
 64+ # Stash the file
 65+ echo( "Saving {$base}..." );
5966
60 - # copy() doesn't create paths so if the hash path doesn't exist, we
61 - # have to create it
62 - makeHashPath( wfGetHashPath( $image->name ) );
 67+ $archive = $image->publish( $file );
 68+ if ( WikiError::isError( $archive ) ) {
 69+ echo( "failed.\n" );
 70+ continue;
 71+ }
 72+ echo( "importing..." );
6373
64 - # Stash the file
65 - echo( "Saving {$base}..." );
66 -
67 - if( copy( $file, $image->getFullPath() ) ) {
68 -
69 - echo( "importing..." );
70 -
71 - # Grab the metadata
72 - $image->loadFromFile();
73 -
74 - # Record the upload
75 - if( $image->recordUpload( '', $comment, $license ) ) {
76 -
77 - # We're done!
78 - echo( "done.\n" );
79 -
80 - } else {
81 - echo( "failed.\n" );
82 - }
83 -
84 - } else {
85 - echo( "failed.\n" );
86 - }
87 -
88 - } else {
89 - echo( "{$base} could not be imported; a file with this name exists in the wiki\n" );
90 - }
91 -
 74+ if ( $image->recordUpload( $archive, $comment, $license ) ) {
 75+ # We're done!
 76+ echo( "done.\n" );
9277 } else {
93 - echo( "{$base} could not be imported; a valid title cannot be produced\n" );
 78+ echo( "failed.\n" );
9479 }
95 -
9680 }
9781
9882 } else {
Index: branches/filerepo-work/phase3/maintenance/importImages.inc.php
@@ -47,20 +47,4 @@
4848 return array( $fname, $ext );
4949 }
5050
51 -/**
52 - * Given an image hash, check that the structure exists to save the image file
53 - * and create it if it doesn't
54 - *
55 - * @param $hash Part of an image hash, e.g. /f/fd/
56 - */
57 -function makeHashPath( $hash ) {
58 - global $wgUploadDirectory;
59 - $parts = explode( '/', substr( $hash, 1, strlen( $hash ) - 2 ) );
60 - if( !is_dir( $wgUploadDirectory . '/' . $parts[0] ) )
61 - mkdir( $wgUploadDirectory . '/' . $parts[0] );
62 - if( !is_dir( $wgUploadDirectory . '/' . $hash ) )
63 - mkdir( $wgUploadDirectory . '/' . $hash );
64 -}
65 -
66 -
67 -?>
\ No newline at end of file
 51+?>
Index: branches/filerepo-work/phase3/maintenance/cleanupImages.php
@@ -89,7 +89,10 @@
9090 }
9191
9292 function filePath( $name ) {
93 - return wfImageDir( $name ) . "/$name";
 93+ if ( !isset( $this->repo ) ) {
 94+ $this->repo = RepoGroup::singleton()->getLocalRepo();
 95+ }
 96+ return $this->repo->getRootDirectory() . '/' . $this->repo->getHashPath( $name ) . $name;
9497 }
9598
9699 function pokeFile( $orig, $new ) {
Index: branches/filerepo-work/phase3/maintenance/FiveUpgrade.inc
@@ -693,10 +693,7 @@
694694 return $copy;
695695 }
696696
697 - function imageInfo( $name, $subdirCallback='wfImageDir', $basename = null ) {
698 - if( is_null( $basename ) ) $basename = $name;
699 - $dir = call_user_func( $subdirCallback, $basename );
700 - $filename = $dir . '/' . $name;
 697+ function imageInfo( $filename ) {
701698 $info = array(
702699 'width' => 0,
703700 'height' => 0,
@@ -711,20 +708,13 @@
712709
713710 $info['media'] = $magic->getMediaType( $filename, $mime );
714711
715 - # Height and width
716 - $gis = false;
717 - if( $mime == 'image/svg' ) {
718 - $gis = wfGetSVGsize( $filename );
719 - } elseif( $magic->isPHPImageType( $mime ) ) {
720 - $gis = getimagesize( $filename );
721 - } else {
722 - $this->log( "Surprising mime type: $mime" );
723 - }
724 - if( $gis ) {
725 - $info['width' ] = $gis[0];
726 - $info['height'] = $gis[1];
727 - }
728 - if( isset( $gis['bits'] ) ) {
 712+ $image = UnregisteredLocalFile::newFromPath( $filename, $mime );
 713+
 714+ $info['width'] = $image->getWidth();
 715+ $info['height'] = $image->getHeight();
 716+
 717+ $gis = $image->getImageSize();
 718+ if ( isset( $gis['bits'] ) ) {
729719 $info['bits'] = $gis['bits'];
730720 }
731721
@@ -896,7 +886,7 @@
897887 }
898888
899889 function upgradeLogging() {
900 - $tabledef = <<<END
 890+ $tabledef = <<<ENDS
901891 CREATE TABLE $1 (
902892 -- Symbolic keys for the general log type and the action type
903893 -- within the log. The output format will be controlled by the
@@ -926,7 +916,7 @@
927917 KEY page_time (log_namespace, log_title, log_timestamp)
928918
929919 ) TYPE=InnoDB
930 -END;
 920+ENDS;
931921 $fields = array(
932922 'log_type' => MW_UPGRADE_COPY,
933923 'log_action' => MW_UPGRADE_COPY,
@@ -940,7 +930,7 @@
941931 }
942932
943933 function upgradeArchive() {
944 - $tabledef = <<<END
 934+ $tabledef = <<<ENDS
945935 CREATE TABLE $1 (
946936 ar_namespace int NOT NULL default '0',
947937 ar_title varchar(255) binary NOT NULL default '',
@@ -960,7 +950,7 @@
961951 KEY name_title_timestamp (ar_namespace,ar_title,ar_timestamp)
962952
963953 ) TYPE=InnoDB
964 -END;
 954+ENDS;
965955 $fields = array(
966956 'ar_namespace' => MW_UPGRADE_COPY,
967957 'ar_title' => MW_UPGRADE_ENCODE,
@@ -979,7 +969,7 @@
980970 function upgradeImagelinks() {
981971 global $wgUseLatin1;
982972 if( $wgUseLatin1 ) {
983 - $tabledef = <<<END
 973+ $tabledef = <<<ENDS
984974 CREATE TABLE $1 (
985975 -- Key to page_id of the page containing the image / media link.
986976 il_from int(8) unsigned NOT NULL default '0',
@@ -993,7 +983,7 @@
994984 KEY (il_to)
995985
996986 ) TYPE=InnoDB
997 -END;
 987+ENDS;
998988 $fields = array(
999989 'il_from' => MW_UPGRADE_COPY,
1000990 'il_to' => MW_UPGRADE_ENCODE );
@@ -1004,7 +994,7 @@
1005995 function upgradeCategorylinks() {
1006996 global $wgUseLatin1;
1007997 if( $wgUseLatin1 ) {
1008 - $tabledef = <<<END
 998+ $tabledef = <<<ENDS
1009999 CREATE TABLE $1 (
10101000 cl_from int(8) unsigned NOT NULL default '0',
10111001 cl_to varchar(255) binary NOT NULL default '',
@@ -1015,7 +1005,7 @@
10161006 KEY cl_sortkey(cl_to,cl_sortkey),
10171007 KEY cl_timestamp(cl_to,cl_timestamp)
10181008 ) TYPE=InnoDB
1019 -END;
 1009+ENDS;
10201010 $fields = array(
10211011 'cl_from' => MW_UPGRADE_COPY,
10221012 'cl_to' => MW_UPGRADE_ENCODE,
@@ -1028,7 +1018,7 @@
10291019 function upgradeIpblocks() {
10301020 global $wgUseLatin1;
10311021 if( $wgUseLatin1 ) {
1032 - $tabledef = <<<END
 1022+ $tabledef = <<<ENDS
10331023 CREATE TABLE $1 (
10341024 ipb_id int(8) NOT NULL auto_increment,
10351025 ipb_address varchar(40) binary NOT NULL default '',
@@ -1044,7 +1034,7 @@
10451035 INDEX ipb_user (ipb_user)
10461036
10471037 ) TYPE=InnoDB
1048 -END;
 1038+ENDS;
10491039 $fields = array(
10501040 'ipb_id' => MW_UPGRADE_COPY,
10511041 'ipb_address' => MW_UPGRADE_COPY,
@@ -1060,7 +1050,7 @@
10611051
10621052 function upgradeRecentchanges() {
10631053 // There's a format change in the namespace field
1064 - $tabledef = <<<END
 1054+ $tabledef = <<<ENDS
10651055 CREATE TABLE $1 (
10661056 rc_id int(8) NOT NULL auto_increment,
10671057 rc_timestamp varchar(14) binary NOT NULL default '',
@@ -1098,7 +1088,7 @@
10991089 INDEX rc_ip (rc_ip)
11001090
11011091 ) TYPE=InnoDB
1102 -END;
 1092+ENDS;
11031093 $fields = array(
11041094 'rc_id' => MW_UPGRADE_COPY,
11051095 'rc_timestamp' => MW_UPGRADE_COPY,
@@ -1124,7 +1114,7 @@
11251115
11261116 function upgradeQuerycache() {
11271117 // There's a format change in the namespace field
1128 - $tabledef = <<<END
 1118+ $tabledef = <<<ENDS
11291119 CREATE TABLE $1 (
11301120 -- A key name, generally the base name of of the special page.
11311121 qc_type char(32) NOT NULL,
@@ -1139,7 +1129,7 @@
11401130 KEY (qc_type,qc_value)
11411131
11421132 ) TYPE=InnoDB
1143 -END;
 1133+ENDS;
11441134 $fields = array(
11451135 'qc_type' => MW_UPGRADE_COPY,
11461136 'qc_value' => MW_UPGRADE_COPY,
Index: branches/filerepo-work/phase3/maintenance/rebuildImages.php
@@ -40,8 +40,18 @@
4141
4242 $this->maxLag = 10; # if slaves are lagged more than 10 secs, wait
4343 $this->dryrun = $dryrun;
 44+ if ( $dryrun ) {
 45+ $GLOBALS['wgReadOnly'] = 'Dry run mode, image upgrades are suppressed';
 46+ }
4447 }
4548
 49+ function getRepo() {
 50+ if ( !isset( $this->repo ) ) {
 51+ $this->repo = RepoGroup::singleton()->getLocalRepo();
 52+ }
 53+ return $this->repo;
 54+ }
 55+
4656 function build() {
4757 $this->buildImage();
4858 $this->buildOldImage();
@@ -94,13 +104,7 @@
95105
96106 while( $row = $this->dbr->fetchObject( $result ) ) {
97107 $update = call_user_func( $callback, $row );
98 - if( is_array( $update ) ) {
99 - if( !$this->dryrun ) {
100 - $this->dbw->update( $table,
101 - $update,
102 - array( $key => $row->$key ),
103 - $fname );
104 - }
 108+ if( $update ) {
105109 $this->progress( 1 );
106110 } else {
107111 $this->progress( 0 );
@@ -116,97 +120,43 @@
117121 }
118122
119123 function imageCallback( $row ) {
120 - if( $row->img_width ) {
121 - // Already processed
122 - return null;
123 - }
124 -
125 - // Fill in the new image info fields
126 - $info = $this->imageInfo( $row->img_name );
127 -
128 - global $wgMemc;
129 - $key = wfMemcKey( "Image", md5( $row->img_name ) );
130 - $wgMemc->delete( $key );
131 -
132 - return array(
133 - 'img_width' => $info['width'],
134 - 'img_height' => $info['height'],
135 - 'img_bits' => $info['bits'],
136 - 'img_media_type' => $info['media'],
137 - 'img_major_mime' => $info['major'],
138 - 'img_minor_mime' => $info['minor'] );
 124+ // Create a File object from the row
 125+ // This will also upgrade it
 126+ $file = $this->getRepo()->newFileFromRow( $row );
 127+ return $file->getUpgraded();
139128 }
140129
141 -
142130 function buildOldImage() {
143131 $this->buildTable( 'oldimage', 'oi_archive_name',
144132 array( &$this, 'oldimageCallback' ) );
145133 }
146134
147135 function oldimageCallback( $row ) {
148 - if( $row->oi_width ) {
149 - return null;
 136+ // Create a File object from the row
 137+ // This will also upgrade it
 138+ if ( $row->oi_archive_name == '' ) {
 139+ $this->log( "Empty oi_archive_name for oi_name={$row->oi_name}" );
 140+ return false;
150141 }
151 -
152 - // Fill in the new image info fields
153 - $info = $this->imageInfo( $row->oi_archive_name, 'wfImageArchiveDir', $row->oi_name );
154 - return array(
155 - 'oi_width' => $info['width' ],
156 - 'oi_height' => $info['height'],
157 - 'oi_bits' => $info['bits' ] );
 142+ $file = $this->getRepo()->newFileFromRow( $row );
 143+ return $file->getUpgraded();
158144 }
159145
160146 function crawlMissing() {
161 - global $wgUploadDirectory, $wgHashedUploadDirectory;
162 - if( $wgHashedUploadDirectory ) {
163 - for( $i = 0; $i < 16; $i++ ) {
164 - for( $j = 0; $j < 16; $j++ ) {
165 - $dir = sprintf( '%s%s%01x%s%02x',
166 - $wgUploadDirectory,
167 - DIRECTORY_SEPARATOR,
168 - $i,
169 - DIRECTORY_SEPARATOR,
170 - $i * 16 + $j );
171 - $this->crawlDirectory( $dir );
172 - }
173 - }
174 - } else {
175 - $this->crawlDirectory( $wgUploadDirectory );
176 - }
 147+ $repo = RepoGroup::singleton()->getLocalRepo();
 148+ $repo->enumFilesInFS( array( $this, 'checkMissingImage' ) );
177149 }
178150
179 - function crawlDirectory( $dir ) {
180 - if( !file_exists( $dir ) ) {
181 - return $this->log( "no directory, skipping $dir" );
 151+ function checkMissingImage( $fullpath ) {
 152+ $fname = 'ImageBuilder::checkMissingImage';
 153+ $filename = wfBaseName( $fullpath );
 154+ if( is_dir( $fullpath ) ) {
 155+ return;
182156 }
183 - if( !is_dir( $dir ) ) {
184 - return $this->log( "not a directory?! skipping $dir" );
 157+ if( is_link( $fullpath ) ) {
 158+ $this->log( "skipping symlink at $fullpath" );
 159+ return;
185160 }
186 - if( !is_readable( $dir ) ) {
187 - return $this->log( "dir not readable, skipping $dir" );
188 - }
189 - $source = opendir( $dir );
190 - if( $source === false ) {
191 - return $this->log( "couldn't open dir, skipping $dir" );
192 - }
193 -
194 - $this->log( "crawling $dir" );
195 - while( false !== ( $filename = readdir( $source ) ) ) {
196 - $fullpath = $dir . DIRECTORY_SEPARATOR . $filename;
197 - if( is_dir( $fullpath ) ) {
198 - continue;
199 - }
200 - if( is_link( $fullpath ) ) {
201 - $this->log( "skipping symlink at $fullpath" );
202 - continue;
203 - }
204 - $this->checkMissingImage( $filename, $fullpath );
205 - }
206 - closedir( $source );
207 - }
208 -
209 - function checkMissingImage( $filename, $fullpath ) {
210 - $fname = 'ImageBuilder::checkMissingImage';
211161 $row = $this->dbw->selectRow( 'image',
212162 array( 'img_name' ),
213163 array( 'img_name' => $filename ),
@@ -224,7 +174,7 @@
225175 $fname = 'ImageBuilder::addMissingImage';
226176
227177 $size = filesize( $fullpath );
228 - $info = $this->imageInfo( $filename );
 178+ $info = $this->imageInfo( $fullpath );
229179 $timestamp = $this->dbw->timestamp( filemtime( $fullpath ) );
230180
231181 global $wgContLang;
@@ -242,23 +192,14 @@
243193 $this->log( "Empty filename for $fullpath" );
244194 return;
245195 }
246 -
247 - $fields = array(
248 - 'img_name' => $filename,
249 - 'img_size' => $size,
250 - 'img_width' => $info['width'],
251 - 'img_height' => $info['height'],
252 - 'img_metadata' => '', // filled in on-demand
253 - 'img_bits' => $info['bits'],
254 - 'img_media_type' => $info['media'],
255 - 'img_major_mime' => $info['major'],
256 - 'img_minor_mime' => $info['minor'],
257 - 'img_description' => '(recovered file, missing upload log entry)',
258 - 'img_user' => 0,
259 - 'img_user_text' => 'Conversion script',
260 - 'img_timestamp' => $timestamp );
261 - if( !$this->dryrun ) {
262 - $this->dbw->insert( 'image', $fields, $fname );
 196+ if ( !$this->dryrun ) {
 197+ $file = wfLocalFile( $filename );
 198+ if ( !$file->recordUpload( '', '(recovered file, missing upload log entry)', '', '', '',
 199+ false, $timestamp ) )
 200+ {
 201+ $this->log( "Error uploading file $fullpath" );
 202+ return;
 203+ }
263204 }
264205 $this->log( $fullpath );
265206 }
Index: branches/filerepo-work/phase3/includes/filerepo/OldLocalFile.php
@@ -12,12 +12,33 @@
1313 const MAX_CACHE_ROWS = 20;
1414
1515 function newFromTitle( $title, $repo, $time ) {
16 - return new OldLocalFile( $title, $repo, $time );
 16+ return new self( $title, $repo, $time, null );
1717 }
1818
19 - function __construct( $title, $repo, $time ) {
 19+ function newFromArchiveName( $title, $repo, $archiveName ) {
 20+ return new self( $title, $repo, null, $archiveName );
 21+ }
 22+
 23+ function newFromRow( $row, $repo ) {
 24+ $title = Title::makeTitle( NS_IMAGE, $row->oi_name );
 25+ $file = new self( $title, $repo, null, $row->oi_archive_name );
 26+ $file->loadFromRow( $row, 'oi_' );
 27+ return $file;
 28+ }
 29+
 30+ /**
 31+ * @param Title $title
 32+ * @param FileRepo $repo
 33+ * @param string $time Timestamp or null to load by archive name
 34+ * @param string $archiveName Archive name or null to load by timestamp
 35+ */
 36+ function __construct( $title, $repo, $time, $archiveName ) {
2037 parent::__construct( $title, $repo );
2138 $this->requestedTime = $time;
 39+ $this->archive_name = $archiveName;
 40+ if ( is_null( $time ) && is_null( $archiveName ) ) {
 41+ throw new MWException( __METHOD__.': must specify at least one of $time or $archiveName' );
 42+ }
2243 }
2344
2445 function getCacheKey() {
@@ -26,7 +47,9 @@
2748 }
2849
2950 function getArchiveName() {
30 - $this->load();
 51+ if ( !isset( $this->archive_name ) ) {
 52+ $this->load();
 53+ }
3154 return $this->archive_name;
3255 }
3356
@@ -48,22 +71,32 @@
4972 $oldImages = $wgMemc->get( $key );
5073
5174 if ( isset( $oldImages['version'] ) && $oldImages['version'] == MW_OLDFILE_VERSION ) {
52 - unset( $oldImages['version'];
 75+ unset( $oldImages['version'] );
5376 $more = isset( $oldImages['more'] );
5477 unset( $oldImages['more'] );
55 - krsort( $oldImages );
5678 $found = false;
57 - foreach ( $oldImages as $timestamp => $info ) {
58 - if ( $timestamp <= $this->desiredTimestamp ) {
59 - $found = true;
60 - break;
 79+ if ( is_null( $this->requestedTime ) ) {
 80+ foreach ( $oldImages as $timestamp => $info ) {
 81+ if ( $info['archive_name'] == $this->archive_name ) {
 82+ $found = true;
 83+ break;
 84+ }
6185 }
 86+ } else {
 87+ krsort( $oldImages );
 88+ foreach ( $oldImages as $timestamp => $info ) {
 89+ if ( $timestamp <= $this->requestedTime ) {
 90+ $found = true;
 91+ break;
 92+ }
 93+ }
6294 }
6395 if ( $found ) {
6496 wfDebug( "Pulling file metadata from cache key {$key}[{$timestamp}]\n" );
65 - $this->loadFromRow( (object)$cachedValues ) );
66 - $this->fileExists = true;
6797 $this->dataLoaded = true;
 98+ foreach ( $cachedValues as $name => $value ) {
 99+ $this->$name = $value;
 100+ }
68101 } elseif ( $more ) {
69102 wfDebug( "Cache key was truncated, oldimage row might be found in the database\n" );
70103 } else {
@@ -122,16 +155,16 @@
123156 function loadFromDB() {
124157 wfProfileIn( __METHOD__ );
125158 $dbr = $this->repo->getSlaveDB();
 159+ $conds = array( 'oi_name' => $this->getName() );
 160+ if ( is_null( $this->requestedTimestamp ) ) {
 161+ $conds['oi_archive_name'] = $this->archive_name;
 162+ } else {
 163+ $conds[] = 'oi_timestamp <= ' . $dbr->addQuotes( $this->requestedTimestamp );
 164+ }
126165 $row = $dbr->selectRow( 'oldimage', $this->getCacheFields( 'oi_' ),
127 - array(
128 - 'oi_name' => $this->getName(),
129 - 'oi_timestamp <= ' . $this->requestedTimestamp
130 - ), __METHOD__, array( 'ORDER BY' => 'oi_timestamp DESC' ) );
 166+ $conds, __METHOD__, array( 'ORDER BY' => 'oi_timestamp DESC' ) );
131167 if ( $row ) {
132 - $this->decodeRow( $row, 'oi_' );
133168 $this->loadFromRow( $row, 'oi_' );
134 - // Check for rows from a previous schema, quietly upgrade them
135 - $this->maybeUpgradeRow();
136169 } else {
137170 $this->fileExists = false;
138171 }
@@ -141,14 +174,19 @@
142175 function getCacheFields( $prefix = 'img_' ) {
143176 $fields = parent::getCacheFields( $prefix );
144177 $fields[] = $prefix . 'archive_name';
 178+
 179+ // XXX: Temporary hack before schema update
 180+ $fields = array_diff( $fields, array(
 181+ 'oi_media_type', 'oi_major_mime', 'oi_minor_mime', 'oi_metadata' ) );
 182+ return $fields;
145183 }
146184
147185 function getRel() {
148 - return 'archive/' . $this->getHashPath() . '/' . $this->archive_name;
 186+ return 'archive/' . $this->getHashPath() . $this->getArchiveName();
149187 }
150188
151189 function getUrlRel() {
152 - return 'archive/' . $this->getHashPath() . '/' . urlencode( $this->archive_name );
 190+ return 'archive/' . $this->getHashPath() . urlencode( $this->getArchiveName() );
153191 }
154192
155193 function upgradeRow() {
@@ -165,15 +203,19 @@
166204 'oi_width' => $this->width,
167205 'oi_height' => $this->height,
168206 'oi_bits' => $this->bits,
169 - 'oi_media_type' => $this->media_type,
170 - 'oi_major_mime' => $major,
171 - 'oi_minor_mime' => $minor,
172 - 'oi_metadata' => $this->metadata,
 207+ #'oi_media_type' => $this->media_type,
 208+ #'oi_major_mime' => $major,
 209+ #'oi_minor_mime' => $minor,
 210+ #'oi_metadata' => $this->metadata,
173211 ), array( 'oi_name' => $this->getName(), 'oi_timestamp' => $this->requestedTime ),
174212 __METHOD__
175213 );
176214 wfProfileOut( __METHOD__ );
177215 }
 216+
 217+ // XXX: Temporary hack before schema update
 218+ function maybeUpgradeRow() {}
 219+
178220 }
179221
180222
Index: branches/filerepo-work/phase3/includes/filerepo/LocalFile.php
@@ -34,7 +34,8 @@
3535 $size, # Size in bytes (loadFromXxx)
3636 $metadata, # Metadata
3737 $timestamp, # Upload timestamp
38 - $dataLoaded; # Whether or not all this has been loaded from the database (loadFromXxx)
 38+ $dataLoaded, # Whether or not all this has been loaded from the database (loadFromXxx)
 39+ $upgraded; # Whether the row was upgraded on load
3940
4041 /**#@-*/
4142
@@ -42,6 +43,13 @@
4344 return new self( $title, $repo );
4445 }
4546
 47+ function newFromRow( $row, $repo ) {
 48+ $title = Title::makeTitle( NS_IMAGE, $row->img_name );
 49+ $file = new self( $title, $repo );
 50+ $file->loadFromRow( $row );
 51+ return $file;
 52+ }
 53+
4654 function __construct( $title, $repo ) {
4755 if( !is_object( $title ) ) {
4856 throw new MWException( __CLASS__.' constructor given bogus title.' );
@@ -80,7 +88,9 @@
8189 if ( $this->fileExists ) {
8290 unset( $cachedValues['version'] );
8391 unset( $cachedValues['fileExists'] );
84 - $this->loadFromRow( $cachedValues, '' );
 92+ foreach ( $cachedValues as $name => $value ) {
 93+ $this->$name = $value;
 94+ }
8595 }
8696 }
8797 if ( $this->dataLoaded ) {
@@ -196,60 +206,63 @@
197207 function loadFromDB() {
198208 wfProfileIn( __METHOD__ );
199209
 210+ # Unconditionally set loaded=true, we don't want the accessors constantly rechecking
 211+ $this->dataLoaded = true;
 212+
200213 $dbr = $this->repo->getSlaveDB();
201214
202215 $row = $dbr->selectRow( 'image', $this->getCacheFields( 'img_' ),
203216 array( 'img_name' => $this->getName() ), __METHOD__ );
204217 if ( $row ) {
205 - $this->fileExists = true;
206 - $this->decodeRow( $row );
207218 $this->loadFromRow( $row );
208 - // Check for rows from a previous schema, quietly upgrade them
209 - $this->maybeUpgradeRow();
210219 } else {
211220 $this->fileExists = false;
212221 }
213222
214 - # Unconditionally set loaded=true, we don't want the accessors constantly rechecking
215 - $this->dataLoaded = true;
216223 wfProfileOut( __METHOD__ );
217224 }
218225
219 - function decodeRow( &$row, $prefix = 'img_' ) {
220 - $tsName = $prefix . 'timestamp';
221 - $row->$tsName = wfTimestamp( TS_MW, $row->$tsName );
222 - }
223 -
224 - function encodeRow( &$row, $db, $prefix = 'img_' ) {
225 - $tsName = $prefix . 'timestamp';
226 - $row->$tsName = $db->timestamp( $row->$tsName );
227 - }
228 -
229 - /*
230 - * Load file metadata from a DB result row
 226+ /**
 227+ * Decode a row from the database (either object or array) to an array
 228+ * with timestamps and MIME types decoded, and the field prefix removed.
231229 */
232 - function loadFromRow( $row, $prefix = 'img_' ) {
 230+ function decodeRow( $row, $prefix = 'img_' ) {
233231 $array = (array)$row;
234232 $prefixLength = strlen( $prefix );
235233 // Sanity check prefix once
236234 if ( substr( key( $array ), 0, $prefixLength ) !== $prefix ) {
237235 throw new MWException( __METHOD__. ': incorrect $prefix parameter' );
238 - }
 236+ }
 237+ $decoded = array();
239238 foreach ( $array as $name => $value ) {
240239 $deprefixedName = substr( $name, $prefixLength );
241 - $this->$deprefixedName = $value;
 240+ $decoded[substr( $name, $prefixLength )] = $value;
242241 }
243 - if ( !$this->major_mime ) {
244 - $this->mime = "unknown/unknown";
 242+ $decoded['timestamp'] = wfTimestamp( TS_MW, $decoded['timestamp'] );
 243+ if ( empty( $decoded['major_mime'] ) ) {
 244+ $decoded['mime'] = "unknown/unknown";
245245 } else {
246 - if (!$this->minor_mime) {
247 - $this->minor_mime = "unknown";
 246+ if (!$decoded['minor_mime']) {
 247+ $decoded['minor_mime'] = "unknown";
248248 }
249 - $this->mime = $this->major_mime.'/'.$this->minor_mime;
 249+ $decoded['mime'] = $decoded['major_mime'].'/'.$decoded['minor_mime'];
250250 }
251 - $this->dataLoaded = true;
 251+ return $decoded;
252252 }
253253
 254+ /*
 255+ * Load file metadata from a DB result row
 256+ */
 257+ function loadFromRow( $row, $prefix = 'img_' ) {
 258+ $array = $this->decodeRow( $row, $prefix );
 259+ foreach ( $array as $name => $value ) {
 260+ $this->$name = $value;
 261+ }
 262+ $this->fileExists = true;
 263+ // Check for rows from a previous schema, quietly upgrade them
 264+ $this->maybeUpgradeRow();
 265+ }
 266+
254267 /**
255268 * Load file metadata from cache or DB, unless already loaded
256269 */
@@ -267,16 +280,25 @@
268281 * Upgrade a row if it needs it
269282 */
270283 function maybeUpgradeRow() {
 284+ if ( wfReadOnly() ) {
 285+ return;
 286+ }
271287 if ( is_null($this->media_type) || $this->mime == 'image/svg' ) {
272288 $this->upgradeRow();
 289+ $this->upgraded = true;
273290 } else {
274291 $handler = $this->getHandler();
275292 if ( $handler && !$handler->isMetadataValid( $this, $this->metadata ) ) {
276293 $this->upgradeRow();
 294+ $this->upgraded = true;
277295 }
278296 }
279297 }
280298
 299+ function getUpgraded() {
 300+ return $this->upgraded;
 301+ }
 302+
281303 /**
282304 * Fix assorted version-related problems with the image row by reloading it from the file
283305 */
@@ -302,6 +324,7 @@
303325 ), array( 'img_name' => $this->getName() ),
304326 __METHOD__
305327 );
 328+ $this->saveToCache();
306329 wfProfileOut( __METHOD__ );
307330 }
308331
@@ -590,7 +613,9 @@
591614 /**
592615 * Record a file upload in the upload log and the image table
593616 */
594 - function recordUpload( $oldver, $desc, $license = '', $copyStatus = '', $source = '', $watch = false ) {
 617+ function recordUpload( $oldver, $desc, $license = '', $copyStatus = '', $source = '',
 618+ $watch = false, $timestamp = false )
 619+ {
595620 global $wgUser, $wgUseCopyrightUpload;
596621
597622 $dbw = $this->repo->getMasterDB();
@@ -622,7 +647,9 @@
623648 }
624649 }
625650
626 - $now = $dbw->timestamp();
 651+ if ( $timestamp === false ) {
 652+ $timestamp = $dbw->timestamp();
 653+ }
627654
628655 #split mime type
629656 if (strpos($this->mime,'/')!==false) {
@@ -646,7 +673,7 @@
647674 'img_media_type' => $this->media_type,
648675 'img_major_mime' => $major,
649676 'img_minor_mime' => $minor,
650 - 'img_timestamp' => $now,
 677+ 'img_timestamp' => $timestamp,
651678 'img_description' => $desc,
652679 'img_user' => $wgUser->getID(),
653680 'img_user_text' => $wgUser->getName(),
@@ -684,7 +711,7 @@
685712 'img_media_type' => $this->media_type,
686713 'img_major_mime' => $major,
687714 'img_minor_mime' => $minor,
688 - 'img_timestamp' => $now,
 715+ 'img_timestamp' => $timestamp,
689716 'img_description' => $desc,
690717 'img_user' => $wgUser->getID(),
691718 'img_user_text' => $wgUser->getName(),
Index: branches/filerepo-work/phase3/includes/filerepo/UnregisteredLocalFile.php
@@ -76,7 +76,7 @@
7777 if ( !$this->getHandler() ) {
7878 return false;
7979 }
80 - return $this->handler->getImageSize( $this, $this->getImagePath() );
 80+ return $this->handler->getImageSize( $this, $this->getPath() );
8181 }
8282
8383 function getMetadata() {
@@ -84,7 +84,7 @@
8585 if ( !$this->getHandler() ) {
8686 $this->metadata = false;
8787 } else {
88 - $this->metadata = $this->handler->getMetadata( $this, $this->getImagePath() );
 88+ $this->metadata = $this->handler->getMetadata( $this, $this->getPath() );
8989 }
9090 }
9191 return $this->metadata;
Index: branches/filerepo-work/phase3/includes/filerepo/FSRepo.php
@@ -333,6 +333,36 @@
334334 }
335335 }
336336 }
 337+
 338+ /**
 339+ * Call a callback function for every file in the repository.
 340+ * Uses the filesystem even in child classes.
 341+ */
 342+ function enumFilesInFS( $callback ) {
 343+ $numDirs = 1 << ( $this->hashLevels * 4 );
 344+ for ( $flatIndex = 0; $flatIndex < $numDirs; $flatIndex++ ) {
 345+ $hexString = sprintf( "%0{$this->hashLevels}x", $flatIndex );
 346+ $path = $this->directory;
 347+ for ( $hexPos = 0; $hexPos < $this->hashLevels; $hexPos++ ) {
 348+ $path .= '/' . substr( $hexString, 0, $hexPos + 1 );
 349+ }
 350+ if ( !file_exists( $path ) || !is_dir( $path ) ) {
 351+ continue;
 352+ }
 353+ $dir = opendir( $path );
 354+ while ( false !== ( $name = readdir( $dir ) ) ) {
 355+ call_user_func( $callback, $path . '/' . $name );
 356+ }
 357+ }
 358+ }
 359+
 360+ /**
 361+ * Call a callaback function for every file in the repository
 362+ * May use either the database or the filesystem
 363+ */
 364+ function enumFiles( $callback ) {
 365+ $this->enumFilesInFS( $callback );
 366+ }
337367 }
338368
339369 ?>
Index: branches/filerepo-work/phase3/includes/filerepo/LocalRepo.php
@@ -13,4 +13,14 @@
1414 function getMasterDB() {
1515 return wfGetDB( DB_MASTER );
1616 }
 17+
 18+ function newFileFromRow( $row ) {
 19+ if ( isset( $row->img_name ) ) {
 20+ return LocalFile::newFromRow( $row, $this );
 21+ } elseif ( isset( $row->oi_name ) ) {
 22+ return OldLocalFile::newFromRow( $row, $this );
 23+ } else {
 24+ throw new MWException( __METHOD__.': invalid row' );
 25+ }
 26+ }
1727 }
Index: branches/filerepo-work/phase3/includes/AutoLoader.php
@@ -257,6 +257,7 @@
258258 'Image' => 'includes/filerepo/LocalFile.php',
259259 'LocalFile' => 'includes/filerepo/LocalFile.php',
260260 'LocalRepo' => 'includes/filerepo/LocalRepo.php',
 261+ 'OldLocalFile' => 'includes/filerepo/OldLocalFile.php',
261262 'RepoGroup' => 'includes/filerepo/RepoGroup.php',
262263 'UnregisteredLocalFile' => 'includes/filerepo/UnregisteredLocalFile.php',
263264