Apparently we've got Unknown Object (Phabricator User) in translation project now. Not sure how it became invalid, but automated scripts better be robust for this.
291 lines
8.1 KiB
PHP
Executable File
291 lines
8.1 KiB
PHP
Executable File
#!/usr/local/bin/php
|
|
<?php
|
|
|
|
$root = dirname(dirname(dirname(__FILE__)));
|
|
require_once $root.'/scripts/__init_script__.php';
|
|
|
|
function escape_name($name) {
|
|
return preg_replace('/[^A-Za-z0-9\-]/', '_', $name);
|
|
}
|
|
|
|
function startswith($string, $prefix) {
|
|
return substr($string, 0, strlen($prefix)) == $prefix;
|
|
}
|
|
|
|
function endswith($string, $suffix) {
|
|
$suffix_length = strlen($suffix);
|
|
return substr($string, strlen($string) - $suffix_length,
|
|
$suffix_length) == $suffix;
|
|
}
|
|
|
|
function write_ini_file($array, $file) {
|
|
$res = array();
|
|
foreach ($array as $key => $val) {
|
|
if (is_array($val)) {
|
|
$res[] = "[$key]";
|
|
foreach ($val as $skey => $sval) {
|
|
$res[] = "$skey = $sval";
|
|
}
|
|
$res[] = '';
|
|
} else {
|
|
$res[] = "$key = $val";
|
|
}
|
|
}
|
|
file_put_contents($file, implode("\n", $res));
|
|
}
|
|
|
|
// Get user's heys and put them to the configuration
|
|
function handleSingleUserPHID(
|
|
$keydir, $viewer, $userPHID, $system_keys, &$used_keys) {
|
|
$user = id(new PhabricatorPeopleQuery())
|
|
->setViewer($viewer)
|
|
->withPHIDs(array($userPHID))
|
|
->executeOne();
|
|
if (!$user) {
|
|
return;
|
|
}
|
|
|
|
$keys = id(new PhabricatorUserSSHKey())->loadAllWhere(
|
|
'userPHID = %s',
|
|
$user->getPHID());
|
|
|
|
$members = array();
|
|
foreach ($keys as $key) {
|
|
$full_key_content =
|
|
$key->getKeyType().' '.
|
|
$key->getKeyBody().' '.
|
|
$key->getKeyComment()."\n";
|
|
|
|
if (array_key_exists($full_key_content, $system_keys)) {
|
|
$members[] = $system_keys[$full_key_content];
|
|
} else {
|
|
$escaped_key_name = escape_name($key->getName());
|
|
$member = 'PHAB_'.$user->getUserName().
|
|
'_'.$escaped_key_name.
|
|
'_'.$key->getID();
|
|
$members[] = $member;
|
|
if (!array_key_exists($member, $used_keys)) {
|
|
$used_keys[$member] = true;
|
|
file_put_contents("$keydir/$member.pub", $full_key_content);
|
|
}
|
|
}
|
|
}
|
|
return $members;
|
|
}
|
|
|
|
// Parse repository and put it's members to the config file
|
|
function handleSingleRepository(
|
|
$keydir, $viewer, $repository, $all_repositories, $system_keys,
|
|
&$new_configuration, &$used_keys) {
|
|
$policies = PhabricatorPolicyQuery::loadPolicies(
|
|
$viewer,
|
|
$repository);
|
|
|
|
$pushable = $policies[DiffusionCapabilityPush::CAPABILITY];
|
|
$type = phid_get_type($pushable->getPHID());
|
|
|
|
$members = array();
|
|
|
|
if ($type == PhabricatorProjectPHIDTypeProject::TYPECONST) {
|
|
$project = id(new PhabricatorProjectQuery())
|
|
->setViewer($viewer)
|
|
->needMembers(true)
|
|
->withPHIDs(array($pushable->getPHID()))
|
|
->executeOne();
|
|
|
|
$memberPHIDs = $project->getMemberPHIDs();
|
|
foreach ($memberPHIDs as $memberPHID) {
|
|
$members = array_merge($members,
|
|
handleSingleUserPHID($keydir, $viewer, $memberPHID,
|
|
$system_keys, $used_keys));
|
|
}
|
|
} else if ($type == PhabricatorPeoplePHIDTypeUser::TYPECONST) {
|
|
$members = handleSingleUserPHID(
|
|
$keydir, $viewer, $pushable->getPHID(), $system_keys, $used_keys);
|
|
} else if ($type == PhabricatorPolicyPHIDTypePolicy::TYPECONST) {
|
|
/* pass */
|
|
} else {
|
|
/* pass */
|
|
}
|
|
|
|
if (count($members)) {
|
|
$uri = $repository->getRemoteURI();
|
|
$repository_name = basename($uri, '.git');
|
|
$escaped_repository_name = escape_name($repository->getName());
|
|
$group_name = "PHAB_${escaped_repository_name}";
|
|
$values = array();
|
|
$values['members'] = join(' ', $members);
|
|
$values['readonly'] = join(' ', $all_repositories);
|
|
$values['writable'] = $repository_name;
|
|
$new_configuration["group $group_name"] = $values;
|
|
}
|
|
}
|
|
|
|
// Remove groups from previous automated configuration built
|
|
function getCleanOldConfiguration($old_configuration) {
|
|
$new_configuration = array();
|
|
foreach ($old_configuration as $group => $values) {
|
|
if (!startswith($group, 'group PHAB')) {
|
|
$new_configuration[$group] = $values;
|
|
}
|
|
}
|
|
return $new_configuration;
|
|
}
|
|
|
|
// Get non-phab keys
|
|
function getSystemPublicKeys($keydir) {
|
|
$files = scandir($keydir);
|
|
$system_keys = array();
|
|
foreach ($files as $file) {
|
|
if (!startswith($file, "PHAB") && endswith($file, '.pub')) {
|
|
$key = file_get_contents("$keydir/$file");
|
|
$system_keys[$key] = basename($file, '.pub');
|
|
}
|
|
}
|
|
return $system_keys;
|
|
}
|
|
|
|
// Remove unused public keys
|
|
function removeUnusedPublicKeys($keydir, $used_keys) {
|
|
$files = scandir($keydir);
|
|
foreach ($files as $file) {
|
|
if (startswith($file, "PHAB")) {
|
|
$member = basename($file, '.pub');
|
|
if (!array_key_exists($member, $used_keys)) {
|
|
unlink("$keydir/$file");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function rebuildConfiguration($gitosis_root) {
|
|
$keydir = "$gitosis_root/keydir";
|
|
$configuration_file = "$gitosis_root/gitosis.conf";
|
|
|
|
if (!file_exists($configuration_file)) {
|
|
print("Not found: $configuration_file\n");
|
|
return false;
|
|
}
|
|
|
|
$viewer = id(new PhabricatorUser())
|
|
->loadOneWhere('username = %s', 'sergey');
|
|
|
|
$old_configuration = parse_ini_file(
|
|
$configuration_file, true, INI_SCANNER_RAW);
|
|
|
|
$new_configuration = getCleanOldConfiguration(
|
|
$old_configuration);
|
|
|
|
// Get "system" keys to re-use if phab account uses the
|
|
// same public key
|
|
$system_keys = getSystemPublicKeys($keydir);
|
|
|
|
// Get list of all repos which is awailable for read
|
|
$all_repositories = array();
|
|
foreach ($old_configuration as $group => $values) {
|
|
if (startswith($group, 'repo')) {
|
|
$repository_name = substr($group, 5, strlen($group) - 5);
|
|
if ($repository_name == 'gitosis-admin')
|
|
continue;
|
|
$all_repositories[] = $repository_name;
|
|
}
|
|
}
|
|
|
|
// Fill in new configuration and keys
|
|
$used_keys = array();
|
|
$repositories = id(new PhabricatorRepositoryQuery())
|
|
->setViewer($viewer)
|
|
->execute();
|
|
|
|
foreach ($repositories as $repository_id => $repository) {
|
|
$type = $repository->getVersionControlSystem();
|
|
if ($type == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) {
|
|
handleSingleRepository(
|
|
$keydir, $viewer, $repository, $all_repositories, $system_keys,
|
|
$new_configuration, $used_keys);
|
|
}
|
|
}
|
|
|
|
write_ini_file($new_configuration, $configuration_file);
|
|
removeUnusedPublicKeys($keydir, $used_keys);
|
|
|
|
return true;
|
|
}
|
|
|
|
function getGitCommand($repository) {
|
|
$git_dir = realpath("$repository/.git");
|
|
$git = "git --git-dir='$git_dir'";
|
|
$git .= ' --work-tree='.realpath($repository);
|
|
return $git;
|
|
}
|
|
|
|
function runGitCommand($repository, $arguments,
|
|
&$output=null, &$return_var=null) {
|
|
$git = getGitCommand($repository);
|
|
$git .= " $arguments";
|
|
exec($git, $output, $return_var);
|
|
return $return_var == 0;
|
|
}
|
|
|
|
function runGitSshCommand($repository, $key, $arguments,
|
|
&$output=null, &$return_var=null) {
|
|
$gitx_ssh = realpath(dirname(__FILE__) . "/gitx-ssh");
|
|
$abs_key = realpath($key);
|
|
$git = "SSH_KEYFILE=$abs_key GIT_SSH=$gitx_ssh ";
|
|
$git .= getGitCommand($repository);
|
|
$git .= " $arguments";
|
|
exec($git, $output, $return_var);
|
|
return $return_var == 0;
|
|
}
|
|
|
|
function repositoryPull($repository, $key) {
|
|
return runGitSshCommand($repository, $key, 'pull');
|
|
}
|
|
|
|
function repositoryCommitAll($repository, $author, $message) {
|
|
if (!runGitCommand(
|
|
$repository, 'ls-files --other --exclude-standard', $untracked_files)) {
|
|
return false;
|
|
}
|
|
if (count($untracked_files)) {
|
|
$flat_files = join(' ', $untracked_files);
|
|
if (!runGitCommand($repository, "add $flat_files")) {
|
|
return false;
|
|
}
|
|
}
|
|
runGitCommand($repository, "update-index -q --refresh", $output);
|
|
runGitCommand($repository, "diff-index --name-only HEAD --", $output);
|
|
if (count($output)) {
|
|
return runGitCommand(
|
|
$repository, "commit --author='$author' -a -m '$message'", $output);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (count($argv) != 3) {
|
|
print("Usage: {$argv[0]} /path/to/gitosis-admin /path/to/id_rsa.pub\n");
|
|
exit(1);
|
|
}
|
|
|
|
$gitosis_root = $argv[1];
|
|
$key = $argv[2];
|
|
|
|
if (!repositoryPull($gitosis_root, $key)) {
|
|
print("Failed to pull changes from server.\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (!rebuildConfiguration($gitosis_root)) {
|
|
exit(1);
|
|
}
|
|
|
|
if (!repositoryCommitAll(
|
|
$gitosis_root, 'Rebuild Gitadmin <null@git.blender.org>',
|
|
'Update to correspond changes in Phabricator')) {
|
|
print("Failed to commit changes.\n");
|
|
exit(1);
|
|
}
|
|
|
|
runGitSshCommand($gitosis_root, $key, 'push origin master');
|
|
?>
|