From 402a8850dcc5868989d19448108180ca317fb682 Mon Sep 17 00:00:00 2001 From: Maxime Mangel Date: Fri, 8 Jun 2018 13:09:55 +0200 Subject: [PATCH 1/3] Add Fake.Rsync --- build.fsx | 7 +- src/app/Fake.Rsync/Fake.Rsync.fsproj | 16 ++ src/app/Fake.Rsync/Rsync.fs | 415 +++++++++++++++++++++++++++ src/app/Fake.Rsync/paket.references | 4 + 4 files changed, 439 insertions(+), 3 deletions(-) create mode 100644 src/app/Fake.Rsync/Fake.Rsync.fsproj create mode 100644 src/app/Fake.Rsync/Rsync.fs create mode 100644 src/app/Fake.Rsync/paket.references diff --git a/build.fsx b/build.fsx index 156f60b4099..58a0e90cc7b 100644 --- a/build.fsx +++ b/build.fsx @@ -420,6 +420,7 @@ let dotnetAssemblyInfos = "Fake.Net.Http", "HTTP Client" "Fake.netcore", "Command line tool" "Fake.Runtime", "Core runtime features" + "Fake.Rsync", "Running Rsync commands" "Fake.Sql.DacPac", "Sql Server Data Tools DacPac operations" "Fake.Testing.Common", "Common testing data types" "Fake.Testing.ReportGenerator", "Convert XML coverage output to various formats" @@ -1280,9 +1281,9 @@ let rec nugetPush tries nugetpackage = if not ignore_conflict || not (r.Errors |> Seq.exists (fun err -> err.Contains "409")) then - let msgs = r.Results |> Seq.map (fun c -> (if c.IsError then "(Err) " else "") + c.Message) + let msgs = r.Results |> Seq.map (fun c -> (if c.IsError then "(Err) " else "") + c.Message) let msg = System.String.Join ("\n", msgs) - + failwithf "failed to push package %s (code %d): \n%s" nugetpackage r.ExitCode msg else Trace.traceFAKE "ignore conflict error because IGNORE_CONFLICT=true!") else Trace.traceFAKE "could not push '%s', because api key was not set" nugetpackage @@ -1567,7 +1568,7 @@ let mutable prev = None for runtime in "current" :: "portable" :: runtimes do let rawTargetName = sprintf "_DotNetPublish_%s" runtime let targetName = sprintf "DotNetPublish_%s" runtime - Target.Description (sprintf "publish fake 5 runner for %s" runtime) + Target.description (sprintf "publish fake 5 runner for %s" runtime) Target.create targetName ignore "SetAssemblyInfo" ==> rawTargetName diff --git a/src/app/Fake.Rsync/Fake.Rsync.fsproj b/src/app/Fake.Rsync/Fake.Rsync.fsproj new file mode 100644 index 00000000000..bca9586a275 --- /dev/null +++ b/src/app/Fake.Rsync/Fake.Rsync.fsproj @@ -0,0 +1,16 @@ + + + netstandard1.6;netstandard2.0 + Fake.Rsync + Library + + + + + + + + + + + diff --git a/src/app/Fake.Rsync/Rsync.fs b/src/app/Fake.Rsync/Rsync.fs new file mode 100644 index 00000000000..f8f1dc68c97 --- /dev/null +++ b/src/app/Fake.Rsync/Rsync.fs @@ -0,0 +1,415 @@ +namespace Fake.Rsync + +open Fake.Core +open Fake.IO +open System +open System.IO + +/// Helpers for running rsync tool +/// +/// Under windows you will need to add it yourself to your system or use something like cygwin/babun +/// +/// ## Sample +/// +/// let result = +/// Rsync.exec +/// (Rsync.Options.WithActions +/// [ +/// Rsync.Compress +/// Rsync.Archive +/// Rsync.Verbose +/// Rsync.NoOption Rsync.Perms +/// Rsync.Delete +/// Rsync.Exclude ".keep" +/// ] +/// >> Rsync.Options.WithSources +/// [ FleetMapping.server "build" +/// FleetMapping.server "package.json" +/// FleetMapping.server "yarn.lock" ] +/// >> Rsync.Options.WithDestination "remote@myserver.com:deploy") +/// "" +/// +/// if not result.OK then failwithf "Rsync failed with code %i" result.ExitCode +[] +module Rsync = + + type Action = + /// Increase verbosity + | Verbose + /// Suppress non-error messages + | Quiet + /// Suppress daemon-mode MOTD (see manpage caveat) + | NoMotd + /// Skip based on checksum, not mod-time & size + | Checksum + /// Archive mode; same as -rlptgoD (no -H) + | Archive + /// Turn off an implied OPTION (e.g. --no-D) + /// NoOption Verbose ==> --no-verbose + | NoOption of Action + /// Recurse into directories + | Recursive + /// Use relative path names + | Relative + /// Don't send implied dirs with --relative + | NoImpliedDirs + /// Make backups (see --suffix & --backup-dir) + | Backup + /// Make backups into hierarchy based in DIR + | BackupDir of string + /// Set backup suffix (default ~ w/o --backup-dir) + | Suffix of string + /// Skip files that are newer on the receiver + | Update + /// Update destination files in-place (SEE MAN PAGE) + | InPlace + /// Append data onto shorter files + | Append + /// Transfer directories without recursing + | Dirs + /// Copy symlinks as symlinks + | Links + /// Transform symlink into referent file/dir + | CopyLinks + /// Only "unsafe" symlinks are transformed + | CopyUnsafeLinks + /// Ignore symlinks that point outside the source tree + | SafeLinks + /// Transform symlink to a dir into referent dir + | CopyDirLinks + /// Treat symlinked dir on receiver as dir + | KeepDirLinks + /// Preserve hard links + | HardLinks + /// Preserve permissions + | Perms + /// Preserve the file's executability + | Executability + /// Affect file and/or directory permissions + | Chmod of string + /// Preserve owner (super-user only) + | Owner + /// Preserve group + | Group + /// Preserve device files (super-user only) + | Devices + /// Preserve special files + | Specials + /// Same as --devices --specials + | D + /// Preserve times + | Times + /// Omit directories when preserving times + | OmitDirTimes + /// Receiver attempts super-user activities + | Super + /// Handle sparse files efficiently + | Sparse + /// Show what would have been transferred + | DryRun + /// Copy files whole (without rsync algorithm) + | WholeFile + /// Don't cross filesystem boundaries + | OneFileSystem + /// Force a fixed checksum block-size + | BlockSize of string + /// Specify the remote shell to use + | Rsh of string + /// Specify the rsync to run on the remote machine + | RsyncPath of string + /// Skip creating new files on receiver + | Existing + /// Skip updating files that already exist on receiver + | IgnoreExisting + /// Sender removes synchronized files (non-dirs) + | RemoveSourceFiles + /// An alias for --delete-during + | Del + /// Delete extraneous files from destination dirs + | Delete + /// Receiver deletes before transfer (default) + | DeleteBefore + /// Receiver deletes during transfer, not before + | DeleteDuring + /// Receiver deletes after transfer, not before + | DeleteAfter + /// Also delete excluded files from destination dirs + | DeleteExcluded + /// Delete even if there are I/O errors + | IgnoreErrors + /// Force deletion of directories even if not empty + | Force + /// Don't delete more than NUM files + | MaxDelete of int + /// Don't transfer any file larger than SIZE + | MaxSize of string + /// Don't transfer any file smaller than SIZE + | MinSize of string + /// Keep partially transferred files + | Partial + /// Put a partially transferred file into DIR + | PartialDir of string + /// Put all updated files into place at transfer's end + | DelayUpdates + /// Prune empty directory chains from the file-list + | PruneEmptyDirs + /// Don't map uid/gid values by user/group name + | NumericIds + /// Set I/O timeout in seconds + | Timeout of int + /// Don't skip files that match in size and mod-time + | IgnoreTimes + /// Skip files that match in size + | SizeOnly + /// Compare mod-times with reduced accuracy + | ModifyWindow of string + /// Create temporary files in directory DIR + | TempDir of string + /// Find similar file for basis if no dest file + | Fuzzy + /// Also compare destination files relative to DIR + | CompareDest of string + /// ... and include copies of unchanged files + | CopyDest of string + /// Hardlink to files in DIR when unchanged + | LinkDest of string + /// Compress file data during the transfer + | Compress + /// Explicitly set compression level + | CompressLevel of int + /// Auto-ignore files the same way CVS does + | CvsExclude + /// Add a file-filtering RULE + | Filter of string + /// Same as --filter='dir-merge /.rsync-filter' + /// repeated: --filter='- .rsync-filter' + | F + /// Exclude files matching PATTERN + | Exclude of string + /// Read exclude patterns from FILE + | ExcludeFrom of string + /// Don't exclude files matching PATTERN + | Include of string + /// Read include patterns from FILE + | IncludeFrom of string + /// Read list of source-file names from FILE + | FilesFrom of string + /// All *-from/filter files are delimited by 0s + | From0 + /// Bind address for outgoing socket to daemon + | Address of string + /// Specify double-colon alternate port number + | Port of int + /// Specify custom TCP options + | Sockopts of string + /// Use blocking I/O for the remote shell + | BlockingIO + /// Give some file-transfer stats + | Stats + /// Leave high-bit chars unescaped in output + | HeightBitsOutput + /// Output numbers in a human-readable format + | HumanReadable + /// Show progress during transfer + | Progress + /// Same as --partial --progress + | P + /// Output a change-summary for all updates + | ItemizeChanges + /// Output updates using the specified FORMAT + | OutFormat of string + /// Log what we're doing to the specified FILE + | LogFile of string + /// Log updates using the specified FMT + | LogFileFormat of string + /// Read password from FILE + | PasswordFile of string + /// List the files instead of copying them + | ListOnly + /// Limit I/O bandwidth; KBytes per second + | Bwlimit of string + /// Write a batched update to FILE + | WriteBatch of string + /// Like --write-batch but w/o updating destination + | OnlyWriteBatch of string + /// Read a batched update from FILE + | ReadBatch of string + /// Force an older protocol version to be used + | Protocol of int + /// Copy extended attributes + | ExtendedAttributes + /// Disable fcntl(F_NOCACHE) + | Cache + /// Prefer IPv4 + | Ipv4 + /// Prefer IPv6 + | Ipv6 + /// Print version number + | Version + /// Show this help (-h works with no other options) + | Help + + type Options = + { /// Command working directory + WorkingDirectory: string + Actions : Action list + Sources : string list + Destination : string } + + static member Create () = + { WorkingDirectory = Directory.GetCurrentDirectory() + Actions = [] + Sources = [] + Destination = "" } + + static member WithActions actions options = + { options with Actions = actions } + + static member WithSources sources options = + { options with Sources = sources } + + static member WithDestination dest options = + { options with Destination = dest } + + let rec actionToString = + function + | Verbose -> "--verbose" + | Quiet -> "--quit" + | NoMotd -> "--no-motd" + | Checksum -> "--checksum" + | Archive -> "--archive" + | NoOption action -> + let action = actionToString action + "--no-" + action.TrimStart([|'-'|]) + | Recursive -> "--recursive" + | Relative -> "--relative" + | NoImpliedDirs -> "--no-implied-dirs" + | Backup -> "--backup" + | BackupDir dir -> "--backup-dir=" + dir + | Suffix suffix -> "--suffix=" + suffix + | Update -> "--update" + | InPlace -> "--in-place" + | Append -> "--append" + | Dirs -> "--dirs" + | Links -> "--links" + | CopyLinks -> "--copy-links" + | CopyUnsafeLinks -> "--copy-unsafe-links" + | SafeLinks -> "--safe-links" + | CopyDirLinks -> "--copy-dirlinks" + | KeepDirLinks -> "--keep-dirlinks" + | HardLinks -> "--hard-links" + | Perms -> "--perms" + | Executability -> "--executability" + | Chmod chmod -> "--chmod=" + chmod + | Owner -> "--owner" + | Group -> "--group" + | Devices -> "--devices" + | Specials -> "--specials" + | D -> "-D" + | Times -> "--times" + | OmitDirTimes -> "--omit-dir-times" + | Super -> "--super" + | Sparse -> "--sparse" + | DryRun -> "--dry-run" + | WholeFile -> "--whole-file" + | OneFileSystem -> "--one-file-system" + | BlockSize size -> "--block-size=" + size + | Rsh command -> "--rsh=" + command + | RsyncPath program -> "--zsync-path=" + program + | Existing -> "--existing" + | IgnoreExisting -> "--ignore-existing" + | RemoveSourceFiles -> "--remove-source-files" + | Del -> "--del" + | Delete -> "--delete" + | DeleteBefore -> "--delete-before" + | DeleteDuring -> "--delete-during" + | DeleteAfter -> "--delete-after" + | DeleteExcluded -> "--delete-excluded" + | IgnoreErrors -> "--ignore-errors" + | Force -> "--force" + | MaxDelete num -> "--max-delete=" + string num + | MaxSize size -> "--max-size=" + size + | MinSize size -> "--min-size=" + size + | Partial -> "--partial" + | PartialDir dir -> "--partial-dir=" + dir + | DelayUpdates -> "--delay-updates" + | PruneEmptyDirs -> "--prune-empty-dirs" + | NumericIds -> "--numeric-ids" + | Timeout time -> "--timeout=" + string time + | IgnoreTimes -> "--ignore-times" + | SizeOnly -> "--size-only" + | ModifyWindow num -> "--modify-window=" + num + | TempDir dir -> "--temp-dir" + dir + | Fuzzy -> "--fuzzy" + | CompareDest dir -> "--compare-dest=" + dir + | CopyDest dir -> "--copy-dest=" + dir + | LinkDest dir -> "--link-dest=" + dir + | Compress -> "--compress" + | CompressLevel level -> "--compress-level=" + string level + | CvsExclude -> "--csv-exclude" + | Filter rule -> "--filter=" + rule + | F -> "-F" + | Exclude pattern -> "--exclude=" + pattern + | ExcludeFrom file -> "--exclude-from=" + file + | Include pattern -> "--include=" + pattern + | IncludeFrom file -> "--include-from=" + file + | FilesFrom file -> "--files-from=" + file + | From0 -> "--from0" + | Address address -> "--address=" + address + | Port port -> "--port=" + string port + | Sockopts options -> "--sockopts=" + options + | BlockingIO -> "--blocking-io" + | Stats -> "--stats" + | HeightBitsOutput -> "--8-bit-output" + | HumanReadable -> "--human-readable" + | Progress -> "--progress" + | P -> "-P" + | ItemizeChanges -> "--itemize-changes" + | OutFormat format -> "--out-format=" + format + | LogFile file -> "--log-file=" + file + | LogFileFormat format -> "--log-file-format=" + format + | PasswordFile file -> "--password-file=" + file + | ListOnly -> "--list-only" + | Bwlimit kbps -> "--bwlimit=" + kbps + | WriteBatch file -> "--write-bratch=" + file + | OnlyWriteBatch file -> "--only-write-batch=" + file + | ReadBatch file -> "--read-batch=" + file + | Protocol num -> "--protocol=" + string num + | ExtendedAttributes -> "--extended-attributes" + | Cache -> "--cache" + | Ipv4 -> "--ipv4" + | Ipv6 -> "--ipv6" + | Version -> "--version" + | Help -> "--help" + + let private buildCommonArgs (param: Options) = + (param.Actions |> List.map actionToString) + @ param.Sources + @ [ param.Destination ] + |> String.concat " " + + let exec (buildOptions: Options -> Options) args = + let results = new System.Collections.Generic.List() + let timeout = TimeSpan.MaxValue + + let errorF msg = + Trace.traceError msg + results.Add (ConsoleMessage.CreateError msg) + + let messageF msg = + Trace.trace msg + results.Add (ConsoleMessage.CreateOut msg) + + let options = buildOptions (Options.Create()) + let commonOptions = buildCommonArgs options + let cmdArgs = sprintf "%s %s " commonOptions args + + let result = + let f (info:ProcStartInfo) = + { info with + FileName = "rsync" + WorkingDirectory = options.WorkingDirectory + Arguments = cmdArgs } + + Process.execRaw f timeout true errorF messageF + ProcessResult.New result (results |> List.ofSeq) diff --git a/src/app/Fake.Rsync/paket.references b/src/app/Fake.Rsync/paket.references new file mode 100644 index 00000000000..2c8a7ddfd73 --- /dev/null +++ b/src/app/Fake.Rsync/paket.references @@ -0,0 +1,4 @@ +group netcore + +FSharp.Core +NETStandard.Library \ No newline at end of file From bb12da963cd0c6fdbcbeb9bb91fe93ca3573bc51 Mon Sep 17 00:00:00 2001 From: Maxime Mangel Date: Mon, 18 Jun 2018 15:32:27 +0200 Subject: [PATCH 2/3] Add AssemblyInfo.fs file for CI --- src/app/Fake.Rsync/AssemblyInfo.fs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/app/Fake.Rsync/AssemblyInfo.fs diff --git a/src/app/Fake.Rsync/AssemblyInfo.fs b/src/app/Fake.Rsync/AssemblyInfo.fs new file mode 100644 index 00000000000..6a83058992b --- /dev/null +++ b/src/app/Fake.Rsync/AssemblyInfo.fs @@ -0,0 +1,17 @@ +// Auto-Generated by FAKE; do not edit +namespace System +open System.Reflection + +[] +[] +[] +[] +[] +do () + +module internal AssemblyVersionInformation = + let [] AssemblyTitle = "FAKE - F# Make Core runtime features" + let [] AssemblyProduct = "FAKE - F# Make" + let [] AssemblyVersion = "5.0.0" + let [] AssemblyInformationalVersion = "5.0.0-beta025" + let [] AssemblyFileVersion = "5.0.0" From 6d7f5643015af880c0d0d7b13e57cf4a3ba7957a Mon Sep 17 00:00:00 2001 From: Maxime Mangel Date: Mon, 9 Jul 2018 16:18:35 +0200 Subject: [PATCH 3/3] Update according to comments --- src/app/Fake.Rsync/Rsync.fs | 40 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/app/Fake.Rsync/Rsync.fs b/src/app/Fake.Rsync/Rsync.fs index f8f1dc68c97..655f9543296 100644 --- a/src/app/Fake.Rsync/Rsync.fs +++ b/src/app/Fake.Rsync/Rsync.fs @@ -11,25 +11,25 @@ open System.IO /// /// ## Sample /// -/// let result = -/// Rsync.exec -/// (Rsync.Options.WithActions -/// [ -/// Rsync.Compress -/// Rsync.Archive -/// Rsync.Verbose -/// Rsync.NoOption Rsync.Perms -/// Rsync.Delete -/// Rsync.Exclude ".keep" -/// ] -/// >> Rsync.Options.WithSources -/// [ FleetMapping.server "build" -/// FleetMapping.server "package.json" -/// FleetMapping.server "yarn.lock" ] -/// >> Rsync.Options.WithDestination "remote@myserver.com:deploy") -/// "" -/// -/// if not result.OK then failwithf "Rsync failed with code %i" result.ExitCode +/// > let result = +/// > Rsync.exec +/// > (Rsync.Options.WithActions +/// > [ +/// > Rsync.Compress +/// > Rsync.Archive +/// > Rsync.Verbose +/// > Rsync.NoOption Rsync.Perms +/// > Rsync.Delete +/// > Rsync.Exclude ".keep" +/// > ] +/// > >> Rsync.Options.WithSources +/// > [ FleetMapping.server "build" +/// > FleetMapping.server "package.json" +/// > FleetMapping.server "yarn.lock" ] +/// > >> Rsync.Options.WithDestination "remote@myserver.com:deploy") +/// > "" +/// > +/// > if not result.OK then failwithf "Rsync failed with code %i" result.ExitCode [] module Rsync = @@ -271,7 +271,7 @@ module Rsync = static member WithDestination dest options = { options with Destination = dest } - let rec actionToString = + let rec private actionToString = function | Verbose -> "--verbose" | Quiet -> "--quit"