Project

General

Profile

Paste
Download (12.5 KB) Statistics
| Branch: | Revision:

root / .drush / drush_make / drush_make.drush.inc @ master

1
<?php
2
// $Id: drush_make.drush.inc,v 1.11.2.71 2010/09/04 16:17:42 dmitrig01 Exp $
3

    
4
define('DRUSH_MAKE_UPDATE_DEFAULT_URL', 'http://updates.drupal.org/release-history');
5
define('DRUSH_MAKE_VERSION_BEST', 'best');
6

    
7
include_once 'drush_make.utilities.inc';
8
include_once 'drush_make.download.inc';
9
include_once 'drush_make.project.inc';
10

    
11
/**
12
 * Implement EXTENSION_drush_init().
13
 */
14
function drush_make_drush_init() {
15
  // The default URL to use for retrieving update XML files.
16
  drush_set_default('drush-make-update-default-url', DRUSH_MAKE_UPDATE_DEFAULT_URL);
17
}
18

    
19
/**
20
 * Implementation of hook_drush_command().
21
 */
22
function drush_make_drush_command() {
23
  $items['make'] = array(
24
    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
25
    'description' => 'Turns a makefile into a working drupal install.',
26
    'arguments' => array(
27
      'makefile' => 'Filename of the makefile to use for this build.',
28
      'build path' => 'The path at which to build the makefile.',
29
    ),
30
    'examples' => array(
31
      'drush make example.make example' => 'Build the example.make makefile in the example directory.',
32
    ),
33
    'options' => array(
34
      '--version' => 'Print the version and exit.',
35
      '--contrib-destination=path' => 'Specify a path under which modules and themes should be placed. Defaults to sites/all.',
36
      '--force-complete' => 'Force a complete build even if errors occur.',
37
      '--md5' => 'Output an md5 hash of the current build after completion.',
38
      '--no-clean' => 'Leave temporary build directories in place instead of cleaning up after completion.',
39
      '--no-core' => 'Do not require a Drupal core project to be specified.',
40
      '--no-patch-txt' => 'Do not write a PATCHES.txt file in the directory of each patched project.',
41
      '--prepare-install' => 'Prepare the built site for installation. Generate a properly permissioned settings.php and files directory.',
42
      '--tar' => 'Generate a tar archive of the build. The output filename will be [build path].tar.gz.',
43
      '--test' => 'Run a temporary test build and clean up.',
44
      '--translations=languages' => 'Retrieve translations for the specified comma-separated list of language(s) if available for all projects.',
45
      '--working-copy' => 'Where possible, retrieve a working copy of projects from their respective repositories.',
46
    ),
47
  );
48

    
49
  $items['make-test'] = array(
50
    'bootstrap' => DRUSH_BOOTSTRAP_DRUSH,
51
    'description' => 'Run a drush make test.',
52
    'arguments' => array(
53
      'test' => 'Name of the test to run or ALL to run all tests.',
54
    ),
55
    'examples' => array(
56
      'drush make-test svn' => 'Run tests for SVN integration.',
57
    ),
58
  );
59

    
60
  $items['generate-makefile'] = array(
61
    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
62
    'description' => 'Attempts to generate a makefile from the current drupal install.',
63
  );
64

    
65
  return $items;
66
}
67

    
68
/**
69
 * Implementation of hook_drush_help().
70
 */
71
function drush_make_drush_help($section) {
72
  switch ($section) {
73
    case 'drush:make':
74
      return dt('Turns a makefile into a working drupal install. For a full description of options and makefile syntax, see the README.txt included with drush make.');
75
    case 'drush:make-test':
76
      return dt('Run a drush make test.');
77
    case 'drush:generate-makefile':
78
      return dt('Attempts to generate a makefile from the current drupal install.');
79
  }
80
}
81

    
82
/**
83
 * Drush callback; make based on the makefile.
84
 */
