Skip to content

VOL 00 / CH 05 / LESSON 05

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.

bash
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)'
deactivate

The 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 ​

bash
(
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:

bash
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.App

The 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:

bash
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 ​

  1. Print the runtime and tool versions to confirm that the expected version of the project is being executed.
  2. Distinguish between network/authentication issues, version mismatches, validation, compilation, and classpath errors during runtime.
  3. Examine the dependency tree and import paths without deleting the lock file first.
  4. Mirrors are part of the supply chain configuration. Do not permanently write tutorial mirrors into the global configuration, and do not submit credentials.
  5. Record the path before clearing the cache; cache corruption is not the cause of all installation errors.

Cleaning Up ​

bash
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.

→ Next Chapter: Reading Errors and Logs

Built with VitePress | Software Systems Atlas