Proper dependency handling of files: include flags and version.

This commit is contained in:
Frederik Carlier
2017-05-07 14:22:04 +02:00
parent f7a5ac6233
commit 6bfffbb43a
9 changed files with 262 additions and 80 deletions

View File

@@ -14,23 +14,23 @@ namespace Packaging.Targets.Tests.Rpm
internal class PlistFileAnalyzer : FileAnalyzer
{
/// <inheritdoc/>
public override Collection<string> DetermineProvides(string filename, CpioHeader fileHeader, byte[] header)
public override Collection<PackageDependency> DetermineProvides(string filename, CpioHeader fileHeader, byte[] header)
{
switch (filename)
{
case "/usr/bin/plistutil":
return new Collection<string>()
return new Collection<PackageDependency>()
{
};
case "/usr/lib64/libplist++.so.3.1.0":
return new Collection<string>()
return new Collection<PackageDependency>()
{
"libplist++.so.3()(64bit)",
new PackageDependency("libplist++.so.3()(64bit)", RpmSense.RPMSENSE_FIND_PROVIDES, "")
};
case "/usr/lib64/libplist.so.3.1.0":
return new Collection<string>()
return new Collection<PackageDependency>()
{
"libplist.so.3()(64bit)",
new PackageDependency("libplist.so.3()(64bit)", RpmSense.RPMSENSE_FIND_PROVIDES, "")
};
}
@@ -38,46 +38,46 @@ namespace Packaging.Targets.Tests.Rpm
}
/// <inheritdoc/>
public override Collection<string> DetermineRequires(string filename, CpioHeader fileHeader, byte[] header)
public override Collection<PackageDependency> DetermineRequires(string filename, CpioHeader fileHeader, byte[] header)
{
switch (filename)
{
case "/usr/bin/plistutil":
return new Collection<string>()
return new Collection<PackageDependency>()
{
"libpthread.so.0(GLIBC_2.2.5)(64bit)",
"libc.so.6(GLIBC_2.2.5)(64bit)",
"libplist.so.3()(64bit)",
"libpthread.so.0()(64bit)",
"libc.so.6()(64bit)",
"rtld(GNU_HASH)"
new PackageDependency("libpthread.so.0(GLIBC_2.2.5)(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libc.so.6(GLIBC_2.2.5)(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libplist.so.3()(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libpthread.so.0()(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libc.so.6()(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("rtld(GNU_HASH)", RpmSense.RPMSENSE_FIND_REQUIRES, "")
};
case "/usr/lib64/libplist++.so.3.1.0":
return new Collection<string>()
return new Collection<PackageDependency>()
{
"libgcc_s.so.1(GCC_3.0)(64bit)",
"libpthread.so.0(GLIBC_2.2.5)(64bit)",
"libc.so.6(GLIBC_2.14)(64bit)",
"libc.so.6(GLIBC_2.2.5)(64bit)",
"libstdc++.so.6(CXXABI_1.3)(64bit)",
"libstdc++.so.6(GLIBCXX_3.4)(64bit)",
"libplist.so.3()(64bit)",
"libpthread.so.0()(64bit)",
"libstdc++.so.6()(64bit)",
"libm.so.6()(64bit)",
"libc.so.6()(64bit)",
"libgcc_s.so.1()(64bit)",
"rtld(GNU_HASH)"
new PackageDependency("libgcc_s.so.1(GCC_3.0)(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libpthread.so.0(GLIBC_2.2.5)(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libc.so.6(GLIBC_2.14)(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libc.so.6(GLIBC_2.2.5)(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libstdc++.so.6(CXXABI_1.3)(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libstdc++.so.6(GLIBCXX_3.4)(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libplist.so.3()(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libpthread.so.0()(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libstdc++.so.6()(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libm.so.6()(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libc.so.6()(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libgcc_s.so.1()(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("rtld(GNU_HASH)", RpmSense.RPMSENSE_FIND_REQUIRES, "")
};
case "/usr/lib64/libplist.so.3.1.0":
return new Collection<string>()
return new Collection<PackageDependency>()
{
"libpthread.so.0(GLIBC_2.2.5)(64bit)",
"libc.so.6(GLIBC_2.14)(64bit)",
"libc.so.6(GLIBC_2.2.5)(64bit)",
"libpthread.so.0()(64bit)",
"libc.so.6()(64bit)",
"rtld(GNU_HASH)"
new PackageDependency("libpthread.so.0(GLIBC_2.2.5)(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libc.so.6(GLIBC_2.14)(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libc.so.6(GLIBC_2.2.5)(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libpthread.so.0()(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("libc.so.6()(64bit)", RpmSense.RPMSENSE_FIND_REQUIRES, ""),
new PackageDependency("rtld(GNU_HASH)", RpmSense.RPMSENSE_FIND_REQUIRES, "")
};
}

View File

@@ -15,5 +15,10 @@ namespace Packaging.Targets.Tests.Rpm
{
base.SetStringArray(tag, value);
}
public void SetIntArrayPublic(IndexTag tag, int[] value)
{
base.SetIntArray(tag, value);
}
}
}

View File

@@ -69,7 +69,9 @@ namespace Packaging.Targets.Tests.Rpm
Assert.Equal("ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=44864a4aec49ec94f3dc1486068ff0d308e3ae37, stripped", files[0].Class);
Assert.Equal(RpmFileColor.RPMFC_ELF64, files[0].Color);
Assert.Equal(6, files[0].Requires.Count);
Assert.Equal("libpthread.so.0(GLIBC_2.2.5)(64bit)", files[0].Requires[0]);
Assert.Equal("libpthread.so.0(GLIBC_2.2.5)(64bit)", files[0].Requires[0].Name);
Assert.Equal(RpmSense.RPMSENSE_FIND_REQUIRES, files[0].Requires[0].Flags);
Assert.Equal("", files[0].Requires[0].Version);
Assert.Equal(1, files[0].Device);
Assert.Equal(RpmFileFlags.None, files[0].Flags);
Assert.Equal("root", files[0].GroupName);
@@ -144,6 +146,56 @@ namespace Packaging.Targets.Tests.Rpm
"rpmlib(PayloadIsXz)",
});
metadata.SetIntArrayPublic(
IndexTag.RPMTAG_REQUIREFLAGS,
new int[]
{
(int)(RpmSense.RPMSENSE_INTERP | RpmSense.RPMSENSE_SCRIPT_POST),
(int)(RpmSense.RPMSENSE_INTERP | RpmSense.RPMSENSE_SCRIPT_POSTUN),
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)(RpmSense.RPMSENSE_LESS | RpmSense.RPMSENSE_EQUAL | RpmSense.RPMSENSE_RPMLIB),
(int)(RpmSense.RPMSENSE_LESS | RpmSense.RPMSENSE_EQUAL | RpmSense.RPMSENSE_RPMLIB),
(int)(RpmSense.RPMSENSE_LESS | RpmSense.RPMSENSE_EQUAL | RpmSense.RPMSENSE_RPMLIB),
(int)RpmSense.RPMSENSE_FIND_REQUIRES,
(int)(RpmSense.RPMSENSE_LESS | RpmSense.RPMSENSE_EQUAL | RpmSense.RPMSENSE_RPMLIB),
});
metadata.SetStringArrayPublic(
IndexTag.RPMTAG_REQUIREVERSION,
new string[]
{
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"3.0.4-1",
"4.6.0-1",
"4.0-1",
"",
"5.2-1",
});
metadata.SetStringArrayPublic(
IndexTag.RPMTAG_PROVIDENAME,
new string[]
@@ -154,6 +206,26 @@ namespace Packaging.Targets.Tests.Rpm
"libplist.so.3()(64bit)"
});
metadata.SetIntArrayPublic(
IndexTag.RPMTAG_PROVIDEFLAGS,
new int[]
{
(int)RpmSense.RPMSENSE_FIND_PROVIDES,
(int)RpmSense.RPMSENSE_FIND_PROVIDES,
(int)RpmSense.RPMSENSE_FIND_PROVIDES,
(int)RpmSense.RPMSENSE_FIND_PROVIDES
});
metadata.SetStringArrayPublic(
IndexTag.RPMTAG_PROVIDEVERSION,
new string[]
{
"",
"",
"",
""
});
metadata.Files = files;
this.AssertTagEqual(IndexTag.RPMTAG_FILESIZES, originalPackage, package);
@@ -179,7 +251,11 @@ namespace Packaging.Targets.Tests.Rpm
this.AssertTagEqual(IndexTag.RPMTAG_DIRNAMES, originalPackage, package);
this.AssertTagEqual(IndexTag.RPMTAG_REQUIRENAME, originalPackage, package);
this.AssertTagEqual(IndexTag.RPMTAG_REQUIREFLAGS, originalPackage, package);
this.AssertTagEqual(IndexTag.RPMTAG_REQUIREVERSION, originalPackage, package);
this.AssertTagEqual(IndexTag.RPMTAG_PROVIDENAME, originalPackage, package);
this.AssertTagEqual(IndexTag.RPMTAG_REQUIREFLAGS, originalPackage, package);
this.AssertTagEqual(IndexTag.RPMTAG_REQUIREVERSION, originalPackage, package);
this.AssertTagEqual(IndexTag.RPMTAG_FILEDEPENDSN, originalPackage, package);
this.AssertTagEqual(IndexTag.RPMTAG_FILEDEPENDSX, originalPackage, package);
this.AssertTagEqual(IndexTag.RPMTAG_DEPENDSDICT, originalPackage, package);

