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 @@ -210,6 +210,11 @@ private static String extractDepFull(String requirementLine) {
}

private String[] splitToNameVersion(String nameVersion) {
// Strip PEP 508 environment markers (everything after ";")
int markerIndex = nameVersion.indexOf(';');
if (markerIndex != -1) {
nameVersion = nameVersion.substring(0, markerIndex).trim();
}
String[] result;
if (nameVersion.matches(
"[a-zA-Z0-9-_()]+={2}[0-9]{1,4}[.][0-9]{1,4}(([.][0-9]{1,4})|([.][a-zA-Z0-9]+)|([a-zA-Z0-9]+)|([.][a-zA-Z0-9]+[.][a-z-A-Z0-9]+))?")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,31 +388,24 @@ public static String getDependencyName(String dep) {
requirement = requirement.substring(0, extrasStart) + requirement.substring(extrasEnd + 1);
}
}
int rightTriangleBracket = requirement.indexOf(">");
int leftTriangleBracket = requirement.indexOf("<");
int equalsSign = requirement.indexOf("=");
int minimumIndex = getFirstSign(rightTriangleBracket, leftTriangleBracket, equalsSign);
// Find the first PEP 508 version operator character (~=, !=, ==, >=, <=, >, <, ===)
int firstOperatorChar = -1;
for (int i = 0; i < requirement.length(); i++) {
char c = requirement.charAt(i);
if (c == '>' || c == '<' || c == '=' || c == '~' || c == '!') {
firstOperatorChar = i;
break;
}
}
String depName;
if (rightTriangleBracket == -1 && leftTriangleBracket == -1 && equalsSign == -1) {
if (firstOperatorChar == -1) {
depName = requirement;
} else {
depName = requirement.substring(0, minimumIndex);
depName = requirement.substring(0, firstOperatorChar);
}
return depName.trim();
}

private static int getFirstSign(
int rightTriangleBracket, int leftTriangleBracket, int equalsSign) {
rightTriangleBracket = rightTriangleBracket == -1 ? 999 : rightTriangleBracket;
leftTriangleBracket = leftTriangleBracket == -1 ? 999 : leftTriangleBracket;
equalsSign = equalsSign == -1 ? 999 : equalsSign;
return equalsSign < leftTriangleBracket && equalsSign < rightTriangleBracket
? equalsSign
: (leftTriangleBracket < equalsSign && leftTriangleBracket < rightTriangleBracket
? leftTriangleBracket
: rightTriangleBracket);
}

static List<String> splitPipShowLines(String pipShowOutput) {
return Arrays.stream(
pipShowOutput.split(System.lineSeparator() + "---" + System.lineSeparator()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,39 @@ void Test_The_ProvideComponent_Path_Should_Throw_Exception() {
.isThrownBy(() -> new PythonPipProvider(Path.of(".")).provideComponent());
}

@Test
void getIgnoredDependencies_strips_environment_markers() throws IOException {
Path tempFile = Files.createTempFile("requirements", ".txt");
try {
Files.writeString(
tempFile,
String.join(
System.lineSeparator(),
"requests==2.25.1 ; python_version >= \"3.6\" #trustify-da-ignore",
"idna==2.10 ; python_version >= \"3.6\" # trustify-da-ignore",
"six==1.16.0 ; python_version < \"3.0\" or python_version >= \"3.3\""
+ " #trustify-da-ignore",
"chardet==4.0.0 ; python_version >= \"3.6\" and sys_platform == \"linux\""
+ " #trustify-da-ignore",
"flask==2.0.3"));
var provider = new PythonPipProvider(tempFile);
var ignored = provider.getIgnoredDependencies(Files.readString(tempFile));
var ignoredMap =
ignored.stream()
.collect(
java.util.stream.Collectors.toMap(
com.github.packageurl.PackageURL::getName,
com.github.packageurl.PackageURL::getVersion));
assertThat(ignoredMap).containsEntry("requests", "2.25.1");
assertThat(ignoredMap).containsEntry("idna", "2.10");
assertThat(ignoredMap).containsEntry("six", "1.16.0");
assertThat(ignoredMap).containsEntry("chardet", "4.0.0");
assertThat(ignoredMap).doesNotContainKey("flask");
} finally {
Files.deleteIfExists(tempFile);
}
}

private String dropIgnored(String s) {
return s.replaceAll("\\s+", "").replaceAll("\"timestamp\":\"[a-zA-Z0-9\\-\\:]+\"", "");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,16 @@ void get_Dependency_Name_with_markers() {
PythonControllerRealEnv.getDependencyName("certifi==2023.7.22 ; python_version >= \"3\""));
}

/** Verifies getDependencyName handles compatibility (~=) and exclusion (!=) operators. */
@Test
void get_Dependency_Name_with_compatibility_and_exclusion_operators() {
assertEquals("urllib3", PythonControllerRealEnv.getDependencyName("urllib3~=1.26.0"));
assertEquals("click", PythonControllerRealEnv.getDependencyName("click!=7.1.1"));
assertEquals("certifi", PythonControllerRealEnv.getDependencyName("certifi>=2021.0.0"));
assertEquals("package", PythonControllerRealEnv.getDependencyName("package~=2.0"));
assertEquals("package", PythonControllerRealEnv.getDependencyName("package!=1.0.0"));
}

/** Verifies getDependencyName strips PEP 508 extras from requirements. */
@Test
void get_Dependency_Name_with_extras() {
Expand All @@ -313,6 +323,17 @@ void get_Dependency_Name_with_extras() {
"package[extra1]>=1.0 ; python_version >= \"3.8\""));
}

/** Verifies getDependencyName handles extras combined with special version operators. */
@Test
void get_Dependency_Name_with_extras_and_special_operators() {
assertEquals(
"requests", PythonControllerRealEnv.getDependencyName("requests[security,socks]==2.25.1"));
assertEquals("httpx", PythonControllerRealEnv.getDependencyName("httpx [http2] >=0.23.0"));
assertEquals(
"package",
PythonControllerRealEnv.getDependencyName("package[extra]~=1.0 ; python_version >= \"3\""));
}

@Test
void automaticallyInstallPackageOnEnvironment() {
assertFalse(pythonControllerRealEnv.automaticallyInstallPackageOnEnvironment());
Expand Down
Loading