Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development: Allow all filenames in programming exercise templates #8684

Merged
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
7aaa340
Development: Include git resources in jar
magaupp May 27, 2024
49ada25
Development: Filter directories from ResourceLoaderService
magaupp May 27, 2024
301d1e1
Development: Rename ResourceLoaderService methods to clarify behavior
magaupp May 27, 2024
7678a1f
Development: Add ResourceLoaderService tests
magaupp May 27, 2024
89930f5
Development: Apply filename replacements of resource files
magaupp May 28, 2024
262baf6
Development: Remove filename replacement test
magaupp May 28, 2024
65e7f18
Development: Remove local exception handling
magaupp May 29, 2024
c76621c
Merge branch 'develop' into chore/programming-exercises/allow-all-tem…
magaupp Jun 1, 2024
59759b4
Fix filtering for other resource types
magaupp Jun 3, 2024
dd44e62
Merge branch 'refs/heads/develop' into chore/programming-exercises/al…
magaupp Jun 3, 2024
895be28
Add Javadoc for getFileResources
magaupp Jun 3, 2024
e323780
Merge branch 'develop' into chore/programming-exercises/allow-all-tem…
magaupp Jun 5, 2024
c17aad9
Merge branch 'develop' into chore/programming-exercises/allow-all-tem…
magaupp Jun 7, 2024
5019c2e
Merge branch 'develop' into chore/programming-exercises/allow-all-tem…
magaupp Jun 9, 2024
82c1894
Merge branch 'refs/heads/develop' into chore/programming-exercises/al…
magaupp Jun 16, 2024
81cd641
Merge branch 'develop' into chore/programming-exercises/allow-all-tem…
magaupp Jun 21, 2024
167901e
Merge branch 'develop' into chore/programming-exercises/allow-all-tem…
magaupp Jun 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.apache.tools.ant.DirectoryScanner