View File

@@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Packaging.Targets.Rpm
{
/// <summary>
/// Provides extension methods for the <see cref="Collection{T}"/> class.
/// </summary>
internal static class CollectionExtensions
{
/// <summary>
/// Adds multiple values at once.
/// </summary>
/// <typeparam name="T">
/// The type of the values.
/// </typeparam>
/// <param name="collection">
/// The collection to which to add the values.
/// </param>
/// <param name="values">
/// The values to add.
/// </param>
public static void AddRange<T>(this Collection<T> collection, IEnumerable<T> values)
{
foreach(var v in values)
{
collection.Add(v);
}
}
}
}

View File

@@ -11,19 +11,19 @@ namespace Packaging.Targets.Rpm
internal class FileAnalyzer : IFileAnalyzer
{
/// <inheritdoc/>
public virtual Collection<string> DetermineRequires(string filename, CpioHeader fileHeader, byte[] header)
public virtual Collection<PackageDependency> DetermineRequires(string filename, CpioHeader fileHeader, byte[] header)
{
// For now, report no dependencies at all. Could be enhanced if ELF parsing is available.
var dependencies = new Collection<string>();
var dependencies = new Collection<PackageDependency>();
return dependencies;
}
/// <inheritdoc/>
public virtual Collection<string> DetermineProvides(string filename, CpioHeader fileHeader, byte[] header)
public virtual Collection<PackageDependency> DetermineProvides(string filename, CpioHeader fileHeader, byte[] header)
{
// For now, report no provides at all. Could be enhanced if ELF parsing is available.
var dependencies = new Collection<string>();
var dependencies = new Collection<PackageDependency>();
return dependencies;
}

View File

@@ -40,7 +40,7 @@ namespace Packaging.Targets.Rpm
/// <returns>
/// The dependencies for the file.
/// </returns>
Collection<string> DetermineRequires(string fileName, CpioHeader fileHeader, byte[] header);
Collection<PackageDependency> DetermineRequires(string fileName, CpioHeader fileHeader, byte[] header);
/// <summary>
/// Gets the dependencies fulfilled by this file.
@@ -57,7 +57,7 @@ namespace Packaging.Targets.Rpm
/// <returns>
/// The dependencies fulfilled by the file.
/// </returns>
Collection<string> DetermineProvides(string fileName, CpioHeader fileHeader, byte[] header);
Collection<PackageDependency> DetermineProvides(string fileName, CpioHeader fileHeader, byte[] header);
/// <summary>
/// Gets the <see cref="RpmFileColor"/> for this file.

View File

@@ -9,6 +9,32 @@ namespace Packaging.Targets.Rpm
/// </summary>
internal class PackageDependency
{
/// <summary>
/// Initializes a new instance of the <see cref="PackageDependency"/> class.
/// </summary>
public PackageDependency()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PackageDependency"/> class.
/// </summary>
/// <param name="name">
/// The name of the dependency.
/// </param>
/// <param name="flags">
/// The dependency flags.
/// </param>
/// <param name="version">
/// The dependency version.
/// </param>
public PackageDependency(string name, RpmSense flags, string version)
{
this.Name = name;
this.Flags = flags;
this.Version = version;
}
/// <summary>
/// Gets or sets a value indicating the dependency constraints.
/// </summary>
@@ -35,5 +61,26 @@ namespace Packaging.Targets.Rpm
get;
set;
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
var other = obj as PackageDependency;
if (other == null)
{
return false;
}
return string.Equals(this.Name, other.Name, StringComparison.Ordinal)
&& this.Flags == other.Flags
&& string.Equals(this.Version, other.Version, StringComparison.Ordinal);
}
/// <inheritdoc/>
public override string ToString()
{
return $"{this.Name} {this.Flags} {this.Version}";
}
}
}

