-
Notifications
You must be signed in to change notification settings - Fork 529
[WIP] removing Mono.Cecil #3223
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: master
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| Newtonsoft.Json | ||
| Mono.Cecil | ||
| System.Reflection.Metadata | ||
| Chessie | ||
| System.Security.Cryptography.ProtectedData | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| module Paket.AssemblyMetadata | ||
|
|
||
| open Chessie.ErrorHandling | ||
| open System | ||
| open System.IO | ||
| open System.Globalization | ||
| open System.Reflection | ||
| open System.Reflection | ||
| open System.Reflection.Metadata | ||
| open System.Reflection.PortableExecutable | ||
|
|
||
| /// Calculates the short form of the public key token for use with binding redirects, if it exists. | ||
| let getPublicKeyToken (assembly:AssemblyName) = | ||
| ("", assembly.GetPublicKeyToken()) | ||
| ||> Array.fold(fun state b -> state + b.ToString("X2")) | ||
| |> function | ||
| | "" -> None | ||
| | token -> Some (token.ToLower()) | ||
|
|
||
| /// Creates AssemblyName of AssemblyReference opened on the MetadataReader; | ||
| /// expected to be part of next release of the Metadata support, so we can remove this. | ||
| /// Can throw AccessViolation if used incorrectly, with unrelated or disposed reader. | ||
| let private getAssemblyName (reader:MetadataReader) (reference:AssemblyReference) = | ||
| let assemblyName = reader.GetString(reference.Name) | ||
| let cultureInfo = | ||
| if reference.Culture.IsNil then null | ||
| else CultureInfo(reader.GetString(reference.Culture)) | ||
| let hasPublicKey = reference.Flags.HasFlag(AssemblyFlags.PublicKey) | ||
| let assemblyFlag = | ||
| if hasPublicKey then AssemblyNameFlags.PublicKey else AssemblyNameFlags.None | ||
| let assemblyName = | ||
| new AssemblyName( | ||
| Name = assemblyName, | ||
| Flags = assemblyFlag, | ||
| Version = reference.Version, | ||
| CultureInfo = cultureInfo) | ||
| let keyOrToken = | ||
| let keyOrTokenHandle = reference.PublicKeyOrToken | ||
| if keyOrTokenHandle.IsNil then null else reader.GetBlobBytes(keyOrTokenHandle) | ||
| if hasPublicKey then | ||
| assemblyName.SetPublicKey(keyOrToken) | ||
| else | ||
| assemblyName.SetPublicKeyToken(keyOrToken) | ||
| assemblyName; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. semicolon?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. still new to F# :) is this incorrect? I prefer using semicolon when using a variable like this, just to make it the return value
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. usually we leave out semicolons ;) |
||
|
|
||
| type AssemblyDefinition = | ||
| | AssemblyFile of String | ||
| | AssemblyInfo of FileInfo | ||
| | AssemblyName of AssemblyName | ||
|
|
||
| /// Uses the assembly file metadata from the provided source, | ||
| /// to return AssemblyName list of its referenced assemblies. | ||
| let getAssemblyReferences (assembly:AssemblyDefinition) = | ||
| try | ||
| let assemblyFilePath = | ||
| match assembly with | ||
| | AssemblyFile file -> file | ||
| | AssemblyInfo info -> info.FullName | ||
| | AssemblyName name -> Uri(name.CodeBase).LocalPath | ||
| use file = File.OpenRead(assemblyFilePath) | ||
| use reader = new PEReader(file, PEStreamOptions.PrefetchMetadata) | ||
| let metadataReader = reader.GetMetadataReader() | ||
| metadataReader.AssemblyReferences | ||
| |> Seq.map (fun aref -> | ||
| try | ||
| let reference = metadataReader.GetAssemblyReference(aref) | ||
| pass(getAssemblyName metadataReader reference) | ||
| with | ||
| | ex -> fail ex) | ||
| |> collect | ||
| with | ||
| | ex -> fail ex | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,15 +2,18 @@ | |
| module Paket.InstallProcess | ||
|
|
||
| open Paket | ||
| open System | ||
| open Chessie.ErrorHandling | ||
| open Paket | ||
| open Paket.Domain | ||
| open Paket.Logging | ||
| open Paket.BindingRedirects | ||
| open System.IO | ||
| open Paket.PackageSources | ||
| open Paket.Requirements | ||
| open ProviderImplementation.AssemblyReader | ||
| open System.Collections.Generic | ||
| open System | ||
| open System.Reflection | ||
|
|
||
| let updatePackagesConfigFile (model: Map<GroupName*PackageName,SemVerInfo*InstallSettings>) packagesConfigFileName = | ||
| let packagesInConfigFile = PackagesConfigFile.Read packagesConfigFileName | ||
|
|
@@ -293,20 +296,31 @@ let private applyBindingRedirects isFirstGroup createNewBindingFiles cleanBindin | |
| librariesForPackage | ||
| |> Seq.choose(fun (library,redirects,profile) -> | ||
| try | ||
| let assembly = Mono.Cecil.AssemblyDefinition.ReadAssembly(library.Path) | ||
| Some (assembly, BindingRedirects.getPublicKeyToken assembly, assembly.MainModule.AssemblyReferences, redirects, profile) | ||
| let assemblyName = AssemblyName.GetAssemblyName(library.Path) | ||
| let publicKeyToken = AssemblyMetadata.getPublicKeyToken assemblyName | ||
| let metadataName = AssemblyMetadata.AssemblyName assemblyName | ||
| let references = | ||
| match AssemblyMetadata.getAssemblyReferences metadataName with | ||
| | Trial.Pass list -> list | ||
| | Trial.Warn(list, warn) -> | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where does
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chessie – it seemed convenient to use here
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But I don't see it emitted, so this case can never happen, correct?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAIK it can be produced in |
||
| warn |> List.iter (fun ex -> ex |> string |> traceWarn) | ||
| list | ||
| | Trial.Fail exns -> | ||
| exns |> List.iter (fun ex -> ex |> string |> traceError) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Depending on the scenarios where this happens (traceError and traceWarn) we might need to restrict this to verbose mode later.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it should only happen on metadata errors, not really expected – it might be safely restricted to one-time warning or error though |
||
| List.empty | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably not – should I just re-throw here?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably yes, it will be caught with an evil
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it would get double-logged then -- but I think we can do a throw with inner exception here to keep the original info/stack and get it logged in the caller only |
||
| Some (assemblyName, publicKeyToken, references, redirects, profile) | ||
| with _ -> None) | ||
| |> Seq.sortBy(fun (assembly,_,_,_,_) -> assembly.Name.Version) | ||
| |> Seq.sortBy(fun (assembly,_,_,_,_) -> assembly.Version) | ||
| |> Seq.toList | ||
| |> List.rev | ||
| |> function | head :: _ -> Some head | _ -> None) | ||
| |> Seq.cache | ||
|
|
||
| let referencesDifferentProfiles (assemblyName : Mono.Cecil.AssemblyNameDefinition) profile = | ||
| let referencesDifferentProfiles (assemblyName : AssemblyName) profile = | ||
| (targetProfiles |> Seq.exists ((=) profile)) | ||
| && assemblies | ||
| |> Seq.filter (fun (_,_,_,_,p) -> p <> profile) | ||
| |> Seq.map (fun (a,_,_,_,_) -> a.Name) | ||
| |> Seq.map (fun (a,_,_,_,_) -> a) | ||
| |> Seq.filter (fun a -> a.Name = assemblyName.Name) | ||
| |> Seq.exists (fun a -> a.Version <> assemblyName.Version) | ||
|
|
||
|
|
@@ -320,16 +334,16 @@ let private applyBindingRedirects isFirstGroup createNewBindingFiles cleanBindin | |
| | Some BindingRedirectsSettings.Off -> false | ||
| | _ -> false) | ||
| |> Seq.filter (fun (assembly,_,_,redirects,profile) -> | ||
| let assemblyName = assembly.Name | ||
| let assemblyName = assembly | ||
| redirects = Some BindingRedirectsSettings.Force | ||
| || referencesDifferentProfiles assemblyName profile | ||
| || assemblies | ||
| |> Seq.collect (fun (_,_,refs,_,_) -> refs) | ||
| |> Seq.filter (fun a -> assemblyName.Name = a.Name) | ||
| |> Seq.exists (fun a -> assemblyName.Version > a.Version)) | ||
| |> Seq.map(fun (assembly, token,_,_,_) -> | ||
| { BindingRedirect.AssemblyName = assembly.Name.Name | ||
| Version = assembly.Name.Version.ToString() | ||
| { BindingRedirect.AssemblyName = assembly.Name | ||
| Version = assembly.Version.ToString() | ||
| PublicKeyToken = token | ||
| Culture = None }) | ||
| |> Seq.sort | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to ILMerge this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for current platforms as it's part of netstandard, but might be needed to support older platforms and/or resolve discussed version conflict/s