85
function drush_drush_make_make($makefile = NULL, $build_path = NULL) {
86
  if (!drush_make_ensure_version()) {
87
    return;
88
  }
89
  if (drush_get_option('version', FALSE)) {
90
    drush_print(drush_make_version());
91
    return;
92
  }
93
  if (!($build_path = drush_make_build_path($build_path))) {
94
    return;
95
  }
96
  if (!($info = drush_make_validate_info_file(drush_make_parse_info_file($makefile)))) {
97
    return;
98
  }
99

    
100
  drush_make_projects(FALSE, drush_get_option('contrib-destination', 'sites/all'), $info, $build_path);
101
  drush_make_libraries(drush_get_option('contrib-destination', 'sites/all'), $info, $build_path);
102

    
103
  if (drush_get_option('prepare-install')) {
104
    drush_make_prepare_install($build_path);
105
  }
106
  if (drush_get_option('md5')) {
107
    drush_make_md5();
108
  }
109

    
110
  // Only take final build steps if not in testing mode.
111
  if (!drush_get_option('test')) {
112
    if (drush_get_option('tar')) {
113
      drush_make_tar($build_path);
114
    }
115
    else {
116
      drush_make_move_build($build_path);
117
    }
118
  }
119

    
120
  drush_make_clean_tmp();
121
}
122

    
123
function drush_make_projects($recursion, $contrib_destination, $info, $build_path) {
124
  $projects = array();
125
  if (empty($info['projects'])) {
126
    return;
127
  }
128
  foreach ($info['projects'] as $key => $project) {
129
    // Merge the known data onto the project info.
130
    $project += array(
131
      'name'                => $key,
132
      'core'                => $info['core'],
133
      'build_path'          => $build_path,
134
      'contrib_destination' => $contrib_destination,
135
      'version'             => DRUSH_MAKE_VERSION_BEST,
136
      'location'            => drush_get_option('drush-make-update-default-url'),
137
      'subdir'              => '',
138
      'directory_name'      => '',
139
    );
140
    $project = drush_make_updatexml($project);
141
    $class_name = 'DrushMakeProject_' . $project['type'];
142
    $projects[($project['type'] == 'core' ? 'core' : 'contrib')][$project['name']] = new $class_name($project);
143
  }
144

    
145
  if (!empty($projects['core'])) {
146
    $cores = count($projects['core']);
147
  }
148
  else {
149
    $cores = 0;
150
  }
151

    
152
  if (drush_get_option('no-core')) {
153
    unset($projects['core']);
154
  }
155
  elseif ($cores == 0 && !$recursion) {
156
    drush_set_error(dt('No core project specified.'));
157
    return FALSE;
158
  }
159
  elseif ($cores == 1 && $recursion) {
160
    unset($projects['core']);
161
  }
162
  elseif ($cores > 1) {
163
    drush_set_error(dt('More than one core project specified.'));
164
    return FALSE;
165
  }
166
  if (isset($projects['core'])) {
167
    foreach ($projects['core'] as $project) {
168
      $project->make();
169
    }
170
  }
171

    
172
  if (isset($projects['contrib'])) {
173
    foreach ($projects['contrib'] as $project) {
174
      $project->make();
175
    }
176
  }
177
}
178

    
179
function drush_make_libraries($contrib_destination, $info, $build_path) {
180
  if (!empty($info['libraries'])) {
181
    foreach ($info['libraries'] as $key => $library) {
182
      if (!is_string($key) || !is_array($library)) {
183
        // TODO Print a prettier message
184
        continue;
185
      }
186
      // Merge the known data onto the library info.
187
      $library += array(
188
        'name'                => $key,
189
        'core'                => $info['core'],
190
        'build_path'          => $build_path,
191
        'contrib_destination' => $contrib_destination,
192
        'subdir'              => '',
193
        'directory_name'      => $key,
194
      );
195
      $class = new DrushMakeProject_Library($library);
196
      $class->make();
197
    }
198
  }
199
}
200

    
201
function drush_make_updatexml($project) {
202
  if (isset($project['download']) && isset($project['type'])) {
203
    return $project;
204
  }
205
  if ($filename = _drush_make_download_file($project['location'] . '/' . $project['name'] . '/' . $project['core'])) {
206
    $release_history = simplexml_load_string(file_get_contents($filename));
207
    drush_op('unlink', $filename);
208
  }
209
  // First, get the release history.
210
  if (!is_object($release_history) || !$release_history->title) {
211
    drush_make_error('XML_ERROR', dt("Could not retrieve version information for %project.", array('%project' => $project['name'])));
212
    return FALSE;
213
  }
214
  drush_log(dt('Project information for %project retrieved.', array('%project' => $project['name'])), 'ok');
215
  $project['release_history'] = $release_history;
216
  if (!isset($project['type'])) {
217
    // Determine the project type.
218
    $term_map = array(
219
      'Modules' => 'module',
220
      'Themes' => 'theme',
221
      'Drupal project' => 'core',
222
      'Installation profiles' => 'profile',
223
      'Translations' => 'translation'
224
    );
225
    // Iterate through all terms related to this project.
226
    foreach ($release_history->terms->term as $term) {
227
      // If we find a term from the term map, add it.
228
      if (in_array((string) $term->value, array_keys($term_map))) {
229
        $project['type'] = $term_map[(string)$term->value];
230
        break;
231
      }
232
    }
233
    if (!isset($project['type'])) {
234
      drush_make_error('BUILD_ERROR', dt("Unable to determine project type for %project.", array('%project' => $project['name'])));
235
      return FALSE;
236
    }
237
  }
238
  if (!isset($project['download'])) {
239
    $project = drush_make_update_xml_download($project);
240
  }
241
  return $project;
242
}
243

    
244
function drush_make_update_xml_download($project) {
245
  // Make an array of releases.
246
  foreach ($project['release_history']->releases->release as $release) {
247
    $version = (string) $release->version_major;
248
    // there should be version_patch attribute for every stable release
249
    // so checking whether the attribute exists should be enough
250
    if (isset($release->version_patch)) {
251
      $version .= '.' . (string) $release->version_patch;
252
    }
253
    // if version_patch attribute does not exist, then it should be a dev release
254
    // and the version string should be in format MAJOR_VERSION.x-dev
255
    else {
256
      $version .= '.x';
257
    }
258
    if ($extra_version = (string) $release->version_extra) {
259
      $version .= '-' . $extra_version;
260
    }
261
    $releases[$version] = array(
262
      'file' => (string) $release->download_link,
263
      'md5' => (string) $release->mdhash,
264
      'version' => (string) $release->version,
265
    );
266
    foreach (array('major', 'patch', 'extra') as $part) {
267
      $releases[$version][$part] = (string) $release->{'version_' . $part};
268
    }
269
  }
270

    
271
  // Find the best release.
272
  if ($project['version'] == DRUSH_MAKE_VERSION_BEST) {
273
    $recommended_major = (string)$project['release_history']->recommended_major;
274
    $project['version'] = _drush_make_update_xml_best_version($recommended_major, $releases);
275
  }
276
  // Find the best release for the specified version.
277
  else {
278
    $exploded_version = explode('.', $project['version']);
279
    if (count($exploded_version) == 1) {
280
      list($major) = $exploded_version;
281
      $project['version'] = _drush_make_update_xml_best_version($major, $releases);
282
    }
283
    // Otherwise we have a full version.
284
  }
285

    
286
  $final_version = empty($project['version']) ? '' : $project['version'];
287

    
288
  // Uh oh, couldn't find a valid version.
289
  if (empty($final_version) || empty($releases[$final_version])) {
290
    drush_make_error('BUILD_ERROR', dt("Invalid version %version for %project.", array('%version' => $final_version, '%project' => $project['name'])));
291
    return FALSE;
292
  }
293

    
294
  $release = $releases[$final_version];
295
  $project['download'] = array(
296
    'type' => 'get',
297
    'url'  => $release['file'],
298
    'md5'  => $release['md5'],
299
  );
300
  return $project;
301
}
302

    
303
function _drush_make_update_xml_best_version($major, $releases) {
304
  $best = NULL;
305
  foreach ($releases as $version => $release_info) {
306
    if ($release_info['major'] == $major && version_compare($best, $version, '<')) {
307
      $best = $version;
308
    }
309
  }
310
  return $best;
311
}
312

    
313
function drush_make_build_path($build_path) {
314
  // Determine the base of the build.
315
  if (drush_get_option('tar')) {
316
    $build_path = dirname($build_path) . '/' . basename($build_path, '.tar.gz') . '.tar.gz';
317
  }
318
  elseif (isset($build_path) && (!empty($build_path) || $build_path == '.')) {
319
    $build_path = rtrim($build_path, '/');
320
  }
321
  // Allow tests to run without a specified base path.
322
  elseif (drush_get_option('test') || drush_confirm(dt("Make new site in the current directory?"))) {
323
    $build_path = '.';
324
  }
325
  else {
326
    drush_log(dt('Build aborted.'), 'ok');
327
    return FALSE;
328
  }
329
  if ($build_path != '.' && file_exists($build_path)) {
330
    drush_set_error(dt('Base path %path already exists', array('%path' => $build_path)));
331
    return FALSE;
332
  }
333
  return $build_path;
334
}
335

    
336
function drush_make_move_build($build_path) {
337
  $tmp_path = drush_make_tmp();
338
  if ($build_path == '.') {
339
    drush_shell_exec('ls -A %s', $tmp_path . '/__build__');
340
    $info = drush_shell_exec_output();
341
    foreach ($info as $file) {
342
      drush_shell_exec("cp -Rf %s %s", $tmp_path . '/__build__/' . $file, $build_path);
343
    }
344
  }
345
  else {
346
    drush_make_mkdir(dirname($build_path));
347
    drush_shell_exec("mv %s %s", $tmp_path . '/__build__', $tmp_path . '/' . basename($build_path));
348
    drush_shell_exec("cp -Rf %s %s", $tmp_path . '/' . basename($build_path), dirname($build_path));
349
  }
350
  return TRUE;
351
}
352

    
353
function drush_make_version() {
354
  return '2.0-dev';
355
}
356

    
357
/**
358
 * Drush callback; make a makefile from the current install.
359
 */
360
function drush_drush_make_generate_makefile($file) {
361
  include_once 'drush_make.generate.inc';
362
  _drush_generate_makefile($file);
363
}
364

    
365
/**
366
 * Drush callback; run a drush make test.
367
 */
368
function drush_drush_make_make_test($test = NULL) {
369
  include_once 'drush_make.test.inc';
370
  drush_make_test($test);
371
}