View File

@@ -148,7 +148,7 @@ namespace Packaging.Targets.Rpm
/// Gets or sets a list of all dependencies of this file. If the file is an ELF file, the dependencies
/// are the ELF dependencies.
/// </summary>
public Collection<string> Requires
public Collection<PackageDependency> Requires
{
get;
set;
@@ -158,7 +158,7 @@ namespace Packaging.Targets.Rpm
/// Gets or sets a list of all dependencies fulfilled by this file. If the file is an ELF file,
/// these are the ELF provides.
/// </summary>
public Collection<string> Provides
public Collection<PackageDependency> Provides
{
get;
set;

View File

@@ -347,8 +347,8 @@ namespace Packaging.Targets.Rpm
for (int i = 0; i < sizes.Count; i++)
{
Collection<string> requires = new Collection<string>();
Collection<string> provides = new Collection<string>();
Collection<PackageDependency> requires = new Collection<PackageDependency>();
Collection<PackageDependency> provides = new Collection<PackageDependency>();
for (int j = dependsX[i]; j < dependsX[i] + dependsN[i]; j++)
{
@@ -359,9 +359,37 @@ namespace Packaging.Targets.Rpm
var index = value & 0x00ffffff;
var values = this.GetStringArray(dependencyType);
var dependency = values[index];
Collection<string> versions;
RpmSense[] types;
switch(dependencyType)
switch (dependencyType)
{
case IndexTag.RPMTAG_REQUIRENAME:
versions = this.GetStringArray(IndexTag.RPMTAG_REQUIREVERSION);
types = this.GetIntArray(IndexTag.RPMTAG_REQUIREFLAGS).Select(e => (RpmSense)e).ToArray();
break;
case IndexTag.RPMTAG_PROVIDENAME:
versions = this.GetStringArray(IndexTag.RPMTAG_PROVIDEVERSION);
types = this.GetIntArray(IndexTag.RPMTAG_PROVIDEFLAGS).Select(e => (RpmSense)e).ToArray();
break;
default:
throw new ArgumentOutOfRangeException(nameof(dependencyType));
}
var dependencyName = values[index];
var dependencyVersion = versions[index];
var dependencyFlags = types[index];
var dependency = new PackageDependency()
{
Flags = dependencyFlags,
Name = dependencyName,
Version = dependencyVersion
};
switch (dependencyType)
{
case IndexTag.RPMTAG_REQUIRENAME:
requires.Add(dependency);
@@ -437,16 +465,18 @@ namespace Packaging.Targets.Rpm
var classDict = new Collection<string>();
var dependsDict = new Collection<int>();
var requireNames = new Collection<string>();
foreach (var requireName in this.GetStringArray(IndexTag.RPMTAG_REQUIRENAME))
{
requireNames.Add(requireName);
}
var requireFlags = new Collection<RpmSense>();
var requireVersions = new Collection<string>();
requireNames.AddRange(this.GetStringArray(IndexTag.RPMTAG_REQUIRENAME));
requireFlags.AddRange(this.GetIntArray(IndexTag.RPMTAG_REQUIREFLAGS).Select(v => (RpmSense)v));
requireVersions.AddRange(this.GetStringArray(IndexTag.RPMTAG_REQUIREVERSION));
var provideNames = new Collection<string>();
foreach (var provideName in this.GetStringArray(IndexTag.RPMTAG_PROVIDENAME))
{
provideNames.Add(provideName);
}
var provideFlags = new Collection<RpmSense>();
var provideVersions = new Collection<string>();
provideNames.AddRange(this.GetStringArray(IndexTag.RPMTAG_PROVIDENAME));
provideFlags.AddRange(this.GetIntArray(IndexTag.RPMTAG_PROVIDEFLAGS).Select(v => (RpmSense)v));
provideVersions.AddRange(this.GetStringArray(IndexTag.RPMTAG_PROVIDEVERSION));
for (int i = 0; i < files.Length; i++)
{
@@ -483,24 +513,6 @@ namespace Packaging.Targets.Rpm
dirIndexes[i] = dirNames.IndexOf(dirName);
baseNames[i] = fileName;
/*
Collection<string> dependencies = new Collection<string>();
for (int j = dependsX[i]; j < dependsX[i] + dependsN[i]; j++)
{
// https://github.com/rpm-software-management/rpm/blob/8f509d669b9ae79c86dd510c5a4bc5109f60d733/build/rpmfc.c#L734
var value = dependsDict[j];
var dependencyType = GetDependencyTag((char)((value >> 24) & 0xFF));
var index = value & 0x00ffffff;
var values = this.GetStringArray(dependencyType);
var dependency = values[index];
dependencies.Add(dependency);
}*/
int dependX = dependsDict.Count;
dependsN[i] = file.Requires.Count + file.Provides.Count;
dependsX[i] = dependsN[i] == 0 ? 0 : dependX;
@@ -509,12 +521,15 @@ namespace Packaging.Targets.Rpm
{
byte type = (byte)GetDependencyType(IndexTag.RPMTAG_PROVIDENAME);
if (!provideNames.Contains(provide))
if (!provideNames.Contains(provide.Name))
{
provideNames.Add(provide);
// Incomplete - we should check for not only name but also flags & version
provideNames.Add(provide.Name);
provideFlags.Add(provide.Flags);
provideVersions.Add(provide.Version);
}
var index = provideNames.IndexOf(provide);
var index = provideNames.IndexOf(provide.Name);
index |= (type << 24);
dependsDict.Add(index);
@@ -524,12 +539,15 @@ namespace Packaging.Targets.Rpm
{
byte type = (byte)GetDependencyType(IndexTag.RPMTAG_REQUIRENAME);
if (!requireNames.Contains(dependency))
if (!requireNames.Contains(dependency.Name))
{
requireNames.Add(dependency);
// Incomplete - we should check for not only name but also flags & version
requireNames.Add(dependency.Name);
requireFlags.Add(dependency.Flags);
requireVersions.Add(dependency.Version);
}
var index = requireNames.IndexOf(dependency);
var index = requireNames.IndexOf(dependency.Name);
index |= (type << 24);
dependsDict.Add(index);
@@ -561,7 +579,11 @@ namespace Packaging.Targets.Rpm
this.SetStringArray(IndexTag.RPMTAG_CLASSDICT, classDict.ToArray());
this.SetIntArray(IndexTag.RPMTAG_DEPENDSDICT, dependsDict.ToArray());
this.SetStringArray(IndexTag.RPMTAG_REQUIRENAME, requireNames.ToArray());
this.SetIntArray(IndexTag.RPMTAG_REQUIREFLAGS, requireFlags.Select(v => (int)v).ToArray());
this.SetStringArray(IndexTag.RPMTAG_REQUIREVERSION, requireVersions.ToArray());
this.SetStringArray(IndexTag.RPMTAG_PROVIDENAME, provideNames.ToArray());
this.SetIntArray(IndexTag.RPMTAG_PROVIDEFLAGS, provideFlags.Select(v => (int)v).ToArray());
this.SetStringArray(IndexTag.RPMTAG_PROVIDEVERSION, provideVersions.ToArray());
}
}
@@ -696,6 +718,7 @@ namespace Packaging.Targets.Rpm
{
return this.GetValue<Collection<int>>(tag, IndexType.RPM_INT32_TYPE, true);
}
protected void SetIntArray(IndexTag tag, int[] value)
{
this.SetValue(tag, IndexType.RPM_INT32_TYPE, value);