Skip to content

Commit

Permalink
Fix tests and some more msbuild foo to handle invalid cache files.
Browse files Browse the repository at this point in the history
  • Loading branch information
matthid committed Jul 2, 2019
1 parent fe85d95 commit d8302c7
Show file tree
Hide file tree
Showing 13 changed files with 91 additions and 29 deletions.
2 changes: 1 addition & 1 deletion integrationtests/Paket.IntegrationTests/InfoSpecs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ let ``#3200 info should locate paket.dependencies``() =

let ``paket info --paket-dependencies-dir`` workingDir =
directPaketInPathEx "info --paket-dependencies-dir" workingDir
|> Seq.map PaketMsg.getMessage
|> Seq.map OutputMsg.getMessage
|> List.ofSeq

// paket.dependencies not exists
Expand Down
4 changes: 3 additions & 1 deletion integrationtests/Paket.IntegrationTests/InitSpecs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ let ``#1743 empty log file``() =
use __ = paket "init --log-file" "i001040-init-downloads-bootstrapper" |> fst
failwith "expected error"
with
| exn when exn.Message.Split('\n').[0].Contains "--log-file" -> ()
| ProcessFailedWithExitCode(_, _, msgs) ->
(msgs.Errors |> Seq.head).Contains "--log-file"
|> shouldEqual true

[<Test>]
#if PAKET_NETCORE
Expand Down
12 changes: 11 additions & 1 deletion integrationtests/Paket.IntegrationTests/RestoreSpecs.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ open FsUnit
open Paket
open Paket.Utils

[<Test>]
let ``#3608 dotnet build should work with unparsable cache``() =
let project = "console"
let scenario = "i003608-invalid-cache"
use __ = prepareSdk scenario

let wd = (scenarioTempPath scenario) @@ project
// Build should work immediately (and call 'paket restore')
directDotnet true (sprintf "build %s.fsproj" project) wd
|> ignore

[<Test>]
let ``#2684 Paket should not be called the second time in msbuild (Restore Performance)``() =
let project = "console"
Expand All @@ -24,7 +35,6 @@ let ``#2684 Paket should not be called the second time in msbuild (Restore Perfo
directDotnet true (sprintf "build %s.fsproj" project) wd
|> ignore


[<Test>]
let ``#2496 Paket fails on projects that target multiple frameworks``() =
let project = "EmptyTarget"
Expand Down
33 changes: 20 additions & 13 deletions integrationtests/Paket.IntegrationTests/TestHelper.fs
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,21 @@ let prepareSdk scenario =
FileHelper.CopyFile tmpPaketFolder targetsFile
cleanup

type PaketMsg =
type OutputMsg =
{ IsError : bool; Message : string }
static member isError ({ IsError = e}:PaketMsg) = e
static member getMessage ({ Message = msg }:PaketMsg) = msg
static member isError ({ IsError = e}:OutputMsg) = e
static member getMessage ({ Message = msg }:OutputMsg) = msg
type OutputData =
internal { _Messages : ResizeArray<OutputMsg> }
member x.Messages : seq<OutputMsg> = x._Messages :> _
member x.Errors = x._Messages |> Seq.filter OutputMsg.isError |> Seq.map OutputMsg.getMessage
member x.Outputs = x._Messages |> Seq.filter (not << OutputMsg.isError) |> Seq.map OutputMsg.getMessage

exception ProcessFailedWithExitCode of exitCode:int * fileName:string * msgs:OutputData
with
override x.Message =
let output = String.Join(Environment.NewLine,x.msgs.Messages |> Seq.map (fun m -> (if m.IsError then "ERR:" else "OUT:") + m.Message ))
sprintf "The process '%s' exited with code %i, output: \n%s" x.fileName x.exitCode output

let directToolEx env isPaket toolInfo commands workingDir =
let processFilename, processArgs =
Expand Down Expand Up @@ -123,7 +134,7 @@ let directToolEx env isPaket toolInfo commands workingDir =
Environment.SetEnvironmentVariable("PAKET_DETAILED_WARNINGS", "true")
printfn "%s> %s %s" workingDir (if isPaket then "paket" else processFilename) processArgs
let perfMessages = ResizeArray()
let msgs = ResizeArray<PaketMsg>()
let msgs = ResizeArray<OutputMsg>()
let mutable perfMessagesStarted = false
let addAndPrint isError msg =
if not isError then
Expand Down Expand Up @@ -165,18 +176,14 @@ let directToolEx env isPaket toolInfo commands workingDir =
if isPaket then
// Only throw after the result <> 0 check because the current test might check the argument parsing
// this is the only case where no performance is printed
let isUsageError = result <> 0 && msgs |> Seq.filter PaketMsg.isError |> Seq.map PaketMsg.getMessage |> Seq.exists (fun msg -> msg.Contains "USAGE:")
let isUsageError = result <> 0 && msgs |> Seq.filter OutputMsg.isError |> Seq.map OutputMsg.getMessage |> Seq.exists (fun msg -> msg.Contains "USAGE:")
if not isUsageError then
printfn "Performance:"
for msg in perfMessages do
printfn "%s" msg

