/* Copyright (c) 2012-2014 Boundless and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/edl-v10.html
*
* Contributors:
* Michael Fawcett (LMN Solutions) - initial implementation
*/
package org.locationtech.geogig.api.porcelain;
import java.util.HashMap;
import java.util.Map;
import org.locationtech.geogig.api.AbstractGeoGigOp;
import org.locationtech.geogig.api.porcelain.ConfigException.StatusCode;
import org.locationtech.geogig.di.CanRunDuringConflict;
import org.locationtech.geogig.storage.ConfigDatabase;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
/**
* Get and set repository or global options
* <p>
* You can query/set options with this command. The name is actually the section and key separated
* by a dot.
* <p>
* Global options are usually stored in ~/.geogigconfig. Repository options will be stored in
* repo/.geogig/config
*
* @see ConfigDatabase
*/
@CanRunDuringConflict
public class ConfigOp extends AbstractGeoGigOp<Optional<Map<String, String>>> {
/**
* Enumeration of the possible actions of this command.
*/
public enum ConfigAction {
CONFIG_NO_ACTION, CONFIG_GET, CONFIG_SET, CONFIG_UNSET, CONFIG_REMOVE_SECTION, CONFIG_LIST
};
/**
* Enumeration of the possible options to pass to config --list command
*
*/
public enum ConfigScope {
LOCAL, GLOBAL, DEFAULT
};
private ConfigScope scope;
private ConfigAction action;
private String name;
private String value;
private ConfigDatabase configDbOverride;
public ConfigOp() {
//
}
@VisibleForTesting
public ConfigOp(ConfigDatabase configDb) {
this.configDbOverride = configDb;
}
@Override
protected ConfigDatabase configDatabase() {
return configDbOverride == null ? super.configDatabase() : configDbOverride;
}
/**
* Executes the config command with the specified options.
*
* @return Optional<String> if querying for a value, empty Optional if no matching name was
* found or if setting a value.
* @throws ConfigException if an error is encountered. More specific information can be found in
* the exception's statusCode.
*/
@Override
protected Optional<Map<String, String>> _call() {
final ConfigDatabase config = configDatabase();
switch (action) {
case CONFIG_GET: {
if (name == null || name.isEmpty())
throw new ConfigException(StatusCode.SECTION_OR_NAME_NOT_PROVIDED);
if (value == null || value.isEmpty()) {
Optional<String> val = Optional.absent();
if (scope == ConfigScope.GLOBAL) {
val = config.getGlobal(name);
} else {
try {
val = config.get(name);
} catch (ConfigException e) {
if (scope == ConfigScope.LOCAL) {
throw new ConfigException(e.statusCode);
}
}
// Fallback on global config file if name wasn't found locally
if (!val.isPresent()) {
val = config.getGlobal(name);
}
}
if (val.isPresent()) {
Map<String, String> resultMap = new HashMap<String, String>();
resultMap.put(name, val.get());
return Optional.of(resultMap);
}
} else {
throw new ConfigException(StatusCode.TOO_MANY_ARGS);
}
break;
}
case CONFIG_SET: {
if (name == null || name.isEmpty())
throw new ConfigException(StatusCode.SECTION_OR_NAME_NOT_PROVIDED);
if (scope == ConfigScope.GLOBAL) {
config.putGlobal(name, value);
} else {
config.put(name, value);
}
break;
}
case CONFIG_UNSET: {
if (name == null || name.isEmpty())
throw new ConfigException(StatusCode.SECTION_OR_NAME_NOT_PROVIDED);
if (scope == ConfigScope.GLOBAL) {
config.removeGlobal(name);
} else {
config.remove(name);
}
break;
}
case CONFIG_REMOVE_SECTION: {
if (name == null || name.isEmpty())
throw new ConfigException(StatusCode.SECTION_OR_NAME_NOT_PROVIDED);
if (scope == ConfigScope.GLOBAL) {
config.removeSectionGlobal(name);
} else {
config.removeSection(name);
}
break;
}
case CONFIG_LIST: {
Map<String, String> results = null;
if (scope == ConfigScope.LOCAL) {
results = config.getAll();
} else {
results = config.getAllGlobal();
if (scope == ConfigScope.DEFAULT) {
try {
Map<String, String> localresults = config.getAll();
results.putAll(localresults);
} catch (ConfigException e) {
}
}
}
return Optional.of(results);
}
default:
throw new ConfigException(StatusCode.OPTION_DOES_NOT_EXIST);
}
return Optional.absent();
}
/**
* @param scope if ConfigScope.CONFIG_GLOBAL, config actions will be executed on the global
* configuration file. If ConfigScope.CONFIG_LOCAL or ConfigScope.CONFIG_DEFAULT, then
* all actions will be done on the config file in the local repository.
* @return {@code this}
*/
public ConfigOp setScope(ConfigScope scope) {
this.scope = scope;
return this;
}
/**
* @param action the action to execute when the command is called.
* @return {@code this}
*/
public ConfigOp setAction(ConfigAction action) {
this.action = action;
return this;
}
/**
* @param name the variable name to act on
* @return {@code this}
*/
public ConfigOp setName(String name) {
this.name = name;
return this;
}
/**
* @param value the value to set
* @return {@code this}
*/
public ConfigOp setValue(String value) {
this.value = value;
return this;
}
}