function display_changeset_link($p_event, $p_bug_id) { $this->changesets = SourceChangeset::load_by_bug($p_bug_id, true); if (count($this->changesets) > 0) { return array(plugin_lang_get('related_changesets', 'Source') => '#changesets'); } return array(); }
/** * Return a set of changeset objects from a database result. * Assumes selecting * from changeset_table. * @param object Database result * @return array Changeset objects */ static function from_result($p_result, $p_load_files = false) { $t_changesets = array(); while ($t_row = db_fetch_array($p_result)) { $t_changeset = new SourceChangeset($t_row['repo_id'], $t_row['revision']); $t_changeset->id = $t_row['id']; $t_changeset->parent = $t_row['parent']; $t_changeset->branch = $t_row['branch']; $t_changeset->timestamp = $t_row['timestamp']; $t_changeset->user_id = $t_row['user_id']; $t_changeset->author = $t_row['author']; $t_changeset->author_email = $t_row['author_email']; $t_changeset->message = $t_row['message']; $t_changeset->info = $t_row['info']; $t_changeset->ported = $t_row['ported']; $t_changeset->committer = $t_row['committer']; $t_changeset->committer_email = $t_row['committer_email']; $t_changeset->committer_id = $t_row['committer_id']; if ($p_load_files) { $t_changeset->load_files(); } $t_changesets[$t_changeset->id] = $t_changeset; } return $t_changesets; }
<?php # Copyright (c) 2012 John Reese # Licensed under the MIT license access_ensure_project_level(plugin_config_get('update_threshold')); $f_changeset_id = gpc_get_int('id'); $t_changeset = SourceChangeset::load($f_changeset_id); $t_repos = SourceRepo::load_by_changesets($t_changeset); if (count($t_repos) < 1) { trigger_error(ERROR_GENERIC, ERROR); } $t_repo = array_shift($t_repos); $t_repo->load_branches(); if (plugin_config_get('enable_porting')) { $f_ported = gpc_get_string('ported', ''); if (0 == $f_ported || in_array($f_ported, $t_repo->branches)) { $t_changeset->ported = $f_ported; } } $t_changeset->save(); print_successful_redirect(plugin_page('view', true) . '&id=' . $t_changeset->id);
private function json_commit_changeset($p_repo, $p_json, $p_branch = '') { echo "processing {$p_json->hash} ... "; if (!SourceChangeset::exists($p_repo->id, $p_json->hash)) { $t_parents = array(); foreach ($p_json->parents as $t_parent) { $t_parents[] = $t_parent->hash; } $t_changeset = new SourceChangeset($p_repo->id, $p_json->hash, $p_branch, date('Y-m-d H:i:s', strtotime($p_json->date)), $this->get_author_name($p_json->author->raw), $p_json->message); if (count($p_json->parents) > 0) { $t_parent = $p_json->parents[0]; $t_changeset->parent = $t_parent->hash; } $t_changeset->author_email = $this->get_author_email($p_json->author->raw); $t_changeset->committer = $t_changeset->author; $t_changeset->committer_email = $t_changeset->author_email; $t_username = $p_repo->info['bit_username']; $t_reponame = $p_repo->info['bit_reponame']; $t_commit_id = $p_json->hash; $t_url = $this->api_url10("repositories/{$t_username}/{$t_reponame}/changesets/{$t_commit_id}/diffstat/"); $t_files = $this->api_json_url($p_repo, $t_url); if (!empty($t_files)) { foreach ($t_files as $t_file) { switch ($t_file->type) { case 'added': $t_changeset->files[] = new SourceFile(0, '', $t_file->file, 'add'); break; case 'modified': $t_changeset->files[] = new SourceFile(0, '', $t_file->file, 'mod'); break; case 'removed': $t_changeset->files[] = new SourceFile(0, '', $t_file->file, 'rm'); break; } } } $t_changeset->save(); echo "saved.\n"; return array($t_changeset, $t_parents); } else { echo "already exists.\n"; return array(null, array()); } }
private function commit_changeset($p_repo, $p_input, $p_branch = '') { // Clean the input $t_input = $this->clean_input($p_input); // Get the revision $t_commit['revision'] = $this->commit_revision($t_input); echo "processing {$t_commit['revision']} ... "; // Only process if it doesn't exist yet if (!SourceChangeset::exists($p_repo->id, $t_commit['revision'])) { // Author and committer data $t_commit = array_merge($this->commit_author($t_input), $t_commit); // Commit parents $t_parents = $this->commit_parents($t_input); // Set the last parent as the main parent of this commit $t_commit['parent'] = $t_parents[count($t_parents) - 1]; // Set the message $t_commit['message'] = $this->commit_message($t_input); # Parse for changed file data $t_commit['files'] = $this->commit_files($t_input); // Create the changeset $t_changeset = new SourceChangeset($p_repo->id, $t_commit['revision'], $p_branch, $t_commit['date'], $t_commit['author'], $t_commit['message'], 0, isset($t_commit['parent']) ? $t_commit['parent'] : ''); $t_changeset->author_email = $t_commit['author_email']; $t_changeset->committer = $t_commit['committer']; $t_changeset->committer_email = $t_commit['committer_email']; foreach ($t_commit['files'] as $t_file) { $t_changeset->files[] = new SourceFile(0, $t_file['revision'], $t_file['filename'], $t_file['action']); } $t_changeset->save(); echo "saved.\n"; return array($t_changeset, $t_parents); } else { echo "already exists.\n"; return array(null, array()); } }
private function commit_changeset($p_repo, $p_input, $p_branch = '') { $t_input = str_replace(array(PHP_EOL, '<', '>', ' '), array('', '<', '>', ' '), $p_input); # Exract sections of commit data and changed files $t_input_p1 = strpos($t_input, '<div class="title_text">'); $t_input_p2 = strpos($t_input, '<div class="list_head">'); if (false === $t_input_p1 || false === $t_input_p2) { echo 'commit data failure.'; var_dump(strlen($t_input), $t_input_p1, $t_input_p2); die; } $t_gitweb_data = substr($t_input, $t_input_p1, $t_input_p2 - $t_input_p1); $t_input_p1 = strpos($t_input, '<table class="diff_tree">'); if (false === $t_input_p1) { $t_input_p1 = strpos($t_input, '<table class="combined diff_tree">'); } $t_input_p2 = strpos($t_input, '<div class="page_footer">'); if (false === $t_input_p1 || false === $t_input_p2) { echo 'file data failure.'; var_dump(strlen($t_input), $t_input_p1, $t_input_p2); die; } $t_gitweb_files = substr($t_input, $t_input_p1, $t_input_p2 - $t_input_p1); # Get commit revsion and make sure it's not a dupe preg_match('#<tr><td>commit</td><td class="sha1">([a-f0-9]*)</td></tr>#', $t_gitweb_data, $t_matches); $t_commit['revision'] = $t_matches[1]; echo "processing {$t_commit['revision']} ... "; if (!SourceChangeset::exists($p_repo->id, $t_commit['revision'])) { # Parse for commit data preg_match('#<tr><td>author</td><td>(?:<a[^>]*>)?([^<>]*)(?:</a>)? *(?:<a[^>]*>)?<([^<>]*)>(?:</a>)?</td>(?:<[^<>]*>\\s*)*?</tr>\\n<tr><td></td><td><span class="datetime">\\w*, (\\d* \\w* \\d* \\d*:\\d*:\\d*)#', $t_gitweb_data, $t_matches); $t_commit['author'] = $t_matches[1]; $t_commit['author_email'] = $t_matches[2]; $t_commit['date'] = date('Y-m-d H:i:s', strtotime($t_matches[3])); if (preg_match('#<tr><td>committer</td><td>(?:<a[^>]*>)?([^<>]*)(?:</a>)? *(?:<a[^>]*>)?<([^<>]*)>(?:</a>)?</td>(?:<[^<>]*>\\s*)*?</tr>#', $t_gitweb_data, $t_matches)) { $t_commit['committer'] = $t_matches[1]; $t_commit['committer_email'] = $t_matches[2]; } $t_parents = array(); if (preg_match_all('#<tr><td>parent</td><td class="sha1"><a [^<>]*>([a-f0-9]*)</a></td>#', $t_gitweb_data, $t_matches)) { foreach ($t_matches[1] as $t_match) { $t_parents[] = $t_commit['parent'] = $t_match; } } preg_match('#<div class="page_body">\\n(.*)\\n</div>#', $t_gitweb_data, $t_matches); $t_commit['message'] = trim(str_replace('<br/>', PHP_EOL, $t_matches[1])); # Strip ref links and signoff spans from commit message $t_commit['message'] = preg_replace(array('@<a[^>]*>([^<]*)<\\/a>@', '@<span[^>]*>([^<]*<[^>]*>[^<]*)<\\/span>@'), '$1', $t_commit['message']); # Parse for changed file data $t_commit['files'] = array(); preg_match_all('#<tr class="(?:light|dark)">\\n<td><a class="list" href="[^"]*;h=(\\w+);[^"]*">([^<>]+)</a></td>' . '\\n<td>(?:<span class="file_status (\\w+)">[^<>]*</span>)?</td>#', $t_gitweb_files, $t_matches, PREG_SET_ORDER); foreach ($t_matches as $t_file_matches) { $t_file = array(); $t_file['filename'] = $t_file_matches[2]; $t_file['revision'] = $t_file_matches[1]; if (isset($t_file_matches[3])) { if ('new' == $t_file_matches[3]) { $t_file['action'] = 'add'; } else { if ('deleted' == $t_file_matches[3]) { $t_file['action'] = 'rm'; } } } else { $t_file['action'] = 'mod'; } $t_commit['files'][] = $t_file; } $t_changeset = new SourceChangeset($p_repo->id, $t_commit['revision'], $p_branch, $t_commit['date'], $t_commit['author'], $t_commit['message'], 0, isset($t_commit['parent']) ? $t_commit['parent'] : ''); $t_changeset->author_email = $t_commit['author_email']; $t_changeset->committer = $t_commit['committer']; $t_changeset->committer_email = $t_commit['committer_email']; foreach ($t_commit['files'] as $t_file) { $t_changeset->files[] = new SourceFile(0, $t_file['revision'], $t_file['filename'], $t_file['action']); } $t_changeset->save(); echo "saved.\n"; return array($t_changeset, $t_parents); } else { echo "already exists.\n"; return array(null, array()); } }
foreach ($t_changeset->bugs as $t_bug_id) { $t_bug_row = bug_cache_row($t_bug_id, false); if (false === $t_bug_row) { continue; } $t_bug_rows[$t_bug_id] = $t_bug_row; } $t_affected_rowspan = count($t_bug_rows) + ($t_can_update ? 1 : 0); $t_repos = SourceRepo::load_by_changesets($t_changeset); if (count($t_repos) < 1) { trigger_error(ERROR_GENERIC, ERROR); } $t_repo = array_shift($t_repos); $t_repo->load_branches(); if ($t_changeset->parent) { $t_changeset_parent = SourceChangeset::load_by_revision($t_repo, $t_changeset->parent); } else { $t_changeset_parent = null; } $t_vcs = SourceVCS::repo($t_repo); $t_type = SourceType($t_repo->type); $t_use_porting = plugin_config_get('enable_porting'); $t_columns = ($t_use_porting ? 1 : 0) + 5; $t_update_form = $t_use_porting && $t_can_update; html_page_top1(plugin_lang_get('title')); html_page_top2(); ?> <br/> <?php if ($t_update_form) {
private function json_commit_changeset($p_repo, $p_json, $p_branch = '') { echo "processing {$p_json->id} ... "; if (!SourceChangeset::exists($p_repo->id, $p_json->id)) { $t_parents = array(); foreach ($p_json->parent_ids as $t_parent) { $t_parents[] = $t_parent; } # Message will be replaced by title in gitlab version earlier than 7.2 $t_message = !property_exists($p_json, 'message') ? $p_json->title : $p_json->message; $t_changeset = new SourceChangeset($p_repo->id, $p_json->id, $p_branch, date('Y-m-d H:i:s', strtotime($p_json->created_at)), $p_json->author_name, $t_message); if (count($p_json->parents) > 0) { $t_parent = $p_json->parents[0]; $t_changeset->parent = $t_parent->id; } $t_changeset->author_email = $p_json->author_email; $t_changeset->save(); echo "saved.\n"; return array($t_changeset, $t_parents); } else { echo "already exists.\n"; return array(null, array()); } }
<?php # Copyright (c) 2012 John Reese # Licensed under the MIT license require_once config_get('plugin_path') . 'Source/Source.ViewAPI.php'; access_ensure_global_level(plugin_config_get('view_threshold')); $f_repo_id = gpc_get_int('id'); $f_offset = gpc_get_int('offset', 1); $f_perpage = 25; $t_repo = SourceRepo::load($f_repo_id); $t_vcs = SourceVCS::repo($t_repo); $t_type = SourceType($t_repo->type); $t_stats = $t_repo->stats(false); $t_changesets = SourceChangeset::load_by_repo($t_repo->id, true, $f_offset, $f_perpage); html_page_top1(plugin_lang_get('title')); html_page_top2(); ?> <br/> <table class="width100" cellspacing="1" align="center"> <tr> <td class="form-title" colspan="2"><?php echo plugin_lang_get('changesets'), ': ', $t_repo->name; ?> </td> <td class="right" colspan="2"> <?php if (access_has_global_level(plugin_config_get('manage_threshold'))) { print_bracket_link(plugin_page('repo_manage_page') . '&id=' . $t_repo->id, plugin_lang_get('manage')); }
$bugs = array(); $status = array(); $columns = plugin_config_get("board_columns"); $sevcolors = plugin_config_get("board_severity_colors"); $rescolors = plugin_config_get("board_resolution_colors"); $sprint_length = plugin_config_get("sprint_length"); $use_source = plugin_is_loaded("Source"); $resolved_count = 0; foreach ($bug_ids as $bug_id) { $bug = bug_get($bug_id); $bugs[$bug->status][] = $bug; $source_count[$bug_id] = $use_source ? count(SourceChangeset::load_by_bug($bug_id)) : ""; if ($bug->status >= $resolved_threshold) { $resolved_count++; } } $bug_count = count($bug_ids); if ($bug_count > 0) { $resolved_percent = floor(100 * $resolved_count / $bug_count); } else { $resolved_percent = 0; }
private function commit_changeset($p_repo, $p_input, $p_branch = '') { $t_input = str_replace(array("\r", "\n", '<', '>', ' '), array('', '', '<', '>', ' '), $p_input); # Extract sections of commit data and changed files $t_input_p1 = strpos($t_input, '<div class="title_text">'); $t_input_p2 = strpos($t_input, '<div class="list_head">'); if (false === $t_input_p1 || false === $t_input_p2) { echo "commit data failure.\n"; var_dump(strlen($t_input), $t_input_p1, $t_input_p2); die; } $t_gitweb_data = substr($t_input, $t_input_p1, $t_input_p2 - $t_input_p1); $t_input_p1 = strpos($t_input, '<table class="diff_tree">'); if (false === $t_input_p1) { $t_input_p1 = strpos($t_input, '<table class="combined diff_tree">'); } $t_input_p2 = strpos($t_input, '<div class="page_footer">'); if (false === $t_input_p1 || false === $t_input_p2) { echo 'file data failure.'; var_dump(strlen($t_input), $t_input_p1, $t_input_p2); die; } $t_gitweb_files = substr($t_input, $t_input_p1, $t_input_p2 - $t_input_p1); # Get commit revsion and make sure it's not a dupe preg_match('#<tr><td>commit</td><td class="sha1">([a-f0-9]*)</td></tr>#', $t_gitweb_data, $t_matches); $t_commit['revision'] = $t_matches[1]; echo "processing {$t_commit['revision']} ... "; if (!SourceChangeset::exists($p_repo->id, $t_commit['revision'])) { # Parse for commit data preg_match('#authored by ([^"]*).*?authored by ([^"]*).*?>([^<]*\\d*:\\d*:\\d*[^(<]*)' . '.*?committed by ([^"]*).*?committed by ([^"]*).*?page_body">(.*?)</div>#', $t_gitweb_data, $t_matches); $t_commit['author'] = $t_matches[1]; $t_commit['author_email'] = $t_matches[2]; $t_commit['date'] = date('Y-m-d H:i:s', strtotime($t_matches[3])); $t_commit['committer'] = $t_matches[4]; $t_commit['committer_email'] = $t_matches[5]; $t_commit['message'] = trim(str_replace('<br/>', PHP_EOL, $t_matches[6])); $t_parents = array(); if (preg_match_all('#parent</td><td class="sha1"><[^>]*h=([0-9a-f]*)#', $t_gitweb_data, $t_matches)) { foreach ($t_matches[1] as $t_match) { $t_parents[] = $t_commit['parent'] = $t_match; } } # Strip ref links and signoff spans from commit message $t_commit['message'] = preg_replace(array('#<a[^>]*>([^<]*)</a>#', '#<span[^>]*>(.*?)</span>#'), '$1', $t_commit['message']); # Prepend a # sign to mantis number $t_commit['message'] = preg_replace('#(mantis)\\s+(\\d+)#i', '$1 #$2', $t_commit['message']); # Parse for changed file data $t_commit['files'] = array(); preg_match_all('#class="list".*?h=(\\w*).*?>(.*?)<.a>(?:(?:<.td><td><span class="file_status| with \\d*%) (\\w*))?#', $t_gitweb_files, $t_matches, PREG_SET_ORDER); foreach ($t_matches as $t_file_matches) { $t_file = array(); $t_file['filename'] = $t_file_matches[2]; $t_file['revision'] = $t_file_matches[1]; if (isset($t_file_matches[3])) { if ($t_file_matches[3] == 'new' or $t_file_matches[3] == 'moved') { $t_file['action'] = 'add'; } else { if ($t_file_matches[3] == 'deleted' or $t_file_matches[3] == 'similarity') { $t_file['action'] = 'rm'; } else { $t_file['action'] = 'mod'; } } } else { $t_file['action'] = 'mod'; } $t_commit['files'][] = $t_file; } $t_changeset = new SourceChangeset($p_repo->id, $t_commit['revision'], $p_branch, $t_commit['date'], $t_commit['author'], $t_commit['message'], 0, isset($t_commit['parent']) ? $t_commit['parent'] : ''); $t_changeset->author_email = $t_commit['author_email']; $t_changeset->committer = $t_commit['committer']; $t_changeset->committer_email = $t_commit['committer_email']; foreach ($t_commit['files'] as $t_file) { $t_changeset->files[] = new SourceFile(0, $t_file['revision'], $t_file['filename'], $t_file['action']); } $t_changeset->save(); echo "saved.\n"; return array($t_changeset, $t_parents); } else { echo "already exists.\n"; return array(null, array()); } }
private function json_commit_changeset($p_repo, $p_json, $p_branch = '') { echo "processing {$p_json->id} ... "; if (!SourceChangeset::exists($p_repo->id, $p_json->sha)) { $t_parents = array(); foreach ($p_json->parents as $t_parent) { $t_parents[] = $t_parent->sha; } $t_changeset = new SourceChangeset($p_repo->id, $p_json->sha, $p_branch, $p_json->commit->author->date, $p_json->commit->author->name, $p_json->commit->message); if (count($p_json->parents) > 0) { $t_parent = $p_json->parents[0]; $t_changeset->parent = $t_parent->sha; } $t_changeset->author_email = $p_json->commit->author->email; $t_changeset->committer = $p_json->commit->committer->name; $t_changeset->committer_email = $p_json->commit->committer->email; if (isset($p_json->files)) { foreach ($p_json->files as $t_file) { switch ($t_file->status) { case 'added': $t_changeset->files[] = new SourceFile(0, '', $t_file->filename, 'add'); break; case 'modified': $t_changeset->files[] = new SourceFile(0, '', $t_file->filename, 'mod'); break; case 'removed': $t_changeset->files[] = new SourceFile(0, '', $t_file->filename, 'rm'); break; } } } $t_changeset->save(); echo "saved.\n"; return array($t_changeset, $t_parents); } else { echo "already exists.\n"; return array(null, array()); } }
private function commit_changeset($p_repo, $p_input, $p_branch = '') { $t_parents = array(); $t_message = array(); $t_input = explode("\n", $p_input); foreach ($t_input as $t_line) { if (strpos($t_line, '#') === 0) { if (!isset($t_commit['revision']) && preg_match('@^# Node ID +([a-f0-9]+)@', $t_line, $t_matches)) { $t_commit['revision'] = $t_matches[1]; echo 'Processing ' . string_display_line($t_commit[revision]) . '... '; if (SourceChangeset::exists($p_repo->id, $t_commit['revision'])) { echo "already exists.\n"; return array(null, array()); } } else { if (!isset($t_commit['author']) && preg_match('@^# User ([^<>]*)(?(?=(?=<))<([^<>]*)>|.*)@', $t_line, $t_matches)) { $t_commit['author'] = trim($t_matches[1]); $t_commit['author_email'] = $t_matches[2]; } else { if (!isset($t_commit['date']) && preg_match('@^# Date +(\\d+) (-?\\d+)@', $t_line, $t_matches)) { $t_timestamp_gmt = $t_matches[1] - (int) $t_matches[2]; $t_commit['date'] = gmdate('Y-m-d H:i:s', $t_timestamp_gmt); } else { if (!isset($t_commit['parent']) && preg_match('@^# Parent +([a-f0-9]+)@', $t_line, $t_matches)) { $t_parents[] = $t_matches[1]; $t_commit['parent'] = $t_matches[1]; } } } } } else { if (isset($t_commit['revision'])) { if (preg_match('@^diff @', $t_line, $t_matches)) { break; } $t_message[] = $t_line; } } } if (!SourceChangeset::exists($p_repo->id, $t_commit['revision'])) { $t_commit['message'] = implode("\n", $t_message); $t_changeset = new SourceChangeset($p_repo->id, $t_commit['revision'], $p_branch, $t_commit['date'], $t_commit['author'], $t_commit['message'], 0, isset($t_commit['parent']) ? $t_commit['parent'] : ''); $t_changeset->author_email = empty($t_commit['author_email']) ? '' : $t_commit['author_email']; preg_match_all('#diff[\\s]*-r[\\s]([^\\s]*)[\\s]*-r[\\s]([^\\s]*)[\\s]([^\\n]*)\\n(Binary file[\\s]([^\\s]*)[\\s]has changed|\\-{3}[\\s](/dev/null)?[^\\t]*[^\\n]*\\n\\+{3}[\\s](/dev/null)?[^\\t]*\\t[^\\n]*)#', $p_input, $t_matches, PREG_SET_ORDER); $t_commit['files'] = array(); foreach ($t_matches as $t_file_matches) { $t_file = array(); $t_file['filename'] = $t_file_matches[3]; $t_file['revision'] = $t_commit['revision']; if (!empty($t_file_matches[3])) { if (!empty($t_file_matches[5])) { $t_file['action'] = 'bin'; } else { if ("/dev/null" == $t_file_matches[7]) { $t_file['action'] = 'rm'; } else { if ("/dev/null" == $t_file_matches[6]) { $t_file['action'] = 'add'; } else { if ("/dev/null" == $t_file_matches[7] && "/dev/null" == $t_file_matches[6]) { $t_file['action'] = 'n/a'; } else { if (empty($t_file_matches[5]) && empty($t_file_matches[6]) && empty($t_file_matches[7])) { $t_file['action'] = 'mod'; } } } } } } $t_commit['files'][] = $t_file; } foreach ($t_commit['files'] as $t_file) { $t_changeset->files[] = new SourceFile(0, $t_file['revision'], $t_file['filename'], $t_file['action']); } $t_changeset->save(); echo "saved.\n"; return array($t_changeset, $t_parents); } else { echo "already exists.\n"; return array(null, array()); } }
public function commit($p_repo, $p_data) { if (preg_match('/(\\d+)/', $p_data, $p_matches)) { $svn = $this->svn_call($p_repo); $t_url = $p_repo->url; $t_revision = $p_matches[1]; $t_svnlog = explode("\n", shell_exec("{$svn} log -v {$t_url} -r{$t_revision}")); if (SourceChangeset::exists($p_repo->id, $t_revision)) { echo "Revision {$t_revision} already committed!\n"; return null; } return $this->process_svn_log($p_repo, $t_svnlog); } }
private function json_commit_changeset($p_repo, $p_json, $p_branch = '') { echo "processing {$p_json->id} ... "; if (!SourceChangeset::exists($p_repo->id, $p_json->id)) { $t_parents = array(); foreach ($p_json->parent_ids as $t_parent) { $t_parents[] = $t_parent; } $t_changeset = new SourceChangeset($p_repo->id, $p_json->id, $p_branch, date('Y-m-d H:i:s', strtotime($p_json->authored_date)), $p_json->author_name, $p_json->message); if (count($p_json->parents) > 0) { $t_parent = $p_json->parents[0]; $t_changeset->parent = $t_parent->id; } $t_changeset->author_email = $p_json->author_email; $t_changeset->save(); echo "saved.\n"; return array($t_changeset, $t_parents); } else { echo "already exists.\n"; return array(null, array()); } }