if result <> 0 then
let output = String.Join(Environment.NewLine,msgs |> Seq.map (fun m -> (if m.IsError then "ERR:" else "OUT:") + m.Message ))
//if String.IsNullOrWhiteSpace errors then
failwithf "The process '%s' exited with code %i, output: \n%s" processFilename result output
//else
// failwith errors
if result <> 0 then
raise <| ProcessFailedWithExitCode(result, processFilename, { _Messages = msgs })

msgs
#endif
Expand All @@ -186,7 +193,7 @@ let directPaketInPathEx command scenarioPath =

let checkResults msgs =
msgs
|> Seq.filter PaketMsg.isError
|> Seq.filter OutputMsg.isError
|> Seq.toList
|> shouldEqual []

Expand All @@ -200,7 +207,7 @@ let directDotnet checkZeroWarn command workingDir =
directDotnetEx [] checkZeroWarn command workingDir

let private fromMessages msgs =
String.Join(Environment.NewLine,msgs |> Seq.map PaketMsg.getMessage)
String.Join(Environment.NewLine,msgs |> Seq.map OutputMsg.getMessage)

let directPaketInPath command scenarioPath = directPaketInPathEx command scenarioPath |> fromMessages

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Learn more about F# at http://fsharp.org

open System

[<EntryPoint>]
let main argv =
printfn "Hello World from F#!"
0 // return an integer exit code
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<Compile Include="Program.fs" />
</ItemGroup>

