From c1a6780fbc51abdf565e4e142afbd902a54b4178 Mon Sep 17 00:00:00 2001 From: Volodymyr Lukashevych Date: Wed, 17 Jan 2018 18:05:21 -0800 Subject: [PATCH 1/3] Change API to throw exceptions in case of error, so it's consistent with other APIs --- src/app/Fake.Net.Http/HttpLoader.fs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/app/Fake.Net.Http/HttpLoader.fs b/src/app/Fake.Net.Http/HttpLoader.fs index d801ea5876f..09f0552bb10 100644 --- a/src/app/Fake.Net.Http/HttpLoader.fs +++ b/src/app/Fake.Net.Http/HttpLoader.fs @@ -60,14 +60,15 @@ module Http = let urlResult = createUri input.Uri createDownloadInfoRecord filePathResult <*> urlResult + /// Unwraps the Result type and throws an exception if download process failed /// [omit] - let private printDownloadResults result = + let private processResults result = match result with | Ok result -> - Trace.log <| sprintf "Downloaded : [%A]" result + Trace.log "Download succeeded" + result | Error errs -> - Trace.traceError <| sprintf "Failed: %A" errs - result + failwith <| sprintf "Download failed : [%A]" errs /// [omit] let private saveStreamToFileAsync (filePath: FilePath) (stream: Stream) : Async> = @@ -95,7 +96,7 @@ module Http = return! saveStreamToFileAsync info.LocalFilePath stream with | ex -> - let err = sprintf "[%s] %s" info.Uri.Host ex.Message + let err = sprintf "[%s] %s" info.Uri.OriginalString ex.Message return Error [err ] } @@ -109,24 +110,24 @@ module Http = Async.result (Error errs) /// Download file by the given file path and Uri - /// string -> string -> Result + /// string -> string -> string /// ## Parameters /// - `localFilePath` - A local file path to download file /// - `uri` - A Uri to download from /// ## Returns - /// - `Result` type. Success branch contains a downloaded file path. Failure branch contains a list of errors - let downloadFile (localFilePath: string) (uri: string) : Result = + /// - `string` type. Contains a downloaded file path + let downloadFile (localFilePath: string) (uri: string) : string = downloadFileAsync { Uri=uri; Path=localFilePath } |> Async.RunSynchronously - |> printDownloadResults + |> processResults /// Download list of Uri's in parallel - /// DownloadParameters -> Result + /// DownloadParameters -> string list /// ## Parameters /// - `input` - List of Http.DownloadParameters. Each Http.DownloadParameters record type contains Uri and file path /// ## Returns - /// - `Result` type. Success branch contains a list of downloaded file paths. Failure branch contains a list of errors - let downloadFiles (input: DownloadParameters list) : Result = + /// - `string list` type. Contains a list of downloaded file paths + let downloadFiles (input: DownloadParameters list) : string list = input // DownloadParameters -> "Async> list" |> List.map downloadFileAsync @@ -135,4 +136,4 @@ module Http = // "Async list>" -> "Async>" |> Async.map List.sequenceResultA |> Async.RunSynchronously - |> printDownloadResults \ No newline at end of file + |> processResults From 782241e1901193859206995c9e0c63a44394ea25 Mon Sep 17 00:00:00 2001 From: Volodymyr Lukashevych Date: Thu, 18 Jan 2018 15:01:42 -0800 Subject: [PATCH 2/3] Add Fake.Net.Http documentation --- FAKE.sln | 1 + help/markdown/net-http.md | 67 +++++++++++++++++++++++++++ help/templates/template.cshtml | 8 +++- src/app/Fake.Net.Http/AssemblyInfo.fs | 4 +- src/app/Fake.Net.Http/Async.fs | 8 +++- src/app/Fake.Net.Http/HttpLoader.fs | 4 ++ src/app/Fake.Net.Http/List.fs | 5 ++ src/app/Fake.Net.Http/Result.fs | 3 ++ 8 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 help/markdown/net-http.md diff --git a/FAKE.sln b/FAKE.sln index 44050341d27..ebb4533a9e1 100644 --- a/FAKE.sln +++ b/FAKE.sln @@ -85,6 +85,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "markdown", "markdown", "{B9 help\markdown\legacy-core-targets.md = help\markdown\legacy-core-targets.md help\markdown\legacy-gettingstarted.md = help\markdown\legacy-gettingstarted.md help\markdown\legacy-index.md = help\markdown\legacy-index.md + help\markdown\net-http.md = help\markdown\net-http.md help\markdown\testing-sonarqube.md = help\markdown\testing-sonarqube.md help\markdown\todo-androidpublisher.md = help\markdown\todo-androidpublisher.md help\markdown\todo-azurecloudservices.md = help\markdown\todo-azurecloudservices.md diff --git a/help/markdown/net-http.md b/help/markdown/net-http.md new file mode 100644 index 00000000000..57d1e25bd08 --- /dev/null +++ b/help/markdown/net-http.md @@ -0,0 +1,67 @@ +# Downloading Files Over HTTP + +The `Fake.Net.Http` module provides a functionality to download files over HTTP. + +[API-Reference](apidocs/fake-net-http.html) + +## Including the Fake.Net.Http dependency + +In order to open the `Fake.Net.Http` module from a build script you have to add a `Fake.Net.Http` dependency into your +`paket.dependencies` file: + + group NetcoreBuild + source https://api.nuget.org/v3/index.json + + nuget Fake.Net.Http prerelease + + .... other dependencies, like + nuget Fake.Core.Target prerelease + +Please see more details on referencing FAKE 5 modules [here](fake-fake5-modules.html). + +## Downloading a Single File + +To download a single file over HTTP use `downloadFile` from the Http module: + + open Fake.Net + open Fake.Core + + Target.Create "DownloadFile" (fun _ -> + let absoluteFilePath = Http.downloadFile "/tmp/5.zip" @"http://ipv4.download.thinkbroadband.com/5MB.zip" + printfn "File path: %s" absoluteFilePath + ) + +A console output should be: + + Downloading [http://ipv4.download.thinkbroadband.com/5MB.zip] ... + Download succeeded + File path: /tmp/5.zip + +## Downloading Multiple Files + +To download multiple files in parallel use `downloadFiles` from the Http module: + + open Fake.Net + open Fake.Core + + Target.Create "DownloadFiles" (fun _ -> + let files: Http.DownloadParameters list = [ + {Path = "/tmp/5.zip"; Uri = "http://ipv4.download.thinkbroadband.com/5MB.zip"}; + {Path = "/tmp/10.zip"; Uri = "http://ipv4.download.thinkbroadband.com/10MB.zip"}] + let filePaths = Http.downloadFiles files + printfn "File paths: %A" filePaths + ) + +A console output should be: + + Downloading [http://ipv4.download.thinkbroadband.com/5MB.zip] ... + Downloading [http://ipv4.download.thinkbroadband.com/10MB.zip] ... + Download succeeded + File paths: ["/tmp/5.zip"; "/tmp/10.zip"] + +## More Details + +* `downloadFile` and `downloadFiles` throw an Exception and fail a FAKE Target if any error occurs (invalid URI, invalid local file + path/permissions, etc.) + +* file with the same name will be overwritten if exists in the target location diff --git a/help/templates/template.cshtml b/help/templates/template.cshtml index c73f0edacbc..cc671efd45a 100644 --- a/help/templates/template.cshtml +++ b/help/templates/template.cshtml @@ -112,6 +112,12 @@
  • Paket
  • +
  • + Net + +
  • Tools
      @@ -297,4 +303,4 @@ - \ No newline at end of file + diff --git a/src/app/Fake.Net.Http/AssemblyInfo.fs b/src/app/Fake.Net.Http/AssemblyInfo.fs index 98f03b42c0a..d1eda9720a1 100644 --- a/src/app/Fake.Net.Http/AssemblyInfo.fs +++ b/src/app/Fake.Net.Http/AssemblyInfo.fs @@ -5,7 +5,7 @@ open System.Reflection [] [] [] -[] +[] [] do () @@ -13,5 +13,5 @@ module internal AssemblyVersionInformation = let [] AssemblyTitle = "FAKE - F# Make HTTP Client" let [] AssemblyProduct = "FAKE - F# Make" let [] AssemblyVersion = "5.0.0" - let [] AssemblyInformationalVersion = "5.0.0-beta010" + let [] AssemblyInformationalVersion = "5.0.0" let [] AssemblyFileVersion = "5.0.0" diff --git a/src/app/Fake.Net.Http/Async.fs b/src/app/Fake.Net.Http/Async.fs index 332a0f20c7e..136a5878e18 100644 --- a/src/app/Fake.Net.Http/Async.fs +++ b/src/app/Fake.Net.Http/Async.fs @@ -1,17 +1,23 @@ namespace Fake.Net.Async +/// [omit] module Async = + /// [omit] let result = async.Return + + /// [omit] let map f value = async { let! v = value return f v } + /// [omit] let bind f xAsync = async { let! x = xAsync return! f x } + /// [omit] let apply fAsync xAsync = async { // start the two asyncs in parallel let! fChild = Async.StartChild fAsync @@ -23,4 +29,4 @@ module Async = // apply the function to the results return f x - } \ No newline at end of file + } diff --git a/src/app/Fake.Net.Http/HttpLoader.fs b/src/app/Fake.Net.Http/HttpLoader.fs index 09f0552bb10..a99d64063b4 100644 --- a/src/app/Fake.Net.Http/HttpLoader.fs +++ b/src/app/Fake.Net.Http/HttpLoader.fs @@ -15,7 +15,9 @@ module Http = /// Input parameter type type DownloadParameters = { + /// The URI from which to download data Uri: string + /// The name of the local file that is to receive the data Path: string } @@ -114,6 +116,7 @@ module Http = /// ## Parameters /// - `localFilePath` - A local file path to download file /// - `uri` - A Uri to download from + /// /// ## Returns /// - `string` type. Contains a downloaded file path let downloadFile (localFilePath: string) (uri: string) : string = @@ -125,6 +128,7 @@ module Http = /// DownloadParameters -> string list /// ## Parameters /// - `input` - List of Http.DownloadParameters. Each Http.DownloadParameters record type contains Uri and file path + /// /// ## Returns /// - `string list` type. Contains a list of downloaded file paths let downloadFiles (input: DownloadParameters list) : string list = diff --git a/src/app/Fake.Net.Http/List.fs b/src/app/Fake.Net.Http/List.fs index b2b2c5d247e..a4382b2290c 100644 --- a/src/app/Fake.Net.Http/List.fs +++ b/src/app/Fake.Net.Http/List.fs @@ -3,11 +3,13 @@ open Fake.Net.Async open Fake.Net.Result +/// [omit] // List extensions for traversing Result and Async types // Functions from fsharpforfunandprofit.com, please see details here: // https://fsharpforfunandprofit.com/posts/elevated-world-5/ module List = + /// [omit] /// Map a Async producing function over a list to get a new Async /// using applicative style /// ('a -> Async<'b>) -> 'a list -> Async<'b list> @@ -27,10 +29,12 @@ module List = List.foldBack folder list initState + /// [omit] /// Transform a "list" into a "Async" /// and collect the results using apply. let sequenceAsyncA x = traverseAsyncA id x + /// [omit] /// Map a Result producing function over a list to get a new Result /// using applicative style /// ('a -> Result<'b>) -> 'a list -> Result<'b list> @@ -50,6 +54,7 @@ module List = List.foldBack folder list initState + /// [omit] /// Transform a "list" into a "Result" /// and collect the results using apply. let sequenceResultA x = traverseResultA id x diff --git a/src/app/Fake.Net.Http/Result.fs b/src/app/Fake.Net.Http/Result.fs index ebf3a433960..05bc509c369 100644 --- a/src/app/Fake.Net.Http/Result.fs +++ b/src/app/Fake.Net.Http/Result.fs @@ -1,7 +1,9 @@ namespace Fake.Net.Result +/// [omit] module Result = + /// [omit] type ResultBuilder() = member __.Bind(m, f) = match m with @@ -11,6 +13,7 @@ module Result = member __.Return(x) = Ok x + /// [omit] let apply fResult xResult = match fResult,xResult with | Ok f, Ok x -> From e999fc4a865b35ee876d74c4576a54ad52938e95 Mon Sep 17 00:00:00 2001 From: Volodymyr Lukashevych Date: Fri, 19 Jan 2018 20:06:44 -0800 Subject: [PATCH 3/3] Include files from Http module into FakeLib to generate docs --- src/app/FakeLib/FakeLib.fsproj | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/app/FakeLib/FakeLib.fsproj b/src/app/FakeLib/FakeLib.fsproj index 6d4d2df7e8a..79d670b787f 100644 --- a/src/app/FakeLib/FakeLib.fsproj +++ b/src/app/FakeLib/FakeLib.fsproj @@ -296,6 +296,18 @@ Fake.DotNet.Xamarin/Xamarin.fs + + Fake.Net.Http/Async.fs + + + Fake.Net.Http/Result.fs + + + Fake.Net.Http/List.fs + + + Fake.Net.Http/HttpLoader.fs +