Projet

Général

Profil

Paste
Télécharger (12,3 ko) Statistiques
| Branche: | Révision:

root / .drush / drush_make / contrib / drush_make_d_o.convert.inc @ 85ad3d82

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