1
|
<?php
|
2
|
// $Id: drush_make_d_o.convert.inc,v 1.1.2.17 2010/09/09 07:11:00 dmitrig01 Exp $
|
3
|
|
4
|
class DrushMakeDrupalorgVersionChecker {
|
5
|
function latestVersion($project_name, $version) {
|
6
|
|
7
|
// Project types that are valid for the version checker.
|
8
|
$allowed_project_types = array(
|
9
|
'core',
|
10
|
'module',
|
11
|
'theme',
|
12
|
);
|
13
|
|
14
|
$project = array(
|
15
|
'name' => $project_name,
|
16
|
'core' => $this->core,
|
17
|
'version' => $version,
|
18
|
'location' => drush_get_option('drush-make-update-default-url'),
|
19
|
);
|
20
|
$project = drush_make_updatexml($project);
|
21
|
|
22
|
// Because the version data we get back from the XML may not be the same
|
23
|
// data we passed, and because we can fail even if version data is
|
24
|
// returned, track both the success/failure of the request, and the
|
25
|
// version data.
|
26
|
|
27
|
// Check for bad projects and branch releases.
|
28
|
if (empty($project) || preg_match('/.*-dev$/', $project['version'])) {
|
29
|
// Use the passed version if no version was returned.
|
30
|
if (empty($project)) {
|
31
|
$final_version = $version;
|
32
|
}
|
33
|
else {
|
34
|
$final_version = $project['version'];
|
35
|
}
|
36
|
if ($project_name == 'drupal') {
|
37
|
drush_make_error('BUILD_ERROR', dt("Drupal core does not have an official release for version '%version' yet.", array('%version' => $final_version)));
|
38
|
}
|
39
|
else {
|
40
|
drush_make_error('BUILD_ERROR', dt("Project '%project' does not have an official release for version '%version'.", array('%project' => $project_name, '%version' => $final_version)));
|
41
|
}
|
42
|
$result = FALSE;
|
43
|
}
|
44
|
// Make sure the project is an allowed project type.
|
45
|
elseif (!in_array($project['type'], $allowed_project_types)) {
|
46
|
drush_make_error('BUILD_ERROR', dt("Project %project of type '%type' is not permitted.", array('%project' => $project_name, '%type' => $project['type'])));
|
47
|
$final_version = $project['version'];
|
48
|
$result = FALSE;
|
49
|
}
|
50
|
else {
|
51
|
$final_version = $project['version'];
|
52
|
$result = TRUE;
|
53
|
}
|
54
|
return array($result, $final_version);
|
55
|
}
|
56
|
}
|
57
|
|
58
|
class DrushMakeDrupalorgConverter extends DrushMakeDrupalorgVersionChecker {
|
59
|
function __construct($from, $to = NULL) {
|
60
|
$this->from = $from;
|
61
|
$this->to = $to;
|
62
|
$this->log = array();
|
63
|
}
|
64
|
|
65
|
function run() {
|
66
|
if ($this->read()) {
|
67
|
if ($this->convert()) {
|
68
|
$this->write();
|
69
|
}
|
70
|
}
|
71
|
}
|
72
|
|
73
|
function read() {
|
74
|
if (!($this->old_info = drush_make_parse_info_file($this->from))) {
|
75
|
drush_make_error('FILE_ERROR', dt("Unable to parse file %file", array('%file' => $this->from)));
|
76
|
return FALSE;
|
77
|
}
|
78
|
return TRUE;
|
79
|
}
|
80
|
|
81
|
function log($message, $type = 'ok') {
|
82
|
// Save the log messages so they can be put into the output for the .make
|
83
|
// file.
|
84
|
if (empty($this->to)) {
|
85
|
$this->log[] = "[$type]: \t $message";
|
86
|
}
|
87
|
// Only log to screen if we're outputting the conversion to file.
|
88
|
else {
|
89
|
drush_log($message, $type);
|
90
|
}
|
91
|
}
|
92
|
|
93
|
function convert() {
|
94
|
// Run the regular validation first. This performs basic syntax
|
95
|
// validation, and also pre-converts special syntax into a standard
|
96
|
// format. Since the info file validation doesn't return any data if
|
97
|
// validation fails, we have to bail here.
|
98
|
if (!($this->old_info = drush_make_validate_info_file($this->old_info))) {
|
99
|
return FALSE;
|
100
|
}
|
101
|
|
102
|
// The list of currently allowed top-leval attributes.
|
103
|
$top_level_attribute_whitelist = array('core', 'api', 'core_release', 'projects');
|
104
|
|
105
|
// The list of currently allowed project-level attributes.
|
106
|
$project_attribute_whitelist = array('version', 'subdir', 'patch');
|
107
|
|
108
|
// The list of currently disallowed projects.
|
109
|
$project_disallowed_list = array('drupal');
|
110
|
|
111
|
// Assume no errors to start.
|
112
|
$errors = FALSE;
|
113
|
|
114
|
// First order of business: convert core version.
|
115
|
$parts = explode('.', $this->old_info['core']);
|
116
|
$core_major = $parts[0];
|
117
|
$this->core = $core_major . '.x';
|
118
|
|
119
|
// Check for a stable release on the branch.
|
120
|
list($result, $final_version) = $this->latestVersion('drupal', $core_major);
|
121
|
if ($result) {
|
122
|
$this->new_info['core'] = $final_version;
|
123
|
$this->log(dt('Setting the Drupal core version to %version.', array('%version' => $final_version)));
|
124
|
}
|
125
|
else {
|
126
|
$errors = TRUE;
|
127
|
}
|
128
|
$this->new_info['api'] = 2;
|
129
|
|
130
|
if (isset($this->old_info['projects'])) {
|
131
|
foreach ($this->old_info['projects'] as $project => $project_data) {
|
132
|
|
133
|
// Skip conversion for disallowed projects.
|
134
|
if (in_array($project, $project_disallowed_list)) {
|
135
|
if ($project == 'drupal') {
|
136
|
$this->log(dt("It is not permitted to include Drupal core as a project in an install profile -- it has been removed"), 'warning');
|
137
|
}
|
138
|
else {
|
139
|
$this->log(dt("Removed disallowed project '%project'", array('%project' => $project)), 'warning');
|
140
|
}
|
141
|
continue;
|
142
|
}
|
143
|
|
144
|
// Clean out disallowed project attributes.
|
145
|
foreach ($project_data as $attribute => $attribute_value) {
|
146
|
if (!in_array($attribute, $project_attribute_whitelist)) {
|
147
|
$this->log(dt("The '%attribute' attribute is not allowed for the '%project' project, removing.", array('%attribute' => $attribute, '%project' => $project)), 'warning');
|
148
|
unset($project_data[$attribute]);
|
149
|
}
|
150
|
}
|
151
|
|
152
|
// Check that patches do in fact come from drupal.org.
|
153
|
if (isset($project_data['patch'])) {
|
154
|
foreach ($project_data['patch'] as $key => $patch) {
|
155
|
if (strpos($patch, 'http://drupal.org/files/issues') !== 0) {
|
156
|
$this->log(dt("The patch '%patch' is not hosted on drupal.org -- it has been removed.", array('%patch' => $patch)), 'warning');
|
157
|
unset($project_data['patches'][$key]);
|
158
|
}
|
159
|
}
|
160
|
}
|
161
|
|
162
|
// Reset the versioning variables to start fresh for every project.
|
163
|
$version = NULL;
|
164
|
$result = FALSE;
|
165
|
$final_version = '';
|
166
|
|
167
|
// Figure out the basic version string.
|
168
|
if (empty($project_data['version'])) {
|
169
|
$version = DRUSH_MAKE_VERSION_BEST;
|
170
|
}
|
171
|
elseif (preg_match('/^(\d+)((\.\d+)(-[a-z0-9]+)?)?$/', $project_data['version'], $matches)) {
|
172
|
// Branch version only.
|
173
|
if (empty($matches[2])) {
|
174
|
$version = $matches[1];
|
175
|
}
|
176
|
// Development snapshots not allowed.
|
177
|
elseif (!empty($matches[4]) && $matches[4] == '-dev') {
|
178
|
drush_make_error('BUILD_ERROR', dt("An official release is required for '%project' -- a development version cannot be used.", array('%project' => $project)));
|
179
|
$errors = TRUE;
|
180
|
// Move on, nothing more needs to be done with this project.
|
181
|
continue;
|
182
|
}
|
183
|
// All regular releases.
|
184
|
else {
|
185
|
$version = $matches[1] . $matches[2];
|
186
|
}
|
187
|
}
|
188
|
|
189
|
// Use the update XML to verify this project actually has a valid
|
190
|
// release.
|
191
|
if (isset($version)) {
|
192
|
list($result, $final_version) = $this->latestVersion($project, $version);
|
193
|
}
|
194
|
if ($result) {
|
195
|
$this->log(dt("Setting version for project '%project' to '%version'", array('%project' => $project, '%version' => $final_version)));
|
196
|
$project_data['version'] = $final_version;
|
197
|
if (array_keys($project_data) == array('version')) {
|
198
|
$project_data = $project_data['version'];
|
199
|
}
|
200
|
|
201
|
$this->new_info['projects'][$project] = $project_data;
|
202
|
}
|
203
|
else {
|
204
|
$errors = TRUE;
|
205
|
}
|
206
|
}
|
207
|
}
|
208
|
|
209
|
// Clean out disallowed top-level attributes.
|
210
|
foreach ($this->old_info as $attribute => $attribute_value) {
|
211
|
if (!in_array($attribute, $top_level_attribute_whitelist)) {
|
212
|
$this->log(dt("The '%attribute' make file attribute is not allowed, removing.", array('%attribute' => $attribute, )), 'warning');
|
213
|
}
|
214
|
}
|
215
|
|
216
|
if ($errors) {
|
217
|
return FALSE;
|
218
|
}
|
219
|
return TRUE;
|
220
|
}
|
221
|
|
222
|
function write() {
|
223
|
$output = $this->render($this->new_info);
|
224
|
// Write to stdout.
|
225
|
if (empty($this->to)) {
|
226
|
$log = '';
|
227
|
if (!empty($this->log)) {
|
228
|
$log .= dt("; Logged conversion messages follow. The final converted .make file follows these messages.\n");
|
229
|
foreach ($this->log as $message) {
|
230
|
$log .= "; $message\n";
|
231
|
}
|
232
|
}
|
233
|
print $log . $output;
|
234
|
}
|
235
|
// Write to file.
|
236
|
else {
|
237
|
if (file_put_contents($this->to, $output)) {
|
238
|
drush_log(dt("Successfully wrote converted .make file %file.", array('%file' => $this->to)), 'ok');
|
239
|
}
|
240
|
else {
|
241
|
drush_make_error('FILE_ERROR', dt("Unable to write .make file %file.", array('%file' => $this->to)));
|
242
|
}
|
243
|
}
|
244
|
}
|
245
|
|
246
|
function render($info, $parents = array()) {
|
247
|
$output = '';
|
248
|
foreach ($info as $key => $value) {
|
249
|
if (is_numeric($key)) {
|
250
|
$key = '';
|
251
|
}
|
252
|
if (is_array($value)) {
|
253
|
$p = $parents;
|
254
|
$p[] = $key;
|
255
|
$output .= $this->render($value, $p);
|
256
|
}
|
257
|
else {
|
258
|
// For simplicity
|
259
|
$first = TRUE;
|
260
|
$p = $parents;
|
261
|
$p[] = $key;
|
262
|
foreach ($p as $parent) {
|
263
|
if ($first) {
|
264
|
$key_definition = $parent;
|
265
|
$first = FALSE;
|
266
|
}
|
267
|
else {
|
268
|
$key_definition .= '[' . $parent . ']';
|
269
|
}
|
270
|
}
|
271
|
$output .= "$key_definition = $value\n";
|
272
|
}
|
273
|
if (count($parents) < 2) {
|
274
|
$output .= "\n";
|
275
|
}
|
276
|
}
|
277
|
return $output;
|
278
|
}
|
279
|
|
280
|
}
|
281
|
|
282
|
class DrushMakeDrupalorgVerifier extends DrushMakeDrupalorgVersionChecker {
|
283
|
function __construct($makefile) {
|
284
|
$this->makefile = $makefile;
|
285
|
}
|
286
|
|
287
|
function run() {
|
288
|
if ($makefile = $this->read($this->makefile)) {
|
289
|
$this->verify($makefile);
|
290
|
}
|
291
|
}
|
292
|
|
293
|
function read($makefile) {
|
294
|
if (!($makefile = drush_make_parse_info_file($makefile))) {
|
295
|
drush_make_error('FILE_ERROR', dt("Unable to parse file %file", array('%file' => $makefile)));
|
296
|
return FALSE;
|
297
|
}
|
298
|
return $makefile;
|
299
|
}
|
300
|
|
301
|
function verify($makefile) {
|
302
|
// Run the regular validation first. This performs basic syntax
|
303
|
// validation, and also pre-converts special syntax into a standard
|
304
|
// format. Since the info file validation doesn't return any data if
|
305
|
// validation fails, we have to bail here.
|
306
|
if (!($makefile = drush_make_validate_info_file($makefile))) {
|
307
|
return FALSE;
|
308
|
}
|
309
|
|
310
|
// Now run drupal.org specific validation on the file.
|
311
|
if (!($makefile = drush_make_d_o_validate_info_file($makefile))) {
|
312
|
return FALSE;
|
313
|
}
|
314
|
|
315
|
$this->core = $makefile['core'];
|
316
|
// Check for a stable release on the branch.
|
317
|
list($result, $final_version) = $this->latestVersion('drupal', $makefile['core_release']);
|
318
|
if (!$result) {
|
319
|
$errors = TRUE;
|
320
|
}
|
321
|
|
322
|
if (isset($makefile['projects'])) {
|
323
|
|
324
|
// The list of currently disallowed projects.
|
325
|
$project_disallowed_list = array('drupal');
|
326
|
foreach ($makefile['projects'] as $project => $project_data) {
|
327
|
// Error out on disallowed projects.
|
328
|
if (in_array($project, $project_disallowed_list)) {
|
329
|
if ($project == 'drupal') {
|
330
|
drush_make_error('BUILD_ERROR', dt("It is not permitted to include Drupal core as a project in an install profile."));
|
331
|
}
|
332
|
else {
|
333
|
drush_make_error('BUILD_ERROR', dt("Project '%project' is not permitted in an install profile.", array('%project' => $project)));
|
334
|
}
|
335
|
$errors = TRUE;
|
336
|
}
|
337
|
else {
|
338
|
// Use the update XML to verify this project actually has this
|
339
|
// release.
|
340
|
list($result, $final_version) = $this->latestVersion($project, $project_data['version']);
|
341
|
if (!$result) {
|
342
|
$errors = TRUE;
|
343
|
}
|
344
|
}
|
345
|
}
|
346
|
}
|
347
|
if (!$errors) {
|
348
|
drush_log(dt('No errors were found.'), 'ok');
|
349
|
}
|
350
|
else {
|
351
|
drush_make_error('BUILD_ERROR', dt('Errors were found.'));
|
352
|
}
|
353
|
}
|
354
|
}
|
355
|
|
356
|
|
357
|
/**
|
358
|
* Custom logging function for conversions going to STDOUT.
|
359
|
*
|
360
|
* Drush doesn't output drush_set_error() messages to STDERR, lame-o... :(
|
361
|
*
|
362
|
* This helper function overcomes that deficiency by manually writing error
|
363
|
* messages to STDERR in the case where output is going to STDOUT.
|
364
|
*/
|
365
|
function drush_make_d_o_convert_log_stdout_handler($entry) {
|
366
|
if ($entry['type'] == 'error' || $entry['type'] == 'failed') {
|
367
|
fwrite(STDERR, dt("ERROR") . ": " . $entry['message'] . "\n");
|
368
|
}
|
369
|
}
|
370
|
|