diff options
author | James Moger <james.moger@gitblit.com> | 2014-03-30 14:21:19 -0400 |
---|---|---|
committer | James Moger <james.moger@gitblit.com> | 2014-04-10 19:00:52 -0400 |
commit | 413e9b486b1a84960d4c8ddac130e87280f64c6a (patch) | |
tree | 92468e43da3eb8125a5da9f5e39e1a7aee1dd9a8 /src/main/java | |
parent | a9dc74e73eea068b8cbb5c96958abccae88b4abc (diff) | |
download | gitblit-413e9b486b1a84960d4c8ddac130e87280f64c6a.tar.gz gitblit-413e9b486b1a84960d4c8ddac130e87280f64c6a.zip |
Split administration commands into a plugin, enhance plugin manager
Diffstat (limited to 'src/main/java')
18 files changed, 391 insertions, 2268 deletions
diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java index 0001706c..6b1cc8a5 100644 --- a/src/main/java/com/gitblit/manager/GitblitManager.java +++ b/src/main/java/com/gitblit/manager/GitblitManager.java @@ -42,7 +42,9 @@ import org.eclipse.jgit.transport.RefSpec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ro.fortsoft.pf4j.PluginClassLoader; import ro.fortsoft.pf4j.PluginWrapper; +import ro.fortsoft.pf4j.RuntimeMode; import com.gitblit.Constants; import com.gitblit.Constants.AccessPermission; @@ -1187,4 +1189,54 @@ public class GitblitManager implements IGitblit { public PluginWrapper whichPlugin(Class<?> clazz) { return pluginManager.whichPlugin(clazz); } + + @Override + public boolean deletePlugin(PluginWrapper wrapper) { + return pluginManager.deletePlugin(wrapper); + } + + @Override + public List<PluginWrapper> getPlugins() { + return pluginManager.getPlugins(); + } + + @Override + public List<PluginWrapper> getResolvedPlugins() { + return pluginManager.getResolvedPlugins(); + } + + @Override + public List<PluginWrapper> getUnresolvedPlugins() { + return pluginManager.getUnresolvedPlugins(); + } + + @Override + public List<PluginWrapper> getStartedPlugins() { + return pluginManager.getStartedPlugins(); + } + + @Override + public void loadPlugins() { + pluginManager.loadPlugins(); + } + + @Override + public void startPlugins() { + pluginManager.startPlugins(); + } + + @Override + public void stopPlugins() { + pluginManager.stopPlugins(); + } + + @Override + public PluginClassLoader getPluginClassLoader(String pluginId) { + return pluginManager.getPluginClassLoader(pluginId); + } + + @Override + public RuntimeMode getRuntimeMode() { + return pluginManager.getRuntimeMode(); + } } diff --git a/src/main/java/com/gitblit/manager/IPluginManager.java b/src/main/java/com/gitblit/manager/IPluginManager.java index 670e9769..11b81ea3 100644 --- a/src/main/java/com/gitblit/manager/IPluginManager.java +++ b/src/main/java/com/gitblit/manager/IPluginManager.java @@ -15,19 +15,10 @@ */ package com.gitblit.manager; -import java.util.List; - +import ro.fortsoft.pf4j.PluginManager; import ro.fortsoft.pf4j.PluginWrapper; -public interface IPluginManager extends IManager { - - /** - * Retrieves the extension for given class 'clazz'. - * - * @param clazz extension point class to retrieve extension for - * @return list of extensions - */ - public <T> List<T> getExtensions(Class<T> clazz); +public interface IPluginManager extends IManager, PluginManager { /** * Retrieves the {@link PluginWrapper} that loaded the given class 'clazz'. @@ -35,5 +26,13 @@ public interface IPluginManager extends IManager { * @param clazz extension point class to retrieve extension for * @return PluginWrapper that loaded the given class */ - public PluginWrapper whichPlugin(Class<?> clazz); + PluginWrapper whichPlugin(Class<?> clazz); + + /** + * Delete the plugin represented by {@link PluginWrapper}. + * + * @param wrapper + * @return true if successful + */ + boolean deletePlugin(PluginWrapper wrapper); } diff --git a/src/main/java/com/gitblit/manager/PluginManager.java b/src/main/java/com/gitblit/manager/PluginManager.java index 5eb00e92..e23aaec0 100644 --- a/src/main/java/com/gitblit/manager/PluginManager.java +++ b/src/main/java/com/gitblit/manager/PluginManager.java @@ -15,12 +15,16 @@ */ package com.gitblit.manager; +import java.io.File; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ro.fortsoft.pf4j.DefaultPluginManager; +import ro.fortsoft.pf4j.PluginWrapper; import com.gitblit.Keys; +import com.gitblit.utils.FileUtils; /** * The plugin manager maintains the lifecycle of plugins. It is exposed as @@ -30,27 +34,45 @@ import com.gitblit.Keys; * @author David Ostrovsky * */ -public class PluginManager extends DefaultPluginManager implements - IPluginManager { +public class PluginManager extends DefaultPluginManager implements IPluginManager { private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final IRuntimeManager runtimeManager; public PluginManager(IRuntimeManager runtimeManager) { - super(runtimeManager.getFileOrFolder(Keys.plugins.folder, - "${baseFolder}/plugins")); + super(runtimeManager.getFileOrFolder(Keys.plugins.folder, "${baseFolder}/plugins")); + this.runtimeManager = runtimeManager; } @Override public PluginManager start() { - logger.info("Plugin manager started"); + logger.info("Loading plugins..."); loadPlugins(); + logger.info("Starting loaded plugins..."); startPlugins(); return this; } @Override public PluginManager stop() { + logger.info("Stopping loaded plugins..."); stopPlugins(); return null; } + + @Override + public boolean deletePlugin(PluginWrapper pw) { + File folder = runtimeManager.getFileOrFolder(Keys.plugins.folder, "${baseFolder}/plugins"); + File pluginFolder = new File(folder, pw.getPluginPath()); + File pluginZip = new File(folder, pw.getPluginPath() + ".zip"); + + if (pluginFolder.exists()) { + FileUtils.delete(pluginFolder); + } + if (pluginZip.exists()) { + FileUtils.delete(pluginZip); + } + return true; + } } diff --git a/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java b/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java index 6809ba62..4341a3ea 100644 --- a/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java +++ b/src/main/java/com/gitblit/transport/ssh/WelcomeShell.java @@ -165,7 +165,7 @@ public class WelcomeShell implements Factory<Command> { 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(String.format(" cat ~/.ssh/id_rsa.pub | ssh -l %s -p %d %s keys add", user.username, port, hostname)); msg.append(nl); msg.append(nl); diff --git a/src/main/java/com/gitblit/transport/ssh/commands/PluginDispatcher.java b/src/main/java/com/gitblit/transport/ssh/commands/PluginDispatcher.java new file mode 100644 index 00000000..5c413db2 --- /dev/null +++ b/src/main/java/com/gitblit/transport/ssh/commands/PluginDispatcher.java @@ -0,0 +1,293 @@ +/* + * 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 java.util.ArrayList; +import java.util.List; + +import org.kohsuke.args4j.Argument; + +import ro.fortsoft.pf4j.PluginDependency; +import ro.fortsoft.pf4j.PluginDescriptor; +import ro.fortsoft.pf4j.PluginState; +import ro.fortsoft.pf4j.PluginWrapper; + +import com.gitblit.manager.IGitblit; +import com.gitblit.models.UserModel; +import com.gitblit.utils.FlipTable; +import com.gitblit.utils.FlipTable.Borders; + +/** + * The plugin dispatcher and commands for runtime plugin management. + * + * @author James Moger + * + */ +@CommandMetaData(name = "plugin", description = "Plugin management commands", admin = true) +public class PluginDispatcher extends DispatchCommand { + + @Override + protected void setup(UserModel user) { + register(user, ListPlugins.class); + register(user, StartPlugin.class); + register(user, StopPlugin.class); + register(user, ShowPlugin.class); + register(user, RemovePlugin.class); + register(user, UploadPlugin.class); + } + + @CommandMetaData(name = "list", aliases = { "ls" }, description = "List the loaded plugins") + public static class ListPlugins extends ListCommand<PluginWrapper> { + + @Override + protected List<PluginWrapper> getItems() throws UnloggedFailure { + IGitblit gitblit = getContext().getGitblit(); + List<PluginWrapper> list = gitblit.getPlugins(); + return list; + } + + @Override + protected void asTable(List<PluginWrapper> list) { + String[] headers; + if (verbose) { + String [] h = { "#", "Id", "Version", "State", "Mode", "Path", "Provider"}; + headers = h; + } else { + String [] h = { "#", "Id", "Version", "State", "Path"}; + headers = h; + } + Object[][] data = new Object[list.size()][]; + for (int i = 0; i < list.size(); i++) { + PluginWrapper p = list.get(i); + PluginDescriptor d = p.getDescriptor(); + if (verbose) { + data[i] = new Object[] { "" + (i + 1), d.getPluginId(), d.getVersion(), p.getPluginState(), p.getRuntimeMode(), p.getPluginPath(), d.getProvider() }; + } else { + data[i] = new Object[] { "" + (i + 1), d.getPluginId(), d.getVersion(), p.getPluginState(), p.getPluginPath() }; + } + } + + stdout.println(FlipTable.of(headers, data, Borders.BODY_HCOLS)); + } + + @Override + protected void asTabbed(List<PluginWrapper> list) { + for (PluginWrapper pw : list) { + PluginDescriptor d = pw.getDescriptor(); + if (verbose) { + outTabbed(d.getPluginId(), d.getVersion(), pw.getPluginState(), pw.getRuntimeMode(), pw.getPluginPath(), d.getProvider()); + } else { + outTabbed(d.getPluginId(), d.getVersion(), pw.getPluginState(), pw.getPluginPath()); + } + } + } + } + + @CommandMetaData(name = "start", description = "Start a plugin") + public static class StartPlugin extends SshCommand { + + @Argument(index = 0, required = true, metaVar = "ALL|<id>", usage = "the plugin to start") + protected String plugin; + + @Override + public void run() throws UnloggedFailure { + IGitblit gitblit = getContext().getGitblit(); + if (plugin.equalsIgnoreCase("ALL")) { + gitblit.startPlugins(); + stdout.println("All plugins started"); + } else { + try { + int index = Integer.parseInt(plugin); + List<PluginWrapper> plugins = gitblit.getPlugins(); + if (index > plugins.size()) { + throw new UnloggedFailure(1, "Invalid plugin index specified!"); + } + PluginWrapper pw = plugins.get(index - 1); + start(pw); + } catch (NumberFormatException n) { + for (PluginWrapper pw : gitblit.getPlugins()) { + PluginDescriptor pd = pw.getDescriptor(); + if (pd.getPluginId().equalsIgnoreCase(plugin)) { + start(pw); + break; + } + } + } + } + } + + protected void start(PluginWrapper pw) throws UnloggedFailure { + String id = pw.getDescriptor().getPluginId(); + if (pw.getPluginState() == PluginState.STARTED) { + throw new UnloggedFailure(1, String.format("%s is already started.", id)); + } + try { + pw.getPlugin().start(); +// pw.setPluginState(PluginState.STARTED); + stdout.println(String.format("%s started", id)); + } catch (Exception pe) { + throw new UnloggedFailure(1, String.format("Failed to start %s", id), pe); + } + } + } + + + @CommandMetaData(name = "stop", description = "Stop a plugin") + public static class StopPlugin extends SshCommand { + + @Argument(index = 0, required = true, metaVar = "ALL|<id>", usage = "the plugin to stop") + protected String plugin; + + @Override + public void run() throws UnloggedFailure { + IGitblit gitblit = getContext().getGitblit(); + if (plugin.equalsIgnoreCase("ALL")) { + gitblit.stopPlugins(); + stdout.println("All plugins stopped"); + } else { + try { + int index = Integer.parseInt(plugin); + List<PluginWrapper> plugins = gitblit.getPlugins(); + if (index > plugins.size()) { + throw new UnloggedFailure(1, "Invalid plugin index specified!"); + } + PluginWrapper pw = plugins.get(index - 1); + stop(pw); + } catch (NumberFormatException n) { + for (PluginWrapper pw : gitblit.getPlugins()) { + PluginDescriptor pd = pw.getDescriptor(); + if (pd.getPluginId().equalsIgnoreCase(plugin)) { + stop(pw); + break; + } + } + } + } + } + + protected void stop(PluginWrapper pw) throws UnloggedFailure { + String id = pw.getDescriptor().getPluginId(); + if (pw.getPluginState() == PluginState.STOPPED) { + throw new UnloggedFailure(1, String.format("%s is already stopped.", id)); + } + try { + pw.getPlugin().stop(); +// pw.setPluginState(PluginState.STOPPED); + stdout.println(String.format("%s stopped", id)); + } catch (Exception pe) { + throw new UnloggedFailure(1, String.format("Failed to stop %s", id), pe); + } + } + } + + @CommandMetaData(name = "show", description = "Show the details of a plugin") + public static class ShowPlugin extends SshCommand { + + @Argument(index = 0, required = true, metaVar = "<id>", usage = "the plugin to stop") + protected int index; + + @Override + public void run() throws UnloggedFailure { + IGitblit gitblit = getContext().getGitblit(); + List<PluginWrapper> plugins = gitblit.getPlugins(); + if (index > plugins.size()) { + throw new UnloggedFailure(1, "Invalid plugin index specified!"); + } + PluginWrapper pw = plugins.get(index - 1); + PluginDescriptor d = pw.getDescriptor(); + + // FIELDS + StringBuilder sb = new StringBuilder(); + sb.append("Version : ").append(d.getVersion()).append('\n'); + sb.append("Provider : ").append(d.getProvider()).append('\n'); + sb.append("Path : ").append(pw.getPluginPath()).append('\n'); + sb.append("State : ").append(pw.getPluginState()).append('\n'); + final String fields = sb.toString(); + + // TODO EXTENSIONS + sb.setLength(0); + List<String> exts = new ArrayList<String>(); + String extensions; + if (exts.isEmpty()) { + extensions = FlipTable.EMPTY; + } else { + String[] headers = { "Id", "Version" }; + Object[][] data = new Object[exts.size()][]; + for (int i = 0; i < exts.size(); i++) { + String ext = exts.get(i); + data[0] = new Object[] { ext.toString(), ext.toString() }; + } + extensions = FlipTable.of(headers, data, Borders.COLS); + } + + // DEPENDENCIES + sb.setLength(0); + List<PluginDependency> deps = d.getDependencies(); + String dependencies; + if (deps.isEmpty()) { + dependencies = FlipTable.EMPTY; + } else { + String[] headers = { "Id", "Version" }; + Object[][] data = new Object[deps.size()][]; + for (int i = 0; i < deps.size(); i++) { + PluginDependency dep = deps.get(i); + data[0] = new Object[] { dep.getPluginId(), dep.getPluginVersion() }; + } + dependencies = FlipTable.of(headers, data, Borders.COLS); + } + + String[] headers = { d.getPluginId() }; + Object[][] data = new Object[5][]; + data[0] = new Object[] { fields }; + data[1] = new Object[] { "EXTENSIONS" }; + data[2] = new Object[] { extensions }; + data[3] = new Object[] { "DEPENDENCIES" }; + data[4] = new Object[] { dependencies }; + stdout.println(FlipTable.of(headers, data)); + } + } + + @CommandMetaData(name = "remove", aliases= { "rm", "del" }, description = "Remove a plugin", hidden = true) + public static class RemovePlugin extends SshCommand { + + @Argument(index = 0, required = true, metaVar = "<id>", usage = "the plugin to stop") + protected int index; + + @Override + public void run() throws UnloggedFailure { + IGitblit gitblit = getContext().getGitblit(); + List<PluginWrapper> plugins = gitblit.getPlugins(); + if (index > plugins.size()) { + throw new UnloggedFailure(1, "Invalid plugin index specified!"); + } + PluginWrapper pw = plugins.get(index - 1); + PluginDescriptor d = pw.getDescriptor(); + if (gitblit.deletePlugin(pw)) { + stdout.println(String.format("Deleted %s %s", d.getPluginId(), d.getVersion())); + } else { + throw new UnloggedFailure(1, String.format("Failed to delete %s %s", d.getPluginId(), d.getVersion())); + } + } + } + + @CommandMetaData(name = "receive", aliases= { "upload" }, description = "Upload a plugin to the server", hidden = true) + public static class UploadPlugin extends SshCommand { + + @Override + public void run() throws UnloggedFailure { + } + } +} diff --git a/src/main/java/com/gitblit/transport/ssh/commands/RootDispatcher.java b/src/main/java/com/gitblit/transport/ssh/commands/RootDispatcher.java index 8a871ebb..3c378669 100644 --- a/src/main/java/com/gitblit/transport/ssh/commands/RootDispatcher.java +++ b/src/main/java/com/gitblit/transport/ssh/commands/RootDispatcher.java @@ -24,7 +24,7 @@ import com.gitblit.manager.IGitblit; import com.gitblit.models.UserModel; import com.gitblit.transport.ssh.SshDaemonClient; import com.gitblit.transport.ssh.git.GitDispatcher; -import com.gitblit.transport.ssh.gitblit.GitblitDispatcher; +import com.gitblit.transport.ssh.keys.KeysDispatcher; /** * The root dispatcher is the dispatch command that handles registering all @@ -41,8 +41,10 @@ class RootDispatcher extends DispatchCommand { setContext(new SshCommandContext(gitblit, client, cmdLine)); UserModel user = client.getUser(); - register(user, GitblitDispatcher.class); + register(user, VersionCommand.class); register(user, GitDispatcher.class); + register(user, KeysDispatcher.class); + register(user, PluginDispatcher.class); List<DispatchCommand> exts = gitblit.getExtensions(DispatchCommand.class); for (DispatchCommand ext : exts) { diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/VersionCommand.java b/src/main/java/com/gitblit/transport/ssh/commands/VersionCommand.java index 384c6ce4..3a2fd5e2 100644 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/VersionCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/commands/VersionCommand.java @@ -14,11 +14,9 @@ * limitations under the License. */ -package com.gitblit.transport.ssh.gitblit; +package com.gitblit.transport.ssh.commands; import com.gitblit.Constants; -import com.gitblit.transport.ssh.commands.CommandMetaData; -import com.gitblit.transport.ssh.commands.SshCommand; @CommandMetaData(name="version", description = "Display the Gitblit version") public class VersionCommand extends SshCommand { diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/ConfigCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/ConfigCommand.java deleted file mode 100644 index f6740349..00000000 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/ConfigCommand.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.gitblit.transport.ssh.gitblit; - -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.kohsuke.args4j.Argument; -import org.kohsuke.args4j.Option; -import org.parboiled.common.StringUtils; - -import com.gitblit.manager.IGitblit; -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") - protected String setting; - - @Argument(index = 1, metaVar = "VALUE", usage = "The new value for the setting") - protected String value; - - @Option(name = "--list", aliases = { "-l" }, usage = "List all settings") - private boolean listAll; - - @Option(name = "--modified", aliases = { "-m" }, usage = "List modified settings") - private boolean listModified; - - @Option(name = "--reset", usage = "Reset a setting to it's default value") - private boolean reset; - - @Override - public void run() throws UnloggedFailure { - IGitblit gitblit = getContext().getGitblit(); - ServerSettings settings = gitblit.getSettingsModel(); - - if (listAll || listModified) { - /* - * List settings - */ - List<SettingModel> list = new ArrayList<SettingModel>(); - int maxLen = 0; - for (String key : settings.getKeys()) { - SettingModel model = settings.get(key); - if (listModified) { - if (!model.isDefaultValue()) { - list.add(model); - } else { - continue; - } - } else { - list.add(model); - } - - if (key.length() > maxLen) { - maxLen = key.length(); - } - } - String pattern = MessageFormat.format("%s%-{0,number,0}s : %s", maxLen); - for (SettingModel model : list) { - stdout.println(String.format(pattern, - model.isDefaultValue() ? " " : "*", - model.name, - model.currentValue)); - } - } else if (!StringUtils.isEmpty(setting) && value == null && !reset) { - /* - * Describe a setting - */ - SettingModel model = settings.get(setting); - if (model == null) { - // unknown setting - String value = gitblit.getSettings().getString(setting, null); - if (value == null) { - // setting does not exist, can not describe - stdout.println(String.format("\"%s\" is not a valid setting.", setting)); - return; - } - - model = new SettingModel(); - model.defaultValue = ""; - model.currentValue = value; - } - stdout.println(); - stdout.println(model.name); - if (!StringUtils.isEmpty(model.since)) { - stdout.println(SettingModel.SINCE + " " + model.since); - } - if (model.restartRequired) { - stdout.println(SettingModel.RESTART_REQUIRED); - } - if (model.spaceDelimited) { - stdout.println(SettingModel.SPACE_DELIMITED); - } - if (!StringUtils.isEmpty(model.description)) { - stdout.println(); - stdout.println(model.description); - } - stdout.println(); - if (model.defaultValue != null) { - stdout.println("default: " + model.defaultValue); - } - if (!model.isDefaultValue()) { - stdout.println("current: " + model.currentValue); - } else { - stdout.println("current: <default>"); - } - stdout.println(); - } else if (!StringUtils.isEmpty(setting) && value == null && reset) { - /* - * Reset a setting - */ - SettingModel model = settings.get(setting); - if (model == null) { - stdout.println(String.format("\"%s\" is not a valid setting.", setting)); - return; - } - - if (model.defaultValue == null || model.defaultValue.equals("null")) { - // no default value, remove setting - gitblit.getSettings().removeSetting(setting); - gitblit.getSettings().saveSettings(); - settings.remove(setting); - - stdout.println(String.format("%s removed.", setting)); - } else { - // reset to default value - Map<String, String> updates = Maps.newHashMap(); - updates.put(setting, model.defaultValue == null ? "" : model.defaultValue); - gitblit.getSettings().saveSettings(updates); - - // confirm reset - String newValue = gitblit.getSettings().getString(setting, null); - if (model.defaultValue.equals(newValue)) { - stdout.println(String.format("%s reset to the default value.", setting)); - } else { - stdout.println(String.format("failed to reset %s!", setting)); - } - } - - } else if (!StringUtils.isEmpty(setting) && value != null) { - /* - * Update a setting - */ - Map<String, String> updates = Maps.newHashMap(); - updates.put(setting, value); - gitblit.getSettings().saveSettings(updates); - - // confirm update - String newValue = gitblit.getSettings().getString(setting, null); - if (value.equals(newValue)) { - stdout.println(String.format("%s updated.", setting)); - } else { - stdout.println(String.format("failed to update %s!", setting)); - } - } else { - // Display usage - showHelp(); - } - } -}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatcher.java deleted file mode 100644 index 67fedeaa..00000000 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/GitblitDispatcher.java +++ /dev/null @@ -1,40 +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 com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.commands.CommandMetaData; -import com.gitblit.transport.ssh.commands.DispatchCommand; - -@CommandMetaData(name = "gitblit", description = "Gitblit server commands") -public class GitblitDispatcher extends DispatchCommand { - - @Override - protected void setup(UserModel user) { - // commands in this dispatcher - register(user, VersionCommand.class); - register(user, ConfigCommand.class); - - // nested dispatchers - register(user, ListDispatcher.class); - register(user, KeysDispatcher.class); - register(user, TicketsDispatcher.class); - register(user, UsersDispatcher.class); - register(user, TeamsDispatcher.class); - register(user, ProjectsDispatcher.class); - register(user, RepositoriesDispatcher.class); - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/ListDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/ListDispatcher.java deleted file mode 100644 index 343e59aa..00000000 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/ListDispatcher.java +++ /dev/null @@ -1,58 +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 com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.commands.CommandMetaData; -import com.gitblit.transport.ssh.commands.DispatchCommand; - -/** - * The dispatcher and it's commands for Gitblit object listing. - * - * @author James Moger - * - */ -@CommandMetaData(name = "list", aliases = { "ls" }, description = "Gitblit object list commands") -public class ListDispatcher extends DispatchCommand { - - @Override - protected void setup(UserModel user) { - register(user, ListRepositories.class); - register(user, ListProjects.class); - register(user, ListUsers.class); - register(user, ListKeys.class); - } - - /* List SSH public keys */ - @CommandMetaData(name = "keys", description = "List your public keys") - public static class ListKeys extends KeysDispatcher.ListKeys { - } - - /* List repositories */ - @CommandMetaData(name = "repositories", aliases = { "repos" }, description = "List repositories") - public static class ListRepositories extends RepositoriesDispatcher.ListRepositories { - } - - /* List projects */ - @CommandMetaData(name = "projects", description = "List projects") - public static class ListProjects extends ProjectsDispatcher.ListProjects { - } - - /* List users */ - @CommandMetaData(name = "users", description = "List users", admin = true) - public static class ListUsers extends UsersDispatcher.ListUsers { - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/ProjectsDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/ProjectsDispatcher.java deleted file mode 100644 index 97076adf..00000000 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/ProjectsDispatcher.java +++ /dev/null @@ -1,94 +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 java.util.List; - -import com.gitblit.manager.IGitblit; -import com.gitblit.models.ProjectModel; -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.utils.FlipTable; -import com.gitblit.utils.FlipTable.Borders; - -@CommandMetaData(name = "projects", description = "Project management commands") -public class ProjectsDispatcher extends DispatchCommand { - - @Override - protected void setup(UserModel user) { - register(user, ListProjects.class); - } - - /* List projects */ - @CommandMetaData(name = "list", aliases= { "ls" }, description = "List projects") - public static class ListProjects extends ListFilterCommand<ProjectModel> { - - @Override - protected List<ProjectModel> getItems() { - IGitblit gitblit = getContext().getGitblit(); - UserModel user = getContext().getClient().getUser(); - - List<ProjectModel> projects = gitblit.getProjectModels(user, false); - return projects; - } - - @Override - protected boolean matches(String filter, ProjectModel p) { - return p.name.matches(filter); - } - - @Override - protected void asTable(List<ProjectModel> list) { - String[] headers; - if (verbose) { - String[] h = { "Name", "Description", "Last Modified", "# Repos" }; - headers = h; - } else { - String[] h = { "Name", "Last Modified", "# Repos" }; - headers = h; - } - - Object[][] data = new Object[list.size()][]; - for (int i = 0; i < list.size(); i++) { - ProjectModel p = list.get(i); - - if (verbose) { - data[i] = new Object[] { p.name, p.description, formatDate(p.lastChange), p.repositories.size() }; - } else { - data[i] = new Object[] { p.name, formatDate(p.lastChange), p.repositories.size() }; - } - } - stdout.println(FlipTable.of(headers, data, Borders.BODY_HCOLS)); - } - - @Override - protected void asTabbed(List<ProjectModel> list) { - if (verbose) { - for (ProjectModel project : list) { - outTabbed(project.name, - project.description == null ? "" : project.description, - formatDate(project.lastChange)); - } - } else { - for (ProjectModel project : list) { - outTabbed(project.name); - } - } - } - } -}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/RepositoriesDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/RepositoriesDispatcher.java deleted file mode 100644 index 292c2126..00000000 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/RepositoriesDispatcher.java +++ /dev/null @@ -1,532 +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 java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.kohsuke.args4j.Argument; - -import com.gitblit.GitBlitException; -import com.gitblit.Keys; -import com.gitblit.Constants.AccessRestrictionType; -import com.gitblit.Constants.AuthorizationControl; -import com.gitblit.manager.IGitblit; -import com.gitblit.models.RegistrantAccessPermission; -import com.gitblit.models.RepositoryModel; -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.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 = "repositories", aliases = { "repos" }, description = "Repository management commands") -public class RepositoriesDispatcher extends DispatchCommand { - - @Override - protected void setup(UserModel user) { - // primary commands - register(user, NewRepository.class); - register(user, RenameRepository.class); - register(user, RemoveRepository.class); - register(user, ShowRepository.class); - register(user, ListRepositories.class); - - // repository-specific commands - register(user, SetField.class); - } - - public static abstract class RepositoryCommand extends SshCommand { - @Argument(index = 0, required = true, metaVar = "REPOSITORY", usage = "repository") - protected String repository; - - protected RepositoryModel getRepository(boolean requireRepository) throws UnloggedFailure { - IGitblit gitblit = getContext().getGitblit(); - RepositoryModel repo = gitblit.getRepositoryModel(repository); - if (requireRepository && repo == null) { - throw new UnloggedFailure(1, String.format("Repository %s does not exist!", repository)); - } - return repo; - } - - protected String sanitize(String name) throws UnloggedFailure { - // automatically convert backslashes to forward slashes - name = name.replace('\\', '/'); - // Automatically replace // with / - name = name.replace("//", "/"); - - // prohibit folder paths - if (name.startsWith("/")) { - throw new UnloggedFailure(1, "Illegal leading slash"); - } - if (name.startsWith("../")) { - throw new UnloggedFailure(1, "Illegal relative slash"); - } - if (name.contains("/../")) { - throw new UnloggedFailure(1, "Illegal relative slash"); - } - if (name.endsWith("/")) { - name = name.substring(0, name.length() - 1); - } - return name; - } - } - - @CommandMetaData(name = "new", aliases = { "add" }, description = "Create a new repository") - @UsageExample(syntax = "${cmd} myRepo") - public static class NewRepository extends RepositoryCommand { - - @Override - public void run() throws UnloggedFailure { - - UserModel user = getContext().getClient().getUser(); - - String name = sanitize(repository); - - if (!user.canCreate(name)) { - // try to prepend personal path - String path = StringUtils.getFirstPathElement(name); - if ("".equals(path)) { - name = user.getPersonalPath() + "/" + name; - } - } - - if (getRepository(false) != null) { - throw new UnloggedFailure(1, String.format("Repository %s already exists!", name)); - } - - if (!user.canCreate(name)) { - throw new UnloggedFailure(1, String.format("Sorry, you do not have permission to create %s", name)); - } - - IGitblit gitblit = getContext().getGitblit(); - - RepositoryModel repo = new RepositoryModel(); - repo.name = name; - repo.projectPath = StringUtils.getFirstPathElement(name); - String restriction = gitblit.getSettings().getString(Keys.git.defaultAccessRestriction, "PUSH"); - repo.accessRestriction = AccessRestrictionType.fromName(restriction); - String authorization = gitblit.getSettings().getString(Keys.git.defaultAuthorizationControl, null); - repo.authorizationControl = AuthorizationControl.fromName(authorization); - - if (user.isMyPersonalRepository(name)) { - // personal repositories are private by default - repo.addOwner(user.username); - repo.accessRestriction = AccessRestrictionType.VIEW; - repo.authorizationControl = AuthorizationControl.NAMED; - } - - try { - gitblit.updateRepositoryModel(repository, repo, true); - stdout.println(String.format("%s created.", repo.name)); - } catch (GitBlitException e) { - log.error("Failed to add " + repository, e); - throw new UnloggedFailure(1, e.getMessage()); - } - } - } - - @CommandMetaData(name = "rename", aliases = { "mv" }, description = "Rename a repository") - @UsageExample(syntax = "${cmd} myRepo.git otherRepo.git", description = "Rename the repository from myRepo.git to otherRepo.git") - public static class RenameRepository extends RepositoryCommand { - @Argument(index = 1, required = true, metaVar = "NEWNAME", usage = "the new repository name") - protected String newRepositoryName; - - @Override - public void run() throws UnloggedFailure { - RepositoryModel repo = getRepository(true); - IGitblit gitblit = getContext().getGitblit(); - UserModel user = getContext().getClient().getUser(); - - String name = sanitize(newRepositoryName); - if (!user.canCreate(name)) { - // try to prepend personal path - String path = StringUtils.getFirstPathElement(name); - if ("".equals(path)) { - name = user.getPersonalPath() + "/" + name; - } - } - - if (null != gitblit.getRepositoryModel(name)) { - throw new UnloggedFailure(1, String.format("Repository %s already exists!", name)); - } - - if (repo.name.equalsIgnoreCase(name)) { - throw new UnloggedFailure(1, "Repository names are identical"); - } - - if (!user.canAdmin(repo)) { - throw new UnloggedFailure(1, String.format("Sorry, you do not have permission to rename %s", repository)); - } - - if (!user.canCreate(name)) { - throw new UnloggedFailure(1, String.format("Sorry, you don't have permission to move %s to %s/", repository, name)); - } - - // set the new name - repo.name = name; - - try { - gitblit.updateRepositoryModel(repository, repo, false); - stdout.println(String.format("Renamed repository %s to %s.", repository, name)); - } catch (GitBlitException e) { - String msg = String.format("Failed to rename repository from %s to %s", repository, name); - log.error(msg, e); - throw new UnloggedFailure(1, msg); - } - } - } - - @CommandMetaData(name = "set", description = "Set the specified field of a repository") - @UsageExample(syntax = "${cmd} myRepo description John's personal projects", description = "Set the description of a repository") - public static class SetField extends RepositoryCommand { - - @Argument(index = 1, required = true, metaVar = "FIELD", usage = "the field to update") - protected String fieldName; - - @Argument(index = 2, required = true, metaVar = "VALUE", usage = "the new value") - protected List<String> fieldValues = new ArrayList<String>(); - - protected enum Field { - description; - - static Field fromString(String name) { - for (Field field : values()) { - if (field.name().equalsIgnoreCase(name)) { - return field; - } - } - return null; - } - } - - @Override - protected String getUsageText() { - String fields = Joiner.on(", ").join(Field.values()); - StringBuilder sb = new StringBuilder(); - sb.append("Valid fields are:\n ").append(fields); - return sb.toString(); - } - - @Override - public void run() throws UnloggedFailure { - RepositoryModel repo = getRepository(true); - - Field field = Field.fromString(fieldName); - if (field == null) { - throw new UnloggedFailure(1, String.format("Unknown field %s", fieldName)); - } - - if (!getContext().getClient().getUser().canAdmin(repo)) { - throw new UnloggedFailure(1, String.format("Sorry, you do not have permission to administer %s", repository)); - } - - String value = Joiner.on(" ").join(fieldValues).trim(); - IGitblit gitblit = getContext().getGitblit(); - - switch(field) { - case description: - repo.description = value; - break; - default: - throw new UnloggedFailure(1, String.format("Field %s was not properly handled by the set command.", fieldName)); - } - - try { - gitblit.updateRepositoryModel(repo.name, repo, false); - stdout.println(String.format("Set %s.%s = %s", repo.name, fieldName, value)); - } catch (GitBlitException e) { - String msg = String.format("Failed to set %s.%s = %s", repo.name, fieldName, value); - log.error(msg, e); - throw new UnloggedFailure(1, msg); - } - } - - protected boolean toBool(String value) throws UnloggedFailure { - String v = value.toLowerCase(); - if (v.equals("t") - || v.equals("true") - || v.equals("yes") - || v.equals("on") - || v.equals("y") - || v.equals("1")) { - return true; - } else if (v.equals("f") - || v.equals("false") - || v.equals("no") - || v.equals("off") - || v.equals("n") - || v.equals("0")) { - return false; - } - throw new UnloggedFailure(1, String.format("Invalid boolean value %s", value)); - } - } - - @CommandMetaData(name = "remove", aliases = { "rm" }, description = "Remove a repository") - @UsageExample(syntax = "${cmd} myRepo.git", description = "Delete myRepo.git") - public static class RemoveRepository extends RepositoryCommand { - - @Override - public void run() throws UnloggedFailure { - - RepositoryModel repo = getRepository(true); - - if (!getContext().getClient().getUser().canAdmin(repo)) { - throw new UnloggedFailure(1, String.format("Sorry, you do not have permission to delete %s", repository)); - } - - IGitblit gitblit = getContext().getGitblit(); - if (gitblit.deleteRepositoryModel(repo)) { - stdout.println(String.format("%s has been deleted.", repository)); - } else { - throw new UnloggedFailure(1, String.format("Failed to delete %s!", repository)); - } - } - } - - @CommandMetaData(name = "show", description = "Show the details of a repository") - @UsageExample(syntax = "${cmd} myRepo.git", description = "Display myRepo.git") - public static class ShowRepository extends RepositoryCommand { - - @Override - public void run() throws UnloggedFailure { - - RepositoryModel r = getRepository(true); - - if (!getContext().getClient().getUser().canAdmin(r)) { - throw new UnloggedFailure(1, String.format("Sorry, you do not have permission to see the %s settings.", repository)); - } - - IGitblit gitblit = getContext().getGitblit(); - - // fields - StringBuilder fb = new StringBuilder(); - fb.append("Description : ").append(toString(r.description)).append('\n'); - fb.append("Origin : ").append(toString(r.origin)).append('\n'); - fb.append("Default Branch : ").append(toString(r.HEAD)).append('\n'); - fb.append('\n'); - fb.append("GC Period : ").append(r.gcPeriod).append('\n'); - fb.append("GC Threshold : ").append(r.gcThreshold).append('\n'); - fb.append('\n'); - fb.append("Accept Tickets : ").append(toString(r.acceptNewTickets)).append('\n'); - fb.append("Accept Patchsets : ").append(toString(r.acceptNewPatchsets)).append('\n'); - fb.append("Require Approval : ").append(toString(r.requireApproval)).append('\n'); - fb.append("Merge To : ").append(toString(r.mergeTo)).append('\n'); - fb.append('\n'); - fb.append("Incremental push tags : ").append(toString(r.useIncrementalPushTags)).append('\n'); - fb.append("Show remote branches : ").append(toString(r.showRemoteBranches)).append('\n'); - fb.append("Skip size calculations : ").append(toString(r.skipSizeCalculation)).append('\n'); - fb.append("Skip summary metrics : ").append(toString(r.skipSummaryMetrics)).append('\n'); - fb.append("Max activity commits : ").append(r.maxActivityCommits).append('\n'); - fb.append("Author metric exclusions : ").append(toString(r.metricAuthorExclusions)).append('\n'); - fb.append("Commit Message Renderer : ").append(r.commitMessageRenderer).append('\n'); - fb.append("Mailing Lists : ").append(toString(r.mailingLists)).append('\n'); - fb.append('\n'); - fb.append("Access Restriction : ").append(r.accessRestriction).append('\n'); - fb.append("Authorization Control : ").append(r.authorizationControl).append('\n'); - fb.append('\n'); - fb.append("Is Frozen : ").append(toString(r.isFrozen)).append('\n'); - fb.append("Allow Forks : ").append(toString(r.allowForks)).append('\n'); - fb.append("Verify Committer : ").append(toString(r.verifyCommitter)).append('\n'); - fb.append('\n'); - fb.append("Federation Strategy : ").append(r.federationStrategy).append('\n'); - fb.append("Federation Sets : ").append(toString(r.federationSets)).append('\n'); - fb.append('\n'); - fb.append("Indexed Branches : ").append(toString(r.indexedBranches)).append('\n'); - fb.append('\n'); - fb.append("Pre-Receive Scripts : ").append(toString(r.preReceiveScripts)).append('\n'); - fb.append(" inherited : ").append(toString(gitblit.getPreReceiveScriptsInherited(r))).append('\n'); - fb.append("Post-Receive Scripts : ").append(toString(r.postReceiveScripts)).append('\n'); - fb.append(" inherited : ").append(toString(gitblit.getPostReceiveScriptsInherited(r))).append('\n'); - String fields = fb.toString(); - - // owners - String owners; - if (r.owners.isEmpty()) { - owners = FlipTable.EMPTY; - } else { - String[] pheaders = { "Account", "Name" }; - Object [][] pdata = new Object[r.owners.size()][]; - for (int i = 0; i < r.owners.size(); i++) { - String owner = r.owners.get(i); - UserModel u = gitblit.getUserModel(owner); - pdata[i] = new Object[] { owner, u == null ? "" : u.getDisplayName() }; - } - owners = FlipTable.of(pheaders, pdata, Borders.COLS); - } - - // team permissions - List<RegistrantAccessPermission> tperms = gitblit.getTeamAccessPermissions(r); - String tpermissions; - if (tperms.isEmpty()) { - tpermissions = FlipTable.EMPTY; - } else { - String[] pheaders = { "Team", "Permission", "Type" }; - Object [][] pdata = new Object[tperms.size()][]; - for (int i = 0; i < tperms.size(); i++) { - RegistrantAccessPermission ap = tperms.get(i); - pdata[i] = new Object[] { ap.registrant, ap.permission, ap.permissionType }; - } - tpermissions = FlipTable.of(pheaders, pdata, Borders.COLS); - } - - // user permissions - List<RegistrantAccessPermission> uperms = gitblit.getUserAccessPermissions(r); - String upermissions; - if (uperms.isEmpty()) { - upermissions = FlipTable.EMPTY; - } else { - String[] pheaders = { "Account", "Name", "Permission", "Type", "Source", "Mutable" }; - Object [][] pdata = new Object[uperms.size()][]; - for (int i = 0; i < uperms.size(); i++) { - RegistrantAccessPermission ap = uperms.get(i); - String name = ""; - try { - String dn = gitblit.getUserModel(ap.registrant).displayName; - if (dn != null) { - name = dn; - } - } catch (Exception e) { - } - pdata[i] = new Object[] { ap.registrant, name, ap.permission, ap.permissionType, ap.source, ap.mutable ? "Y":"" }; - } - upermissions = FlipTable.of(pheaders, pdata, Borders.COLS); - } - - // assemble table - String title = r.name; - String [] headers = new String[] { title }; - String[][] data = new String[8][]; - data[0] = new String [] { "FIELDS" }; - data[1] = new String [] {fields }; - data[2] = new String [] { "OWNERS" }; - data[3] = new String [] { owners }; - data[4] = new String [] { "TEAM PERMISSIONS" }; - data[5] = new String [] { tpermissions }; - data[6] = new String [] { "USER PERMISSIONS" }; - data[7] = new String [] { upermissions }; - stdout.println(FlipTable.of(headers, data)); - } - - protected String toString(String val) { - if (val == null) { - return ""; - } - return val; - } - - protected String toString(Collection<?> collection) { - if (collection == null) { - return ""; - } - return Joiner.on(", ").join(collection); - } - - protected String toString(boolean val) { - if (val) { - return "Y"; - } - return ""; - } - - } - - /* 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 - protected List<RepositoryModel> getItems() { - IGitblit gitblit = getContext().getGitblit(); - UserModel user = getContext().getClient().getUser(); - List<RepositoryModel> repositories = gitblit.getRepositoryModels(user); - return repositories; - } - - @Override - protected boolean matches(String filter, RepositoryModel r) { - return r.name.matches(filter); - } - - @Override - protected void asTable(List<RepositoryModel> list) { - String[] headers; - if (verbose) { - String[] h = { "Name", "Description", "Owners", "Last Modified", "Size" }; - headers = h; - } else { - String[] h = { "Name", "Last Modified", "Size" }; - headers = h; - } - - Object[][] data = new Object[list.size()][]; - for (int i = 0; i < list.size(); i++) { - RepositoryModel r = list.get(i); - - String lm = formatDate(r.lastChange); - String size = r.size; - if (!r.hasCommits) { - lm = ""; - size = FlipTable.EMPTY; - } - if (verbose) { - String owners = ""; - if (!ArrayUtils.isEmpty(r.owners)) { - owners = Joiner.on(",").join(r.owners); - } - data[i] = new Object[] { r.name, r.description, owners, lm, size }; - } else { - data[i] = new Object[] { r.name, lm, size }; - } - } - stdout.println(FlipTable.of(headers, data, Borders.BODY_HCOLS)); - } - - @Override - protected void asTabbed(List<RepositoryModel> list) { - if (verbose) { - for (RepositoryModel r : list) { - String lm = formatDate(r.lastChange); - String owners = ""; - if (!ArrayUtils.isEmpty(r.owners)) { - owners = Joiner.on(",").join(r.owners); - } - String size = r.size; - if (!r.hasCommits) { - lm = ""; - size = "(empty)"; - } - - outTabbed(r.name, r.description == null ? "" : r.description, - owners, lm, size); - } - } else { - for (RepositoryModel r : list) { - outTabbed(r.name); - } - } - } - } -}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/ReviewCommand.java b/src/main/java/com/gitblit/transport/ssh/gitblit/ReviewCommand.java deleted file mode 100644 index b3691cbb..00000000 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/ReviewCommand.java +++ /dev/null @@ -1,89 +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 java.util.HashSet; -import java.util.Set; - -import org.kohsuke.args4j.Argument; -import org.kohsuke.args4j.Option; - -import com.gitblit.models.TicketModel.Change; -import com.gitblit.models.TicketModel.Patchset; -import com.gitblit.models.TicketModel.Score; -import com.gitblit.models.UserModel; -import com.gitblit.transport.ssh.commands.CommandMetaData; -import com.gitblit.transport.ssh.commands.SshCommand; -import com.gitblit.wicket.GitBlitWebSession; - -@CommandMetaData(name = "review", description = "Verify, approve and/or submit one or more patch sets", hidden = true) -public class ReviewCommand extends SshCommand { - - private final static short REV_ID_LEN = 40; - private final Set<Patchset> patchSets = new HashSet<Patchset>(); - - @Argument(index = 0, required = true, multiValued = true, metaVar = "{COMMIT | CHANGE,PATCHSET}", usage = "list of commits or patch sets to review") - void addPatchSetId(final String token) { - try { - patchSets.add(parsePatchSet(token)); - } catch (UnloggedFailure e) { - throw new IllegalArgumentException(e.getMessage(), e); - } - } - - @Option(name = "--project", required = true, aliases = "-p", usage = "project containing the specified patch set(s)") - private String project; - - @Option(name = "--message", aliases = "-m", usage = "cover message to publish on change(s)", metaVar = "MESSAGE") - private String changeComment; - - @Option(name = "--vote", aliases = "-v", usage = "vote on this patch set", metaVar = "VOTE") - private int vote; - - @Option(name = "--submit", aliases = "-s", usage = "submit the specified patch set(s)") - private boolean submitChange; - - @Override - public void run() throws UnloggedFailure { - UserModel user = GitBlitWebSession.get().getUser(); - // TODO ensure user has permission to score +2/-2 - for (Patchset ps : patchSets) { - // review - Change change = new Change(user.username); - change.review(ps, Score.fromScore(vote), false); - // TODO(davido): add patchset comment - if (submitChange) { - // TODO(davido): merge (when desired and the change is mergeable) - } - } - } - - private Patchset parsePatchSet(String ps) throws UnloggedFailure { - // By commit? - // - if (ps.matches("^([0-9a-fA-F]{4," + REV_ID_LEN + "})$")) { - // TODO; parse - } - - // By older style change,patchset? - // - if (ps.matches("^[1-9][0-9]*,[1-9][0-9]*$")) { - // TODO: parse - } - - throw new UnloggedFailure(1, "fatal: Cannot parse patchset: " + ps); - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/TeamsDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/TeamsDispatcher.java deleted file mode 100644 index d0ec58f0..00000000 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/TeamsDispatcher.java +++ /dev/null @@ -1,507 +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 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.GitBlitException; -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 = "teams", description = "Team management commands", admin = true) -public class TeamsDispatcher extends DispatchCommand { - - @Override - protected void setup(UserModel user) { - // primary team commands - register(user, NewTeam.class); - register(user, RenameTeam.class); - register(user, RemoveTeam.class); - register(user, ShowTeam.class); - register(user, ListTeams.class); - - // team-specific commands - register(user, SetField.class); - register(user, Permissions.class); - register(user, Members.class); - } - - public static abstract class TeamCommand extends SshCommand { - @Argument(index = 0, required = true, metaVar = "TEAM", usage = "team name") - protected String teamname; - - protected TeamModel getTeam(boolean requireTeam) throws UnloggedFailure { - IGitblit gitblit = getContext().getGitblit(); - TeamModel team = gitblit.getTeamModel(teamname); - if (requireTeam && team == null) { - throw new UnloggedFailure(1, String.format("Team %s does not exist!", teamname)); - } - return team; - } - } - - @CommandMetaData(name = "new", aliases = { "add" }, description = "Create a new team") - @UsageExample(syntax = "${cmd} contributors --canFork --canCreate") - public static class NewTeam extends TeamCommand { - - @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; - - @Override - public void run() throws UnloggedFailure { - - if (getTeam(false) != null) { - throw new UnloggedFailure(1, String.format("Team %s already exists!", teamname)); - } - - TeamModel team = new TeamModel(teamname); - team.canAdmin = canAdmin; - team.canFork = canFork; - team.canCreate = canCreate; - - IGitblit gitblit = getContext().getGitblit(); - try { - gitblit.addTeam(team); - stdout.println(String.format("%s created.", teamname)); - } catch (GitBlitException e) { - String msg = String.format("Failed to create %s!", teamname); - log.error(msg, e); - throw new UnloggedFailure(1, msg); - } - } - } - - @CommandMetaData(name = "rename", aliases = { "mv" }, description = "Rename a team") - @UsageExample(syntax = "${cmd} contributors friends", description = "Rename the contributors team to the friends team") - public static class RenameTeam extends TeamCommand { - @Argument(index = 1, required = true, metaVar = "NEWNAME", usage = "the new team name") - protected String newTeamName; - - @Override - public void run() throws UnloggedFailure { - TeamModel team = getTeam(true); - IGitblit gitblit = getContext().getGitblit(); - if (null != gitblit.getTeamModel(newTeamName)) { - throw new UnloggedFailure(1, String.format("Team %s already exists!", newTeamName)); - } - - // set the new team name - team.name = newTeamName; - - try { - gitblit.reviseTeam(teamname, team); - stdout.println(String.format("Renamed team %s to %s.", teamname, newTeamName)); - } catch (GitBlitException e) { - String msg = String.format("Failed to rename team from %s to %s", teamname, newTeamName); - log.error(msg, e); - throw new UnloggedFailure(1, msg); - } - } - } - - @CommandMetaData(name = "set", description = "Set the specified field of a team") - @UsageExample(syntax = "${cmd} contributors canFork true", description = "Allow the contributors team to fork repositories") - public static class SetField extends TeamCommand { - - @Argument(index = 1, required = true, metaVar = "FIELD", usage = "the field to update") - protected String fieldName; - - @Argument(index = 2, required = true, metaVar = "VALUE", usage = "the new value") - protected List<String> fieldValues = new ArrayList<String>(); - - protected enum Field { - mailingList, preReceive, postReceive, canAdmin, canFork, canCreate; - - static Field fromString(String name) { - for (Field field : values()) { - if (field.name().equalsIgnoreCase(name)) { - return field; - } - } - return null; - } - } - - @Override - protected String getUsageText() { - String fields = Joiner.on(", ").join(Field.values()); - StringBuilder sb = new StringBuilder(); - sb.append("Valid fields are:\n ").append(fields); - return sb.toString(); - } - - @Override - public void run() throws UnloggedFailure { - TeamModel team = getTeam(true); - - Field field = Field.fromString(fieldName); - if (field == null) { - throw new UnloggedFailure(1, String.format("Unknown field %s", fieldName)); - } - - String value = Joiner.on(" ").join(fieldValues); - IGitblit gitblit = getContext().getGitblit(); - - switch(field) { - case mailingList: - team.mailingLists.clear(); - team.mailingLists.addAll(fieldValues); - break; - case preReceive: - team.preReceiveScripts.clear(); - team.preReceiveScripts.addAll(fieldValues); - break; - case postReceive: - team.postReceiveScripts.clear(); - team.postReceiveScripts.addAll(fieldValues); - break; - case canAdmin: - team.canAdmin = toBool(value); - break; - case canFork: - team.canFork = toBool(value); - break; - case canCreate: - team.canCreate = toBool(value); - break; - default: - throw new UnloggedFailure(1, String.format("Field %s was not properly handled by the set command.", fieldName)); - } - - try { - gitblit.reviseTeam(teamname, team); - stdout.println(String.format("Set %s.%s = %s", teamname, fieldName, value)); - } catch (GitBlitException e) { - String msg = String.format("Failed to set %s.%s = %s", teamname, fieldName, value); - log.error(msg, e); - throw new UnloggedFailure(1, msg); - } - } - - protected boolean toBool(String value) throws UnloggedFailure { - String v = value.toLowerCase(); - if (v.equals("t") - || v.equals("true") - || v.equals("yes") - || v.equals("on") - || v.equals("y") - || v.equals("1")) { - return true; - } else if (v.equals("f") - || v.equals("false") - || v.equals("no") - || v.equals("off") - || v.equals("n") - || v.equals("0")) { - return false; - } - throw new UnloggedFailure(1, String.format("Invalid boolean value %s", value)); - } - } - - @CommandMetaData(name = "permissions", aliases = { "perms" }, description = "Add or remove permissions from a team") - @UsageExample(syntax = "${cmd} contributors RW:alpha/repo.git RWC:alpha/repo2.git", description = "Add or set permissions for contributors") - public static class Permissions extends TeamCommand { - - @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(); - TeamModel team = getTeam(true); - - boolean modified = false; - if (!ArrayUtils.isEmpty(removals)) { - if (removals.contains("ALL")) { - team.permissions.clear(); - } else { - for (String repo : removals) { - team.removeRepositoryPermission(repo); - log.info(String.format("Removing permission for %s from %s", repo, teamname)); - } - } - 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); - team.setRepositoryPermission(repo, ap); - log.info(String.format("Setting %s:%s for %s", ap.name(), repo, teamname)); - } - modified = true; - } - - if (modified && gitblit.updateTeamModel(teamname, team)) { - // reload & display new permissions - team = gitblit.getTeamModel(teamname); - } - - showPermissions(team); - } - - protected void showPermissions(TeamModel team) { - List<RegistrantAccessPermission> perms = team.getRepositoryPermissions(); - String[] pheaders = { "Repository", "Permission", "Type" }; - 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 }; - } - stdout.println(FlipTable.of(pheaders, pdata, Borders.BODY_HCOLS)); - } - } - - @CommandMetaData(name = "members", aliases = { "users" }, description = "Add or remove team members") - @UsageExample(syntax = "${cmd} contributors RW:alpha/repo.git RWC:alpha/repo2.git", description = "Add or set permissions for contributors") - public static class Members extends TeamCommand { - - @Argument(index = 1, multiValued = true, metaVar = "USERNAME", usage = "a username") - protected List<String> members; - - @Option(name = "--remove", aliases = { "-r" }, metaVar = "USERNAME|ALL", usage = "remove a team member") - protected List<String> removals; - - @Override - public void run() throws UnloggedFailure { - IGitblit gitblit = getContext().getGitblit(); - TeamModel team = getTeam(true); - - boolean canEditMemberships = gitblit.supportsTeamMembershipChanges(team); - if (!canEditMemberships) { - String msg = String.format("Team %s (%s) does not permit membership changes!", team.name, team.accountType); - throw new UnloggedFailure(1, msg); - } - - boolean modified = false; - if (!ArrayUtils.isEmpty(removals)) { - if (removals.contains("ALL")) { - team.users.clear(); - } else { - for (String member : removals) { - team.removeUser(member); - log.info(String.format("Removing member %s from %s", member, teamname)); - } - } - modified = true; - } - - if (!ArrayUtils.isEmpty(members)) { - for (String username : members) { - UserModel u = gitblit.getUserModel(username); - if (u == null) { - throw new UnloggedFailure(1, String.format("Unknown user %s", username)); - } - boolean canEditTeams = gitblit.supportsTeamMembershipChanges(u); - if (!canEditTeams) { - String msg = String.format("User %s (%s) does not allow team membership changes ", u.username, u.accountType); - throw new UnloggedFailure(1, msg); - } - team.addUser(username); - } - modified = true; - } - - if (modified && gitblit.updateTeamModel(teamname, team)) { - // reload & display new permissions - team = gitblit.getTeamModel(teamname); - } - - String[] headers = { "Username", "Display Name" }; - Object [][] data = new Object[team.users.size()][]; - int i = 0; - for (String username : team.users) { - UserModel u = gitblit.getUserModel(username); - data[i] = new Object[] { username, u.displayName }; - i++; - } - stdout.println(FlipTable.of(headers, data, Borders.BODY_HCOLS)); - } - } - - @CommandMetaData(name = "remove", aliases = { "rm" }, description = "Remove a team") - @UsageExample(syntax = "${cmd} contributors", description = "Delete the contributors team") - public static class RemoveTeam extends TeamCommand { - - @Override - public void run() throws UnloggedFailure { - - TeamModel team = getTeam(true); - IGitblit gitblit = getContext().getGitblit(); - if (gitblit.deleteTeamModel(team)) { - stdout.println(String.format("%s has been deleted.", teamname)); - } else { - throw new UnloggedFailure(1, String.format("Failed to delete %s!", teamname)); - } - } - } - - @CommandMetaData(name = "show", description = "Show the details of a team") - @UsageExample(syntax = "${cmd} contributors", description = "Display the 'contributors' team") - public static class ShowTeam extends TeamCommand { - - @Override - public void run() throws UnloggedFailure { - - TeamModel t = getTeam(true); - - // fields - StringBuilder fb = new StringBuilder(); - fb.append("Mailing Lists : ").append(Joiner.on(", ").join(t.mailingLists)).append('\n'); - fb.append("Type : ").append(t.accountType).append('\n'); - fb.append("Can Admin : ").append(t.canAdmin ? "Y":"").append('\n'); - fb.append("Can Fork : ").append(t.canFork ? "Y":"").append('\n'); - fb.append("Can Create : ").append(t.canCreate ? "Y":"").append('\n'); - fb.append("Pre-Receive : ").append(Joiner.on(", ").join(t.preReceiveScripts)).append('\n'); - fb.append("Post-Receive : ").append(Joiner.on(", ").join(t.postReceiveScripts)).append('\n'); - String fields = fb.toString(); - - // members - String members; - if (t.users.size() == 0) { - members = FlipTable.EMPTY; - } else { - IGitblit gitblit = getContext().getGitblit(); - String[] headers = { "Username", "Display Name" }; - Object [][] data = new Object[t.users.size()][]; - int i = 0; - for (String username : t.users) { - UserModel u = gitblit.getUserModel(username); - data[i] = new Object[] { username, u == null ? null : u.displayName }; - i++; - } - members = FlipTable.of(headers, data, Borders.COLS); - } - - // permissions - List<RegistrantAccessPermission> perms = t.getRepositoryPermissions(); - String permissions; - if (perms.isEmpty()) { - permissions = FlipTable.EMPTY; - } else { - String[] pheaders = { "Repository", "Permission", "Type" }; - 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 }; - } - permissions = FlipTable.of(pheaders, pdata, Borders.COLS); - } - - // assemble team table - String [] headers = new String[] { t.name }; - String[][] data = new String[6][]; - data[0] = new String [] { "FIELDS" }; - data[1] = new String [] { fields }; - data[2] = new String [] { "MEMBERS" }; - data[3] = new String [] { members }; - data[4] = new String [] { "PERMISSIONS" }; - data[5] = new String [] { permissions }; - stdout.println(FlipTable.of(headers, data)); - } - } - - @CommandMetaData(name = "list", aliases= { "ls" }, description = "List teams") - @UsageExamples(examples = { - @UsageExample(syntax = "${cmd}", description = "List teams as a table"), - @UsageExample(syntax = "${cmd} j.*", description = "List all teams that start with 'j'"), - }) - public static class ListTeams extends ListFilterCommand<TeamModel> { - - @Override - protected List<TeamModel> getItems() { - IGitblit gitblit = getContext().getGitblit(); - List<TeamModel> teams = gitblit.getAllTeams(); - return teams; - } - - @Override - protected boolean matches(String filter, TeamModel t) { - return t.name.matches(filter); - } - - @Override - protected void asTable(List<TeamModel> list) { - String[] headers = { "Name", "Members", "Type", "Create?", "Fork?"}; - Object[][] data = new Object[list.size()][]; - for (int i = 0; i < list.size(); i++) { - TeamModel t = list.get(i); - data[i] = new Object[] { - (t.canAdmin ? "*" : " ") + t.name, - t.users.isEmpty() ? "" : t.users.size(), - t.accountType + (t.canAdmin ? ",admin":""), - (t.canAdmin || t.canCreate) ? "Y":"", - (t.canAdmin || t.canFork) ? "Y" : ""}; - } - stdout.println(FlipTable.of(headers, data, Borders.BODY_HCOLS)); - } - - @Override - protected void asTabbed(List<TeamModel> teams) { - if (verbose) { - for (TeamModel t : teams) { - outTabbed( - t.name, - t.users.isEmpty() ? "" : t.users.size(), - t.accountType + (t.canAdmin ? ",admin":""), - (t.canAdmin || t.canCreate) ? "Y":"", - (t.canAdmin || t.canFork) ? "Y" : ""); - } - } else { - for (TeamModel u : teams) { - outTabbed((u.canAdmin ? "*" : " ") + u.name); - } - } - } - } -}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/TicketsDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/TicketsDispatcher.java deleted file mode 100644 index dd29b6ac..00000000 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/TicketsDispatcher.java +++ /dev/null @@ -1,157 +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 java.util.List; - -import org.kohsuke.args4j.Argument; - -import com.gitblit.manager.IGitblit; -import com.gitblit.models.RepositoryModel; -import com.gitblit.models.TicketModel.Status; -import com.gitblit.models.UserModel; -import com.gitblit.tickets.ITicketService; -import com.gitblit.tickets.QueryBuilder; -import com.gitblit.tickets.QueryResult; -import com.gitblit.tickets.TicketIndexer.Lucene; -import com.gitblit.transport.ssh.commands.CommandMetaData; -import com.gitblit.transport.ssh.commands.DispatchCommand; -import com.gitblit.transport.ssh.commands.ListCommand; -import com.gitblit.utils.ArrayUtils; -import com.gitblit.utils.FlipTable; -import com.gitblit.utils.FlipTable.Borders; -import com.gitblit.utils.StringUtils; - -@CommandMetaData(name = "tickets", description = "Ticket commands", hidden = true) -public class TicketsDispatcher extends DispatchCommand { - - @Override - protected void setup(UserModel user) { - register(user, ReviewCommand.class); - register(user, ListTickets.class); - } - - /* List tickets */ - @CommandMetaData(name = "list", aliases = { "ls" }, description = "List tickets") - public static class ListTickets extends ListCommand<QueryResult> { - - private final String ALL = "ALL"; - - @Argument(index = 0, metaVar = "ALL|REPOSITORY", usage = "the repository or ALL") - protected String repository; - - @Argument(index = 1, multiValued = true, metaVar="CONDITION", usage = "query condition") - protected List<String> query; - - protected String userQuery; - - @Override - protected List<QueryResult> getItems() throws UnloggedFailure { - IGitblit gitblit = getContext().getGitblit(); - ITicketService tickets = gitblit.getTicketService(); - - QueryBuilder sb = new QueryBuilder(); - if (ArrayUtils.isEmpty(query)) { - sb.and(Lucene.status.matches(Status.New.toString())).or(Lucene.status.matches(Status.Open.toString())); - } else { - StringBuilder b = new StringBuilder(); - for (String q : query) { - b.append(q).append(' '); - } - b.setLength(b.length() - 1); - sb.and(b.toString()); - } - - QueryBuilder qb; - if (StringUtils.isEmpty(repository) || ALL.equalsIgnoreCase(repository)) { - qb = sb; - userQuery = sb.build(); - } else { - qb = new QueryBuilder(); - RepositoryModel r = gitblit.getRepositoryModel(repository); - if (r == null) { - throw new UnloggedFailure(1, String.format("%s is not a repository!", repository)); - } - qb.and(Lucene.rid.matches(r.getRID())); - qb.and(sb.toSubquery().toString()); - userQuery = sb.build(); - } - - String query = qb.build(); - List<QueryResult> list = tickets.queryFor(query, 0, 0, null, true); - return list; - } - - @Override - protected void asTable(List<QueryResult> list) { - boolean forRepo = !StringUtils.isEmpty(repository) && !ALL.equalsIgnoreCase(repository); - String[] headers; - if (verbose) { - if (forRepo) { - String[] h = { "ID", "Title", "Status", "Last Modified", "Votes", "Commits" }; - headers = h; - } else { - String[] h = { "Repository", "ID", "Title", "Status", "Last Modified", "Votes", "Commits" }; - headers = h; - } - } else { - if (forRepo) { - String[] h = { "ID", "Title", "Status", "Last Modifed" }; - headers = h; - } else { - String[] h = { "Repository", "ID", "Title", "Status", "Last Modified" }; - headers = h; - } - } - - Object[][] data = new Object[list.size()][]; - for (int i = 0; i < list.size(); i++) { - QueryResult q = list.get(i); - - if (verbose) { - if (forRepo) { - data[i] = new Object[] { q.number, q.title, q.status, formatDate(q.getDate()), q.votesCount, q.patchset == null ? "": q.patchset.commits }; - } else { - data[i] = new Object[] { q.repository, q.number, q.title, q.status, formatDate(q.getDate()), q.votesCount, q.patchset == null ? "": q.patchset.commits }; - } - } else { - if (forRepo) { - data[i] = new Object[] { q.number, q.title, q.status, formatDate(q.getDate()) }; - } else { - data[i] = new Object[] { q.repository, q.number, q.title, q.status, formatDate(q.getDate()) }; - } - } - } - stdout.print(FlipTable.of(headers, data, Borders.BODY_HCOLS)); - stdout.println(" " + repository + ": " + userQuery); - stdout.println(); - } - - @Override - protected void asTabbed(List<QueryResult> list) { - if (verbose) { - for (QueryResult q : list) { - outTabbed(q.repository, q.number, q.title, q.status.toString(), - formatDate(q.getDate())); - } - } else { - for (QueryResult q : list) { - outTabbed(q.repository, q.number, q.title); - } - } - } - } -} diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/UsersDispatcher.java b/src/main/java/com/gitblit/transport/ssh/gitblit/UsersDispatcher.java deleted file mode 100644 index 1a6dee46..00000000 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/UsersDispatcher.java +++ /dev/null @@ -1,592 +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 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.GitBlitException; -import com.gitblit.Keys; -import com.gitblit.manager.IGitblit; -import com.gitblit.models.RegistrantAccessPermission; -import com.gitblit.models.RepositoryModel; -import com.gitblit.models.UserModel; -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.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, RenameUser.class); - register(user, RemoveUser.class); - register(user, ShowUser.class); - register(user, ListUsers.class); - - // user-specific commands - register(user, SetField.class); - register(user, Permissions.class); - register(user, DisableUser.class); - register(user, EnableUser.class); - } - - 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", aliases = { "add" }, 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(); - try { - gitblit.addUser(user); - stdout.println(String.format("%s created.", username)); - } catch (GitBlitException e) { - log.error("Failed to add " + username, e); - throw new UnloggedFailure(1, e.getMessage()); - } - } - } - - @CommandMetaData(name = "rename", aliases = { "mv" }, description = "Rename an account") - @UsageExample(syntax = "${cmd} john frank", description = "Rename the account from john to frank") - public static class RenameUser extends UserCommand { - @Argument(index = 1, required = true, metaVar = "NEWNAME", usage = "the new account name") - protected String newUserName; - - @Override - public void run() throws UnloggedFailure { - UserModel user = getUser(true); - IGitblit gitblit = getContext().getGitblit(); - if (null != gitblit.getTeamModel(newUserName)) { - throw new UnloggedFailure(1, String.format("Team %s already exists!", newUserName)); - } - - // set the new name - user.username = newUserName; - - try { - gitblit.reviseUser(username, user); - stdout.println(String.format("Renamed user %s to %s.", username, newUserName)); - } catch (GitBlitException e) { - String msg = String.format("Failed to rename user from %s to %s", username, newUserName); - log.error(msg, e); - throw new UnloggedFailure(1, msg); - } - } - } - - @CommandMetaData(name = "set", description = "Set the specified field of an account") - @UsageExample(syntax = "${cmd} john name John Smith", description = "Set the display name to \"John Smith\" for john's account") - public static class SetField extends UserCommand { - - @Argument(index = 1, required = true, metaVar = "FIELD", usage = "the field to update") - protected String fieldName; - - @Argument(index = 2, required = true, metaVar = "VALUE", usage = "the new value") - protected List<String> fieldValues = new ArrayList<String>(); - - protected enum Field { - name, displayName, email, password, canAdmin, canFork, canCreate, disabled; - - static Field fromString(String name) { - for (Field field : values()) { - if (field.name().equalsIgnoreCase(name)) { - return field; - } - } - return null; - } - } - - @Override - protected String getUsageText() { - String fields = Joiner.on(", ").join(Field.values()); - StringBuilder sb = new StringBuilder(); - sb.append("Valid fields are:\n ").append(fields); - return sb.toString(); - } - - @Override - public void run() throws UnloggedFailure { - UserModel user = getUser(true); - - Field field = Field.fromString(fieldName); - if (field == null) { - throw new UnloggedFailure(1, String.format("Unknown field %s", fieldName)); - } - - String value = Joiner.on(" ").join(fieldValues).trim(); - IGitblit gitblit = getContext().getGitblit(); - - boolean editCredentials = gitblit.supportsCredentialChanges(user); - boolean editDisplayName = gitblit.supportsDisplayNameChanges(user); - boolean editEmailAddress = gitblit.supportsEmailAddressChanges(user); - - String m = String.format("Can not edit %s for %s (%s)", field, user.username, user.accountType); - - switch(field) { - case name: - case displayName: - if (!editDisplayName) { - throw new UnloggedFailure(1, m); - } - user.displayName = value; - break; - case email: - if (!editEmailAddress) { - throw new UnloggedFailure(1, m); - } - user.emailAddress = value; - break; - case password: - if (!editCredentials) { - throw new UnloggedFailure(1, m); - } - int minLength = gitblit.getSettings().getInteger(Keys.realm.minPasswordLength, 5); - if (minLength < 4) { - minLength = 4; - } - if (value.trim().length() < minLength) { - throw new UnloggedFailure(1, "Password is too short."); - } - - // Optionally store the password MD5 digest. - String type = gitblit.getSettings().getString(Keys.realm.passwordStorage, "md5"); - if (type.equalsIgnoreCase("md5")) { - // store MD5 digest of password - user.password = StringUtils.MD5_TYPE + StringUtils.getMD5(value); - } else if (type.equalsIgnoreCase("combined-md5")) { - // store MD5 digest of username+password - user.password = StringUtils.COMBINED_MD5_TYPE + StringUtils.getMD5(username + value); - } else { - user.password = value; - } - - // reset the cookie - user.cookie = StringUtils.getSHA1(user.username + value); - break; - case canAdmin: - user.canAdmin = toBool(value); - break; - case canFork: - user.canFork = toBool(value); - break; - case canCreate: - user.canCreate = toBool(value); - break; - case disabled: - user.disabled = toBool(value); - break; - default: - throw new UnloggedFailure(1, String.format("Field %s was not properly handled by the set command.", fieldName)); - } - - try { - gitblit.reviseUser(username, user); - stdout.println(String.format("Set %s.%s = %s", username, fieldName, value)); - } catch (GitBlitException e) { - String msg = String.format("Failed to set %s.%s = %s", username, fieldName, value); - log.error(msg, e); - throw new UnloggedFailure(1, msg); - } - } - - protected boolean toBool(String value) throws UnloggedFailure { - String v = value.toLowerCase(); - if (v.equals("t") - || v.equals("true") - || v.equals("yes") - || v.equals("on") - || v.equals("y") - || v.equals("1")) { - return true; - } else if (v.equals("f") - || v.equals("false") - || v.equals("no") - || v.equals("off") - || v.equals("n") - || v.equals("0")) { - return false; - } - throw new UnloggedFailure(1, String.format("Invalid boolean value %s", value)); - } - } - - @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(); - 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 - StringBuilder fb = new StringBuilder(); - fb.append("Email : ").append(u.emailAddress == null ? "": u.emailAddress).append('\n'); - fb.append("Type : ").append(u.accountType).append('\n'); - fb.append("Can Admin : ").append(u.canAdmin() ? "Y":"").append('\n'); - fb.append("Can Fork : ").append(u.canFork() ? "Y":"").append('\n'); - fb.append("Can Create : ").append(u.canCreate() ? "Y":"").append('\n'); - String fields = fb.toString(); - - // teams - String teams; - if (u.teams.size() == 0) { - teams = FlipTable.EMPTY; - } else { - teams = Joiner.on(", ").join(u.teams); - } - - // owned repositories - String ownedTable; - List<RepositoryModel> owned = new ArrayList<RepositoryModel>(); - for (RepositoryModel repository : getContext().getGitblit().getRepositoryModels(u)) { - if (repository.isOwner(u.username)) { - owned.add(repository); - } - } - if (owned.isEmpty()) { - ownedTable = FlipTable.EMPTY; - } else { - String [] theaders = new String [] { "Repository", "Description" }; - Object [][] tdata = new Object[owned.size()][]; - int i = 0; - for (RepositoryModel r : owned) { - tdata[i] = new Object [] { r.name, r.description }; - i++; - } - ownedTable = FlipTable.of(theaders, tdata, Borders.COLS); - } - - // permissions - List<RegistrantAccessPermission> perms = u.getRepositoryPermissions(); - 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); - } - - // keys - String keyTable; - List<SshKey> keys = getContext().getGitblit().getPublicKeyManager().getKeys(u.username); - if (ArrayUtils.isEmpty(keys)) { - keyTable = FlipTable.EMPTY; - } else { - String[] headers = { "#", "Fingerprint", "Comment", "Type" }; - int len = keys == null ? 0 : keys.size(); - Object[][] data = new Object[len][]; - for (int i = 0; i < len; i++) { - // show 1-based index numbers with the fingerprint - // this is useful for comparing with "ssh-add -l" - SshKey k = keys.get(i); - data[i] = new Object[] { (i + 1), k.getFingerprint(), k.getComment(), k.getAlgorithm() }; - } - keyTable = FlipTable.of(headers, data, Borders.COLS); - } - - // assemble user table - 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[8][]; - data[0] = new String [] { "FIELDS" }; - data[1] = new String [] { fields }; - data[2] = new String [] { "TEAMS" }; - data[3] = new String [] { teams }; - data[4] = new String [] { "OWNED REPOSITORIES" }; - data[5] = new String [] { ownedTable }; - data[4] = new String [] { "PERMISSIONS" }; - data[5] = new String [] { permissions }; - data[6] = new String [] { "SSH PUBLIC KEYS" }; - data[7] = new String [] { keyTable }; - stdout.println(FlipTable.of(headers, data)); - } - } - - @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 - protected List<UserModel> getItems() { - IGitblit gitblit = getContext().getGitblit(); - List<UserModel> users = gitblit.getAllUsers(); - return users; - } - - @Override - protected boolean matches(String filter, UserModel u) { - return u.username.matches(filter); - } - - @Override - protected void asTable(List<UserModel> list) { - String[] headers; - if (verbose) { - String[] h = { "Name", "Display name", "Email", "Type", "Teams", "Create?", "Fork?"}; - headers = h; - } else { - String[] h = { "Name", "Display name", "Email", "Type"}; - headers = h; - } - - Object[][] data = new Object[list.size()][]; - for (int i = 0; i < list.size(); i++) { - UserModel u = list.get(i); - - String name = (u.disabled ? "-" : ((u.canAdmin() ? "*" : " "))) + u.username; - if (verbose) { - data[i] = new Object[] { - name, - u.displayName, - u.emailAddress, - u.accountType + (u.canAdmin() ? ",admin":""), - u.teams.isEmpty() ? "" : u.teams.size(), - (u.canAdmin() || u.canCreate()) ? "Y":"", - (u.canAdmin() || u.canFork()) ? "Y" : ""}; - } else { - data[i] = new Object[] { - name, - u.displayName, - u.emailAddress, - u.accountType + (u.canAdmin() ? ",admin":"")}; - } - } - stdout.print(FlipTable.of(headers, data, Borders.BODY_HCOLS)); - stdout.println(" * = admin account, - = disabled account"); - stdout.println(); - } - - @Override - protected void asTabbed(List<UserModel> users) { - if (verbose) { - for (UserModel u : users) { - outTabbed( - u.disabled ? "-" : ((u.canAdmin() ? "*" : " ")) + u.username, - u.getDisplayName(), - u.emailAddress == null ? "" : u.emailAddress, - u.accountType + (u.canAdmin() ? ",admin":""), - u.teams.isEmpty() ? "" : u.teams.size(), - (u.canAdmin() || u.canCreate()) ? "Y":"", - (u.canAdmin() || u.canFork()) ? "Y" : ""); - } - } else { - for (UserModel u : users) { - outTabbed(u.disabled ? "-" : ((u.canAdmin() ? "*" : " ")) + u.username); - } - } - } - } -}
\ No newline at end of file diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/BaseKeyCommand.java b/src/main/java/com/gitblit/transport/ssh/keys/BaseKeyCommand.java index 930c058f..588770f4 100644 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/BaseKeyCommand.java +++ b/src/main/java/com/gitblit/transport/ssh/keys/BaseKeyCommand.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.gitblit.transport.ssh.gitblit; +package com.gitblit.transport.ssh.keys; import java.io.BufferedReader; import java.io.IOException; diff --git a/src/main/java/com/gitblit/transport/ssh/gitblit/KeysDispatcher.java b/src/main/java/com/gitblit/transport/ssh/keys/KeysDispatcher.java index 9bb60003..ad373060 100644 --- a/src/main/java/com/gitblit/transport/ssh/gitblit/KeysDispatcher.java +++ b/src/main/java/com/gitblit/transport/ssh/keys/KeysDispatcher.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.gitblit.transport.ssh.gitblit; +package com.gitblit.transport.ssh.keys; import java.io.IOException; import java.util.ArrayList; |