Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import org.sourcegrade.jagr.core.export.rubric.GermanCSVExporter
import org.sourcegrade.jagr.core.export.rubric.MoodleJSONExporter
import org.sourcegrade.jagr.core.export.submission.EclipseSubmissionExporter
import org.sourcegrade.jagr.core.export.submission.GradleSubmissionExporter
import org.sourcegrade.jagr.core.extra.ExtrasManagerImpl
import org.sourcegrade.jagr.core.io.SerializationFactoryLocatorImpl
import org.sourcegrade.jagr.core.rubric.CriterionFactoryImpl
import org.sourcegrade.jagr.core.rubric.CriterionHolderPointCalculatorFactoryImpl
Expand All @@ -56,7 +55,6 @@ import org.sourcegrade.jagr.launcher.env.ModuleFactory
import org.sourcegrade.jagr.launcher.executor.GradingQueue
import org.sourcegrade.jagr.launcher.executor.RuntimeGrader
import org.sourcegrade.jagr.launcher.executor.RuntimeInvoker
import org.sourcegrade.jagr.launcher.io.ExtrasManager
import org.sourcegrade.jagr.launcher.io.GradedRubricExporter
import org.sourcegrade.jagr.launcher.io.SerializerFactory
import org.sourcegrade.jagr.launcher.io.SubmissionExporter
Expand All @@ -74,7 +72,6 @@ class CommonModule(private val configuration: LaunchConfiguration) : AbstractMod
bind(ClassTransformer.Factory::class.java).to(ClassTransformerFactoryImpl::class.java)
bind(Criterion.Factory::class.java).to(CriterionFactoryImpl::class.java)
bind(CriterionHolderPointCalculator.Factory::class.java).to(CriterionHolderPointCalculatorFactoryImpl::class.java)
bind(ExtrasManager::class.java).to(ExtrasManagerImpl::class.java)
bind(GradedRubricExporter.CSV::class.java).to(GermanCSVExporter::class.java)
bind(GradedRubricExporter.HTML::class.java).to(BasicHTMLExporter::class.java)
bind(GradedRubricExporter.Moodle::class.java).to(MoodleJSONExporter::class.java)
Expand Down

This file was deleted.

36 changes: 36 additions & 0 deletions docs/usage/command-line/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## Basic Command-Line Usage

