Projet

Général

Profil

Paste
Télécharger (11,2 ko) Statistiques
| Branche: | Révision:

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

1
<?php
2
// $Id: drush_make_d_o.drush.inc,v 1.1.2.19 2010/09/09 07:11:00 dmitrig01 Exp $
3

    
4
/**
5
 * @file
6
 * drush_make extension for integrating with the drupal.org packaging system.
7
 *
8
 * This extension serves the following purposes:
9
 *  - Adds the --drupal-org and --build-run-key command line options,
10
 *    which activate the functionality in the rest of the code.
11
 *  - Validates .make files to ensure they comply with drupal.org packaging
12
 *    requirements.
13
 *  - Restricts download locations to those approved for drupal.org packages.
14
 *  - Implements a custom logging function for error reporting to the packaging
15
 *    script.
16
 *  - Builds a list of package contents (nids of package items), and stores
17
 *    for the packaging system to use.
18
 */
19

    
20
// URI of the 'drush_make on drupal.org' handbook page.
21
define('DRUSH_MAKE_DO_DOCUMENTATION_LINK', 'http://drupal.org/node/642116');
22
// Name of the package contents file used by the packaging script.
23
define('DRUSH_MAKE_DO_PACKAGE_CONTENTS_FILE', 'package_contents.txt');
24
// Name of the build errors file used by the packaging script.
25
define('DRUSH_MAKE_DO_BUILD_ERRORS_FILE', 'build_errors.txt');
26

    
27
/**
28
 * Implement hook_drush_command().
29
 */
30
function drush_make_d_o_drush_command() {
31
  $items = array();
32
  $items['convert-makefile'] = array(
33
    'description' => 'Convert the specified makefile to a drupal.org friendly format, and verify the converted file.',
34
    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
35
  );
36
  $items['verify-makefile'] = array(
37
    'description' => 'Verify the specified makefile is in a drupal.org-friendly format.',
38
    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
39
  );
40

    
41
  return $items;
42
}
43

    
44

    
45
/**
46
 * Drush callback; verify a .make file is in a drupal.org friendly format.
47
 */
48
function drush_drush_make_d_o_verify_makefile($makefile) {
49
  include_once 'drush_make_d_o.convert.inc';
50
  $verifier = new DrushMakeDrupalorgVerifier($makefile);
51
  $verifier->run();
52
}
53

    
54

    
55
/**
56
 * Drush callback; convert the makefile to a drupal.org friendly format.
57
 */
58
function drush_drush_make_d_o_convert_makefile($from, $to = NULL) {
59
  include_once 'drush_make_d_o.convert.inc';
60
  // If output is going to STDOUT, use a custom logger.
61
  if (empty($to)) {
62
    drush_set_context('DRUSH_LOG_CALLBACK', 'drush_make_d_o_convert_log_stdout_handler');
63
  }
64
  $converter = new DrushMakeDrupalorgConverter($from, $to);
65
  $converter->run();
66
}
67

    
68
/**
69
 * Implement EXTENSION_drush_make_init().
70
 */
71
function drush_make_d_o_drush_init() {
72
  if (drush_get_option('drupal-org')) {
73
    // The --drupal-org switch implies these defaults:
74
    // Location to put our custom build files.
75
    drush_set_default('drupal-org-build-root', '.');
76
    // The destination of the downloaded contrib projects.
77
    drush_set_default('contrib-destination', '.');
78
    // Whether to allow a build without core.
79
    drush_set_default('no-core', TRUE);
80

    
81
    // Optionally set up a custom error logger.
82
    if (drush_get_option('drupal-org-log-errors-to-file')) {
83
      drush_set_context('DRUSH_LOG_CALLBACK', 'drush_make_d_o_log_errors_to_file');
84
    }
85

    
86
    // Optionally set up the package contents file. The packaging script
87
    // expects it, so it's created as an empty file here to ensure it
88
    // exists.
89
    if (drush_get_option('drupal-org-log-package-items-to-file')) {
90
      $drupal_org_build_root = drush_get_option('drupal-org-build-root');
91
      if (!touch($drupal_org_build_root . '/' . DRUSH_MAKE_DO_PACKAGE_CONTENTS_FILE)) {
92
        drush_make_error('FILE_ERROR', dt('Unable to write package contents file to %build_root', array('%build_root' => $drupal_org_build_root)));
93
      }
94
    }
95
  }
96
}
97

    
98
/**
99
 * Implement EXTENSION_drush_make_validate_info().
100
 */
