5.5 Dependency and Build Tool Integration Experiment
Prerequisites: Pages 1–4 of this chapter
Estimated time: 25–35 minutes
Exercise environment: Bash, Python 3, Node/npm, and Java; Maven and Gradle require native tools and an offline cache
You are ready to continue when: you can complete the experiment in a temporary directory and explain why an offline build fails due to missing cache items
The dependency, manifest, and version rules are now separate. This lab uses a temporary workspace created by mktemp and does not modify the repository or global configuration. The Python and npm exercises install no third-party dependencies; Maven and Gradle use only local tools and existing caches. If a tool is missing, skip that section instead of changing global package sources.
1. Python Virtual Environment
Run the first two lines to create $workdir even if you skip Python; later sections need this directory variable. The remaining commands require Python with venv and pip available.
workdir=$(mktemp -d)
mkdir -p "$workdir/py-demo"
python3 -m venv "$workdir/py-demo/.venv"
. "$workdir/py-demo/.venv/bin/activate"
python -m pip --version
python -m pip list
python -c 'import sys; print(sys.prefix != sys.base_prefix)'
deactivateThe last line of Python output should be True. The PowerShell activation script is located at .venv\Scripts\Activate.ps1.
2. npm Manifest and Empty Dependency Lock
(
mkdir -p "$workdir/node-demo"
cd "$workdir/node-demo"
npm_config_cache="$workdir/npm-cache"
export npm_config_cache
npm init -y
npm pkg set scripts.check="node -e \"console.log('ok')\""
npm install --package-lock-only --ignore-scripts --offline --no-audit --no-fund
npm run check
test -f package.json
test -f package-lock.json
)The parentheses run these commands in a subshell, so its npm cache variable and directory changes disappear when it exits. Expect npm run check to print ok. This step has no third-party dependencies. package-lock.json still records the root project, and npm's logs and cache are directed to a temporary directory. When real projects add packages, they need to access the configured npm registry.
3. Minimal Maven Project
If command -v mvn finds Maven 3.6.3+ and mvn --version reports JDK 17, create the project:
mkdir -p "$workdir/maven-demo/src/main/java/example"
cat > "$workdir/maven-demo/pom.xml" <<'XML'
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>example.workshop</groupId>
<artifactId>maven-demo</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
</plugin>
</plugins>
</build>
</project>
XML
cat > "$workdir/maven-demo/src/main/java/example/App.java" <<'JAVA'
package example;
public final class App {
public static void main(String[] args) {
System.out.println("build tool ok");
}
}
JAVA
cd "$workdir/maven-demo"
mvn -o package
java -cp target/classes example.AppThe pinned compiler plugin supports maven.compiler.release; after successful compilation the program should print build tool ok. -o prevents Maven's resolver from contacting remote repositories; it is not a network sandbox for arbitrary plugin code. If the local Maven cache does not have the build plugin, the command will fail; deleting -o will access the repository configured in the POM and settings. When the project is officially used, it should generate and submit the Maven Wrapper.
4. Minimal Gradle Project
If command -v gradle can locate Gradle 7 or higher with a version compatible with the local JDK, set up an independent project. Even if the previous section was skipped because Maven was unavailable, this can still run:
mkdir -p "$workdir/gradle-demo/src/main/java/example"
cat > "$workdir/gradle-demo/src/main/java/example/App.java" <<'JAVA'
package example;
public final class App {
public static void main(String[] args) {
System.out.println("build tool ok");
}
}
JAVA
cat > "$workdir/gradle-demo/build.gradle" <<'GRADLE'
plugins {
id 'java'
id 'application'
}
application {
mainClass = 'example.App'
}
GRADLE
cd "$workdir/gradle-demo"
gradle --offline --no-daemon build
gradle --offline --no-daemon run--offline requires that the Gradle distribution, plugins, and dependencies are available; do not misattribute missing items as Java compilation errors. --no-daemon avoids a persistent background process, but differing JVM arguments may still require a single-use daemon that exits after the build. Gradle reads and writes its user cache; a temporary project does not isolate that cache. See the Gradle Daemon documentation. Real projects should submit the Gradle Wrapper and use ./gradlew instead of the native gradle.
Troubleshooting
- Print the runtime and tool versions to confirm that the expected version of the project is being executed.
- Distinguish between network/authentication issues, version mismatches, validation, compilation, and classpath errors during runtime.
- Examine the dependency tree and import paths without deleting the lock file first.
- Mirrors are part of the supply chain configuration. Do not permanently write tutorial mirrors into the global configuration, and do not submit credentials.
- Record the path before clearing the cache; cache corruption is not the cause of all installation errors.
Cleaning Up
cd
ls -ld -- "$workdir"
rm -r -- "$workdir"After cleaning the temporary directory, retain three kinds of evidence: what the project declares, what the resolver selects, and which toolchain performs the build. The next chapter starts debugging a failure log from its exit code, stderr, and stack trace.