-
Notifications
You must be signed in to change notification settings - Fork 62
/
update
executable file
·260 lines (221 loc) · 7.4 KB
/
update
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#!/usr/bin/env php
<?php
$args = $argv;
$cmd = array_shift( $args );
chdir( dirname( __FILE__ ) );
$type = 'all';
if ( ! empty( $args[0] ) ) {
$type = $args[0];
}
$parallel = 12;
if ( ! empty( $args[1] ) ) {
$parallel = (int) $args[1];
}
if (
( $type !== 'readme' && $type !== 'all' ) ||
$parallel < 1 || $parallel > 20
) {
echo $cmd . ": invalid arguments\n";
echo 'Usage: php ' . $cmd . " [command] [parallel=12]\n\n";
echo "Available commands:\n";
echo " all - Downloads full plugin zips. This is the default.\n";
echo " readme - Downloads plugin readmes only.\n";
echo "\n";
echo "Set 'parallel' to control the number of parallel processes.\n";
echo " A smaller number may go more smoothly for slower connections.\n";
echo " More than 12 is not recommended.\n";
die();
}
require_once 'common.php';
echo "Determining most recent SVN revision...\n";
try {
ini_set( 'user_agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0' );
$changelog = @file_get_contents( 'https://plugins.trac.wordpress.org/log/?format=changelog&stop_rev=HEAD' );
print_r( $changelog );
if ( ! $changelog ) {
throw new Exception( 'Could not fetch the SVN changelog' );
}
preg_match( '#\[([0-9]+)\]#', $changelog, $matches );
if ( ! $matches[1] ) {
throw new Exception( 'Could not determine most recent revision.' );
}
} catch ( Exception $e ) {
die( $e->getMessage() . "\n" );
}
$svn_last_revision = (int) $matches[1];
echo "Most recent SVN revision : $svn_last_revision\n";
$last_revision = read_last_revision( $type );
$start_time = time();
if ( $last_revision === $svn_last_revision ) {
// Nothing to do.
echo "Your copy of the plugin repository is up to date.\n";
exit( 0 );
} else if ( $last_revision ) {
// Do a partial sync to update the repository.
echo "Last synced revision : $last_revision\n";
if ( $svn_last_revision - $last_revision > 200000 ) {
echo "Your copy of the plugin repository is VERY far behind.\n";
echo "We'll try to sync, but you may want to delete it and start over.\n";
}
// For each plugin, store an array of revision indices where it was
// updated. These indices point to entries in the $revisions array.
// Structure:
// {
// 'plugin-slug': [
// IndexIn$revisions,
// ...
// ],
// ...
// }
$plugins = array();
// Store an array of revisions too. When a plugin is updated, ALL of its
// associated revisions will be marked as updated in this list. During a
// partial sync, this allows us to accurately determine the latest revision
// saved on the hard drive.
// Structure (note - revisions are in descending order for efficiency):
// [
// {
// 'number': RevisionNumber,
// 'to_update': {
// 'plugin-slug': true,
// ...
// }
// },
// ...
// ]
$revisions = array();
// Fetch the plugins repository changelog using `svn log`.
$changelog_command = sprintf(
'svn log -v -q https://plugins.svn.wordpress.org/ -r %d:%d',
$svn_last_revision,
$last_revision + 1
);
echo "Requesting plugins changelog:\n";
echo "$changelog_command\n";
// Start `svn` process.
$descriptors = array(
1 => array( 'pipe', 'w' ), // `svn` will write to stdout.
);
$svn = proc_open( $changelog_command, $descriptors, $pipes );
// Process output from `svn log`.
$revision = 0;
while ( ( $line = fgets( $pipes[1] ) ) !== false ) {
if ( preg_match( '#^r([0-9]+) \\|#', $line, $matches ) ) {
// This line indicates the revision number for the following
// change(s).
if ( ! $revision ) { // This is the first log entry.
echo "... r$svn_last_revision ";
}
$revision = (int) $matches[1];
if ( ( $revision % 5000 ) === 0 ) {
echo "\n... r$revision ";
} else if ( ( $revision % 100 ) === 0 ) {
echo ".";
}
} else if ( preg_match( '#^ [ADMR] /([^/(]+)/#', $line, $matches ) ) {
// This line indicates an operation performed on a plugin file.
// For copies we get lines like " A /plugin-slug (from /...:###)"
// (r1725406 for example) so trim to remove any extra spaces.
$plugin = trim( $matches[1] );
if ( ! isset( $plugins[ $plugin ] ) ) {
// This is the first time we've seen this plugin.
$plugins[ $plugin ] = array();
}
if (
count( $revisions ) === 0 ||
$revisions[ count( $revisions ) - 1 ]['number'] !== $revision
) {
// Add a new entry for this revision.
array_push( $revisions, array(
'number' => $revision,
'to_update' => array(),
) );
}
$rev_index = count( $revisions ) - 1;
// Mark this plugin as updated by the current revision. (It's
// possible for a plugin author to update multiple plugins in a
// single revision.)
if ( ! isset( $revisions[ $rev_index ]['to_update'][ $plugin ] ) ) {
$revisions[ $rev_index ]['to_update'][ $plugin ] = true;
array_push( $plugins[ $plugin ], $rev_index );
}
}
}
echo "\n";
$status = proc_get_status( $svn );
if ( $status['running'] ) {
throw new Exception(
'svn should not still be running.'
);
}
if ( $status['exitcode'] ) {
throw new Exception( sprintf(
'Unexpected svn exit code: %d. Make sure svn is installed.',
$status['exitcode']
) );
}
proc_close( $svn );
// Make sure we got all the expected changelog entries.
if ( $revision !== $last_revision + 1 ) {
throw new Exception( sprintf(
'Failed to parse plugins changelog (expected revision %d but found %d).',
$last_revision + 1,
$revision
) );
}
// We have data structures with info about all the plugins and revisions we
// need to fetch. Now, loop over all the revisions in reverse order
// (oldest to newest) and fetch plugins in this order.
$plugins_ordered = array();
for ( $i = count( $revisions ) - 1; $i >= 0; $i-- ) {
foreach ( $revisions[ $i ]['to_update'] as $plugin => $ignore ) {
$plugins_ordered[ $plugin ] = true;
}
}
$plugins_ordered = array_keys( $plugins_ordered );
printf(
"%d plugin%s to update (%d SVN revision%s)\n",
count( $plugins ),
( count( $plugins ) === 1 ? '' : 's' ),
count( $revisions ),
( count( $revisions ) === 1 ? '' : 's' )
);
$update_stats = download_plugins( $type, $plugins_ordered, true );
// This should happen during the update but it won't hurt to do it again.
write_last_revision( $type, $svn_last_revision );
} else {
// Do an initial full sync.
echo "\n";
echo "You have not performed a successful sync yet.\n";
echo "Settle in. This will take a while.\n";
echo "\n";
echo "Fetching list of all plugins...\n";
$plugins = file_get_contents( 'https://plugins.svn.wordpress.org/' );
if ( ! $plugins ) {
// Something went wrong; there should be a warning message above
throw new Exception( 'Failed to download plugins list.' );
}
preg_match_all( '#<li><a href="([^/]+)/">([^/]+)/</a></li>#', $plugins, $matches );
$plugins = $matches[1];
printf(
"%d plugins to download\n",
count( $plugins )
);
$update_stats = download_plugins( $type, $plugins, false );
write_last_revision( $type, $svn_last_revision );
}
$end_time = time();
$minutes = floor( ( $end_time - $start_time ) / 60 );
$seconds = ( $end_time - $start_time ) % 60;
echo "[SUCCESS] Done updating plugins!\n";
printf(
"It took %d minute%s and %d second%s to update %d plugin%s (%d failed).\n",
$minutes,
( $minutes === 1 ? '' : 's' ),
$seconds,
( $seconds === 1 ? '' : 's' ),
$update_stats['updated'],
( $update_stats['updated'] === 1 ? '' : 's' ),
$update_stats['failed']
);
echo "[DONE]\n";