101
function drush_make_d_o_drush_make_validate_info($info) {
102
  if (drush_get_option('drupal-org')) {
103
    // The list of currently allowed top-leval attributes.
104
    $top_level_attribute_whitelist = array('core', 'api', 'core_release', 'projects');
105
    
106
    // The list of currently allowed project-level attributes.
107
    $project_attribute_whitelist = array('version', 'subdir', 'patch');
108
    
109
    // Assume no errors to start.
110
    $errors = FALSE;
111
    
112
    // Check for disallowed top-level attributes.
113
    foreach ($info as $attribute => $attribute_data) {
114
      if (!in_array($attribute, $top_level_attribute_whitelist)) {
115
        drush_make_error('BUILD_ERROR', dt("The top-level attribute '%attribute' is not allowed in drupal.org .make files", array('%attribute' => $attribute)));
116
        $errors = TRUE;
117
      }
118
    }
119
    
120
    // Check for a valid core value.
121
    // This is just a basic sanity check for a properly formatted value.
122
    if (!drush_make_d_o_check_valid_version(dt('Drupal core'), $info['core_release'])) {
123
      $errors = TRUE;
124
    }
125
    if (!empty($info['projects'])) {
126
      foreach ($info['projects'] as $project => $project_data) {
127
        // No specifying just project name.
128
        if (!is_array($project_data)) {
129
          $project_data = $info['projects'][$project] = array('version' => $project_data);
130
        }
131
        // Version must be set.
132
        if (!isset($project_data['version'])) {
133
          drush_make_error('BUILD_ERROR', dt('No version specified for project %project -- version is required.', array('%project' => $project)));
134
          $errors = TRUE;
135
        }
136
        // Check for disallowed project-level attributes.
137
        foreach ($project_data as $attribute => $attribute_data) {
138
          if (!in_array($attribute, $project_attribute_whitelist)) {
139
            drush_make_error('BUILD_ERROR', dt("The project-level attribute '%attribute' is not allowed in drupal.org .make files", array('%attribute' => $attribute)));
140
            $errors = TRUE;
141
          }
142
        }
143
        // Check that patches do in fact come from drupal.org.
144
        if (isset($project_data['patch'])) {
145
          foreach ($project_data['patch'] as $patch) {
146
            if (strpos($patch, 'http://drupal.org/files/issues') !== 0) {
147
              drush_make_error('BUILD_ERROR', dt("The patch '%patch' is not hosted on drupal.org", array('%patch' => $patch)));
148
              $errors = TRUE;
149
            }
150
          }
151
        }
152
        // Check for bad project version.
153
        if (!drush_make_d_o_check_valid_version($project, $project_data['version'])) {
154
          $errors = TRUE;
155
        }
156
        $info['projects'][$project] += array(
157
          'name' => $project,
158
          'core' => $info['core'],
159
        );
160
        $info['projects'][$project] = drush_make_d_o_updatexml($info['projects'][$project]);
161
      }
162
    }
163
    // Abort if any errors were found.
164
    if ($errors) {
165
      drush_make_error('BUILD_ERROR', dt('The drupal.org validation check failed -- see @doc_link for more information.', array('@doc_link' => DRUSH_MAKE_DO_DOCUMENTATION_LINK)));
166
      return FALSE;
167
    }
168
  }
169
  return $info;
170
}
171

    
172
/**
173
 * Validate release versions.
174
 *
175
 * @param $name
176
 *   The display name of the project.
177
 * @param $version_string
178
 *   The version string to test.
179
 * @return
180
 * TRUE if the version string is bad, FALSE otherwise.
181
 */
182
function drush_make_d_o_check_valid_version($name, $version_string) {
183
  // Development snapshots not allowed.
184
  if (preg_match('/.*-dev$/', $version_string)) {
185
    drush_make_error('BUILD_ERROR', dt('%project branch releases not allowed.', array('%project' => $name)));
186
    return FALSE;
187
  }
188
  // Basic sanity checking on release version strings. We need this because
189
  // drush_make supports projects[foo][version] = 1, which downloads the latest
190
  // stable release on the major version 1 branch. We require a specific
191
  // release.
192
  elseif (!preg_match('/^\d+\.\d+(-[a-z0-9]+)?$/', $version_string)) {
193
    drush_make_error('BUILD_ERROR', dt('%project version format incorrect -- specifying an official release version is required.', array('%project' => $name)));
194
    return FALSE;
195
  }
196
  return TRUE;
197
}
198

    
199
/**
200
 * Custom implementation of drush_make_updatexml().
201
 *
202
 * Only allows loading update XML files from the default location, which for
203
 * our purposes is updates.drupal.org. This is also the place where package
204
 * items are collected for the package.
205
 */
