use of org.kohsuke.accmod.Restricted in project configuration-as-code-plugin by jenkinsci.
the class BaseConfigurator method describe.
@NonNull
public Set<Attribute<T, ?>> describe() {
Map<String, Attribute<T, ?>> attributes = new HashMap<>();
final Set<String> exclusions = exclusions();
for (Field field : getTarget().getFields()) {
final String name = field.getName();
if (exclusions.contains(name))
continue;
if (PersistedList.class.isAssignableFrom(field.getType())) {
if (Modifier.isTransient(field.getModifiers())) {
exclusions.add(name);
continue;
}
Attribute attribute = createAttribute(name, TypePair.of(field)).getter(// get value by direct access to public final field
field::get);
attributes.put(name, attribute);
}
}
final Class<T> target = getTarget();
// TODO: Overloaded setters with different types can corrupt this logic
for (Method method : target.getMethods()) {
final String methodName = method.getName();
TypePair type;
if (method.getParameterCount() == 0 && methodName.startsWith("get") && PersistedList.class.isAssignableFrom(method.getReturnType())) {
type = TypePair.ofReturnType(method);
} else if (method.getParameterCount() != 1 || !methodName.startsWith("set")) {
// Not an accessor, ignore
continue;
} else {
type = TypePair.ofParameter(method, 0);
}
final String s = methodName.substring(3);
final String name = StringUtils.uncapitalize(s);
if (exclusions.contains(name))
continue;
if (!hasGetter(target, s)) {
// Looks like a property but no actual getter method we can use to read value
continue;
}
LOGGER.log(Level.FINER, "Processing {0} property", name);
if (Map.class.isAssignableFrom(type.rawType)) {
// yaml has support for Maps, but as nobody seem to like them we agreed not to support them
LOGGER.log(Level.FINER, "{0} is a Map<?,?>. We decided not to support Maps.", name);
continue;
}
Attribute attribute = createAttribute(name, type);
if (attribute == null)
continue;
attribute.deprecated(method.getAnnotation(Deprecated.class) != null);
final Restricted r = method.getAnnotation(Restricted.class);
if (r != null)
attribute.restrictions(r.value());
Attribute prevAttribute = attributes.get(name);
// Replace the method if it have more concretized type
if (prevAttribute == null || prevAttribute.type.isAssignableFrom(attribute.type)) {
attributes.put(name, attribute);
}
}
return new HashSet<>(attributes.values());
}
use of org.kohsuke.accmod.Restricted in project configuration-as-code-plugin by jenkinsci.
the class ConfigurationAsCode method toYaml.
@CheckForNull
// for testing only
@Restricted(NoExternalUse.class)
public Node toYaml(CNode config) throws ConfiguratorException {
if (config == null)
return null;
switch(config.getType()) {
case MAPPING:
final Mapping mapping = config.asMapping();
final List<NodeTuple> tuples = new ArrayList<>();
final List<Map.Entry<String, CNode>> entries = new ArrayList<>(mapping.entrySet());
entries.sort(Map.Entry.comparingByKey());
for (Map.Entry<String, CNode> entry : entries) {
final Node valueNode = toYaml(entry.getValue());
if (valueNode == null)
continue;
tuples.add(new NodeTuple(new ScalarNode(Tag.STR, entry.getKey(), null, null, PLAIN), valueNode));
}
if (tuples.isEmpty())
return null;
return new MappingNode(Tag.MAP, tuples, BLOCK);
case SEQUENCE:
final Sequence sequence = config.asSequence();
List<Node> nodes = new ArrayList<>();
for (CNode cNode : sequence) {
final Node valueNode = toYaml(cNode);
if (valueNode == null)
continue;
nodes.add(valueNode);
}
if (nodes.isEmpty())
return null;
return new SequenceNode(Tag.SEQ, nodes, BLOCK);
case SCALAR:
default:
final Scalar scalar = config.asScalar();
final String value = scalar.getValue();
if (value == null || value.length() == 0)
return null;
final DumperOptions.ScalarStyle style;
if (scalar.getFormat().equals(Format.MULTILINESTRING) && !scalar.isRaw()) {
style = LITERAL;
} else if (scalar.isRaw()) {
style = PLAIN;
} else {
style = DOUBLE_QUOTED;
}
return new ScalarNode(getTag(scalar.getFormat()), value, null, null, style);
}
}
use of org.kohsuke.accmod.Restricted in project configuration-as-code-plugin by jenkinsci.
the class ConfigurationAsCode method export.
@Restricted(NoExternalUse.class)
public void export(OutputStream out) throws Exception {
final List<NodeTuple> tuples = new ArrayList<>();
final ConfigurationContext context = new ConfigurationContext(registry);
for (RootElementConfigurator root : RootElementConfigurator.all()) {
final CNode config = root.describe(root.getTargetComponent(context), context);
final Node valueNode = toYaml(config);
if (valueNode == null)
continue;
tuples.add(new NodeTuple(new ScalarNode(Tag.STR, root.getName(), null, null, PLAIN), valueNode));
}
MappingNode root = new MappingNode(Tag.MAP, tuples, BLOCK);
try (Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
serializeYamlNode(root, writer);
} catch (IOException e) {
throw new YAMLException(e);
}
}
use of org.kohsuke.accmod.Restricted in project configuration-as-code-plugin by jenkinsci.
the class ConfigurationAsCode method doReplace.
@RequirePOST
@Restricted(NoExternalUse.class)
public void doReplace(StaplerRequest request, StaplerResponse response) throws Exception {
if (!Jenkins.get().hasPermission(Jenkins.ADMINISTER)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
String newSource = request.getParameter("_.newSource");
String normalizedSource = Util.fixEmptyAndTrim(newSource);
List<String> candidateSources = new ArrayList<>();
for (String candidateSource : inputToCandidateSources(normalizedSource)) {
File file = new File(candidateSource);
if (file.exists() || ConfigurationAsCode.isSupportedURI(candidateSource)) {
candidateSources.add(candidateSource);
} else {
LOGGER.log(Level.WARNING, "Source {0} could not be applied", candidateSource);
// todo: show message in UI
}
}
if (!candidateSources.isEmpty()) {
List<YamlSource> candidates = getConfigFromSources(candidateSources);
if (canApplyFrom(candidates)) {
sources = candidateSources;
configureWith(getConfigFromSources(getSources()));
CasCGlobalConfig config = GlobalConfiguration.all().get(CasCGlobalConfig.class);
if (config != null) {
config.setConfigurationPath(normalizedSource);
config.save();
}
LOGGER.log(Level.FINE, "Replace configuration with: " + normalizedSource);
} else {
LOGGER.log(Level.WARNING, "Provided sources could not be applied");
// todo: show message in UI
}
} else {
LOGGER.log(Level.FINE, "No such source exists, applying default");
// May be do nothing instead?
configure();
}
response.sendRedirect("");
}
use of org.kohsuke.accmod.Restricted in project configuration-as-code-plugin by jenkinsci.
the class ConfigurationAsCode method serializeYamlNode.
// for testing only
@Restricted(NoExternalUse.class)
public static void serializeYamlNode(Node root, Writer writer) throws IOException {
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(BLOCK);
options.setDefaultScalarStyle(PLAIN);
options.setSplitLines(true);
options.setPrettyFlow(true);
Serializer serializer = new Serializer(new Emitter(writer, options), new Resolver(), options, null);
serializer.open();
serializer.serialize(root);
serializer.close();
}
Aggregations