1. Create a [grader](architecture/grader)
2. Create a [submission](architecture/submission)
3. Download the [latest release](https://github.com/sourcegrade/jagr/releases)

!!! tip

The [jagr-bin](https://aur.archlinux.org/packages/jagr-bin) package is available on the AUR for Arch Linux users.

4. Create an empty working directory and copy the Jagr jar into it
5. Run `java -jar Jagr-x.jar`, which should create the following folder structure:

```text
./graders -- input folder for grader jars (tests and rubric providers)
./libs -- for libraries that are required on each submission's classpath
./logs -- saved log files
./rubrics -- the output folder for graded rubrics
./submissions -- input folder for submissions
./submissions-export -- output folder for submissions
```

6. Prepare the grader and submission for grading
1. Prepare the grader jar by running the `graderBuildGrader` Gradle task in the grader project
2. Prepare the submission jar by running the `mainBuildSubmission` Gradle task in the submission project
3. Locate the respective jars in the `build/libs` folder of the grader and submission projects

7. Copy the grader jar into the `graders` folder and the submission jar into the `submissions` folder.
If the grader requires any runtime dependencies (that are not already included in Jagr), copy them into the `libs` folder

!!! tip

The `graderBuildLibs` gradle task provided by the jagr-gradle plugin can be used to generate a fat jar containing all runtime dependencies.
This task automatically excludes dependencies already present in the Jagr runtime.

8. Run `java -jar Jagr-x-x-x.jar` again to grade the submission
1 change: 1 addition & 0 deletions docs/usage/command-line/moodle-unpack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Moodle Unpack
8 changes: 8 additions & 0 deletions docs/usage/command-line/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ Progress bar style.

Choices: "rainbow", "xmas"

### --create-moodle-unpack-config

Creates default moodle unpack config at the requested path and exits.

### --moodle-unpack, -m

Runs a moodle unpack with the given configuration.

### --child (internal)

Waits to receive grading job details via IPC
39 changes: 39 additions & 0 deletions docs/usage/extras/moodle-unpack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Moodle Unpack


## JSON Format

| Name | JSON Key | Default Value |
|---------------------------------------------------------|---------------------------|-------------------------------------------------------------------------------------------------------|
| [Moodle Zip Regex](#moodle-zip-regex) | `moodleZipRegex` | `.*[.]zip` |
| [Assignment Id Regex](#assignment-id-regex) | `assignmentIdRegex` | `.*Abgabe[^0-9]*(?<assignmentId>[0-9]{1,2}).*[.]zip` |
| [Assignment Id Transformer](#assignment-id-transformer) | `assignmentIdTransformer` | `h%id%` |
| [Student Id Regex](#student-id-regex) | `studentIdRegex` | <code>.* - (?<studentId>([a-z]{2}[0-9]{2}[a-z]{4})&#124;([a-z]+_[a-z]+))/submissions/.*[.]jar`</code> |

### Moodle Zip Regex

`moodleZipRegex`

Matches "moodle zip" file names that should be unpacked using this config.

### Assignment Id Regex


The "moodle zip" has a specific path format from which it is usually possible to extract an assignment id.
This is useful for bulk grading where individual submissions may not have correct information.
The format of this regex depends on the name of the submission module in moodle.

### Assignment Id Transformer



The assignment ids extracted from the "moodle zip" are numeric only.
Use this option to transform each numeric assignment id to match the intended full assignment id.
By default, this is "h%id" which prefixes the id with 'h'.

### Student Id Regex

`studentIdRegex`

The "moodle zip" contains each submission at a path that includes the student id.
This regex parses and extracts the id.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Jagr - SourceGrade.org
* Copyright (C) 2021-2022 Alexander Staeding
* Copyright (C) 2021-2022 Contributors
* Copyright (C) 2021-2025 Alexander Städing
* Copyright (C) 2021-2025 Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand All @@ -27,7 +27,6 @@ data class Config(
@field:Comment("The locations of the following directories may be configured here")
val dir: Dir = Dir(),
val executor: Executor = Executor(),
val extras: Extras = Extras(),
val transformers: Transformers = Transformers(),
)

Expand Down Expand Up @@ -106,22 +105,6 @@ invocations of checkTimeout() will result in an AssertionFailedError
val timeoutTotal: Long = 150_000L,
)

@ConfigSerializable
data class Extras(
val moodleUnpack: MoodleUnpack = MoodleUnpack(),
) {
@ConfigSerializable
data class MoodleUnpack(
override val enabled: Boolean = true,
val assignmentIdRegex: String = ".*Abgabe[^0-9]*(?<assignmentId>[0-9]{1,2}).*[.]zip",
val studentRegex: String = ".* - (?<studentId>([a-z]{2}[0-9]{2}[a-z]{4})|([a-z]+_[a-z]+))/submissions/.*[.]jar",
) : Extra

interface Extra {
val enabled: Boolean
}
}

@ConfigSerializable
data class Transformers(
val timeout: TimeoutTransformer = TimeoutTransformer(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import org.apache.logging.log4j.Logger
import org.sourcegrade.jagr.launcher.executor.GradingQueue
import org.sourcegrade.jagr.launcher.executor.RuntimeGrader
import org.sourcegrade.jagr.launcher.executor.RuntimeInvoker
import org.sourcegrade.jagr.launcher.io.ExtrasManager
import org.sourcegrade.jagr.launcher.extra.ExtrasManager
import org.sourcegrade.jagr.launcher.io.SerializerFactory
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KClass
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Jagr - SourceGrade.org
* Copyright (C) 2021-2022 Alexander Staeding
* Copyright (C) 2021-2022 Contributors
* Copyright (C) 2021-2024 Alexander Städing
* Copyright (C) 2021-2024 Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand All @@ -17,9 +17,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.sourcegrade.jagr.core.extra
package org.sourcegrade.jagr.launcher.env

interface Extra {
val name: String
fun run()
}
data class MoodleUnpackConfig(
val moodleZipRegex: String = ".*[.]zip",
val assignmentIdRegex: String = ".*Abgabe[^0-9]*(?<assignmentId>[0-9]{1,2}).*[.]zip",
val assignmentIdTransformer: String = "h%id",
val studentIdRegex: String = ".* - (?<studentId>([a-z]{2}[0-9]{2}[a-z]{4})|([a-z]+_[a-z]+))/submissions/.*[.]jar",
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Jagr - SourceGrade.org
* Copyright (C) 2021-2022 Alexander Staeding
* Copyright (C) 2021-2022 Contributors
* Copyright (C) 2021-2025 Alexander Städing
* Copyright (C) 2021-2025 Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand All @@ -17,8 +17,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.sourcegrade.jagr.launcher.io
package org.sourcegrade.jagr.launcher.extra

interface ExtrasManager {
fun runExtras()
}
import com.google.inject.Inject

class ExtrasManager @Inject constructor(
val moodleUnpack: MoodleUnpack.Factory
)
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Jagr - SourceGrade.org
* Copyright (C) 2021-2022 Alexander Staeding
* Copyright (C) 2021-2022 Contributors
* Copyright (C) 2021-2025 Alexander Städing
* Copyright (C) 2021-2025 Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand All @@ -17,40 +17,43 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.sourcegrade.jagr.core.extra
package org.sourcegrade.jagr.launcher.extra

import com.google.inject.Inject
import org.apache.logging.log4j.Logger
import org.sourcegrade.jagr.launcher.env.Config
import org.sourcegrade.jagr.launcher.env.MoodleUnpackConfig
import java.io.File
import java.util.zip.ZipEntry
import java.util.zip.ZipFile

class MoodleUnpack @Inject constructor(
class MoodleUnpack private constructor(
override val config: Config,
override val logger: Logger,
private val moodleUnpackConfig: MoodleUnpackConfig,
) : Unpack() {
private val assignmentIdRegex = config.extras.moodleUnpack.assignmentIdRegex.toRegex()
override val name: String = "moodle-unpack"
override fun run() {
val submissions = File(config.dir.submissions)
val studentRegex = Regex(config.extras.moodleUnpack.studentRegex)
val moodleZipRegex = Regex(moodleUnpackConfig.moodleZipRegex)
val assignmentIdRegex = Regex(moodleUnpackConfig.assignmentIdRegex)
val studentRegex = Regex(moodleUnpackConfig.studentRegex)
val idRegex = Regex("%id%")
val assignmentIdTransformer = { id: String -> moodleUnpackConfig.assignmentIdTransformer.replace(idRegex, id) }
val unpackedFiles: MutableList<SubmissionInfoVerification> = mutableListOf()
for (candidate in submissions.listFiles { _, t -> t.endsWith(".zip") }!!) {
logger.info("extra($name) :: Discovered candidate zip $candidate")
for (candidate in submissions.listFiles { _, name -> name.matches(moodleZipRegex) }!!) {
logger.info("moodle-unpack :: Discovered candidate zip $candidate")
val zipFile = ZipFile(candidate)
// TODO: Fix this hack
val assignmentId = assignmentIdRegex.matchEntire(candidate.name)
?.run { groups["assignmentId"]?.value }
?.padStart(length = 2, padChar = '0')
?.let { "h$it" }
?.let(assignmentIdTransformer)
?: "none"
for (entry in zipFile.entries()) {
val matcher = studentRegex.matchEntire(entry.name) ?: continue
try {
unpackedFiles += zipFile.unpackEntry(entry, submissions, assignmentId, matcher)
} catch (e: Throwable) {
logger.info("extra($name) :: Unable to unpack entry ${entry.name} in candidate $candidate", e)
logger.info("moodle-unpack :: Unable to unpack entry ${entry.name} in candidate $candidate", e)
}
}
}
Expand Down Expand Up @@ -78,4 +81,11 @@ class MoodleUnpack @Inject constructor(
studentId = studentId,
)
}

class Factory @Inject constructor(
val config: Config,
val logger: Logger,
) {
fun create(moodleUnpackConfig: MoodleUnpackConfig): MoodleUnpack = MoodleUnpack(config, logger, moodleUnpackConfig)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Jagr - SourceGrade.org
* Copyright (C) 2021-2022 Alexander Staeding
* Copyright (C) 2021-2022 Contributors
* Copyright (C) 2021-2025 Alexander Städing
* Copyright (C) 2021-2025 Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
Expand All @@ -17,14 +17,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package org.sourcegrade.jagr.core.extra
package org.sourcegrade.jagr.launcher.extra

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.SerializationException
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.apache.logging.log4j.Logger
import org.sourcegrade.jagr.launcher.env.Config
Expand All @@ -35,7 +33,9 @@ import java.nio.file.FileSystems
import kotlin.io.path.bufferedReader
import kotlin.io.path.bufferedWriter

abstract class Unpack : Extra {
abstract class Unpack {

abstract fun run()

protected abstract val config: Config
protected abstract val logger: Logger
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ nav:
- Command Line:
- Basics: usage/command-line/basics.md
- Options: usage/command-line/options.md
- Extras:
- Moodle Unpack: usage/extras/moodle-unpack.md
- Development:
- Getting Started:
- Gradle Setup: development/getting-started/gradle-setup.md
Expand Down
Loading