-
Notifications
You must be signed in to change notification settings - Fork 104
Adding support for pub package manager #888
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
93b7e1c
d618d27
a575567
56c99b6
5174fd0
b04c9f1
922841c
10b168a
8d3d725
19c4a8a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,4 +56,7 @@ public enum ComponentType : byte | |
|
||
[EnumMember] | ||
Conan = 17, | ||
|
||
[EnumMember] | ||
Pub = 18, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
namespace Microsoft.ComponentDetection.Contracts.TypedComponent; | ||
|
||
public class PubComponent : TypedComponent | ||
{ | ||
public PubComponent() | ||
{ | ||
/* Reserved for deserialization */ | ||
} | ||
|
||
public PubComponent(string name, string version, string dependency, string hash = null, string url = null) | ||
{ | ||
this.Name = this.ValidateRequiredInput(name, nameof(this.Name), nameof(ComponentType.Pub)); | ||
this.Version = this.ValidateRequiredInput(version, nameof(this.Version), nameof(ComponentType.Pub)); | ||
this.Dependency = dependency; | ||
this.Hash = hash; // Not required; | ||
this.Url = url; | ||
} | ||
|
||
public string Name { get; } | ||
|
||
public string Version { get; } | ||
|
||
public string Hash { get; } | ||
|
||
public string Url { get; } | ||
|
||
public string Dependency { get; } | ||
|
||
public override ComponentType Type => ComponentType.Pub; | ||
|
||
public override string Id => $"{this.Name} {this.Version} - {this.Type}"; | ||
|
||
public override string ToString() | ||
{ | ||
return $"Name={this.Name}\tVersion={this.Version}\tUrl={this.Url}"; | ||
} | ||
|
||
protected bool Equals(PubComponent other) => this.Name == other.Name && this.Version == other.Version && this.Hash == other.Hash && this.Url == other.Url && this.Dependency == other.Dependency; | ||
|
||
public override bool Equals(object obj) | ||
{ | ||
if (obj is null) | ||
{ | ||
return false; | ||
} | ||
|
||
if (ReferenceEquals(this, obj)) | ||
{ | ||
return true; | ||
} | ||
|
||
if (obj.GetType() != this.GetType()) | ||
{ | ||
return false; | ||
} | ||
|
||
return this.Equals((PubComponent)obj); | ||
} | ||
|
||
public override int GetHashCode() => this.Name.GetHashCode() ^ this.Version.GetHashCode() ^ this.Hash.GetHashCode() ^ this.Url.GetHashCode() ^ this.Dependency.GetHashCode(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
namespace Microsoft.ComponentDetection.Detectors.Pub; | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Threading.Tasks; | ||
using Microsoft.ComponentDetection.Contracts; | ||
using Microsoft.ComponentDetection.Contracts.Internal; | ||
using Microsoft.ComponentDetection.Contracts.TypedComponent; | ||
using Microsoft.Extensions.Logging; | ||
using YamlDotNet.Serialization; | ||
|
||
public class PubComponentDetector : FileComponentDetector, IDefaultOffComponentDetector | ||
Check failure on line 13 in src/Microsoft.ComponentDetection.Detectors/pub/PubComponentDetector.cs
|
||
{ | ||
public PubComponentDetector( | ||
IComponentStreamEnumerableFactory componentStreamEnumerableFactory, | ||
IObservableDirectoryWalkerFactory walkerFactory, | ||
ILogger<PubComponentDetector> logger) | ||
{ | ||
this.ComponentStreamEnumerableFactory = componentStreamEnumerableFactory; | ||
this.Scanner = walkerFactory; | ||
this.Logger = logger; | ||
} | ||
|
||
public override string Id => "pub"; | ||
|
||
public override IEnumerable<string> Categories => new[] { Enum.GetName(typeof(DetectorClass), DetectorClass.Pub) }; | ||
|
||
public override IEnumerable<ComponentType> SupportedComponentTypes { get; } = new[] { ComponentType.Pub }; | ||
|
||
public override int Version => 1; | ||
|
||
public override IList<string> SearchPatterns => new List<string> { "pubspec.lock" }; | ||
|
||
protected override async Task OnFileFoundAsync(ProcessRequest processRequest, IDictionary<string, string> detectorArgs) | ||
Check failure on line 35 in src/Microsoft.ComponentDetection.Detectors/pub/PubComponentDetector.cs
|
||
{ | ||
try | ||
{ | ||
using var reader = new StreamReader(processRequest.ComponentStream.Stream); | ||
var text = await reader.ReadToEndAsync(); | ||
|
||
var deserializer = new DeserializerBuilder().IgnoreUnmatchedProperties().Build(); | ||
var parsedFile = deserializer.Deserialize<PubSpecLock>(text); | ||
this.Logger.LogDebug("SDK {Dart}", parsedFile.Sdks.Dart); | ||
|
||
foreach (var package in parsedFile.Packages) | ||
{ | ||
if (package.Value.Source == "hosted") | ||
{ | ||
var component = new PubComponent( | ||
package.Value.GetName(), | ||
package.Value.Version, | ||
package.Value.Dependency, | ||
package.Value.GetSha256(), | ||
package.Value.GePackageDownloadedSource()); | ||
this.Logger.LogInformation("Registering component {Package}", component); | ||
|
||
processRequest.SingleFileComponentRecorder.RegisterUsage(new DetectedComponent(component)); | ||
} | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
this.Logger.LogError(ex, "Error while parsing lock file"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
namespace Microsoft.ComponentDetection.Detectors.Pub; | ||
|
||
using System.Collections.Generic; | ||
using System.Runtime.Serialization; | ||
using YamlDotNet.Serialization; | ||
|
||
/// <summary> | ||
/// Model of the pub-spec lock file. | ||
/// </summary> | ||
[DataContract] | ||
public class PubSpecLock | ||
{ | ||
[YamlMember(Alias = "packages")] | ||
public Dictionary<string, PubSpecLockPackage> Packages { get; set; } | ||
|
||
[YamlMember(Alias = "sdks")] | ||
public SDK Sdks { get; set; } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
namespace Microsoft.ComponentDetection.Detectors.Pub; | ||
|
||
using System.Runtime.Serialization; | ||
using YamlDotNet.Serialization; | ||
|
||
/// <summary> | ||
/// Model of the pub-spec lock file. | ||
/// </summary> | ||
[DataContract] | ||
public class PubSpecLockPackage | ||
{ | ||
[YamlMember(Alias = "source")] | ||
public string Source { get; set; } | ||
|
||
[YamlMember(Alias = "version")] | ||
public string Version { get; set; } | ||
|
||
[YamlMember(Alias = "dependency")] | ||
public string Dependency { get; set; } | ||
|
||
[YamlMember(Alias = "description")] | ||
public dynamic Description { get; set; } | ||
|
||
/// <summary> | ||
/// /// Returns the description\sha256 path | ||
/// The value can be null. | ||
/// </summary> | ||
/// <returns> Returns the package SHA-256 as in the pubspec.lock file.</returns> | ||
public string GetSha256() => this.Description["sha256"]; | ||
|
||
/// <summary> | ||
/// Returns the description\url path | ||
/// The value can be null. | ||
/// </summary> | ||
/// <returns>Returns the package url as in the pubspec.lock file.</returns> | ||
public string GePackageDownloadedSource() => this.Description["url"]; | ||
|
||
/// <summary> | ||
/// Returns the description\name path | ||
/// The value can be null. | ||
/// </summary> | ||
/// <returns>Returns the package name as in the pubspec.lock file.</returns> | ||
public string GetName() => this.Description["name"]; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
namespace Microsoft.ComponentDetection.Detectors.Pub; | ||
|
||
using System.Runtime.Serialization; | ||
using YamlDotNet.Serialization; | ||
|
||
/// <summary> | ||
/// Model of the pub-spec lock file. | ||
/// </summary> | ||
[DataContract] | ||
public class PubSpecLockPackageDescription | ||
{ | ||
[YamlMember(Alias = "name")] | ||
public string Name { get; set; } | ||
|
||
[YamlMember(Alias = "sha256")] | ||
public string Sha256 { get; set; } | ||
|
||
[YamlMember(Alias = "url")] | ||
public string Url { get; set; } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
namespace Microsoft.ComponentDetection.Detectors.Pub; | ||
|
||
using System.Runtime.Serialization; | ||
using YamlDotNet.Serialization; | ||
|
||
[DataContract] | ||
public class SDK | ||
{ | ||
[YamlMember(Alias = "dart")] | ||
public string Dart { get; set; } | ||
|
||
[YamlMember(Alias = "flutter")] | ||
public string Flutter { get; set; } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
namespace Microsoft.ComponentDetection.Detectors.Tests; | ||
|
||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using FluentAssertions; | ||
using Microsoft.ComponentDetection.Contracts; | ||
using Microsoft.ComponentDetection.Contracts.TypedComponent; | ||
using Microsoft.ComponentDetection.Detectors.Pub; | ||
using Microsoft.ComponentDetection.TestsUtilities; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
||
[TestClass] | ||
[TestCategory("Governance/All")] | ||
[TestCategory("Governance/ComponentDetection")] | ||
public class PubComponentDetectorTests : BaseDetectorTest<PubComponentDetector> | ||
{ | ||
private readonly string testPubSpecLockFile = @"# Generated by pub | ||
# See https://dart.dev/tools/pub/glossary#lockfile | ||
packages: | ||
analyzer: | ||
dependency: ""direct dev"" | ||
description: | ||
name: analyzer | ||
sha256: ""sh1"" | ||
url: ""https://pub.dev"" | ||
source: hosted | ||
version: ""5.13.0"" | ||
archive: | ||
dependency: transitive | ||
description: | ||
name: archive | ||
sha256: ""sh2"" | ||
url: ""https://pub.dev"" | ||
source: hosted | ||
version: ""3.4.4"" | ||
async: | ||
dependency: direct main | ||
description: | ||
name: async | ||
sha256: ""sh3"" | ||
url: ""https://pub.dev"" | ||
source: hosted | ||
version: ""2.11.0"" | ||
flutter: | ||
dependency: ""direct main"" | ||
description: flutter | ||
source: sdk | ||
version: ""0.0.0"" | ||
sdks: | ||
dart: "">=3.0.0 <4.0.0"" | ||
flutter: "">=3.10.0"" | ||
"; | ||
|
||
[TestMethod] | ||
public async Task TestDetectorAsync() | ||
{ | ||
var (result, componentRecorder) = await this.DetectorTestUtility | ||
.WithFile("pubspec.lock", this.testPubSpecLockFile) | ||
.ExecuteDetectorAsync(); | ||
|
||
result.ResultCode.Should().Be(ProcessingResultCode.Success); | ||
componentRecorder.GetDetectedComponents().Count().Should().Be(3); | ||
|
||
var components = componentRecorder.GetDetectedComponents().Select(x => x.Component).ToArray(); | ||
|
||
components.Should().Contain(new PubComponent( | ||
"analyzer", | ||
"5.13.0", | ||
"direct dev", | ||
"sh1", | ||
"https://pub.dev")); | ||
|
||
components.Should().Contain(new PubComponent( | ||
"archive", | ||
"3.4.4", | ||
"transitive", | ||
"sh2", | ||
"https://pub.dev")); | ||
|
||
components.Should().Contain(new PubComponent( | ||
"async", | ||
"2.11.0", | ||
"direct main", | ||
"sh3", | ||
"https://pub.dev")); | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.