summaryrefslogtreecommitdiffstats
path: root/src/main
diff options
context:
space:
mode:
authorJames Moger <james.moger@gitblit.com>2014-03-26 21:33:21 -0400
committerJames Moger <james.moger@gitblit.com>2014-04-10 18:58:10 -0400
commit617909819cd1b955647dd8584036fc7b2a014265 (patch)
tree0c608817a000fba9f25984b0f37c0167c7c881d6 /src/main
parentec9703a5aa4bda8d764537ea040e464bd422980b (diff)
downloadgitblit-617909819cd1b955647dd8584036fc7b2a014265.tar.gz
gitblit-617909819cd1b955647dd8584036fc7b2a014265.zip
Improve command help with formatting and usage examples
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/com/gitblit/transport/ssh/WelcomeShell.java71
-rw-r--r--src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java60
-rw-r--r--src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java4
-rw-r--r--src/main/java/com/gitblit/transport/ssh/commands/SshCommand.java4
-rw-r--r--src/main/java/com/gitblit/transport/ssh/commands/UsageExample.java32
-rw-r--r--src/main/java/com/gitblit/transport/ssh/commands/UsageExamples.java31
-rw-r--r--src/main/java/com/gitblit/transport/ssh/git/GarbageCollectionCommand.java2
-rw-r--r--src/main/java/com/gitblit/transport/ssh/gitblit/BaseKeyCommand.java2
-rw-r--r--src/main/java/com/gitblit/transport/ssh/gitblit/ConfigCommand.java8
-rw-r--r--src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java37
-rw-r--r--src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatcher.java2
-rw-r--r--src/main/java/com/gitblit/transport/ssh/gitblit/KeysDispatcher.java7
-rw-r--r--src/main/java/com/gitblit/transport/ssh/gitblit/RepositoriesDispatcher.java4
-rw-r--r--src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java88
-rw-r--r--src/main/java/com/gitblit/transport/ssh/gitblit/UsersDispatcher.java293
-rw-r--r--src/main/java/com/gitblit/utils/FlipTable.java2
16 files changed, 467 insertions, 180 deletions
diff --git a/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java b/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java
index ccf2586b..a9fe6f0f 100644
--- a/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java
+++ b/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java
@@ -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);
}
}
}
diff --git a/src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java
index 6a190df6..d24a7163 100644
--- a/src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java
+++ b/src/main/java/com/gitblit/transport/ssh/commands/BaseCommand.java
@@ -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();
diff --git a/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java
index b916bb17..6e9a87dd 100644
--- a/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java
+++ b/src/main/java/com/gitblit/transport/ssh/commands/DispatchCommand.java
@@ -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);
diff --git a/src/main/java/com/gitblit/transport/ssh/commands/SshCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/SshCommand.java
index ee464e7c..67e2805f 100644
--- a/src/main/java/com/gitblit/transport/ssh/commands/SshCommand.java
+++ b/src/main/java/com/gitblit/transport/ssh/commands/SshCommand.java
@@ -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;
diff --git a/src/main/java/com/gitblit/transport/ssh/commands/UsageExample.java b/src/main/java/com/gitblit/transport/ssh/commands/UsageExample.java
new file mode 100644
index 00000000..428dfde8
--- /dev/null
+++ b/src/main/java/com/gitblit/transport/ssh/commands/UsageExample.java
@@ -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 "";
+}
diff --git a/src/main/java/com/gitblit/transport/ssh/commands/UsageExamples.java b/src/main/java/com/gitblit/transport/ssh/commands/UsageExamples.java
new file mode 100644
index 00000000..0193a98a
--- /dev/null
+++ b/src/main/java/com/gitblit/transport/ssh/commands/UsageExamples.java
@@ -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 {};
+}
diff --git a/src/main/java/com/gitblit/transport/ssh/git/GarbageCollectionCommand.java b/src/main/java/com/gitblit/transport/ssh/git/GarbageCollectionCommand.java
index cc0c00a3..5383786a 100644
--- a/src/main/java/com/gitblit/transport/ssh/git/GarbageCollectionCommand.java
+++ b/src/main/java/com/gitblit/transport/ssh/git/GarbageCollectionCommand.java
@@ -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);
diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/BaseKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/BaseKeyCommand.java
index 55a87e4f..56f2c355 100644
--- a/src/main/java/com/gitblit/transport/ssh/gitblit/BaseKeyCommand.java
+++ b/src/main/java/com/gitblit/transport/ssh/gitblit/BaseKeyCommand.java
@@ -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));
diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/ConfigCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/ConfigCommand.java
index 695f0850..f6740349 100644
--- a/src/main/java/com/gitblit/transport/ssh/gitblit/ConfigCommand.java
+++ b/src/main/java/com/gitblit/transport/ssh/gitblit/ConfigCommand.java
@@ -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")
diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java b/src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java
deleted file mode 100644
index 2917b6d2..00000000
--- a/src/main/java/com/gitblit/transport/ssh/gitblit/CreateRepository.java
+++ /dev/null
@@ -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));
- }
-}
diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatcher.java
index 86d8a8c9..42000646 100644
--- a/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatcher.java
+++ b/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatcher.java
@@ -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
diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/KeysDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/KeysDispatcher.java
index 8c4aa228..61764c42 100644
--- a/src/main/java/com/gitblit/transport/ssh/gitblit/KeysDispatcher.java
+++ b/src/main/java/com/gitblit/transport/ssh/gitblit/KeysDispatcher.java
@@ -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")
diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/RepositoriesDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/RepositoriesDispatcher.java
index 4be60abc..f2fbabbe 100644
--- a/src/main/java/com/gitblit/transport/ssh/gitblit/RepositoriesDispatcher.java
+++ b/src/main/java/com/gitblit/transport/ssh/gitblit/RepositoriesDispatcher.java
@@ -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 = "";
diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java
deleted file mode 100644
index 3f98778a..00000000
--- a/src/main/java/com/gitblit/transport/ssh/gitblit/SetAccountCommand.java
+++ /dev/null
@@ -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);
- }
- }
- }
-}
diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/UsersDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/UsersDispatcher.java
index bed966da..d892d9a0 100644
--- a/src/main/java/com/gitblit/transport/ssh/gitblit/UsersDispatcher.java
+++ b/src/main/java/com/gitblit/transport/ssh/gitblit/UsersDispatcher.java
@@ -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) {
diff --git a/src/main/java/com/gitblit/utils/FlipTable.java b/src/main/java/com/gitblit/utils/FlipTable.java
index 7aa5f0b1..0197517d 100644
--- a/src/main/java/com/gitblit/utils/FlipTable.java
+++ b/src/main/java/com/gitblit/utils/FlipTable.java
@@ -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);