<Import Project="..\.paket\Paket.Restore.targets" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
FSharp.Core
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Some not parsable File
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source https://api.nuget.org/v3/index.json
restriction: || (==netstandard20) (== netcoreapp21)
storage: none
nuget FSharp.Core
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
STORAGE: NONE
RESTRICTION: || (== netcoreapp2.1) (== netstandard2.0)
NUGET
remote: https://api.nuget.org/v3/index.json
FSharp.Core (4.6.2)
5 changes: 4 additions & 1 deletion src/Paket.Core/Installation/InstallProcess.fs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,10 @@ let InstallIntoProjects(options : InstallerOptions, forceTouch, dependenciesFile
first := false

let restoreCacheFile = Path.Combine(root, Constants.PaketRestoreHashFilePath)
Paket.RestoreProcess.saveToFile (lockFile.ToString()) (FileInfo restoreCacheFile) |> ignore
let hash = Paket.RestoreProcess.getLockFileHashFromContent (lockFile.ToString())
// NIT: We probably need to check if we have really fully restored (could be partial install)
// Lets see if users report issues
Paket.RestoreProcess.writeRestoreCache restoreCacheFile { PackagesDownloadedHash = hash; ProjectsRestoredHash = hash }
Paket.RestoreProcess.WriteGitignore restoreCacheFile

for project, _ in projectsAndReferences do
Expand Down
13 changes: 9 additions & 4 deletions src/Paket.Core/Installation/RestoreProcess.fs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ let copiedElements = ref false

type private MyAssemblyFinder () = class end

let saveToFile newContent (targetFile:FileInfo) =
let private saveToFile newContent (targetFile:FileInfo) =
let rec loop trials =
try
if not targetFile.Directory.Exists then
Expand Down Expand Up @@ -567,6 +567,7 @@ let internal getStringHash (s:string) =
|> BitConverter.ToString
|> fun s -> s.Replace("-", "")


type internal Hash =
| Hash of string
member x.HashString =
Expand All @@ -576,7 +577,11 @@ type internal Hash =
match x with
| Hash s -> String.IsNullOrEmpty s
static member OfString s = Hash (getStringHash s)


let internal getLockFileHashFromContent (content:string) =
Hash.OfString content
let internal getLockFileHash (f:string) =
getLockFileHashFromContent (File.ReadAllText f)

type internal RestoreCache =
{ PackagesDownloadedHash : Hash
Expand All @@ -591,7 +596,7 @@ type internal RestoreCache =
{ PackagesDownloadedHash = Hash ""
ProjectsRestoredHash = Hash "" }

let private writeRestoreCache (file:string) { PackagesDownloadedHash = Hash packagesDownloadedHash; ProjectsRestoredHash = Hash projectsRestoredHash} =
let internal writeRestoreCache (file:string) { PackagesDownloadedHash = Hash packagesDownloadedHash; ProjectsRestoredHash = Hash projectsRestoredHash} =
let jobj = new Newtonsoft.Json.Linq.JObject()
jobj.["packagesDownloadedHash"] <- Newtonsoft.Json.Linq.JToken.op_Implicit packagesDownloadedHash
jobj.["projectsRestoredHash"] <- Newtonsoft.Json.Linq.JToken.op_Implicit projectsRestoredHash
Expand Down Expand Up @@ -668,7 +673,7 @@ let Restore(dependenciesFileName,projectFile:RestoreProjectOptions,force,group,i
None, RestoreCache.Empty, Hash "", false
else
let cache = readRestoreCache(lockFileName)
let lockFileHash = Hash.OfString (File.ReadAllText lockFileName.FullName)
let lockFileHash = getLockFileHash lockFileName.FullName
let updatedCache =
{ PackagesDownloadedHash = lockFileHash // we always download all packages in that situation
ProjectsRestoredHash = if projectFile = AllProjects then lockFileHash else cache.ProjectsRestoredHash }
Expand Down
19 changes: 11 additions & 8 deletions src/Paket.Core/embedded/Paket.Restore.targets
Original file line number Diff line number Diff line change
Expand Up @@ -82,32 +82,35 @@
<PropertyGroup>
<PaketRestoreRequired>true</PaketRestoreRequired>
<NoWarn>$(NoWarn);NU1603;NU1604;NU1605;NU1608</NoWarn>
<CacheFilesExist>false</CacheFilesExist>
<CacheFilesExist Condition=" Exists('$(PaketRestoreCacheFile)') And Exists('$(PaketLockFilePath)') ">true</CacheFilesExist>
</PropertyGroup>

<!-- Read the hash of the lockfile -->
<GetFileHash Files="$(PaketLockFilePath)" Algorithm="SHA256" HashEncoding="hex" >
<GetFileHash Condition=" '$(CacheFilesExist)' == 'true' " Files="$(PaketLockFilePath)" Algorithm="SHA256" HashEncoding="hex" >
<Output TaskParameter="Hash" PropertyName="PaketRestoreLockFileHash" />
</GetFileHash>
<!-- Read the hash of the cache, which is json, but a very simple key value object -->
<PropertyGroup>
<PropertyGroup Condition=" '$(CacheFilesExist)' == 'true' ">
<PaketRestoreCachedContents>$([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)'))</PaketRestoreCachedContents>
</PropertyGroup>
<ItemGroup>
<ItemGroup Condition=" '$(CacheFilesExist)' == 'true' ">
<!-- Parse our simple 'paket.restore.cached' json ...-->
<PaketRestoreCachedSplitObject Include="$([System.Text.RegularExpressions.Regex]::Split(`$(PaketRestoreCachedContents)`, `{|}|,`))"></PaketRestoreCachedSplitObject>
<!-- Keep Key, Value ItemGroup-->
<PaketRestoreCachedKeyValue Include="@(PaketRestoreCachedSplitObject)">
<Key>$([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``))</Key>
<Value>$([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``))</Value>
<PaketRestoreCachedKeyValue Include="@(PaketRestoreCachedSplitObject)"
Condition=" $([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `&quot;: &quot;`).Length) &gt; 1 ">
<Key>$([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[0].Replace(`"`, ``).Replace(` `, ``))</Key>
<Value>$([System.Text.RegularExpressions.Regex]::Split(`%(Identity)`, `": "`)[1].Replace(`"`, ``).Replace(` `, ``))</Value>
</PaketRestoreCachedKeyValue>
</ItemGroup>
<PropertyGroup>
<PropertyGroup Condition=" '$(CacheFilesExist)' == 'true' ">
<!-- Retrieve the hashes we are interested in -->
<PackagesDownloadedHash Condition=" '%(PaketRestoreCachedKeyValue.Key)' == 'packagesDownloadedHash' ">%(PaketRestoreCachedKeyValue.Value)</PackagesDownloadedHash>
<ProjectsRestoredHash Condition=" '%(PaketRestoreCachedKeyValue.Key)' == 'projectsRestoredHash' ">%(PaketRestoreCachedKeyValue.Value)</ProjectsRestoredHash>
</PropertyGroup>

<PropertyGroup Condition="Exists('$(PaketRestoreCacheFile)') ">
<PropertyGroup Condition=" '$(CacheFilesExist)' == 'true' ">
<!-- If the restire file doesn't exist we need to restore, otherwise only if hashes don't match -->
<PaketRestoreRequired>true</PaketRestoreRequired>
<PaketRestoreRequired Condition=" '$(PaketRestoreLockFileHash)' == '$(ProjectsRestoredHash)' ">false</PaketRestoreRequired>
Expand Down

0 comments on commit d8302c7

Please sign in to comment.