├── fserver.context.inc
├── fserver.css
├── fserver.drush.inc
├── fserver.features.content.inc
├── fserver.features.inc
├── fserver.features.menu_links.inc
├── fserver.info
├── fserver.js
├── fserver.module
├── fserver.strongarm.inc
├── fserver.views.inc
├── fserver.views_default.inc
└── views
├── fserver-updatexml.tpl.php
├── fserver_handler_field_mdhash.inc
├── fserver_handler_field_release_tag.inc
├── fserver_handler_sort_release_tag.inc
├── fserver_plugin_style_updatexml.inc
└── theme.inc
/fserver.context.inc:
--------------------------------------------------------------------------------
1 | disabled = FALSE; /* Edit this to true to make a default context disabled initially */
10 | $context->api_version = 3;
11 | $context->name = 'fserver-section-project';
12 | $context->description = '';
13 | $context->tag = '';
14 | $context->conditions = array(
15 | 'node' => array(
16 | 'values' => array(
17 | 'fserver_project' => 'fserver_project',
18 | 'fserver_distro' => 'fserver_distro',
19 | ),
20 | 'options' => array(
21 | 'node_form' => 0,
22 | ),
23 | ),
24 | );
25 | $context->reactions = array(
26 | 'block' => array(
27 | 'blocks' => array(
28 | 'views-fserver_releases-block_1' => array(
29 | 'module' => 'views',
30 | 'delta' => 'fserver_releases-block_1',
31 | 'region' => 'content',
32 | 'weight' => 0,
33 | ),
34 | ),
35 | ),
36 | );
37 | $context->condition_mode = 0;
38 |
39 | $export['fserver-section-project'] = $context;
40 | return $export;
41 | }
42 |
--------------------------------------------------------------------------------
/fserver.css:
--------------------------------------------------------------------------------
1 | div#edit-field-fserver-api-value-wrapper,
2 | div#edit-field-fserver-versionmajor-value-wrapper,
3 | div#edit-field-fserver-versionpatch-value-wrapper,
4 | div#edit-field-fserver-versionextra-0-value-wrapper {
5 | float: left;
6 | margin-right: 1em;
7 | }
8 | div#edit-field-fserver-recommended-value-wrapper {
9 | clear: both;
10 | }
11 | ul#fserver-release-info,
12 | ul#fserver-release-info li {
13 | list-style: none;
14 | background: 0;
15 | margin: 0;
16 | padding: 0;
17 | }
--------------------------------------------------------------------------------
/fserver.drush.inc:
--------------------------------------------------------------------------------
1 | 'fserver_drush_status',
26 | 'description' => 'Determine the packaging status of a project.',
27 | );
28 | $items['fserver-package'] = array(
29 | 'callback' => 'fserver_drush_package',
30 | 'description' => 'Update packaging for a project.',
31 | );
32 | $items['fserver-distro'] = array(
33 | 'callback' => 'fserver_drush_distro',
34 | 'description' => 'Update packaging for a distribution.',
35 | );
36 | return $items;
37 | }
38 |
39 | /**
40 | * Implementation of hook_drush_help().
41 | */
42 | function fserver_drush_help($section) {
43 | switch ($section) {
44 | case 'drush:fserver-status':
45 | return dt("Determine the packaging status of a project.");
46 | case 'drush:fserver-package':
47 | return dt("Update packaging for a project.");
48 | case 'drush:fserver-distro':
49 | return dt("Package a new Drupal distribution from a distribution node.");
50 | }
51 | }
52 |
53 | /**
54 | * Package new releases for a specified project or all.
55 | */
56 | function fserver_drush_package() {
57 | if (!drush_get_option('uri') && !drush_get_option('l')) {
58 | drush_die('You must use the --uri option to specify the location of this site.');
59 | }
60 |
61 | $projects = _fserver_drush_get_projects();
62 |
63 | // Filter the project list by the argument.
64 | $args = func_get_args();
65 | $arg = array_shift($args);
66 | if (!empty($arg)) {
67 | if (isset($projects[$arg])) {
68 | $projects = array($arg => $projects[$arg]);
69 | }
70 | else {
71 | drush_die('The project '. $arg .' could not be found.');
72 | }
73 | }
74 |
75 | $rows = array();
76 | foreach ($projects as $project) {
77 | $new_tags = $project->get_new_tags();
78 | if (!empty($new_tags)) {
79 | foreach ($new_tags as $tag_id => $tag) {
80 | $release = $project->create_release($tag_id);
81 | $rows[] = array($project->node->title, $tag_id, $release->field_fserver_file[0]['filename']);
82 | }
83 | }
84 | }
85 | if (!empty($rows)) {
86 | array_unshift($rows, array(dt('Project'), dt('Release'), dt('Filename')));
87 | drush_print_table($rows, TRUE);
88 | }
89 | else {
90 | drush_print(dt('All projects are up to date. No packages were created.'));
91 | }
92 | }
93 |
94 | /**
95 | * Display project packaging status.
96 | */
97 | function fserver_drush_status() {
98 | $projects = _fserver_drush_get_projects();
99 |
100 | // Filter the project list by the argument.
101 | $args = func_get_args();
102 | $arg = array_shift($args);
103 | if (!empty($arg)) {
104 | if (isset($projects[$arg])) {
105 | $projects = array($arg => $projects[$arg]);
106 | }
107 | else {
108 | drush_die('The project '. $arg .' could not be found.');
109 | }
110 | }
111 |
112 | $rows = array(array(dt('Method'), dt('Project'), dt('New tags')));
113 | foreach ($projects as $project) {
114 | $new_tags = $project->get_new_tags();
115 | $rows[] = array(
116 | $project->method,
117 | $project->node->title,
118 | !empty($new_tags) ? implode(', ',array_keys($new_tags)) : dt("Up to date"),
119 | );
120 | }
121 | drush_print_table($rows, TRUE);
122 | }
123 |
124 | /**
125 | * Retrieve all fserver projects from the DB.
126 | */
127 | function _fserver_drush_get_projects() {
128 | static $projects;
129 | if (!isset($projects)) {
130 | $projects = array();
131 | $result = db_query("SELECT nid, title FROM {node} WHERE type = 'fserver_project' AND status = 1");
132 | while ($row = db_fetch_object($result)) {
133 | $node = node_load($row->nid);
134 | $project = new FserverProject($node, $node->field_fserver_name[0]['value'], $node->field_fserver_method[0]['value'], $node->field_fserver_repository[0]['value']);
135 | $projects[$project->name] = $project;
136 | }
137 | }
138 | return $projects;
139 | }
140 |
141 | /**
142 | * Project class. Contains helpful methods for detecting tags, packaging, etc.
143 | */
144 | class FserverProject {
145 | var $node, $name, $method, $repository;
146 |
147 | /**
148 | * We will store the backend object here.
149 | */
150 | var $backend;
151 |
152 | /**
153 | * Constructor.
154 | */
155 | function __construct($node, $name, $method, $repository) {
156 | $this->node = $node;
157 | $this->name = $name;
158 | $this->method = $method;
159 | $this->repository = $repository;
160 |
161 | // We try to create a backend for us to user later:
162 | $method_class = 'FserverProject_' . $this->method;
163 | if (class_exists($method_class)) {
164 | $this->backend = new $method_class($this);
165 | }
166 | }
167 |
168 | /**
169 | * Initialize a working copy for this project.
170 | */
171 | function init_wc() {
172 | if (isset($this->backend)) {
173 | $this->backend->init_wc();
174 | }
175 | }
176 |
177 | /**
178 | * Get new tags that have no corresponding release nodes.
179 | */
180 | function get_new_tags() {
181 | $new_tags = array();
182 | $releases = $this->get_releases();
183 | foreach ($this->get_tags() as $tag_id => $tag) {
184 | if (!isset($releases[$tag_id])) {
185 | $new_tags[$tag_id] = $tag;
186 | }
187 | }
188 | return $new_tags;
189 | }
190 |
191 | /**
192 | * Get release nodes for this project.
193 | */
194 | function get_releases() {
195 | if (!isset($this->releases)) {
196 | $this->releases = array();
197 | $result = db_query("SELECT nid FROM {node} WHERE type = 'fserver_release' AND status = 1");
198 | while ($row = db_fetch_object($result)) {
199 | $node = node_load($row->nid);
200 | if ($node && isset($node->field_fserver_project[0]['nid']) && $node->field_fserver_project[0]['nid'] == $this->node->nid) {
201 | $this->releases[fserver_generate_version($node, TRUE)] = $node;
202 | }
203 | }
204 | }
205 | return $this->releases;
206 | }
207 |
208 | function get_tag($tag_id) {
209 | if (isset($this->backend)) {
210 | return $this->backend->get_tag($tag_id);
211 | }
212 | }
213 |
214 | /**
215 | * Get tags for this project.
216 | */
217 | function get_tags() {
218 | if (isset($this->backend)) {
219 | return $this->backend->get_tags();
220 | }
221 | return array();
222 | }
223 |
224 | /**
225 | * Create a release node for the given tag.
226 | */
227 | function create_release($tag_id) {
228 | $tag = $this->get_tag($tag_id);
229 | if ($tag && $file = $this->create_package($tag_id)) {
230 | $node = new stdClass();
231 | $node->type = 'fserver_release';
232 | $node->status = 1;
233 | $node->created = !empty($tag['timestamp']) ? $tag['timestamp'] : time();
234 | $node->uid = $this->node->uid;
235 | $node->title = "{$this->name} {$tag_id}";
236 | $node->body = !empty($tag['message']) ? $tag['message'] : '';
237 |
238 | $node->field_fserver_file = array(0 => (array) $file);
239 | $node->field_fserver_project = array(0 => array('nid' => $this->node->nid));
240 | $node->field_fserver_api = array(0 => array('value' => $tag['core']));
241 | $node->field_fserver_versionmajor = array(0 => array('value' => $tag['major']));
242 | $node->field_fserver_versionpatch = array(0 => array('value' => $tag['patch']));
243 | $node->field_fserver_versionextra = array(0 => array('value' => $tag['extra']));
244 |
245 | // @TODO
246 | $node->field_fserver_recommended = array(0 => array('value' => 1));
247 | $node->field_fserver_security = array(0 => array('value' => 0));
248 | node_save($node);
249 | }
250 | return $node;
251 | }
252 |
253 | /**
254 | * Create an archive package for the given tag.
255 | */
256 | function create_package($tag_id) {
257 | if (isset($this->backend)) {
258 | return $this->backend->create_package($tag_id);
259 | }
260 | return FALSE;
261 | }
262 |
263 | /**
264 | * Write packaging information for a release.
265 | */
266 | function write_package_info($tag, $exclude_mask = array('.', '..', 'CVS')) {
267 | if (isset($this->backend)) {
268 | $fserver_url = url("fserver", array('purl' => array('disabled' => TRUE), 'absolute' => TRUE));
269 |
270 | $packaging = array();
271 | $packaging[] = "; Information added by fserver";
272 | $packaging[] = "core = \"{$tag['core']}\"";
273 | $packaging[] = "datestamp = \"{$tag['timestamp']}\"";
274 | $packaging[] = "project = \"{$this->name}\"";
275 | $packaging[] = "project status url = \"{$fserver_url}\"";
276 | $packaging[] = "version = \"{$tag['version']}\"";
277 | $packaging = "\n" . implode("\n", $packaging);
278 |
279 | $files = file_scan_directory($this->backend->path, '.info', $exclude_mask);
280 | foreach ($files as $path => $file) {
281 | // @TODO: Parse the info file or not?
282 | $info_file = file_get_contents($file->filename);
283 | $info_file .= $packaging;
284 | file_put_contents($file->filename, $info_file);
285 | }
286 | }
287 | }
288 | }
289 |
290 | class FserverProject_git {
291 |
292 | /**
293 | * We store the parent FserverProject object here.
294 | */
295 | var $FserverProject;
296 |
297 | /**
298 | * Constructor.
299 | */
300 | function __construct(&$FserverProject) {
301 | $this->FserverProject = $FserverProject;
302 | }
303 |
304 | /**
305 | * Destructor.
306 | */
307 | function __destruct() {
308 | if (isset($this->path)) {
309 | drush_op('drush_shell_exec', "rm -rf {$this->path}");
310 | }
311 | }
312 |
313 | /**
314 | * Initialize a working copy for this project.
315 | */
316 | function init_wc() {
317 | if (!isset($this->path)) {
318 | $this->path = file_directory_temp() . '/fserver_git_'. $this->FserverProject->name .'_'. time();
319 | drush_op('drush_shell_exec', "git clone {$this->FserverProject->repository} {$this->path}");
320 | }
321 | }
322 |
323 | /**
324 | * Get tags for this project.
325 | */
326 | function get_tags() {
327 | if (!isset($this->tags)) {
328 | $this->tags = array();
329 | _drush_shell_exec_output_set(' '); // Clear output cache.
330 | drush_op('drush_shell_exec', "git ls-remote --tags {$this->FserverProject->repository} | awk '{print $2;}'");
331 | $lines = drush_shell_exec_output();
332 | while ($line = array_shift($lines)) {
333 | $vc = array_pop(explode('/', $line));
334 | $parsed = fserver_parse_tag_name($vc);
335 | if (!empty($parsed)) {
336 | $this->tags[$parsed['version']] = $vc;
337 | }
338 | }
339 | }
340 | return $this->tags;
341 | }
342 |
343 | function get_tag($tag_id) {
344 | $tags = $this->get_tags();
345 | if (isset($tags[$tag_id])) {
346 | $vc = $tags[$tag_id];
347 | $tag = fserver_parse_tag_name($vc);
348 | $this->init_wc();
349 |
350 | // Retrieve tag info
351 | _drush_shell_exec_output_set(' '); // Clear output cache.
352 | drush_op('drush_shell_exec', "git --git-dir={$this->path}/.git show {$vc}");
353 | $info = drush_shell_exec_output();
354 | if ($info[0] == "tag {$vc}") {
355 | $info = implode("\n", $info);
356 | $info = explode("\n\n", $info);
357 | list($basic, $commit, $message) = $info;
358 |
359 | $basic = explode("\n", $basic);
360 | array_shift($basic); // Removes tag line
361 | array_shift($basic); // Removes author line
362 |
363 | // Set timestamp on the tag
364 | $date = array_shift($basic);
365 | $date = strtotime(trim(substr($date, strpos($date, ':') + 1)));
366 | $tag['timestamp'] = is_numeric($date) ? $date : time();
367 | }
368 | return $tag;
369 | }
370 | }
371 |
372 | /**
373 | * Create an archive package for the given tag.
374 | */
375 | function create_package($tag_id) {
376 | $this->init_wc();
377 | $tag = $this->get_tag($tag_id);
378 | if ($tag) {
379 | $base = "{$this->FserverProject->name}-{$tag_id}";
380 | $file_path = file_directory_path() .'/fserver';
381 | // Create the directory if it doesn't exist.
382 | if (file_check_directory($file_path, TRUE)) {
383 | $vc = $tag['original'];
384 | drush_op('drush_shell_exec', "git --git-dir={$this->path}/.git checkout {$vc}");
385 | $this->FserverProject->write_package_info($tag, array('.git'));
386 | drush_op('drush_shell_exec', "tar -Pcf - --exclude='.git' --transform='s,{$this->path},{$this->FserverProject->name},' {$this->path} | gzip > {$file_path}/{$base}.tgz");
387 |
388 | // @TODO
389 | // We need to properly chown and permission these directories.
390 | // Is it possible for drush to know the web server user?
391 | drush_op('chmod', $file_path, 0775);
392 | drush_op('chgrp', $file_path, fserver_posix_groupname());
393 | drush_op('chmod', "{$file_path}/{$base}.tgz", 0775);
394 | drush_op('chgrp', "{$file_path}/{$base}.tgz", fserver_posix_groupname());
395 |
396 | $file = new stdClass();
397 | $file->uid = $this->node->uid;
398 | $file->filename = "{$base}.tgz";
399 | $file->filepath = "{$file_path}/{$base}.tgz";
400 | $file->filemime = file_get_mimetype($file->filename);
401 | $file->filesize = filesize($file->filepath);
402 | $file->status = FILE_STATUS_PERMANENT;
403 | $file->timestamp = time();
404 | drupal_write_record('files', $file);
405 |
406 | return $file;
407 | }
408 | }
409 | return FALSE;
410 | }
411 |
412 | }
413 |
414 | class FserverProject_svn {
415 | /**
416 | * We store the parent FserverProject object here.
417 | */
418 | var $FserverProject;
419 |
420 | /**
421 | * Constructor.
422 | */
423 | function __construct(&$FserverProject) {
424 | $this->FserverProject = $FserverProject;
425 | }
426 |
427 | /**
428 | * Destructor.
429 | */
430 | function __destruct() {
431 | if (isset($this->path)) {
432 | drush_op('drush_shell_exec', "rm -rf {$this->path}");
433 | }
434 | }
435 |
436 | /**
437 | * Initialize a working copy for this project.
438 | */
439 | function init_wc() {
440 | if (!isset($this->path)) {
441 | $this->path = file_directory_temp() . '/fserver_svn_'. $this->FserverProject->name .'_'. time();
442 | //drush_op('drush_shell_exec', "git clone {$this->FserverProject->repository} {$this->path}");
443 | }
444 | }
445 |
446 | /**
447 | * Get tags for this project.
448 | */
449 | function get_tags() {
450 | if (!isset($this->tags)) {
451 | $this->tags = array();
452 | _drush_shell_exec_output_set(' '); // Clear output cache.
453 | drush_op('drush_shell_exec', "svn ls {$this->FserverProject->repository}/tags | awk '{print $1;}'");
454 | $lines = drush_shell_exec_output();
455 | while ($line = array_shift($lines)) {
456 | $vc = array_shift(explode('/', $line));
457 | $parsed = fserver_parse_tag_name($vc);
458 | if (!empty($parsed)) {
459 | $this->tags[$parsed['version']] = $vc;
460 | }
461 | }
462 | }
463 | return $this->tags;
464 | }
465 |
466 | function get_tag($tag_id) {
467 | $tags = $this->get_tags();
468 | if (isset($tags[$tag_id])) {
469 | $vc = $tags[$tag_id];
470 | $tag = fserver_parse_tag_name($vc);
471 | $this->init_wc();
472 |
473 | // Retrieve tag info
474 | _drush_shell_exec_output_set(' '); // Clear output cache.
475 | drush_op('drush_shell_exec', "svn info --non-interactive --xml {$this->FserverProject->repository}/tags/{$vc}");
476 | $info = drush_shell_exec_output();
477 | if (!empty($info)) {
478 | $info = implode("\n", $info);
479 | // $info is now an xml string:
480 | $info_xml = simplexml_load_string($info);
481 | foreach ($info_xml->xpath('//commit/date') as $date_element) {
482 | $date = strtotime((string)$date_element);
483 | }
484 | }
485 |
486 |
487 | $tag['timestamp'] = is_numeric($date) ? $date : time();
488 | return $tag;
489 | }
490 | }
491 |
492 | /**
493 | * Create an archive package for the given tag.
494 | */
495 | function create_package($tag_id) {
496 | $this->init_wc();
497 | $tag = $this->get_tag($tag_id);
498 | if ($tag) {
499 | $base = "{$this->FserverProject->name}-{$tag_id}";
500 | $file_path = file_directory_path() .'/fserver';
501 | // Create the directory if it doesn't exist.
502 | if (file_check_directory($file_path, TRUE)) {
503 | $vc = $tag['original'];
504 | if (is_dir($this->path)) {
505 | // I'd quite like to do a switch here, but couldn't get it to work reliably.
506 | drush_op('drush_shell_exec', "rm -rf {$this->path}");
507 | }
508 | drush_op('drush_shell_exec', "svn checkout --non-interactive {$this->FserverProject->repository}/tags/{$vc} {$this->path}");
509 | $this->FserverProject->write_package_info($tag, array('.svn'));
510 | drush_op('drush_shell_exec', "tar -Pcf - --exclude='.svn' --transform='s,{$this->path},{$this->FserverProject->name},' {$this->path} | gzip > {$file_path}/{$base}.tgz");
511 |
512 | // @TODO
513 | // We need to properly chown and permission these directories.
514 | // Is it possible for drush to know the web server user?
515 | drush_op('chmod', $file_path, 0775);
516 | drush_op('chgrp', $file_path, fserver_posix_groupname());
517 | drush_op('chmod', "{$file_path}/{$base}.tgz", 0775);
518 | drush_op('chgrp', "{$file_path}/{$base}.tgz", fserver_posix_groupname());
519 |
520 | $file = new stdClass();
521 | $file->uid = $this->node->uid;
522 | $file->filename = "{$base}.tgz";
523 | $file->filepath = "{$file_path}/{$base}.tgz";
524 | $file->filemime = file_get_mimetype($file->filename);
525 | $file->filesize = filesize($file->filepath);
526 | $file->status = FILE_STATUS_PERMANENT;
527 | $file->timestamp = time();
528 | drupal_write_record('files', $file);
529 |
530 | return $file;
531 | }
532 | }
533 | return FALSE;
534 | }
535 | }
536 |
537 | /**
538 | * Discover the web server group. Taken from provision.
539 | */
540 | function fserver_posix_groupname() {
541 | $info = posix_getgrgid(posix_getgid());
542 | $common_groups = array(
543 | 'httpd',
544 | 'www-data',
545 | 'apache',
546 | 'nogroup',
547 | 'nobody',
548 | $info['name']);
549 | foreach ($common_groups as $group) {
550 | $groupname = '';
551 | if (is_numeric($group)) {
552 | $info = posix_getgrgid($group);
553 | $groupname = $info['name'];
554 | }
555 | else {
556 | $info = posix_getgrnam($group);
557 | $groupname = $info['name'];
558 | }
559 | if ($groupname) {
560 | return $groupname;
561 | break;
562 | }
563 | }
564 | return NULL;
565 | }
566 |
567 | function fserver_drush_distro() {
568 | if (!drush_get_option('version')) {
569 | drush_die('No version supplied, please use --version to specify a version for your release.');
570 | }
571 | $distros = _fserver_drush_get_distros();
572 |
573 | // Filter the project list by the argument.
574 | $args = func_get_args();
575 | $arg = array_shift($args);
576 | $version = drush_get_option('version');
577 | if (!empty($arg)) {
578 | if (isset($distros[$arg])) {
579 | $distros = array($arg => $distros[$arg]);
580 | }
581 | else {
582 | drush_die('The distribution '. $arg .' could not be found.');
583 | }
584 | }
585 |
586 | $rows = array();
587 | foreach ($distros as $distro) {
588 | $release = $distro->create_release($version);
589 | $rows[] = array($distro->node->title, $release->field_fserver_file[0]['filename']);
590 | }
591 | if (!empty($rows)) {
592 | array_unshift($rows, array(dt('Project'), dt('Filename')));
593 | drush_print_table($rows, TRUE);
594 | }
595 | else {
596 | drush_print(dt('No distributions to update.'));
597 | }
598 | }
599 |
600 | function _fserver_drush_get_distros() {
601 | static $distros;
602 | if (!isset($distros)) {
603 | $projects = array();
604 | $result = db_query("SELECT nid, title FROM {node} WHERE type = 'fserver_distro' AND status = 1");
605 | while ($row = db_fetch_object($result)) {
606 | $node = node_load($row->nid);
607 | $distro = new FserverDistro($node, $node->field_fserver_name[0]['value']);
608 | $distros[$distro->name] = $distro;
609 | }
610 | }
611 | return $distros;
612 | }
613 |
614 | /**
615 | * Project class. Contains helpful methods for detecting tags, packaging, etc.
616 | */
617 | class FserverDistro {
618 | var $node, $name;
619 |
620 | /**
621 | * Constructor.
622 | */
623 | function __construct($node, $name, $version = NULL) {
624 | $this->node = $node;
625 | $this->name = $name;
626 | //$this->version = $version;
627 | }
628 |
629 | /**
630 | * Destructor.
631 | */
632 | function __destruct() {
633 | if (isset($this->path)) {
634 | drush_op('drush_shell_exec', "rm -rf {$this->path}");
635 | }
636 | }
637 |
638 | /**
639 | * Initialize a working copy for this project.
640 | */
641 | function init_wc() {
642 | if (!isset($this->raw_version)) {
643 | drush_die('Version was not parsed properly. Please supply versions in the drupal-6--1-0-alpha1 format.');
644 | }
645 | if (!isset($this->path)) {
646 | $this->path = file_directory_temp() . '/fserver_'. $this->name .'_'. time();
647 | if (file_check_directory($this->path, TRUE)) {
648 | if(!file_save_data($this->node->field_fserver_drushmake[0]['value'], $this->path .'/'. $this->name .'-'. $this->raw_version .'.make', FILE_EXISTS_REPLACE)) {
649 | return FALSE;
650 | }
651 | // @TODO
652 | // We need to properly chown and permission these directories.
653 | // Is it possible for drush to know the web server user?
654 | drush_op('chmod', $this->path, 0775);
655 | drush_op('chgrp', $this->path, fserver_posix_groupname());
656 | drush_op('chmod', "{$this->path}/{$this->name}-{$this->raw_version}.make", 0775);
657 | drush_op('chgrp', "{$this->path}/{$this->name}-{$this->raw_version}.make", fserver_posix_groupname());
658 | }
659 | }
660 | return TRUE;
661 | }
662 |
663 | /**
664 | * Get release nodes for this project.
665 | */
666 | function get_releases() {
667 | if (!isset($this->releases)) {
668 | $this->releases = array();
669 | $result = db_query("SELECT nid FROM {node} WHERE type = 'fserver_release' AND status = 1");
670 | while ($row = db_fetch_object($result)) {
671 | $node = node_load($row->nid);
672 | if ($node && isset($node->field_fserver_project[0]['nid']) && $node->field_fserver_project[0]['nid'] == $this->node->nid) {
673 | $this->releases[fserver_generate_version($node, TRUE)] = $node;
674 | }
675 | }
676 | }
677 | return $this->releases;
678 | }
679 |
680 | function parse_version($version) {
681 | if (isset($version)) {
682 | $this->version = array();
683 | $parsed = fserver_parse_tag_name($version);
684 | if (!empty($parsed)) {
685 | $extra = $parsed['extra'] ? $parsed['extra'] : 0;
686 | $view = views_get_view('fserver_release_lookup');
687 | $view->set_display('default');
688 | $args = array();
689 | $args[] = $this->node->nid;
690 | $args[] = $parsed['core'];
691 | $args[] = $extra;
692 | $view->set_arguments($args);
693 | $preview = $view->preview($form_state['display_id'], $args);
694 | $query = db_prefix_tables($view->build_info['query']);
695 | _db_query_callback($view->build_info['query_args'], TRUE);
696 | $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
697 | // Next line required because views passes 0 as "IS NULL" to the query, and we actually want 0, so it's been hacked in manually
698 | $query .= " AND (node_data_field_fserver_project.field_fserver_versionmajor_value = %d) AND (node_data_field_fserver_api.field_fserver_versionpatch_value = %d)";
699 | $items = db_query($query, $parsed['major'], $parsed['patch']);
700 | while ($result = db_fetch_object($items)) {
701 | $results[] = $result->nid;
702 | }
703 | if (!$results[0]) {
704 | $this->version = $parsed;
705 | $this->raw_version = $parsed['version'];
706 | }
707 | else {
708 | return FALSE;
709 | }
710 | }
711 | else {
712 | return FALSE;
713 | }
714 | }
715 | return $this->version;
716 | }
717 |
718 | /**
719 | * Create a release node for the given tag.
720 | */
721 | function create_release($version = NULL) {
722 | $version = $this->parse_version($version);
723 | if ($file = $this->create_package()) {
724 | //if ($version) {
725 | $node = new stdClass();
726 | $node->type = 'fserver_release';
727 | $node->status = 1;
728 | $node->created = !empty($tag['timestamp']) ? $tag['timestamp'] : time();
729 | $node->uid = $this->node->uid;
730 | $node->title = "{$this->name} {$tag_id}";
731 | $node->body = !empty($tag['message']) ? $tag['message'] : '';
732 |
733 | $node->field_fserver_file = array(0 => (array) $file);
734 | $node->field_fserver_project = array(0 => array('nid' => $this->node->nid));
735 | $node->field_fserver_api = array(0 => array('value' => $version['core']));
736 | $node->field_fserver_versionmajor = array(0 => array('value' => $version['major']));
737 | $node->field_fserver_versionpatch = array(0 => array('value' => $version['patch']));
738 | $node->field_fserver_versionextra = array(0 => array('value' => $version['extra']));
739 |
740 | // @TODO
741 | $node->field_fserver_recommended = array(0 => array('value' => 1));
742 | $node->field_fserver_security = array(0 => array('value' => 0));
743 | node_save($node);
744 | }
745 | return $node;
746 | }
747 |
748 | /**
749 | * Create an archive package for the given tag.
750 | */
751 | function create_package() {
752 | if (!$this->init_wc()) {
753 | return FALSE;
754 | }
755 | $base = "{$this->name}-{$this->raw_version}";
756 | $file_path = file_directory_path() .'/fserver';
757 | // Create the directory if it doesn't exist.
758 | if (file_check_directory($file_path, TRUE)) {
759 | drush_backend_invoke('make', array("{$this->path}/{$base}.make", "{$file_path}/{$base}", "--tar"));
760 | drush_op('drush_shell_exec', "mv {$file_path}/{$base}.tar.gz {$file_path}/{$base}.tgz");
761 |
762 | // @TODO
763 | // We need to properly chown and permission these directories.
764 | // Is it possible for drush to know the web server user?
765 | drush_op('chmod', $file_path, 0775);
766 | drush_op('chgrp', $file_path, fserver_posix_groupname());
767 | drush_op('chmod', "{$file_path}/{$base}.tgz", 0775);
768 | drush_op('chgrp', "{$file_path}/{$base}.tgz", fserver_posix_groupname());
769 |
770 | $file = new stdClass();
771 | $file->uid = $this->node->uid;
772 | $file->filename = "{$base}.tgz";
773 | $file->filepath = "{$file_path}/{$base}.tgz";
774 | $file->filemime = file_get_mimetype($file->filename);
775 | $file->filesize = filesize($file->filepath);
776 | $file->status = FILE_STATUS_PERMANENT;
777 | $file->timestamp = time();
778 | drupal_write_record('files', $file);
779 |
780 | return $file;
781 | }
782 | return FALSE;
783 | }
784 | }
785 |
--------------------------------------------------------------------------------
/fserver.features.content.inc:
--------------------------------------------------------------------------------
1 | 'field_fserver_drushmake',
12 | 'type_name' => 'fserver_distro',
13 | 'display_settings' => array(
14 | 'label' => array(
15 | 'format' => 'above',
16 | 'exclude' => 0,
17 | ),
18 | 'teaser' => array(
19 | 'format' => 'default',
20 | 'exclude' => 0,
21 | ),
22 | 'full' => array(
23 | 'format' => 'default',
24 | 'exclude' => 0,
25 | ),
26 | '4' => array(
27 | 'format' => 'default',
28 | 'exclude' => 0,
29 | ),
30 | ),
31 | 'widget_active' => '1',
32 | 'type' => 'text',
33 | 'required' => '1',
34 | 'multiple' => '0',
35 | 'module' => 'text',
36 | 'active' => '1',
37 | 'text_processing' => '0',
38 | 'max_length' => '',
39 | 'allowed_values' => '',
40 | 'allowed_values_php' => '',
41 | 'widget' => array(
42 | 'rows' => '5',
43 | 'size' => 60,
44 | 'default_value' => array(
45 | '0' => array(
46 | 'value' => '',
47 | '_error_element' => 'default_value_widget][field_fserver_drushmake][0][value',
48 | ),
49 | ),
50 | 'default_value_php' => NULL,
51 | 'label' => 'Drush Make Script',
52 | 'weight' => '-3',
53 | 'description' => '',
54 | 'type' => 'text_textarea',
55 | 'module' => 'text',
56 | ),
57 | );
58 |
59 | // Exported field: field_fserver_name
60 | $fields['fserver_distro-field_fserver_name'] = array(
61 | 'field_name' => 'field_fserver_name',
62 | 'type_name' => 'fserver_distro',
63 | 'display_settings' => array(
64 | 'weight' => '-4',
65 | 'parent' => '',
66 | 'label' => array(
67 | 'format' => 'hidden',
68 | ),
69 | 'teaser' => array(
70 | 'format' => 'hidden',
71 | 'exclude' => 0,
72 | ),
73 | 'full' => array(
74 | 'format' => 'hidden',
75 | 'exclude' => 0,
76 | ),
77 | '4' => array(
78 | 'format' => 'default',
79 | 'exclude' => 0,
80 | ),
81 | ),
82 | 'widget_active' => '1',
83 | 'type' => 'text',
84 | 'required' => '1',
85 | 'multiple' => '0',
86 | 'module' => 'text',
87 | 'active' => '1',
88 | 'text_processing' => '0',
89 | 'max_length' => '',
90 | 'allowed_values' => '',
91 | 'allowed_values_php' => '',
92 | 'widget' => array(
93 | 'rows' => 5,
94 | 'size' => '30',
95 | 'default_value' => array(
96 | '0' => array(
97 | 'value' => '',
98 | '_error_element' => 'default_value_widget][field_fserver_name][0][value',
99 | ),
100 | ),
101 | 'default_value_php' => NULL,
102 | 'label' => 'Machine name',
103 | 'weight' => '-4',
104 | 'description' => 'The machine-readable name for your project. This name must contain only lowercase letters, numbers, and underscores. Example: cooking_recipes.',
105 | 'type' => 'text_textfield',
106 | 'module' => 'text',
107 | ),
108 | );
109 |
110 | // Exported field: field_fserver_method
111 | $fields['fserver_project-field_fserver_method'] = array(
112 | 'field_name' => 'field_fserver_method',
113 | 'type_name' => 'fserver_project',
114 | 'display_settings' => array(
115 | 'weight' => '-2',
116 | 'parent' => '',
117 | 'label' => array(
118 | 'format' => 'hidden',
119 | ),
120 | 'teaser' => array(
121 | 'format' => 'hidden',
122 | 'exclude' => 0,
123 | ),
124 | 'full' => array(
125 | 'format' => 'hidden',
126 | 'exclude' => 0,
127 | ),
128 | '4' => array(
129 | 'format' => 'default',
130 | 'exclude' => 0,
131 | ),
132 | ),
133 | 'widget_active' => '1',
134 | 'type' => 'text',
135 | 'required' => '1',
136 | 'multiple' => '0',
137 | 'module' => 'text',
138 | 'active' => '1',
139 | 'text_processing' => '0',
140 | 'max_length' => '',
141 | 'allowed_values' => '',
142 | 'allowed_values_php' => 'return fserver_cck_options("method");',
143 | 'widget' => array(
144 | 'default_value' => array(
145 | '0' => array(
146 | 'value' => '',
147 | ),
148 | ),
149 | 'default_value_php' => NULL,
150 | 'label' => 'Packaging method',
151 | 'weight' => '1',
152 | 'description' => 'Choose the packaging method to use for this project.',
153 | 'type' => 'optionwidgets_select',
154 | 'module' => 'optionwidgets',
155 | ),
156 | );
157 |
158 | // Exported field: field_fserver_name
159 | $fields['fserver_project-field_fserver_name'] = array(
160 | 'field_name' => 'field_fserver_name',
161 | 'type_name' => 'fserver_project',
162 | 'display_settings' => array(
163 | 'weight' => '-4',
164 | 'parent' => '',
165 | 'label' => array(
166 | 'format' => 'hidden',
167 | ),
168 | 'teaser' => array(
169 | 'format' => 'hidden',
170 | 'exclude' => 0,
171 | ),
172 | 'full' => array(
173 | 'format' => 'hidden',
174 | 'exclude' => 0,
175 | ),
176 | '4' => array(
177 | 'format' => 'default',
178 | 'exclude' => 0,
179 | ),
180 | ),
181 | 'widget_active' => '1',
182 | 'type' => 'text',
183 | 'required' => '1',
184 | 'multiple' => '0',
185 | 'module' => 'text',
186 | 'active' => '1',
187 | 'text_processing' => '0',
188 | 'max_length' => '',
189 | 'allowed_values' => '',
190 | 'allowed_values_php' => '',
191 | 'widget' => array(
192 | 'rows' => 5,
193 | 'size' => '30',
194 | 'default_value' => array(
195 | '0' => array(
196 | 'value' => '',
197 | '_error_element' => 'default_value_widget][field_fserver_name][0][value',
198 | ),
199 | ),
200 | 'default_value_php' => NULL,
201 | 'label' => 'Machine name',
202 | 'weight' => '-4',
203 | 'description' => 'The machine-readable name for your project. This name must contain only lowercase letters, numbers, and underscores. Example: cooking_recipes.',
204 | 'type' => 'text_textfield',
205 | 'module' => 'text',
206 | ),
207 | );
208 |
209 | // Exported field: field_fserver_redirect
210 | $fields['fserver_project-field_fserver_redirect'] = array(
211 | 'field_name' => 'field_fserver_redirect',
212 | 'type_name' => 'fserver_project',
213 | 'display_settings' => array(
214 | 'label' => array(
215 | 'format' => 'above',
216 | 'exclude' => 0,
217 | ),
218 | '5' => array(
219 | 'format' => 'default',
220 | 'exclude' => 0,
221 | ),
222 | 'teaser' => array(
223 | 'format' => 'default',
224 | 'exclude' => 0,
225 | ),
226 | 'full' => array(
227 | 'format' => 'default',
228 | 'exclude' => 0,
229 | ),
230 | '4' => array(
231 | 'format' => 'default',
232 | 'exclude' => 0,
233 | ),
234 | '2' => array(
235 | 'format' => 'default',
236 | 'exclude' => 0,
237 | ),
238 | '3' => array(
239 | 'format' => 'default',
240 | 'exclude' => 0,
241 | ),
242 | ),
243 | 'widget_active' => '1',
244 | 'type' => 'text',
245 | 'required' => '0',
246 | 'multiple' => '0',
247 | 'module' => 'text',
248 | 'active' => '1',
249 | 'text_processing' => '0',
250 | 'max_length' => '',
251 | 'allowed_values' => '',
252 | 'allowed_values_php' => '',
253 | 'widget' => array(
254 | 'rows' => 5,
255 | 'size' => '60',
256 | 'default_value' => array(
257 | '0' => array(
258 | 'value' => '',
259 | '_error_element' => 'default_value_widget][field_fserver_redirect][0][value',
260 | ),
261 | ),
262 | 'default_value_php' => NULL,
263 | 'label' => 'Redirect URL (for legacy projects)',
264 | 'weight' => '3',
265 | 'description' => 'Enter a redirect URL to use for this project\'s update XML feed if this project has moved.',
266 | 'type' => 'text_textfield',
267 | 'module' => 'text',
268 | ),
269 | );
270 |
271 | // Exported field: field_fserver_repository
272 | $fields['fserver_project-field_fserver_repository'] = array(
273 | 'field_name' => 'field_fserver_repository',
274 | 'type_name' => 'fserver_project',
275 | 'display_settings' => array(
276 | 'weight' => '-1',
277 | 'parent' => '',
278 | 'label' => array(
279 | 'format' => 'inline',
280 | ),
281 | 'teaser' => array(
282 | 'format' => 'default',
283 | 'exclude' => 0,
284 | ),
285 | 'full' => array(
286 | 'format' => 'default',
287 | 'exclude' => 0,
288 | ),
289 | '4' => array(
290 | 'format' => 'default',
291 | 'exclude' => 0,
292 | ),
293 | ),
294 | 'widget_active' => '1',
295 | 'type' => 'text',
296 | 'required' => '0',
297 | 'multiple' => '0',
298 | 'module' => 'text',
299 | 'active' => '1',
300 | 'text_processing' => '0',
301 | 'max_length' => '',
302 | 'allowed_values' => '',
303 | 'allowed_values_php' => '',
304 | 'widget' => array(
305 | 'rows' => 5,
306 | 'size' => '60',
307 | 'default_value' => array(
308 | '0' => array(
309 | 'value' => '',
310 | '_error_element' => 'default_value_widget][field_fserver_repository][0][value',
311 | ),
312 | ),
313 | 'default_value_php' => NULL,
314 | 'label' => 'Repository URL',
315 | 'weight' => '2',
316 | 'description' => 'Example: git://github.com/myname/myproject.git',
317 | 'type' => 'text_textfield',
318 | 'module' => 'text',
319 | ),
320 | );
321 |
322 | // Exported field: field_fserver_type
323 | $fields['fserver_project-field_fserver_type'] = array(
324 | 'field_name' => 'field_fserver_type',
325 | 'type_name' => 'fserver_project',
326 | 'display_settings' => array(
327 | 'weight' => '-3',
328 | 'parent' => '',
329 | 'label' => array(
330 | 'format' => 'hidden',
331 | ),
332 | 'teaser' => array(
333 | 'format' => 'hidden',
334 | 'exclude' => 0,
335 | ),
336 | 'full' => array(
337 | 'format' => 'hidden',
338 | 'exclude' => 0,
339 | ),
340 | '4' => array(
341 | 'format' => 'default',
342 | 'exclude' => 0,
343 | ),
344 | ),
345 | 'widget_active' => '1',
346 | 'type' => 'text',
347 | 'required' => '1',
348 | 'multiple' => '0',
349 | 'module' => 'text',
350 | 'active' => '1',
351 | 'text_processing' => '0',
352 | 'max_length' => '',
353 | 'allowed_values' => '',
354 | 'allowed_values_php' => 'return fserver_cck_options(\'type\');',
355 | 'widget' => array(
356 | 'default_value' => array(
357 | '0' => array(
358 | 'value' => '',
359 | ),
360 | ),
361 | 'default_value_php' => NULL,
362 | 'label' => 'Type',
363 | 'weight' => '-2',
364 | 'description' => '',
365 | 'type' => 'optionwidgets_select',
366 | 'module' => 'optionwidgets',
367 | ),
368 | );
369 |
370 | // Exported field: field_fserver_api
371 | $fields['fserver_release-field_fserver_api'] = array(
372 | 'field_name' => 'field_fserver_api',
373 | 'type_name' => 'fserver_release',
374 | 'display_settings' => array(
375 | 'weight' => '-10',
376 | 'parent' => '',
377 | 'label' => array(
378 | 'format' => 'hidden',
379 | ),
380 | 'teaser' => array(
381 | 'format' => 'hidden',
382 | 'exclude' => 1,
383 | ),
384 | 'full' => array(
385 | 'format' => 'hidden',
386 | 'exclude' => 1,
387 | ),
388 | '4' => array(
389 | 'format' => 'default',
390 | 'exclude' => 0,
391 | ),
392 | ),
393 | 'widget_active' => '1',
394 | 'type' => 'text',
395 | 'required' => '1',
396 | 'multiple' => '0',
397 | 'module' => 'text',
398 | 'active' => '1',
399 | 'text_processing' => '0',
400 | 'max_length' => '',
401 | 'allowed_values' => '',
402 | 'allowed_values_php' => 'return fserver_cck_options(\'core\');',
403 | 'widget' => array(
404 | 'default_value' => array(
405 | '0' => array(
406 | 'value' => '6.x',
407 | ),
408 | ),
409 | 'default_value_php' => NULL,
410 | 'label' => 'Core compatibility',
411 | 'weight' => '-10',
412 | 'description' => '',
413 | 'type' => 'optionwidgets_select',
414 | 'module' => 'optionwidgets',
415 | ),
416 | );
417 |
418 | // Exported field: field_fserver_file
419 | $fields['fserver_release-field_fserver_file'] = array(
420 | 'field_name' => 'field_fserver_file',
421 | 'type_name' => 'fserver_release',
422 | 'display_settings' => array(
423 | 'weight' => '-13',
424 | 'parent' => '',
425 | 'label' => array(
426 | 'format' => 'hidden',
427 | ),
428 | 'teaser' => array(
429 | 'format' => 'hidden',
430 | 'exclude' => 1,
431 | ),
432 | 'full' => array(
433 | 'format' => 'hidden',
434 | 'exclude' => 1,
435 | ),
436 | '4' => array(
437 | 'format' => 'default',
438 | 'exclude' => 0,
439 | ),
440 | ),
441 | 'widget_active' => '1',
442 | 'type' => 'filefield',
443 | 'required' => '1',
444 | 'multiple' => '0',
445 | 'module' => 'filefield',
446 | 'active' => '1',
447 | 'list_field' => '0',
448 | 'list_default' => 1,
449 | 'description_field' => '0',
450 | 'widget' => array(
451 | 'file_extensions' => 'tgz tar gz',
452 | 'file_path' => 'fserver',
453 | 'progress_indicator' => 'bar',
454 | 'max_filesize_per_file' => '',
455 | 'max_filesize_per_node' => '',
456 | 'label' => 'Package',
457 | 'weight' => '-13',
458 | 'description' => '',
459 | 'type' => 'filefield_widget',
460 | 'module' => 'filefield',
461 | ),
462 | );
463 |
464 | // Exported field: field_fserver_project
465 | $fields['fserver_release-field_fserver_project'] = array(
466 | 'field_name' => 'field_fserver_project',
467 | 'type_name' => 'fserver_release',
468 | 'display_settings' => array(
469 | 'weight' => '-11',
470 | 'parent' => '',
471 | 'label' => array(
472 | 'format' => 'hidden',
473 | ),
474 | 'teaser' => array(
475 | 'format' => 'hidden',
476 | 'exclude' => 1,
477 | ),
478 | 'full' => array(
479 | 'format' => 'hidden',
480 | 'exclude' => 1,
481 | ),
482 | '4' => array(
483 | 'format' => 'default',
484 | 'exclude' => 0,
485 | ),
486 | ),
487 | 'widget_active' => '1',
488 | 'type' => 'nodereference',
489 | 'required' => '1',
490 | 'multiple' => '0',
491 | 'module' => 'nodereference',
492 | 'active' => '1',
493 | 'referenceable_types' => array(
494 | 'fserver_distro' => 'fserver_distro',
495 | 'fserver_project' => 'fserver_project',
496 | 'page' => 0,
497 | 'fserver_release' => 0,
498 | 'story' => 0,
499 | ),
500 | 'advanced_view' => '--',
501 | 'advanced_view_args' => '',
502 | 'widget' => array(
503 | 'autocomplete_match' => 'contains',
504 | 'size' => 60,
505 | 'default_value' => array(
506 | '0' => array(
507 | 'nid' => '',
508 | ),
509 | ),
510 | 'default_value_php' => NULL,
511 | 'label' => 'Project',
512 | 'weight' => '-11',
513 | 'description' => '',
514 | 'type' => 'nodereference_select',
515 | 'module' => 'nodereference',
516 | ),
517 | );
518 |
519 | // Exported field: field_fserver_recommended
520 | $fields['fserver_release-field_fserver_recommended'] = array(
521 | 'field_name' => 'field_fserver_recommended',
522 | 'type_name' => 'fserver_release',
523 | 'display_settings' => array(
524 | 'weight' => '-6',
525 | 'parent' => '',
526 | 'label' => array(
527 | 'format' => 'hidden',
528 | ),
529 | 'teaser' => array(
530 | 'format' => 'hidden',
531 | 'exclude' => 1,
532 | ),
533 | 'full' => array(
534 | 'format' => 'hidden',
535 | 'exclude' => 1,
536 | ),
537 | '4' => array(
538 | 'format' => 'default',
539 | 'exclude' => 0,
540 | ),
541 | ),
542 | 'widget_active' => '1',
543 | 'type' => 'text',
544 | 'required' => '1',
545 | 'multiple' => '0',
546 | 'module' => 'text',
547 | 'active' => '1',
548 | 'text_processing' => '0',
549 | 'max_length' => '',
550 | 'allowed_values' => '',
551 | 'allowed_values_php' => 'return fserver_cck_options(\'recommended\');',
552 | 'widget' => array(
553 | 'default_value' => array(
554 | '0' => array(
555 | 'value' => 0,
556 | ),
557 | ),
558 | 'default_value_php' => NULL,
559 | 'label' => 'Recommended',
560 | 'weight' => '-6',
561 | 'description' => 'The recommended releases will be displayed on the project page. The latest recommended release per major version will be offered for update status.',
562 | 'type' => 'optionwidgets_onoff',
563 | 'module' => 'optionwidgets',
564 | ),
565 | );
566 |
567 | // Exported field: field_fserver_security
568 | $fields['fserver_release-field_fserver_security'] = array(
569 | 'field_name' => 'field_fserver_security',
570 | 'type_name' => 'fserver_release',
571 | 'display_settings' => array(
572 | 'weight' => '-5',
573 | 'parent' => '',
574 | 'label' => array(
575 | 'format' => 'hidden',
576 | ),
577 | 'teaser' => array(
578 | 'format' => 'hidden',
579 | 'exclude' => 1,
580 | ),
581 | 'full' => array(
582 | 'format' => 'hidden',
583 | 'exclude' => 1,
584 | ),
585 | '4' => array(
586 | 'format' => 'default',
587 | 'exclude' => 0,
588 | ),
589 | ),
590 | 'widget_active' => '1',
591 | 'type' => 'text',
592 | 'required' => '0',
593 | 'multiple' => '0',
594 | 'module' => 'text',
595 | 'active' => '1',
596 | 'text_processing' => '0',
597 | 'max_length' => '',
598 | 'allowed_values' => '',
599 | 'allowed_values_php' => 'return fserver_cck_options(\'security\');',
600 | 'widget' => array(
601 | 'default_value' => array(
602 | '0' => array(
603 | 'value' => 'Not a security release',
604 | ),
605 | ),
606 | 'default_value_php' => NULL,
607 | 'label' => 'Security release',
608 | 'weight' => '-5',
609 | 'description' => '',
610 | 'type' => 'optionwidgets_onoff',
611 | 'module' => 'optionwidgets',
612 | ),
613 | );
614 |
615 | // Exported field: field_fserver_versionextra
616 | $fields['fserver_release-field_fserver_versionextra'] = array(
617 | 'field_name' => 'field_fserver_versionextra',
618 | 'type_name' => 'fserver_release',
619 | 'display_settings' => array(
620 | 'weight' => '-7',
621 | 'parent' => '',
622 | 'label' => array(
623 | 'format' => 'hidden',
624 | ),
625 | 'teaser' => array(
626 | 'format' => 'hidden',
627 | 'exclude' => 1,
628 | ),
629 | 'full' => array(
630 | 'format' => 'hidden',
631 | 'exclude' => 1,
632 | ),
633 | '4' => array(
634 | 'format' => 'default',
635 | 'exclude' => 0,
636 | ),
637 | ),
638 | 'widget_active' => '1',
639 | 'type' => 'text',
640 | 'required' => '0',
641 | 'multiple' => '0',
642 | 'module' => 'text',
643 | 'active' => '1',
644 | 'text_processing' => '0',
645 | 'max_length' => '',
646 | 'allowed_values' => '',
647 | 'allowed_values_php' => '',
648 | 'widget' => array(
649 | 'rows' => 5,
650 | 'size' => '20',
651 | 'default_value' => array(
652 | '0' => array(
653 | 'value' => '',
654 | '_error_element' => 'default_value_widget][field_fserver_versionextra][0][value',
655 | ),
656 | ),
657 | 'default_value_php' => NULL,
658 | 'label' => 'Extra version',
659 | 'weight' => '-7',
660 | 'description' => '',
661 | 'type' => 'text_textfield',
662 | 'module' => 'text',
663 | ),
664 | );
665 |
666 | // Exported field: field_fserver_versionmajor
667 | $fields['fserver_release-field_fserver_versionmajor'] = array(
668 | 'field_name' => 'field_fserver_versionmajor',
669 | 'type_name' => 'fserver_release',
670 | 'display_settings' => array(
671 | 'weight' => '-9',
672 | 'parent' => '',
673 | 'label' => array(
674 | 'format' => 'hidden',
675 | ),
676 | 'teaser' => array(
677 | 'format' => 'hidden',
678 | 'exclude' => 1,
679 | ),
680 | 'full' => array(
681 | 'format' => 'hidden',
682 | 'exclude' => 1,
683 | ),
684 | '4' => array(
685 | 'format' => 'default',
686 | 'exclude' => 0,
687 | ),
688 | ),
689 | 'widget_active' => '1',
690 | 'type' => 'number_integer',
691 | 'required' => '1',
692 | 'multiple' => '0',
693 | 'module' => 'number',
694 | 'active' => '1',
695 | 'prefix' => '',
696 | 'suffix' => '',
697 | 'min' => '0',
698 | 'max' => '50',
699 | 'allowed_values' => '',
700 | 'allowed_values_php' => 'return fserver_cck_options(\'major\');',
701 | 'widget' => array(
702 | 'default_value' => array(
703 | '0' => array(
704 | 'value' => '',
705 | ),
706 | ),
707 | 'default_value_php' => NULL,
708 | 'label' => 'Major version',
709 | 'weight' => '-9',
710 | 'description' => '',
711 | 'type' => 'optionwidgets_select',
712 | 'module' => 'optionwidgets',
713 | ),
714 | );
715 |
716 | // Exported field: field_fserver_versionpatch
717 | $fields['fserver_release-field_fserver_versionpatch'] = array(
718 | 'field_name' => 'field_fserver_versionpatch',
719 | 'type_name' => 'fserver_release',
720 | 'display_settings' => array(
721 | 'weight' => '-8',
722 | 'parent' => '',
723 | 'label' => array(
724 | 'format' => 'hidden',
725 | ),
726 | 'teaser' => array(
727 | 'format' => 'hidden',
728 | 'exclude' => 1,
729 | ),
730 | 'full' => array(
731 | 'format' => 'hidden',
732 | 'exclude' => 1,
733 | ),
734 | '4' => array(
735 | 'format' => 'default',
736 | 'exclude' => 0,
737 | ),
738 | ),
739 | 'widget_active' => '1',
740 | 'type' => 'number_integer',
741 | 'required' => '1',
742 | 'multiple' => '0',
743 | 'module' => 'number',
744 | 'active' => '1',
745 | 'prefix' => '',
746 | 'suffix' => '',
747 | 'min' => '0',
748 | 'max' => '50',
749 | 'allowed_values' => '',
750 | 'allowed_values_php' => 'return fserver_cck_options(\'patch\');',
751 | 'widget' => array(
752 | 'default_value' => array(
753 | '0' => array(
754 | 'value' => '',
755 | ),
756 | ),
757 | 'default_value_php' => NULL,
758 | 'label' => 'Patch version',
759 | 'weight' => '-8',
760 | 'description' => '',
761 | 'type' => 'optionwidgets_select',
762 | 'module' => 'optionwidgets',
763 | ),
764 | );
765 |
766 | // Translatables
767 | // Included for use with string extractors like potx.
768 | t('Core compatibility');
769 | t('Drush Make Script');
770 | t('Extra version');
771 | t('Machine name');
772 | t('Major version');
773 | t('Package');
774 | t('Packaging method');
775 | t('Patch version');
776 | t('Project');
777 | t('Recommended');
778 | t('Redirect URL (for legacy projects)');
779 | t('Repository URL');
780 | t('Security release');
781 | t('Type');
782 |
783 | return $fields;
784 | }
785 |
--------------------------------------------------------------------------------
/fserver.features.inc:
--------------------------------------------------------------------------------
1 | 3);
10 | }
11 | elseif ($module == "strongarm" && $api == "strongarm") {
12 | return array("version" => 1);
13 | }
14 | }
15 |
16 | /**
17 | * Implementation of hook_node_info().
18 | */
19 | function fserver_node_info() {
20 | $items = array(
21 | 'fserver_distro' => array(
22 | 'name' => t('Distribution'),
23 | 'module' => 'features',
24 | 'description' => t('A feature distribution page. Provides the drush make commands and releases for download.'),
25 | 'has_title' => '1',
26 | 'title_label' => t('Distribution'),
27 | 'has_body' => '1',
28 | 'body_label' => t('Body'),
29 | 'min_word_count' => '0',
30 | 'help' => '',
31 | ),
32 | 'fserver_project' => array(
33 | 'name' => t('Project'),
34 | 'module' => 'features',
35 | 'description' => t('A feature project page. Provides a summary of project information and releases for download.'),
36 | 'has_title' => '1',
37 | 'title_label' => t('Project'),
38 | 'has_body' => '1',
39 | 'body_label' => t('Description'),
40 | 'min_word_count' => '0',
41 | 'help' => '',
42 | ),
43 | 'fserver_release' => array(
44 | 'name' => t('Release'),
45 | 'module' => 'features',
46 | 'description' => t('A single release package for a feature.'),
47 | 'has_title' => '1',
48 | 'title_label' => t('Release'),
49 | 'has_body' => '1',
50 | 'body_label' => t('Notes'),
51 | 'min_word_count' => '0',
52 | 'help' => '',
53 | ),
54 | );
55 | return $items;
56 | }
57 |
58 | /**
59 | * Implementation of hook_views_api().
60 | */
61 | function fserver_views_api() {
62 | return array(
63 | 'api' => '2',
64 | );
65 | }
66 |
--------------------------------------------------------------------------------
/fserver.features.menu_links.inc:
--------------------------------------------------------------------------------
1 | 'features',
12 | 'link_path' => 'fserver',
13 | 'router_path' => 'fserver',
14 | 'link_title' => 'Projects',
15 | 'options' => array(),
16 | 'module' => 'system',
17 | 'hidden' => '0',
18 | 'external' => '0',
19 | 'has_children' => '0',
20 | 'expanded' => '0',
21 | 'weight' => '0',
22 | );
23 | // Translatables
24 | // Included for use with string extractors like potx.
25 | t('Projects');
26 |
27 |
28 | return $menu_links;
29 | }
30 |
--------------------------------------------------------------------------------
/fserver.info:
--------------------------------------------------------------------------------
1 | core = "6.x"
2 | dependencies[] = "context"
3 | dependencies[] = "features"
4 | dependencies[] = "filefield"
5 | dependencies[] = "menu"
6 | dependencies[] = "node"
7 | dependencies[] = "nodereference"
8 | dependencies[] = "number"
9 | dependencies[] = "strongarm"
10 | dependencies[] = "views"
11 | description = "Provides feature projects and releases."
12 | features[content][] = "fserver_distro-field_fserver_drushmake"
13 | features[content][] = "fserver_distro-field_fserver_name"
14 | features[content][] = "fserver_project-field_fserver_method"
15 | features[content][] = "fserver_project-field_fserver_name"
16 | features[content][] = "fserver_project-field_fserver_redirect"
17 | features[content][] = "fserver_project-field_fserver_repository"
18 | features[content][] = "fserver_project-field_fserver_type"
19 | features[content][] = "fserver_release-field_fserver_api"
20 | features[content][] = "fserver_release-field_fserver_file"
21 | features[content][] = "fserver_release-field_fserver_project"
22 | features[content][] = "fserver_release-field_fserver_recommended"
23 | features[content][] = "fserver_release-field_fserver_security"
24 | features[content][] = "fserver_release-field_fserver_versionextra"
25 | features[content][] = "fserver_release-field_fserver_versionmajor"
26 | features[content][] = "fserver_release-field_fserver_versionpatch"
27 | features[context][] = "fserver-section-project"
28 | features[ctools][] = "context:context:3"
29 | features[ctools][] = "strongarm:strongarm:1"
30 | features[menu_links][] = "features:fserver"
31 | features[node][] = "fserver_distro"
32 | features[node][] = "fserver_project"
33 | features[node][] = "fserver_release"
34 | features[variable][] = "content_extra_weights_fserver_project"
35 | features[variable][] = "content_extra_weights_fserver_release"
36 | features[views][] = "fserver_projects"
37 | features[views][] = "fserver_release_lookup"
38 | features[views][] = "fserver_releases"
39 | features[views][] = "fserver_updates"
40 | features[views_api][] = "api:3.0-alpha1"
41 | name = "Feature Server"
42 | package = "Features"
43 |
--------------------------------------------------------------------------------
/fserver.js:
--------------------------------------------------------------------------------
1 | // $Id$
2 |
3 | /**
4 | * JS behaviors for fserver.
5 | */
6 | Drupal.behaviors.fserver = function() {
7 | $('#edit-field-fserver-method-value:not(.processed)').each(function() {
8 | $(this).addClass('processed');
9 | $(this).change(function() {
10 | switch ($(this).val()) {
11 | case '0':
12 | $('#edit-field-fserver-repository-0-value-wrapper').hide();
13 | break;
14 | default:
15 | $('#edit-field-fserver-repository-0-value-wrapper').show();
16 | break;
17 | }
18 | });
19 | $(this).change();
20 | });
21 | };
22 |
--------------------------------------------------------------------------------
/fserver.module:
--------------------------------------------------------------------------------
1 | 'Manual'.
10 | $links = array();
11 | if ($type == 'node' && $object->type == 'fserver_project' && empty($object->field_fserver_method[0]['value'])) {
12 | $item = menu_get_item('node/add/fserver-release');
13 | if ($item && $item['access']) {
14 | $links['fserver-add-release'] = array(
15 | 'title' => t('Add new @release', array('@release' => strtolower($item['title']))),
16 | 'href' => 'node/add/fserver-release',
17 | );
18 | }
19 | }
20 | return $links;
21 | }
22 |
23 | /**
24 | * Implementation of hook_nodeapi().
25 | */
26 | function fserver_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
27 | if ($op == 'view' && $node->type == 'fserver_distro' && menu_get_object()->nid === $node->nid) {
28 | //$node->content['field_fserver_drushmake'][0]['value'] = ''. $node->field_fserver_drushmake[0]['value'] .'
';
29 | $node->content['field_fserver_drushmake']['field']['items'][0]['#item']['safe'] = '
@project.info
", array('@project' => $project)),
40 | '#type' => 'item',
41 | '#value' => "project status url = {$url}
",
42 | ),
43 | 'drush_make' => array(
44 | '#title' => t("For drush make
makefiles"),
45 | '#type' => 'item',
46 | '#value' => "projects[{$project}][location] = {$url}
",
47 | ),
48 | '#weight' => -10,
49 | );
50 | }
51 | else if ($op == 'presave' && $node->type == 'fserver_project') {
52 | if (empty($node->field_fserver_method[0]['value'])) {
53 | $node->field_fserver_repository[0]['value'] = '';
54 | }
55 | }
56 | else if ($op == 'presave' && $node->type == 'fserver_release') {
57 | $node->title = fserver_generate_version($node);
58 |
59 | // If this release is recommended, set all other ones to not recommended.
60 | if ($node->field_fserver_recommended[0]['value'] == 1) {
61 | $view = views_get_view('fserver_releases');
62 | $view->set_arguments(array($node->field_fserver_project[0]['nid'], $node->field_fserver_api[0]['value']));
63 | $view->execute('block_1');
64 | foreach ($view->result as $data) {
65 | if (!isset($node->nid) || $data->nid != $node->nid) {
66 | $release = node_load($data->nid);
67 | $release->field_fserver_recommended[0]['value'] = 0;
68 | node_save($release);
69 | }
70 | }
71 | }
72 | }
73 | else if ($op == 'view' && $node->type == 'fserver_release') {
74 | drupal_add_css(drupal_get_path('module', 'fserver') . '/fserver.css');
75 | $download_url = url($node->field_fserver_file[0]['filepath'], array('purl' => array('disabled' => TRUE), 'absolute' => TRUE));
76 | $contents = file_exists($node->field_fserver_file[0]['filepath']) ? file_get_contents($node->field_fserver_file[0]['filepath']) : '';
77 | $info = array();
78 | $info[] = t('Download: !url', array('!url' => l($download_url, $download_url, array('absolute' => TRUE))));
79 | $info[] = t('md5 hash: !md5', array('!md5' => md5($contents)));
80 | $info[] = t('Size: !size', array('!size' => format_size($node->field_fserver_file[0]['filesize'])));
81 | $node->content['fserver_info'] = array(
82 | '#type' => 'fieldset',
83 | 'content' => array(
84 | '#type' => 'markup',
85 | '#value' => theme('item_list', $info, NULL, 'ul', array('id' => 'fserver-release-info')),
86 | ),
87 | '#weight' => -10,
88 | );
89 | $project = node_load($node->field_fserver_project[0]['nid']);
90 | drupal_set_breadcrumb(array(l(t('Home'), NULL), l($project->title, 'node/' . $project->nid)));
91 | }
92 | }
93 |
94 | /**
95 | * Option field callback for version options.
96 | */
97 | function fserver_cck_options($type = 'core') {
98 | switch ($type) {
99 | case 'core':
100 | return drupal_map_assoc(array('5.x', '6.x', '7.x'));
101 |
102 | case 'major':
103 | $major = range(0, 50);
104 | unset($major[0]);
105 | return $major;
106 |
107 | case 'method':
108 | return array(
109 | 0 => t('Manual upload'),
110 | 'git' => t('GIT repository tags'),
111 | 'svn' => t('SVN repository tags folder'),
112 | );
113 |
114 | case 'patch':
115 | return range(0, 50);
116 |
117 | case 'recommended':
118 | return array(t('Not recommended'), t('Recommended'));
119 |
120 | case 'security':
121 | return array(t('Not a security release'), t('Security release'));
122 |
123 | case 'type':
124 | // We don't use t() here as the update XML requires these strings to be uniform.
125 | return array(
126 | // 'core' => 'Drupal project',
127 | 'profile' => 'Installation profiles',
128 | 'module' => 'Modules',
129 | 'theme' => 'Themes',
130 | // 'theme engine' => 'Theme engines',
131 | // 'translation' => 'Translations',
132 | );
133 | }
134 | }
135 |
136 | /**
137 | * Parse a package name into values: core, major, patch and extra.
138 | */
139 | function fserver_parse_package_name($package_filename) {
140 | // example: fserver-6.x-2.0-rc3.tar.gz
141 | if (preg_match('/^(?