206
function drush_make_d_o_updatexml($project) {
207
  if ($filename = _drush_make_download_file(drush_get_option('drush-make-update-default-url') . '/' . $project['name'] . '/' . $project['core'])) {
208
    $release_history = simplexml_load_string(file_get_contents($filename));
209
    drush_op('unlink', $filename);
210
  }
211
  // First, get the release history.
212
  if (!is_object($release_history) || !$release_history->title) {
213
    drush_make_error('XML_ERROR', dt("Could not retrieve version information for %project.", array('%project' => $project['name'])));
214
    return FALSE;
215
  }
216
  drush_log(dt('Project information for %project retrieved.', array('%project' => $project['name'])), 'ok');
217
  $project['release_history'] = $release_history;
218
  if (!isset($project['type'])) {
219
    // Determine the project type.
220
    $term_map = array(
221
      'Modules' => 'module',
222
      'Themes' => 'theme',
223
      'Drupal project' => 'core',
224
      'Installation profiles' => 'profile',
225
      'Translations' => 'translation'
226
    );
227
    // Iterate through all terms related to this project.
228
    foreach ($release_history->terms->term as $term) {
229
      // If we find a term from the term map, add it.
230
      if (in_array((string) $term->value, array_keys($term_map))) {
231
        $project['type'] = $term_map[(string)$term->value];
232
        break;
233
      }
234
    }
235
    if (!isset($project['type'])) {
236
      drush_make_error('BUILD_ERROR', dt("Unable to determine project type for %project.", array('%project' => $project['name'])));
237
      return FALSE;
238
    }
239
  }
240
  // Process the file download data, and record the item_nid for the package.
241
  if ($project = drush_make_update_xml_download($project)) {
242
    // Optionally log package contents to a file.
243
    if (drush_get_option('drupal-org-log-package-items-to-file')) {
244
      $project = drush_make_d_o_write_package_item_nid($project);
245
    }
246
    return $project;
247
  }
248
  return FALSE;
249
}
250

    
251
/**
252
 * Store a package item in a package summary file.
253
 */
254
function drush_make_d_o_write_package_item_nid($project) {
255
  // Release/version logic ripped off from drush_make_update_xml_download().
256
  // Make an array of releases.
257
  foreach ($project['release_history']->releases->release as $release) {
258
    $version = (string) $release->version_major;
259
    if ((string) $release->version_patch) {
260
      $version .= '.' . (string) $release->version_patch;
261
    }
262
    else {
263
      $version .= '.0';
264
    }
265
    if ($extra_version = (string) $release->version_extra) {
266
      $version .= '-' . $extra_version;
267
    }
268
    // Grab the release nid from the release node link.
269
    $releases[$version] = basename($release->release_link);
270
  }
271
  // Write the item's nid to the package contents file.
272
  if ($project['version'] && ($item_nid = $releases[$project['version']])) {
273
    if (file_put_contents(drush_get_option('drupal-org-build-root') . '/' . DRUSH_MAKE_DO_PACKAGE_CONTENTS_FILE, "$item_nid\n", FILE_APPEND)) {
274
      return $project;
275
    }
276
  }
277
  return FALSE;
278
}
279

    
280
/**
281
 * Custom logging function for packaging errors.
282
 *
283
 * Logs all error messages to a build_errors.txt file in the root of the
284
 * package build.
285
 *
286
 * @see drush_log() for a description of the $entry array.
287
 */
288
function drush_make_d_o_log_errors_to_file($entry) {
289
  if ($entry['type'] == 'error' || $entry['type'] == 'failed') {
290
    file_put_contents(drush_get_option('drupal-org-build-root') . '/' . DRUSH_MAKE_DO_BUILD_ERRORS_FILE, $entry['message'] . "\n", FILE_APPEND);
291
  }
292
}