@@ -113,36 +113,71 @@ public class WelcomeShell implements Factory<Command> { | |||
String getMessage() { | |||
SshDaemonClient client = session.getAttribute(SshDaemonClient.KEY); | |||
UserModel user = client.getUser(); | |||
String hostname = getHostname(); | |||
int port = settings.getInteger(Keys.git.sshPort, 0); | |||
final String b1 = StringUtils.rightPad("", 72, '═'); | |||
final String b2 = StringUtils.rightPad("", 72, '─'); | |||
final String nl = "\r\n"; | |||
StringBuilder msg = new StringBuilder(); | |||
msg.append("\r\n"); | |||
msg.append("Hi "); | |||
msg.append(nl); | |||
msg.append(b1); | |||
msg.append(nl); | |||
msg.append(" "); | |||
msg.append(com.gitblit.Constants.getGitBlitVersion()); | |||
msg.append(nl); | |||
msg.append(b1); | |||
msg.append(nl); | |||
msg.append(nl); | |||
msg.append(" Hi "); | |||
msg.append(user.getDisplayName()); | |||
msg.append(", you have successfully connected to Gitblit over SSH"); | |||
msg.append("\r\n"); | |||
msg.append("with client: "); | |||
msg.append(", you have successfully connected over SSH."); | |||
msg.append(nl); | |||
msg.append(nl); | |||
msg.append(" client: "); | |||
msg.append(session.getClientVersion()); | |||
msg.append("\r\n"); | |||
msg.append("\r\n"); | |||
msg.append(nl); | |||
msg.append(nl); | |||
msg.append("You may clone a repository with the following Git syntax:\r\n"); | |||
msg.append("\r\n"); | |||
msg.append(b2); | |||
msg.append(nl); | |||
msg.append(nl); | |||
msg.append(" You may clone a repository with the following Git syntax:"); | |||
msg.append(nl); | |||
msg.append(nl); | |||
msg.append(" git clone "); | |||
msg.append(formatUrl(user.username)); | |||
msg.append("\r\n"); | |||
msg.append("\r\n"); | |||
msg.append(formatUrl(hostname, port, user.username)); | |||
msg.append(nl); | |||
msg.append(nl); | |||
msg.append(b2); | |||
msg.append(nl); | |||
msg.append(nl); | |||
msg.append(" You may upload an SSH public key with the following syntax:"); | |||
msg.append(nl); | |||
msg.append(nl); | |||
msg.append(String.format(" cat ~/.ssh/id_rsa.pub | ssh -l %s -p %d %s gitblit keys add -", user.username, port, hostname)); | |||
msg.append(nl); | |||
msg.append(nl); | |||
msg.append(b2); | |||
msg.append(nl); | |||
msg.append(nl); | |||
// display the core commands | |||
SshCommandFactory cmdFactory = (SshCommandFactory) session.getFactoryManager().getCommandFactory(); | |||
DispatchCommand root = cmdFactory.createRootDispatcher(client, ""); | |||
String usage = root.usage().replace("\n", "\r\n"); | |||
String usage = root.usage().replace("\n", nl); | |||
msg.append(usage); | |||
return msg.toString(); | |||
} | |||
private String formatUrl(String username) { | |||
private String getHostname() { | |||
String host = null; | |||
String url = settings.getString(Keys.web.canonicalUrl, "https://localhost:8443"); | |||
if (url != null) { | |||
@@ -154,15 +189,17 @@ public class WelcomeShell implements Factory<Command> { | |||
if (StringUtils.isEmpty(host)) { | |||
host = SystemReader.getInstance().getHostname(); | |||
} | |||
return host; | |||
} | |||
int port = settings.getInteger(Keys.git.sshPort, 0); | |||
private String formatUrl(String hostname, int port, String username) { | |||
if (port == 22) { | |||
// standard port | |||
return MessageFormat.format("{0}@{1}/REPOSITORY.git", username, host); | |||
return MessageFormat.format("{0}@{1}/REPOSITORY.git", username, hostname); | |||
} else { | |||
// non-standard port | |||
return MessageFormat.format("ssh://{0}@{1}:{2,number,0}/REPOSITORY.git", | |||
username, host, port); | |||
username, hostname, port); | |||
} | |||
} | |||
} |
@@ -37,7 +37,9 @@ import org.kohsuke.args4j.Option; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import com.gitblit.Keys; | |||
import com.gitblit.utils.IdGenerator; | |||
import com.gitblit.utils.StringUtils; | |||
import com.gitblit.utils.WorkQueue; | |||
import com.gitblit.utils.WorkQueue.CancelableRunnable; | |||
import com.gitblit.utils.cli.CmdLineParser; | |||
@@ -200,9 +202,39 @@ public abstract class BaseCommand implements Command, SessionAware { | |||
} | |||
if (clp.wasHelpRequestedByOption()) { | |||
CommandMetaData meta = getClass().getAnnotation(CommandMetaData.class); | |||
String title = meta.name().toUpperCase() + ": " + meta.description(); | |||
String b = com.gitblit.utils.StringUtils.leftPad("", title.length() + 2, '═'); | |||
StringWriter msg = new StringWriter(); | |||
clp.printDetailedUsage(commandName, msg); | |||
msg.write(usage()); | |||
msg.write('\n'); | |||
msg.write(b); | |||
msg.write('\n'); | |||
msg.write(' '); | |||
msg.write(title); | |||
msg.write('\n'); | |||
msg.write(b); | |||
msg.write("\n\n"); | |||
msg.write("USAGE\n"); | |||
msg.write("─────\n"); | |||
msg.write(' '); | |||
msg.write(commandName); | |||
msg.write('\n'); | |||
msg.write(' '); | |||
clp.printSingleLineUsage(msg, null); | |||
msg.write("\n\n"); | |||
msg.write("ARGUMENTS & OPTIONS\n"); | |||
msg.write("───────────────────\n"); | |||
clp.printUsage(msg, null); | |||
msg.write('\n'); | |||
String examples = usage().trim(); | |||
if (!StringUtils.isEmpty(examples)) { | |||
msg.write('\n'); | |||
msg.write("EXAMPLES\n"); | |||
msg.write("────────\n"); | |||
msg.write(examples); | |||
msg.write('\n'); | |||
} | |||
throw new UnloggedFailure(1, msg.toString()); | |||
} | |||
} | |||
@@ -213,9 +245,33 @@ public abstract class BaseCommand implements Command, SessionAware { | |||
} | |||
public String usage() { | |||
Class<? extends BaseCommand> clazz = getClass(); | |||
if (clazz.isAnnotationPresent(UsageExamples.class)) { | |||
return examples(clazz.getAnnotation(UsageExamples.class).examples()); | |||
} else if (clazz.isAnnotationPresent(UsageExample.class)) { | |||
return examples(clazz.getAnnotation(UsageExample.class)); | |||
} | |||
return ""; | |||
} | |||
protected String examples(UsageExample... examples) { | |||
int sshPort = getContext().getGitblit().getSettings().getInteger(Keys.git.sshPort, 29418); | |||
String username = getContext().getClient().getUsername(); | |||
String hostname = "localhost"; | |||
String ssh = String.format("ssh -l %s -p %d %s", username, sshPort, hostname); | |||
StringBuilder sb = new StringBuilder(); | |||
for (UsageExample example : examples) { | |||
sb.append(example.description()).append("\n\n"); | |||
String syntax = example.syntax(); | |||
syntax = syntax.replace("${ssh}", ssh); | |||
syntax = syntax.replace("${username}", username); | |||
syntax = syntax.replace("${cmd}", commandName); | |||
sb.append(" ").append(syntax).append("\n\n"); | |||
} | |||
return sb.toString(); | |||
} | |||
protected void showHelp() throws UnloggedFailure { | |||
argv = new String [] { "--help" }; | |||
parseCommandLine(); |
@@ -332,9 +332,9 @@ public abstract class DispatchCommand extends BaseCommand implements ExtensionPo | |||
continue; | |||
} | |||
String displayName = name; | |||
String displayName = name + (meta.admin() ? "*" : ""); | |||
if (commandToAliases.containsKey(meta.name())) { | |||
displayName = name + " (" + Joiner.on(',').join(commandToAliases.get(meta.name())) + ")"; | |||
displayName = name + (meta.admin() ? "*" : "")+ " (" + Joiner.on(',').join(commandToAliases.get(meta.name())) + ")"; | |||
} | |||
displayNames.put(name, displayName); | |||
@@ -18,8 +18,12 @@ import java.io.IOException; | |||
import java.io.PrintWriter; | |||
import org.apache.sshd.server.Environment; | |||
import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
public abstract class SshCommand extends BaseCommand { | |||
protected Logger log = LoggerFactory.getLogger(getClass()); | |||
protected PrintWriter stdout; | |||
protected PrintWriter stderr; | |||
@@ -0,0 +1,32 @@ | |||
/* | |||
* Copyright 2014 gitblit.com. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package com.gitblit.transport.ssh.commands; | |||
import static java.lang.annotation.RetentionPolicy.RUNTIME; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.Target; | |||
/** | |||
* Annotation tagged on a concrete Command to describe how to use it. | |||
*/ | |||
@Target({ElementType.TYPE}) | |||
@Retention(RUNTIME) | |||
public @interface UsageExample { | |||
String syntax(); | |||
String description() default ""; | |||
} |
@@ -0,0 +1,31 @@ | |||
/* | |||
* Copyright 2014 gitblit.com. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package com.gitblit.transport.ssh.commands; | |||
import static java.lang.annotation.RetentionPolicy.RUNTIME; | |||
import java.lang.annotation.ElementType; | |||
import java.lang.annotation.Retention; | |||
import java.lang.annotation.Target; | |||
/** | |||
* Annotation tagged on a concrete Command to describe how to use it. | |||
*/ | |||
@Target({ElementType.TYPE}) | |||
@Retention(RUNTIME) | |||
public @interface UsageExamples { | |||
UsageExample [] examples() default {}; | |||
} |
@@ -25,8 +25,10 @@ import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import com.gitblit.transport.ssh.commands.CommandMetaData; | |||
import com.gitblit.transport.ssh.commands.UsageExample; | |||
@CommandMetaData(name = "gc", description = "Cleanup unnecessary files and optimize the local repository", admin = true) | |||
@UsageExample(syntax = "${cmd} test/myrepository.git", description = "Garbage collect \"test/myrepository.git\"") | |||
public class GarbageCollectionCommand extends BaseGitCommand { | |||
private static final Logger log = LoggerFactory.getLogger(GarbageCollectionCommand.class); |
@@ -36,7 +36,7 @@ abstract class BaseKeyCommand extends SshCommand { | |||
protected List<String> readKeys(List<String> sshKeys) | |||
throws UnsupportedEncodingException, IOException { | |||
int idx = -1; | |||
if (sshKeys.isEmpty() || ((idx = sshKeys.indexOf("-")) >= 0)) { | |||
if ((idx = sshKeys.indexOf("-")) >= 0) { | |||
String sshKey = ""; | |||
BufferedReader br = new BufferedReader(new InputStreamReader( | |||
in, Charsets.UTF_8)); |
@@ -14,9 +14,17 @@ import com.gitblit.models.ServerSettings; | |||
import com.gitblit.models.SettingModel; | |||
import com.gitblit.transport.ssh.commands.CommandMetaData; | |||
import com.gitblit.transport.ssh.commands.SshCommand; | |||
import com.gitblit.transport.ssh.commands.UsageExample; | |||
import com.gitblit.transport.ssh.commands.UsageExamples; | |||
import com.google.common.collect.Maps; | |||
@CommandMetaData(name = "config", description = "Administer Gitblit settings", admin = true) | |||
@UsageExamples(examples = { | |||
@UsageExample(syntax = "${cmd} --list", description = "List all settings"), | |||
@UsageExample(syntax = "${cmd} git.sshPort", description = "Describe the git.sshPort setting"), | |||
@UsageExample(syntax = "${cmd} git.sshPort 29418", description = "Set git.sshPort to 29418"), | |||
@UsageExample(syntax = "${cmd} git.sshPort --reset", description = "Reset git.sshPort to it's default value"), | |||
}) | |||
public class ConfigCommand extends SshCommand { | |||
@Argument(index = 0, metaVar = "KEY", usage = "The setting to describe or update") |
@@ -1,37 +0,0 @@ | |||
/* | |||
* Copyright 2014 gitblit.com. | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
package com.gitblit.transport.ssh.gitblit; | |||
import org.kohsuke.args4j.Option; | |||
import com.gitblit.transport.ssh.commands.CommandMetaData; | |||
import com.gitblit.transport.ssh.commands.SshCommand; | |||
@CommandMetaData(name = "create-repository", description = "Create new GIT repository", admin = true, hidden = true) | |||
public class CreateRepository extends SshCommand { | |||
@Option(name = "--name", aliases = {"-n"}, required = true, metaVar = "NAME", usage = "name of repository to be created") | |||
private String name; | |||
@Option(name = "--description", aliases = {"-d"}, metaVar = "DESCRIPTION", usage = "description of repository") | |||
private String repositoryDescription; | |||
@Override | |||
public void run() { | |||
stdout.println(String.format("Repository <%s> was created", name)); | |||
} | |||
} |
@@ -26,8 +26,6 @@ public class GitblitDispatcher extends DispatchCommand { | |||
protected void setup(UserModel user) { | |||
// commands in this dispatcher | |||
register(user, VersionCommand.class); | |||
register(user, CreateRepository.class); | |||
register(user, SetAccountCommand.class); | |||
register(user, ConfigCommand.class); | |||
// nested dispatchers |
@@ -30,6 +30,7 @@ import com.gitblit.transport.ssh.SshKey; | |||
import com.gitblit.transport.ssh.commands.CommandMetaData; | |||
import com.gitblit.transport.ssh.commands.DispatchCommand; | |||
import com.gitblit.transport.ssh.commands.SshCommand; | |||
import com.gitblit.transport.ssh.commands.UsageExample; | |||
import com.gitblit.utils.FlipTable; | |||
import com.gitblit.utils.FlipTable.Borders; | |||
@@ -50,11 +51,12 @@ public class KeysDispatcher extends DispatchCommand { | |||
} | |||
@CommandMetaData(name = "add", description = "Add an SSH public key to your account") | |||
@UsageExample(syntax = "cat ~/.ssh/id_rsa.pub | ${ssh} ${cmd} -", description = "Upload your SSH public key and add it to your account") | |||
public static class AddKey extends BaseKeyCommand { | |||
protected final Logger log = LoggerFactory.getLogger(getClass()); | |||
@Argument(metaVar = "<stdin>|KEY", usage = "the key to add") | |||
@Argument(metaVar = "-|<KEY>", usage = "the key(s) to add", required = true) | |||
private List<String> addKeys = new ArrayList<String>(); | |||
@Override | |||
@@ -70,6 +72,7 @@ public class KeysDispatcher extends DispatchCommand { | |||
} | |||
@CommandMetaData(name = "remove", aliases = { "rm" }, description = "Remove an SSH public key from your account") | |||
@UsageExample(syntax = "${cmd} 2", description = "Remove the SSH key identified as #2 in `keys list`") | |||
public static class RemoveKey extends BaseKeyCommand { | |||
protected final Logger log = LoggerFactory.getLogger(getClass()); | |||
@@ -131,7 +134,7 @@ public class KeysDispatcher extends DispatchCommand { | |||
} | |||
} | |||
@CommandMetaData(name = "list", aliases = { "ls" }, description = "List your registered public keys") | |||
@CommandMetaData(name = "list", aliases = { "ls" }, description = "List your registered SSH public keys") | |||
public static class ListKeys extends SshCommand { | |||
@Option(name = "-L", usage = "list complete public key parameters") |
@@ -23,6 +23,7 @@ import com.gitblit.models.UserModel; | |||
import com.gitblit.transport.ssh.commands.CommandMetaData; | |||
import com.gitblit.transport.ssh.commands.DispatchCommand; | |||
import com.gitblit.transport.ssh.commands.ListFilterCommand; | |||
import com.gitblit.transport.ssh.commands.UsageExample; | |||
import com.gitblit.utils.ArrayUtils; | |||
import com.gitblit.utils.FlipTable; | |||
import com.gitblit.utils.FlipTable.Borders; | |||
@@ -38,6 +39,7 @@ public class RepositoriesDispatcher extends DispatchCommand { | |||
/* List repositories */ | |||
@CommandMetaData(name = "list", aliases = { "ls" }, description = "List repositories") | |||
@UsageExample(syntax = "${cmd} mirror/.* -v", description = "Verbose list of all repositories in the 'mirror' directory") | |||
public static class ListRepositories extends ListFilterCommand<RepositoryModel> { | |||
@Override | |||
@@ -72,7 +74,7 @@ public class RepositoriesDispatcher extends DispatchCommand { | |||
String size = r.size; | |||
if (!r.hasCommits) { | |||
lm = ""; | |||
size = "(empty)"; | |||
size = FlipTable.EMPTY; | |||
} | |||
if (verbose) { | |||
String owners = ""; |
@@ -1,88 +0,0 @@ | |||
//Copyright (C) 2012 The Android Open Source Project | |||
// | |||
//Licensed under the Apache License, Version 2.0 (the "License"); | |||
//you may not use this file except in compliance with the License. | |||
//You may obtain a copy of the License at | |||
// | |||
//http://www.apache.org/licenses/LICENSE-2.0 | |||
// | |||
//Unless required by applicable law or agreed to in writing, software | |||
//distributed under the License is distributed on an "AS IS" BASIS, | |||
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
//See the License for the specific language governing permissions and | |||
//limitations under the License. | |||
package com.gitblit.transport.ssh.gitblit; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.kohsuke.args4j.Argument; | |||
import org.kohsuke.args4j.Option; | |||
import com.gitblit.transport.ssh.SshKey; | |||
import com.gitblit.transport.ssh.commands.CommandMetaData; | |||
/** Set a user's account settings. **/ | |||
@CommandMetaData(name = "set-account", description = "Change an account's settings", admin = true) | |||
public class SetAccountCommand extends BaseKeyCommand { | |||
private static final String ALL = "ALL"; | |||
@Argument(index = 0, required = true, metaVar = "USER", usage = "full name, email-address, ssh username or account id") | |||
private String user; | |||
@Option(name = "--add-ssh-key", metaVar = "-|KEY", usage = "public keys to add to the account") | |||
private List<String> addSshKeys = new ArrayList<String>(); | |||
@Option(name = "--delete-ssh-key", metaVar = "-|KEY", usage = "public keys to delete from the account") | |||
private List<String> deleteSshKeys = new ArrayList<String>(); | |||
@Override | |||
public void run() throws IOException, UnloggedFailure { | |||
validate(); | |||
setAccount(); | |||
} | |||
private void validate() throws UnloggedFailure { | |||
if (addSshKeys.contains("-") && deleteSshKeys.contains("-")) { | |||
throw new UnloggedFailure(1, "Only one option may use the stdin"); | |||
} | |||
if (deleteSshKeys.contains(ALL)) { | |||
deleteSshKeys = Collections.singletonList(ALL); | |||
} | |||
} | |||
private void setAccount() throws IOException, UnloggedFailure { | |||
addSshKeys = readKeys(addSshKeys); | |||
if (!addSshKeys.isEmpty()) { | |||
addSshKeys(addSshKeys); | |||
} | |||
deleteSshKeys = readKeys(deleteSshKeys); | |||
if (!deleteSshKeys.isEmpty()) { | |||
deleteSshKeys(deleteSshKeys); | |||
} | |||
} | |||
private void addSshKeys(List<String> keys) throws UnloggedFailure, | |||
IOException { | |||
for (String key : keys) { | |||
SshKey sshKey = new SshKey(key); | |||
getKeyManager().addKey(user, sshKey); | |||
} | |||
} | |||
private void deleteSshKeys(List<String> keys) { | |||
if (keys.contains(ALL)) { | |||
getKeyManager().removeAllKeys(user); | |||
} else { | |||
for (String key : keys) { | |||
SshKey sshKey = new SshKey(key); | |||
getKeyManager().removeKey(user, sshKey); | |||
} | |||
} | |||
} | |||
} |
@@ -15,75 +15,308 @@ | |||
*/ | |||
package com.gitblit.transport.ssh.gitblit; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.kohsuke.args4j.Argument; | |||
import org.kohsuke.args4j.Option; | |||
import com.gitblit.Constants.AccessPermission; | |||
import com.gitblit.manager.IGitblit; | |||
import com.gitblit.models.RegistrantAccessPermission; | |||
import com.gitblit.models.RepositoryModel; | |||
import com.gitblit.models.TeamModel; | |||
import com.gitblit.models.UserModel; | |||
import com.gitblit.transport.ssh.commands.CommandMetaData; | |||
import com.gitblit.transport.ssh.commands.DispatchCommand; | |||
import com.gitblit.transport.ssh.commands.ListFilterCommand; | |||
import com.gitblit.transport.ssh.commands.SshCommand; | |||
import com.gitblit.transport.ssh.commands.UsageExample; | |||
import com.gitblit.transport.ssh.commands.UsageExamples; | |||
import com.gitblit.utils.ArrayUtils; | |||
import com.gitblit.utils.FlipTable; | |||
import com.gitblit.utils.FlipTable.Borders; | |||
import com.gitblit.utils.StringUtils; | |||
import com.google.common.base.Joiner; | |||
@CommandMetaData(name = "users", description = "User management commands", admin = true) | |||
public class UsersDispatcher extends DispatchCommand { | |||
@Override | |||
protected void setup(UserModel user) { | |||
// primary user commands | |||
register(user, NewUser.class); | |||
register(user, RemoveUser.class); | |||
register(user, ShowUser.class); | |||
register(user, ListUsers.class); | |||
// user-specific commands | |||
register(user, SetName.class); | |||
register(user, Permissions.class); | |||
register(user, DisableUser.class); | |||
register(user, EnableUser.class); | |||
} | |||
@CommandMetaData(name = "show", description = "Show a user") | |||
public static class ShowUser extends SshCommand { | |||
public static abstract class UserCommand extends SshCommand { | |||
@Argument(index = 0, required = true, metaVar = "USERNAME", usage = "username") | |||
protected String username; | |||
protected UserModel getUser(boolean requireUser) throws UnloggedFailure { | |||
IGitblit gitblit = getContext().getGitblit(); | |||
UserModel user = gitblit.getUserModel(username); | |||
if (requireUser && user == null) { | |||
throw new UnloggedFailure(1, String.format("User %s does not exist!", username)); | |||
} | |||
return user; | |||
} | |||
} | |||
@CommandMetaData(name = "new", description = "Create a new user account") | |||
@UsageExample(syntax = "${cmd} john 12345 --email john@smith.com --canFork --canCreate") | |||
public static class NewUser extends UserCommand { | |||
@Argument(index = 1, required = true, metaVar = "PASSWORD", usage = "password") | |||
protected String password; | |||
@Option(name = "--email", metaVar = "ADDRESS", usage = "email address") | |||
protected String email; | |||
@Option(name = "--canAdmin", usage = "can administer the server") | |||
protected boolean canAdmin; | |||
@Option(name = "--canFork", usage = "can fork repositories") | |||
protected boolean canFork; | |||
@Option(name = "--canCreate", usage = "can create personal repositories") | |||
protected boolean canCreate; | |||
@Option(name = "--disabled", usage = "create a disabled user account") | |||
protected boolean disabled; | |||
@Override | |||
public void run() throws UnloggedFailure { | |||
if (getUser(false) != null) { | |||
throw new UnloggedFailure(1, String.format("User %s already exists!", username)); | |||
} | |||
UserModel user = new UserModel(username); | |||
user.password = password; | |||
if (email != null) { | |||
user.emailAddress = email; | |||
} | |||
user.canAdmin = canAdmin; | |||
user.canFork = canFork; | |||
user.canCreate = canCreate; | |||
user.disabled = disabled; | |||
IGitblit gitblit = getContext().getGitblit(); | |||
if (gitblit.updateUserModel(username, user)) { | |||
stdout.println(String.format("%s created.", username)); | |||
} else { | |||
throw new UnloggedFailure(1, String.format("Failed to create %s!", username)); | |||
} | |||
} | |||
} | |||
@CommandMetaData(name = "set-name", description = "Set the display name of an account") | |||
@UsageExample(syntax = "${cmd} john John Smith", description = "The display name to \"John Smith\" for john's account") | |||
public static class SetName extends UserCommand { | |||
@Argument(index = 1, multiValued = true, required = true, metaVar = "NAME", usage = "display name") | |||
protected List<String> displayName = new ArrayList<String>(); | |||
@Override | |||
public void run() throws UnloggedFailure { | |||
UserModel user = getUser(true); | |||
IGitblit gitblit = getContext().getGitblit(); | |||
user.displayName = Joiner.on(" ").join(displayName); | |||
if (gitblit.updateUserModel(username, user)) { | |||
stdout.println(String.format("Set the display name of %s to \"%s\".", username, user.displayName)); | |||
} else { | |||
throw new UnloggedFailure(1, String.format("Failed to set the display name of %s!", username)); | |||
} | |||
} | |||
} | |||
@CommandMetaData(name = "disable", description = "Prohibit an account from authenticating") | |||
@UsageExample(syntax = "${cmd} john", description = "Prevent John from authenticating") | |||
public static class DisableUser extends UserCommand { | |||
@Override | |||
public void run() throws UnloggedFailure { | |||
UserModel user = getUser(true); | |||
user.disabled = true; | |||
IGitblit gitblit = getContext().getGitblit(); | |||
if (gitblit.updateUserModel(username, user)) { | |||
stdout.println(String.format("%s is not allowed to authenticate.", username)); | |||
} else { | |||
throw new UnloggedFailure(1, String.format("Failed to disable %s!", username)); | |||
} | |||
} | |||
} | |||
@CommandMetaData(name = "enable", description = "Allow an account to authenticate") | |||
@UsageExample(syntax = "${cmd} john", description = "Allow John to authenticate") | |||
public static class EnableUser extends UserCommand { | |||
@Override | |||
public void run() throws UnloggedFailure { | |||
UserModel user = getUser(true); | |||
user.disabled = false; | |||
IGitblit gitblit = getContext().getGitblit(); | |||
if (gitblit.updateUserModel(username, user)) { | |||
stdout.println(String.format("%s may now authenticate.", username)); | |||
} else { | |||
throw new UnloggedFailure(1, String.format("Failed to enable %s!", username)); | |||
} | |||
} | |||
} | |||
@CommandMetaData(name = "permissions", aliases = { "perms" }, description = "Add or remove permissions from an account") | |||
@UsageExample(syntax = "${cmd} john RW:alpha/repo.git RWC:alpha/repo2.git", description = "Add or set permissions for John") | |||
public static class Permissions extends UserCommand { | |||
@Argument(index = 1, multiValued = true, metaVar = "[PERMISSION:]REPOSITORY", usage = "a repository expression") | |||
protected List<String> permissions; | |||
@Option(name = "--remove", aliases = { "-r" }, metaVar = "REPOSITORY|ALL", usage = "remove a repository permission") | |||
protected List<String> removals; | |||
@Override | |||
public void run() throws UnloggedFailure { | |||
IGitblit gitblit = getContext().getGitblit(); | |||
UserModel user = getUser(true); | |||
boolean modified = false; | |||
if (!ArrayUtils.isEmpty(removals)) { | |||
if (removals.contains("ALL")) { | |||
user.permissions.clear(); | |||
} else { | |||
for (String repo : removals) { | |||
user.removeRepositoryPermission(repo); | |||
log.info(String.format("Removing permission for %s from %s", repo, username)); | |||
} | |||
} | |||
modified = true; | |||
} | |||
if (!ArrayUtils.isEmpty(permissions)) { | |||
for (String perm : permissions) { | |||
String repo = AccessPermission.repositoryFromRole(perm); | |||
if (StringUtils.findInvalidCharacter(repo) == null) { | |||
// explicit permision, confirm repository | |||
RepositoryModel r = gitblit.getRepositoryModel(repo); | |||
if (r == null) { | |||
throw new UnloggedFailure(1, String.format("Repository %s does not exist!", repo)); | |||
} | |||
} | |||
AccessPermission ap = AccessPermission.permissionFromRole(perm); | |||
user.setRepositoryPermission(repo, ap); | |||
log.info(String.format("Setting %s:%s for %s", ap.name(), repo, username)); | |||
} | |||
modified = true; | |||
} | |||
if (modified && gitblit.updateUserModel(username, user)) { | |||
// reload & display new permissions | |||
user = gitblit.getUserModel(username); | |||
} | |||
showPermissions(user); | |||
} | |||
protected void showPermissions(UserModel user) { | |||
List<RegistrantAccessPermission> perms = user.getRepositoryPermissions(); | |||
String[] pheaders = { "Repository", "Permission", "Type", "Source", "Mutable" }; | |||
Object [][] pdata = new Object[perms.size()][]; | |||
for (int i = 0; i < perms.size(); i++) { | |||
RegistrantAccessPermission ap = perms.get(i); | |||
pdata[i] = new Object[] { ap.registrant, ap.permission, ap.permissionType, ap.source, ap.mutable ? "Y":"" }; | |||
} | |||
stdout.println(FlipTable.of(pheaders, pdata, Borders.BODY_HCOLS)); | |||
} | |||
} | |||
@CommandMetaData(name = "remove", aliases = { "rm" }, description = "Remove a user account") | |||
@UsageExample(syntax = "${cmd} john", description = "Delete john's account") | |||
public static class RemoveUser extends UserCommand { | |||
@Override | |||
public void run() throws UnloggedFailure { | |||
UserModel user = getUser(true); | |||
IGitblit gitblit = getContext().getGitblit(); | |||
UserModel u = gitblit.getUserModel(username); | |||
if (u == null) { | |||
throw new UnloggedFailure(1, String.format("Unknown user \"%s\"", username)); | |||
if (gitblit.deleteUserModel(user)) { | |||
stdout.println(String.format("%s has been deleted.", username)); | |||
} else { | |||
throw new UnloggedFailure(1, String.format("Failed to delete %s!", username)); | |||
} | |||
} | |||
} | |||
@CommandMetaData(name = "show", description = "Show the details of an account") | |||
@UsageExample(syntax = "${cmd} john", description = "Display john's account") | |||
public static class ShowUser extends UserCommand { | |||
@Override | |||
public void run() throws UnloggedFailure { | |||
UserModel u = getUser(true); | |||
// fields | |||
String [] fheaders = new String [] { "Field", "Value" }; | |||
Object [][] fdata = new Object[5][]; | |||
fdata[0] = new Object [] { "Email", u.emailAddress }; | |||
fdata[1] = new Object [] { "Type", u.accountType }; | |||
fdata[2] = new Object [] { "Can Admin", u.canAdmin() ? "Y":"N" }; | |||
fdata[3] = new Object [] { "Can Fork", u.canFork() ? "Y":"N" }; | |||
fdata[4] = new Object [] { "Can Create", u.canCreate() ? "Y":"N" }; | |||
fdata[2] = new Object [] { "Can Admin", u.canAdmin() ? "Y":"" }; | |||
fdata[3] = new Object [] { "Can Fork", u.canFork() ? "Y":"" }; | |||
fdata[4] = new Object [] { "Can Create", u.canCreate() ? "Y":"" }; | |||
String fields = FlipTable.of(fheaders, fdata, Borders.COLS); | |||
// teams | |||
String [] theaders = new String [] { "Team", "Type" }; | |||
Object [][] tdata = new Object[u.teams.size()][]; | |||
int i = 0; | |||
for (TeamModel t : u.teams) { | |||
tdata[i] = new Object [] { t.name, t.accountType }; | |||
i++; | |||
String teams; | |||
if (u.teams.size() == 0) { | |||
teams = FlipTable.EMPTY; | |||
} else { | |||
String [] theaders = new String [] { "Team", "Type" }; | |||
Object [][] tdata = new Object[u.teams.size()][]; | |||
int i = 0; | |||
for (TeamModel t : u.teams) { | |||
tdata[i] = new Object [] { t.name, t.accountType }; | |||
i++; | |||
} | |||
teams = FlipTable.of(theaders, tdata, Borders.COLS); | |||
} | |||
String teams = FlipTable.of(theaders, tdata, Borders.COLS); | |||
// permissions | |||
List<RegistrantAccessPermission> perms = u.getRepositoryPermissions(); | |||
String[] pheaders = { "Repository", "Permission", "Type", "Source", "Mutable" }; | |||
Object [][] pdata = new Object[perms.size()][]; | |||
for (i = 0; i < perms.size(); i++) { | |||
RegistrantAccessPermission ap = perms.get(i); | |||
pdata[i] = new Object[] { ap.registrant, ap.permission, ap.permissionType, ap.source, ap.mutable ? "Y":"N" }; | |||
String permissions; | |||
if (perms.isEmpty()) { | |||
permissions = FlipTable.EMPTY; | |||
} else { | |||
String[] pheaders = { "Repository", "Permission", "Type", "Source", "Mutable" }; | |||
Object [][] pdata = new Object[perms.size()][]; | |||
for (int i = 0; i < perms.size(); i++) { | |||
RegistrantAccessPermission ap = perms.get(i); | |||
pdata[i] = new Object[] { ap.registrant, ap.permission, ap.permissionType, ap.source, ap.mutable ? "Y":"" }; | |||
} | |||
permissions = FlipTable.of(pheaders, pdata, Borders.COLS); | |||
} | |||
String permissions = FlipTable.of(pheaders, pdata, Borders.COLS); | |||
// assemble user table | |||
String [] headers = new String[] { u.getDisplayName() + (u.username.equals(u.getDisplayName()) ? "" : (" (" + u.username + ")")) }; | |||
String userTitle = u.getDisplayName() + (u.username.equals(u.getDisplayName()) ? "" : (" (" + u.username + ")")); | |||
if (u.disabled) { | |||
userTitle += " [DISABLED]"; | |||
} | |||
String [] headers = new String[] { userTitle }; | |||
String[][] data = new String[6][]; | |||
data[0] = new String [] { "FIELDS" }; | |||
data[1] = new String [] { fields }; | |||
@@ -95,7 +328,11 @@ public class UsersDispatcher extends DispatchCommand { | |||
} | |||
} | |||
@CommandMetaData(name = "list", aliases= { "ls" }, description = "List users") | |||
@CommandMetaData(name = "list", aliases= { "ls" }, description = "List accounts") | |||
@UsageExamples( examples = { | |||
@UsageExample(syntax = "${cmd}", description = "List accounts as a table"), | |||
@UsageExample(syntax = "${cmd} j.*", description = "List all accounts that start with 'j'"), | |||
}) | |||
public static class ListUsers extends ListFilterCommand<UserModel> { | |||
@Override | |||
@@ -125,10 +362,12 @@ public class UsersDispatcher extends DispatchCommand { | |||
for (int i = 0; i < list.size(); i++) { | |||
UserModel u = list.get(i); | |||
String name = u.disabled ? "-" : ((u.canAdmin() ? "*" : " ")) + u.username; | |||
String name = (u.disabled ? "-" : ((u.canAdmin() ? "*" : " "))) + u.username; | |||
if (verbose) { | |||
data[i] = new Object[] { name, u.displayName, u.accountType, | |||
u.emailAddress, u.canCreate() ? "Y":"", u.canFork() ? "Y" : ""}; | |||
u.emailAddress, | |||
(u.canAdmin() || u.canCreate()) ? "Y":"", | |||
(u.canAdmin() || u.canFork()) ? "Y" : ""}; | |||
} else { | |||
data[i] = new Object[] { name, u.displayName, u.accountType, | |||
u.emailAddress }; | |||
@@ -147,8 +386,8 @@ public class UsersDispatcher extends DispatchCommand { | |||
u.getDisplayName(), | |||
u.accountType, | |||
u.emailAddress == null ? "" : u.emailAddress, | |||
u.canCreate() ? "Y":"", | |||
u.canFork() ? "Y" : ""); | |||
(u.canAdmin() || u.canCreate()) ? "Y":"", | |||
(u.canAdmin() || u.canFork()) ? "Y" : ""); | |||
} | |||
} else { | |||
for (UserModel u : users) { |
@@ -36,7 +36,7 @@ package com.gitblit.utils; | |||
* </pre> | |||
*/ | |||
public final class FlipTable { | |||
private static final String EMPTY = "(empty)"; | |||
public static final String EMPTY = "(empty)"; | |||
public static enum Borders { | |||
FULL(15), BODY_HCOLS(13), HCOLS(12), BODY(9), HEADER(8), COLS(4); |
@@ -23,14 +23,14 @@ First you'll need to create an SSH key pair, if you don't already have one or if | |||
Then you can upload your *public* key right from the command-line. | |||
cat ~/.ssh/id_rsa.pub | ssh -l <username> -p 29418 <hostname> gitblit keys add | |||
cat c:\<userfolder>\.ssh\id_rsa.pub | ssh -l <username> -p 29418 <hostname> gitblit keys add | |||
cat ~/.ssh/id_rsa.pub | ssh -l <username> -p 29418 <hostname> gitblit keys add - | |||
cat c:\<userfolder>\.ssh\id_rsa.pub | ssh -l <username> -p 29418 <hostname> gitblit keys add - | |||
**NOTE:** It is important to note that *ssh-keygen* generates a public/private keypair (e.g. id_rsa and id_rsa.pub). You want to upload the *public* key, which is denoted by the *.pub* file extension. | |||
Once you've done both of those steps you should be able to execute the following command without a password prompt. | |||
ssh -l <username> -p 29418 <hostname> gitblit version | |||
ssh -l <username> -p 29418 <hostname> | |||
### Setting up an SSH alias | |||
@@ -40,7 +40,7 @@ Typing the following command syntax all the time gets to be rather tedious. | |||
You can define an alias for your server which will reduce your command syntax to something like this. | |||
ssh <alias> gitblit version | |||
ssh <alias> | |||
Create or modify your `~/.ssh/config` file and add a host entry. If you are on Windows, you'll want to create or modify `<userfolder>\.ssh\config`, where *userfolder* is dependent on your version of Windows. Most recently this is `c:\users\<userfolder>`. | |||
@@ -62,22 +62,21 @@ The *gitblit* command has many subcommands for interacting with Gitblit. | |||
Add an SSH public key to your account. This command accepts a public key piped to stdin. | |||
cat ~/.ssh/id_rsa.pub | ssh -l <username> -p 29418 <hostname> gitblit keys add | |||
##### keys remove | |||
cat ~/.ssh/id_rsa.pub | ssh -l <username> -p 29418 <hostname> gitblit keys add - | |||
Remove an SSH public key from your account. This command accepts a public key piped to stdin. | |||
##### keys list | |||
cat ~/.ssh/id_rsa.pub | ssh -l <username> -p 29418 <hostname> gitblit keys remove | |||
Show the SSH public keys you have added to your account. | |||
You can also remove all your public keys from your account. | |||
ssh -l <username> -p 29418 <hostname> gitblit keys list | |||
ssh -l <username> -p 29418 <hostname> gitblit keys remove ALL | |||
##### keys remove | |||
##### keys list | |||
Remove an SSH public key from your account. This command accepts several input values, the most useful one is an index number which matches the index number displayed in the `list` command. | |||
Show the SSH keys you have added to your account. | |||
ssh -l <username> -p 29418 <hostname> gitblit keys remove 2 | |||
ssh -l <username> -p 29418 <hostname> gitblit keys list | |||
You can also remove all your public keys from your account. | |||
ssh -l <username> -p 29418 <hostname> gitblit keys remove ALL | |||