246 lines
6.8 KiB
PHP
Executable File
246 lines
6.8 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 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, &$used_keys) {
|
|
$user = id(new PhabricatorPeopleQuery())
|
|
->setViewer($viewer)
|
|
->withPHIDs(array($userPHID))
|
|
->executeOne();
|
|
|
|
$keys = id(new PhabricatorUserSSHKey())->loadAllWhere(
|
|
'userPHID = %s',
|
|
$user->getPHID());
|
|
|
|
$members = array();
|
|
foreach ($keys as $key) {
|
|
$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;
|
|
$full_key_content =
|
|
$key->getKeyType().' '.
|
|
$key->getKeyBody().' '.
|
|
$key->getKeyComment()."\n";
|
|
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, &$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, $used_keys));
|
|
}
|
|
} else if ($type == PhabricatorPeoplePHIDTypeUser::TYPECONST) {
|
|
$members = handleSingleUserPHID(
|
|
$keydir, $viewer, $pushable->getPHID(), $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'] = '@all';
|
|
$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;
|
|
}
|
|
|
|
// 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);
|
|
|
|
// 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, $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');
|
|
?>
|