Skip to content

Commit

Permalink
Automate spring-security.xsd
Browse files Browse the repository at this point in the history
Closes gh-13819
  • Loading branch information
rwinch committed Sep 14, 2023
1 parent ff4745a commit 5b293d2
Show file tree
Hide file tree
Showing 5 changed files with 263 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.bundling.Zip
import org.springframework.gradle.xsd.CreateVersionlessXsdTask

public class SchemaZipPlugin implements Plugin<Project> {

Expand All @@ -15,7 +16,10 @@ public class SchemaZipPlugin implements Plugin<Project> {
schemaZip.archiveClassifier = 'schema'
schemaZip.description = "Builds -${schemaZip.archiveClassifier} archive containing all " +
"XSDs for deployment at static.springframework.org/schema."

def versionlessXsd = project.tasks.create("versionlessXsd", CreateVersionlessXsdTask) {
description = "Generates spring-security.xsd"
versionlessXsdFile = project.layout.buildDirectory.file("versionlessXsd/spring-security.xsd")
}
project.rootProject.subprojects.each { module ->

module.getPlugins().withType(JavaPlugin.class).all {
Expand All @@ -36,17 +40,14 @@ public class SchemaZipPlugin implements Plugin<Project> {
duplicatesStrategy 'exclude'
from xsdFile.path
}
}
File symlink = module.sourceSets.main.resources.find {
it.path.endsWith('org/springframework/security/config/spring-security.xsd')
}
if (symlink != null) {
schemaZip.into('security') {
duplicatesStrategy 'exclude'
from symlink.path
}
versionlessXsd.getInputFiles().from(xsdFile.path)
}
}
}

schemaZip.into("security") {
from(versionlessXsd.getOutputs())
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright 2019-2023 the original author or authors.
*
* 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
*
* https://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 org.springframework.gradle.xsd;

import org.gradle.api.DefaultTask;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.*;
import org.gradle.work.DisableCachingByDefault;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Creates the spring-security.xsd automatically
*
* @author Rob Winch
*/
@DisableCachingByDefault(because = "not worth it")
public abstract class CreateVersionlessXsdTask extends DefaultTask {

@InputFiles
public abstract ConfigurableFileCollection getInputFiles();

@OutputFile
abstract RegularFileProperty getVersionlessXsdFile();

@TaskAction
void createVersionlessXsd() throws IOException {
XsdFileMajorMinorVersion largest = null;
ConfigurableFileCollection inputFiles = getInputFiles();
if (inputFiles.isEmpty()) {
throw new IllegalStateException("No Inputs configured");
}
for (File file : inputFiles) {
XsdFileMajorMinorVersion current = XsdFileMajorMinorVersion.create(file);
if (current == null) {
continue;
}
if (largest == null) {
largest = current;
}
else if (current.getVersion().isGreaterThan(largest.getVersion())) {
largest = current;
}
}
if (largest == null) {
throw new IllegalStateException("Could not create versionless xsd file because no files matching spring-security-<digit>.xsd were found in " + inputFiles.getFiles());
}
Path to = getVersionlessXsdFile().getAsFile().get().toPath();
Path from = largest.getFile().toPath();
Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
}

static class XsdFileMajorMinorVersion {
private final File file;

private final MajorMinorVersion version;

private XsdFileMajorMinorVersion(File file, MajorMinorVersion version) {
this.file = file;
this.version = version;
}

private static final Pattern FILE_MAJOR_MINOR_VERSION_PATTERN = Pattern.compile("^spring-security-(\\d+)\\.(\\d+)\\.xsd$");

/**
* If matches xsd with major minor version (e.g. spring-security-5.1.xsd returns it, otherwise null
* @param file
* @return
*/
static XsdFileMajorMinorVersion create(File file) {
String fileName = file.getName();
Matcher matcher = FILE_MAJOR_MINOR_VERSION_PATTERN.matcher(fileName);
if (!matcher.find()) {
return null;
}
int major = Integer.parseInt(matcher.group(1));
int minor = Integer.parseInt(matcher.group(2));
MajorMinorVersion version = new MajorMinorVersion(major, minor);
return new XsdFileMajorMinorVersion(file, version);
}

public File getFile() {
return file;
}

public MajorMinorVersion getVersion() {
return version;
}
}

static class MajorMinorVersion {
private final int major;

private final int minor;

MajorMinorVersion(int major, int minor) {
this.major = major;
this.minor = minor;
}

public int getMajor() {
return major;
}

public int getMinor() {
return minor;
}

public boolean isGreaterThan(MajorMinorVersion version) {
if (getMajor() > version.getMajor()) {
return true;
}
if (getMajor() < version.getMajor()) {
return false;
}
if (getMinor() > version.getMinor()) {
return true;
}
if (getMinor() < version.getMinor()) {
return false;
}
// they are equal
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2019-2023 the original author or authors.
*
* 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
*
* https://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 org.springframework.gradle.xsd;

import org.junit.jupiter.api.Test;
import org.springframework.gradle.xsd.CreateVersionlessXsdTask.MajorMinorVersion;
import org.springframework.gradle.xsd.CreateVersionlessXsdTask.XsdFileMajorMinorVersion;

import java.io.File;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

/**
* @author Rob Winch
*/
class CreateVersionlessXsdTaskTests {

@Test
void xsdCreateWhenValid() {
File file = new File("spring-security-2.0.xsd");
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
assertThat(xsdFile).isNotNull();
assertThat(xsdFile.getFile()).isEqualTo(file);
assertThat(xsdFile.getVersion().getMajor()).isEqualTo(2);
assertThat(xsdFile.getVersion().getMinor()).isEqualTo(0);
}

@Test
void xsdCreateWhenPatchReleaseThenNull() {
File file = new File("spring-security-2.0.1.xsd");
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
assertThat(xsdFile).isNull();
}

@Test
void xsdCreateWhenNotXsdFileThenNull() {
File file = new File("spring-security-2.0.txt");
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
assertThat(xsdFile).isNull();
}

@Test
void xsdCreateWhenNotStartWithSpringSecurityThenNull() {
File file = new File("spring-securityNO-2.0.xsd");
XsdFileMajorMinorVersion xsdFile = XsdFileMajorMinorVersion.create(file);
assertThat(xsdFile).isNull();
}

@Test
void isGreaterWhenMajorLarger() {
MajorMinorVersion larger = new MajorMinorVersion(2,0);
MajorMinorVersion smaller = new MajorMinorVersion(1,0);
assertThat(larger.isGreaterThan(smaller)).isTrue();
assertThat(smaller.isGreaterThan(larger)).isFalse();
}

@Test
void isGreaterWhenMinorLarger() {
MajorMinorVersion larger = new MajorMinorVersion(1,1);
MajorMinorVersion smaller = new MajorMinorVersion(1,0);
assertThat(larger.isGreaterThan(smaller)).isTrue();
assertThat(smaller.isGreaterThan(larger)).isFalse();
}

@Test
void isGreaterWhenMajorAndMinorLarger() {
MajorMinorVersion larger = new MajorMinorVersion(2,1);
MajorMinorVersion smaller = new MajorMinorVersion(1,0);
assertThat(larger.isGreaterThan(smaller)).isTrue();
assertThat(smaller.isGreaterThan(larger)).isFalse();
}

@Test
void isGreaterWhenSame() {
MajorMinorVersion first = new MajorMinorVersion(1,0);
MajorMinorVersion second = new MajorMinorVersion(1,0);
assertThat(first.isGreaterThan(second)).isFalse();
assertThat(second.isGreaterThan(first)).isFalse();
}
}
11 changes: 11 additions & 0 deletions config/spring-security-config.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.gradle.xsd.CreateVersionlessXsdTask

apply plugin: 'io.spring.convention.spring-module'
apply plugin: 'trang'
Expand Down Expand Up @@ -113,6 +114,16 @@ dependencies {
testRuntimeOnly 'org.hsqldb:hsqldb'
}

def versionlessXsd = project.tasks.create("versionlessXsd", CreateVersionlessXsdTask) {
inputFiles.from(project.sourceSets.main.resources)
versionlessXsdFile = project.layout.buildDirectory.file("versionlessXsd/spring-security.xsd")
}

processResources {
from(versionlessXsd) {
into 'org/springframework/security/config/'
}
}

rncToXsd {
rncDir = file('src/main/resources/org/springframework/security/config/')
Expand Down

This file was deleted.

0 comments on commit 5b293d2

Please sign in to comment.