pluginManagement {
plugins {
id 'org.springframework.boot' version "${spring_boot_version}"
Expand All @@ -11,3 +13,7 @@ pluginManagement {
}

rootProject.name = 'Artemis'

// needed for programming exercise templates
DirectoryScanner.removeDefaultExclude "**/.gitattributes"
DirectoryScanner.removeDefaultExclude "**/.gitignore"
31 changes: 1 addition & 30 deletions src/main/java/de/tum/in/www1/artemis/service/FileService.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,6 @@ public class FileService implements DisposableBean {

public static final String PICTURE_FILE_SUBPATH = "/api/files/drag-and-drop/drag-items/";

/**
* Filenames for which the template filename differs from the filename it should have in the repository.
*/
// @formatter:off
private static final Map<String, String> FILENAME_REPLACEMENTS = Map.ofEntries(
Map.entry("git.ignore.file", ".gitignore"),
Map.entry("git.attributes.file", ".gitattributes"),
Map.entry("Makefile.file", "Makefile"),
Map.entry("dune.file", "dune"),
Map.entry("Fast.file", "Fastfile"),
Map.entry("App.file", "Appfile"),
Map.entry("Scan.file", "Scanfile"),
Map.entry("gradlew.file", "gradlew"));
// @formatter:on

/**
* These directories get falsely marked as files and should be ignored during copying.
*/
Expand Down Expand Up @@ -421,8 +406,7 @@ private Path generateTargetPath(final Resource resource, final Path prefix, fina
filePath = Path.of(url);
}

final Path targetPath = generateTargetPath(filePath, prefix, targetDirectory, keepParentDirectory);
return applyFilenameReplacements(targetPath);
return generateTargetPath(filePath, prefix, targetDirectory, keepParentDirectory);
}

/**
Expand Down Expand Up @@ -467,19 +451,6 @@ private List<Path> getPathElements(final Path path) {
return elements;
}

/**
* Replaces filenames where the template name differs from the name the file should have in the repository.
*
* @param originalTargetPath The path to a file.
* @return The path with replacements applied where necessary.
*/
private Path applyFilenameReplacements(final Path originalTargetPath) {
final Path filename = originalTargetPath.getFileName();

final String newFilename = FILENAME_REPLACEMENTS.getOrDefault(filename.toString(), filename.toString());
return originalTargetPath.getParent().resolve(newFilename);
}

/**
* Checks if the given path has been identified as a file, but it actually points to a directory.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
Expand Down Expand Up @@ -37,7 +38,7 @@ public class ResourceLoaderService {

private static final Logger log = LoggerFactory.getLogger(ResourceLoaderService.class);

private static final String ALL_FILES_GLOB = "**" + File.separator + "*.*";
private static final String ALL_PATHS_ANT_PATTERN = "**";

@Value("${artemis.template-path:#{null}}")
private Optional<Path> templateFileSystemPath;
Expand Down Expand Up @@ -68,7 +69,7 @@ public Resource getResource(final Path path) {

// Try to load from filesystem if override is allowed for path
if (isOverrideAllowed(path)) {
final String resourceLocation = getFileResourceLocation(path);
final String resourceLocation = getFileSystemResourceLocation(path);
resource = resourceLoader.getResource(resourceLocation);
}

Expand All @@ -84,20 +85,20 @@ public Resource getResource(final Path path) {
/**
* Recursively loads the resources from the specified directory.
* <p>
* Only relative paths are allowed.
* Only relative paths are allowed. Does not return directories.
*
* @param basePath A relative path pattern to a resource.
* @return The resources located by the specified pathPattern.
*/
@NotNull
public Resource[] getResources(final Path basePath) {
return getResources(basePath, ALL_FILES_GLOB);
public Resource[] getFileResources(final Path basePath) {
return getFileResources(basePath, ALL_PATHS_ANT_PATTERN);
}

/**
* Loads the resources from the specified path pattern.
* <p>
* Only relative paths are allowed.
* Only relative paths are allowed. Does not return directories.
* <p>
* Examples for path patterns: {@code *.sh}, {@code base/**}. Use forward slashes to separate path parts.
*
Expand All @@ -106,16 +107,16 @@ public Resource[] getResources(final Path basePath) {
* @return The resources located by the specified pathPattern.
*/
@NotNull
public Resource[] getResources(final Path basePath, final String pattern) {
public Resource[] getFileResources(final Path basePath, final String pattern) {
magaupp marked this conversation as resolved.
Show resolved Hide resolved
checkValidPathElseThrow(basePath);

Resource[] resources = null;

// Try to load from filesystem if override is allowed for pathPattern
if (isOverrideAllowed(basePath)) {
final String resourceLocation = getFileResourceLocation(basePath, pattern);
final String resourceLocation = getFileSystemResourceLocation(basePath, pattern);
try {
resources = resourceLoader.getResources(resourceLocation);
resources = getFileResources(resourceLocation);
}
catch (IOException e) {
log.debug("Could not load resources '{}' from filesystem.", resourceLocation, e);
Expand All @@ -126,7 +127,7 @@ public Resource[] getResources(final Path basePath, final String pattern) {
if (resources == null || resources.length == 0) {
final String resourceLocation = getClassPathResourceLocation(basePath, pattern);
try {
resources = resourceLoader.getResources(resourceLocation);
resources = getFileResources(resourceLocation);
}
catch (IOException e) {
log.debug("Could not load resources '{}' from classpath.", resourceLocation, e);
Expand All @@ -136,17 +137,30 @@ public Resource[] getResources(final Path basePath, final String pattern) {
return Objects.requireNonNullElseGet(resources, () -> new Resource[0]);
}

private Resource[] getFileResources(final String resourceLocation) throws IOException {
final var fileAndDirectoryResources = resourceLoader.getResources(resourceLocation);

final var fileResources = new ArrayList<Resource>();
for (final var resource : fileAndDirectoryResources) {
if (resource.getFile().isFile()) {
fileResources.add(resource);
}
}

return fileResources.toArray(Resource[]::new);
}

private void checkValidPathElseThrow(final Path path) {
if (path.isAbsolute()) {
throw new IllegalArgumentException("Cannot load resources from absolute paths!");
}
}

private String getFileResourceLocation(final Path resourcePath) {
private String getFileSystemResourceLocation(final Path resourcePath) {
return "file:" + resolveResourcePath(resourcePath).toString();
}

private String getFileResourceLocation(final Path resourcePath, final String pathPattern) {
private String getFileSystemResourceLocation(final Path resourcePath, final String pathPattern) {
final String systemPathPattern = File.separator + adaptPathPatternToSystem(pathPattern);
return "file:" + resolveResourcePath(resourcePath).toString() + systemPathPattern;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public BuildScriptProviderService(ResourceLoaderService resourceLoaderService) {
*/
@EventListener(ApplicationReadyEvent.class)
public void cacheOnBoot() {
var resources = this.resourceLoaderService.getResources(Path.of("templates", "aeolus"));
var resources = this.resourceLoaderService.getFileResources(Path.of("templates", "aeolus"));
for (var resource : resources) {
try {
String filename = resource.getFilename();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public AeolusTemplateService(ProgrammingLanguageConfiguration programmingLanguag
@EventListener(ApplicationReadyEvent.class)
public void cacheOnBoot() {
// load all scripts into the cache
var resources = this.resourceLoaderService.getResources(Path.of("templates", "aeolus"));
var resources = this.resourceLoaderService.getFileResources(Path.of("templates", "aeolus"));
for (var resource : resources) {
try {
String filename = resource.getFilename();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,13 @@ private Resource[] getTemplateResources(ProgrammingExercise exercise, String fil
// Get general template resources
final Path programmingLanguageTemplate = ProgrammingExerciseService.getProgrammingLanguageTemplatePath(exercise.getProgrammingLanguage());

Resource[] templatePoms = resourceLoaderService.getResources(programmingLanguageTemplate, filePattern);
Resource[] templatePoms = resourceLoaderService.getFileResources(programmingLanguageTemplate, filePattern);

// Get project type specific template resources
if (exercise.getProjectType() != null) {
final Path projectTypeTemplate = ProgrammingExerciseService.getProgrammingLanguageProjectTypePath(exercise.getProgrammingLanguage(), exercise.getProjectType());

final Resource[] projectTypePoms = resourceLoaderService.getResources(projectTypeTemplate, filePattern);
final Resource[] projectTypePoms = resourceLoaderService.getFileResources(projectTypeTemplate, filePattern);

// Prefer project type specific resources
templatePoms = projectTypePoms.length > 0 ? projectTypePoms : templatePoms;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ private RepositoryResources getRepositoryResources(final ProgrammingExercise pro
// Get path, files and prefix for the programming-language dependent files. They are copied first.
final Path generalTemplatePath = ProgrammingExerciseService.getProgrammingLanguageTemplatePath(programmingExercise.getProgrammingLanguage())
.resolve(projectTypeTemplateDir);
Resource[] resources = resourceLoaderService.getResources(generalTemplatePath);
Resource[] resources = resourceLoaderService.getFileResources(generalTemplatePath);

Path prefix = Path.of(programmingLanguage).resolve(projectTypeTemplateDir);

Expand All @@ -152,7 +152,7 @@ private RepositoryResources getRepositoryResources(final ProgrammingExercise pro
final Path projectTypeSpecificPrefix = generalProjectTypePrefix.resolve(projectTypeTemplateDir);
final Path projectTypeTemplatePath = programmingLanguageProjectTypePath.resolve(projectTypeTemplateDir);

final Resource[] projectTypeSpecificResources = resourceLoaderService.getResources(projectTypeTemplatePath);
final Resource[] projectTypeSpecificResources = resourceLoaderService.getFileResources(projectTypeTemplatePath);

if (ProjectType.XCODE.equals(projectType)) {
// For Xcode, we don't share source code, so we only copy files once
Expand Down Expand Up @@ -312,7 +312,7 @@ private void setupJVMTestTemplateAndPush(final RepositoryResources resources, fi
// Java supports multiple variants as test template
final Path projectTemplatePath = getJavaProjectTemplatePath(templatePath, projectType);

final Resource[] projectTemplate = resourceLoaderService.getResources(projectTemplatePath);
final Resource[] projectTemplate = resourceLoaderService.getFileResources(projectTemplatePath);
// keep the folder structure
fileService.copyResources(projectTemplate, Path.of("projectTemplate"), repoLocalPath, true);

Expand Down Expand Up @@ -375,7 +375,7 @@ private void setupJVMTestTemplateProjectTypeResources(final RepositoryResources
final Path projectTypeProjectTemplatePath = projectTypeTemplatePath.resolve("projectTemplate");

try {
final Resource[] projectTypeProjectTemplate = resourceLoaderService.getResources(projectTypeProjectTemplatePath);
final Resource[] projectTypeProjectTemplate = resourceLoaderService.getFileResources(projectTypeProjectTemplatePath);
fileService.copyResources(projectTypeProjectTemplate, resources.projectTypePrefix, repoLocalPath, false);
}
catch (FileNotFoundException fileNotFoundException) {
Expand All @@ -397,7 +397,7 @@ private void setupTestTemplateRegularTestRuns(final RepositoryResources resource
final ProjectType projectType = programmingExercise.getProjectType();
final Path repoLocalPath = getRepoAbsoluteLocalPath(resources.repository);
final Path testFilePath = templatePath.resolve(TEST_FILES_PATH);
final Resource[] testFileResources = resourceLoaderService.getResources(testFilePath);
final Resource[] testFileResources = resourceLoaderService.getFileResources(testFilePath);
final Path packagePath = repoLocalPath.resolve(TEST_DIR).resolve(PACKAGE_NAME_FOLDER_PLACEHOLDER).toAbsolutePath();

sectionsMap.put("non-sequential", true);
Expand Down Expand Up @@ -440,7 +440,7 @@ private void setupBuildToolProjectFile(final Path repoLocalPath, final ProjectTy

private void setupStaticCodeAnalysisConfigFiles(final RepositoryResources resources, final Path templatePath, final Path repoLocalPath) throws IOException {
final Path staticCodeAnalysisConfigPath = templatePath.resolve("staticCodeAnalysisConfig");
final Resource[] staticCodeAnalysisResources = resourceLoaderService.getResources(staticCodeAnalysisConfigPath);
final Resource[] staticCodeAnalysisResources = resourceLoaderService.getFileResources(staticCodeAnalysisConfigPath);
fileService.copyResources(staticCodeAnalysisResources, resources.prefix, repoLocalPath, true);
}

Expand All @@ -450,7 +450,7 @@ private void overwriteProjectTypeSpecificFiles(final RepositoryResources resourc
.resolve(TEST_DIR);

try {
final Resource[] projectTypeTestFileResources = resourceLoaderService.getResources(projectTypeTemplatePath);
final Resource[] projectTypeTestFileResources = resourceLoaderService.getFileResources(projectTypeTemplatePath);
// filter non-existing resources to avoid exceptions
final List<Resource> existingProjectTypeTestFileResources = new ArrayList<>();
for (final Resource resource : projectTypeTestFileResources) {
Expand Down Expand Up @@ -562,7 +562,7 @@ private void setupBuildStage(final Path resourcePrefix, final Path templatePath,
}

final Path buildStageResourcesPath = templatePath.resolve(TEST_FILES_PATH).resolve(buildStageTemplateSubDirectory);
final Resource[] buildStageResources = resourceLoaderService.getResources(buildStageResourcesPath);
final Resource[] buildStageResources = resourceLoaderService.getFileResources(buildStageResourcesPath);
fileService.copyResources(buildStageResources, resourcePrefix, packagePath, false);

if (projectType != null) {
Expand All @@ -574,7 +574,7 @@ private void overwriteStageFilesForProjectType(final Path resourcePrefix, final
throws IOException {
final Path buildStageResourcesPath = projectTemplatePath.resolve(TEST_FILES_PATH).resolve(buildStageTemplateSubDirectory);
try {
final Resource[] buildStageResources = resourceLoaderService.getResources(buildStageResourcesPath);
final Resource[] buildStageResources = resourceLoaderService.getFileResources(buildStageResourcesPath);
fileService.copyResources(buildStageResources, resourcePrefix, packagePath, false);
}
catch (FileNotFoundException fileNotFoundException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,26 +382,12 @@ void testCopyResourceRemovePrefix(@TempDir Path targetDir) throws IOException {
assertThat(expectedTargetFile).exists().isNotEmptyFile();
}

@Test
void testRenameSpecialFilename(@TempDir Path targetDir) throws IOException {
final Path sourceFile = overridableBasePath.resolve("Makefile.file");
FileUtils.writeStringToFile(sourceFile.toFile(), "content", Charset.defaultCharset());

final Resource[] resources = resourceLoaderService.getResources(overridableBasePath);
assertThat(resources).isNotEmpty();

fileService.copyResources(resources, Path.of("templates"), targetDir, true);

final Path expectedTargetFile = targetDir.resolve("jenkins").resolve("Makefile");
assertThat(expectedTargetFile).exists().isNotEmptyFile();
}

@Test
void testIgnoreDirectoryFalsePositives(@TempDir Path targetDir) throws IOException {
final Path sourceDirectory = overridableBasePath.resolve("package.xcworkspace");
Files.createDirectories(sourceDirectory);

final Resource[] resources = resourceLoaderService.getResources(overridableBasePath);
final Resource[] resources = resourceLoaderService.getFileResources(overridableBasePath);
assertThat(resources).isNotEmpty();

fileService.copyResources(resources, Path.of("templates"), targetDir, true);
Expand Down
Loading
Loading