diff --git a/build.fsx b/build.fsx index f8a530f08d..66bf14a22a 100644 --- a/build.fsx +++ b/build.fsx @@ -64,6 +64,7 @@ let gitRaw = environVarOrDefault "gitRaw" "https://raw.github.com/fsprojects" let buildDir = "bin" let tempDir = "temp" let buildMergedDir = buildDir @@ "merged" +let buildMergedDirPS = buildDir @@ "Paket.PowerShell" // Read additional information from the release notes document @@ -140,7 +141,7 @@ Target "BuildPowerShell" (fun _ -> let result = ExecProcess (fun info -> info.FileName <- Path.Combine(Environment.SystemDirectory, @"WindowsPowerShell\v1.0\powershell.exe") - info.Arguments <- "-executionpolicy bypass -noprofile -file src/Paket.PowerShell/System.Management.Automation.ps1") System.TimeSpan.MaxValue + info.Arguments <- "-executionpolicy bypass -noprofile -file src/Paket.PowerShell/System.Management.Automation.ps1") System.TimeSpan.MaxValue if result <> 0 then failwithf "Error copying System.Management.Automation.dll" !! solutionFilePowerShell @@ -181,7 +182,7 @@ Target "MergePaketTool" (fun _ -> ) Target "MergePowerShell" (fun _ -> - CreateDir buildMergedDir + CreateDir buildMergedDirPS let toPack = ["paket.exe"; "Paket.Core.dll"; "FSharp.Core.dll"; "Newtonsoft.Json.dll"; "UnionArgParser.dll"; "Paket.PowerShell.dll"] @@ -191,10 +192,19 @@ Target "MergePowerShell" (fun _ -> let result = ExecProcess (fun info -> info.FileName <- currentDirectory @@ "packages" @@ "ILRepack" @@ "tools" @@ "ILRepack.exe" - info.Arguments <- sprintf "/verbose /lib:%s /out:%s %s" buildDir (buildMergedDir @@ "Paket.PowerShell.dll") toPack + info.Arguments <- sprintf "/verbose /lib:%s /out:%s %s" buildDir (buildMergedDirPS @@ "Paket.PowerShell.dll") toPack ) (TimeSpan.FromMinutes 5.) if result <> 0 then failwithf "Error during ILRepack execution." + + // copy psd1 & set version + CopyFile (buildMergedDirPS @@ "ArgumentTabCompletion.ps1") "src/Paket.PowerShell/ArgumentTabCompletion.ps1" + let psd1 = buildMergedDirPS @@ "Paket.PowerShell.psd1" + CopyFile psd1 "src/Paket.PowerShell/Paket.PowerShell.psd1" + use psd = File.AppendText psd1 + psd.WriteLine "" + psd.WriteLine (sprintf "ModuleVersion = '%s'" release.AssemblyVersion) + psd.WriteLine "}" ) Target "SignAssemblies" (fun _ -> diff --git a/src/Paket.PowerShell/ArgumentTabCompletion.ps1 b/src/Paket.PowerShell/ArgumentTabCompletion.ps1 new file mode 100644 index 0000000000..47f4fafedb --- /dev/null +++ b/src/Paket.PowerShell/ArgumentTabCompletion.ps1 @@ -0,0 +1,36 @@ + +# http://stackoverflow.com/questions/30923696/add-custom-argument-completer-for-cmdlet + +# https://github.com/mariuszwojcik/RabbitMQTools/blob/master/TabExpansions.ps1 +function createCompletionResult([string]$text, [string]$value, [string]$tooltip) { + if ([string]::IsNullOrEmpty($value)) { return } + if ([string]::IsNullOrEmpty($text)) { $text = $value } + if ([string]::IsNullOrEmpty($tooltip)) { $tooltip = $value } + $completionText = @{$true="'$value'"; $false=$value }[$value -match "\W"] + $completionText = $completionText -replace '\[', '``[' -replace '\]', '``]' + New-Object System.Management.Automation.CompletionResult $completionText, $text, 'ParameterValue', $tooltip | write +} + +$findPackages = { + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) + Paket-FindPackages -SearchText $wordToComplete -Max 100 | % { + createCompletionResult $_ $_ $_ | write + } +} + +$findPackageVersions = { + param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) + if (-not $fakeBoundParameter.NuGet){ return } + Paket-FindPackageVersions -Name $fakeBoundParameter.NuGet -Max 100 | % { + createCompletionResult $_ $_ $_ | write + } +} + +# create and add $global:options to the list of completers +# http://www.powertheshell.com/dynamicargumentcompletion/ +if (-not $global:options) { $global:options = @{CustomArgumentCompleters = @{};NativeArgumentCompleters = @{}}} + +$global:options['CustomArgumentCompleters']['Paket-Add:NuGet'] = $findPackages +$global:options['CustomArgumentCompleters']['Paket-Add:Version'] = $findPackageVersions + +$function:tabexpansion2 = $function:tabexpansion2 -replace 'End\r\n{','End { if ($null -ne $options) { $options += $global:options} else {$options = $global:options}' \ No newline at end of file diff --git a/src/Paket.PowerShell/Paket.PowerShell.fsproj b/src/Paket.PowerShell/Paket.PowerShell.fsproj index 98573321bb..274dadbee1 100644 --- a/src/Paket.PowerShell/Paket.PowerShell.fsproj +++ b/src/Paket.PowerShell/Paket.PowerShell.fsproj @@ -49,6 +49,8 @@ + + diff --git a/src/Paket.PowerShell/Paket.PowerShell.psd1 b/src/Paket.PowerShell/Paket.PowerShell.psd1 new file mode 100644 index 0000000000..7713be7c3b --- /dev/null +++ b/src/Paket.PowerShell/Paket.PowerShell.psd1 @@ -0,0 +1,12 @@ +@{ +GUID = 'e7bdf748-93e9-4e24-95a2-ace98df3d687' +Author = 'Paket' +Copyright = '(c) 2015 Paket. All rights reserved.' +PowerShellVersion = '3.0' +CLRVersion = '4.0' +RootModule = 'Paket.PowerShell.dll' +HelpInfoUri = 'http://fsprojects.github.io/Paket/' +ScriptsToProcess = 'ArgumentTabCompletion.ps1' +# the build will append these lines +# ModuleVersion = '1.0.0' +# } \ No newline at end of file diff --git a/src/Paket.PowerShell/PowerShell.fs b/src/Paket.PowerShell/PowerShell.fs index ea28084fef..d172b4211c 100644 --- a/src/Paket.PowerShell/PowerShell.fs +++ b/src/Paket.PowerShell/PowerShell.fs @@ -25,7 +25,11 @@ module PaketPs = async { try do! Async.SwitchToNewThread() - do! computation + // prevent an exception from killing the thread, PS thread, and PS exe + try + do! computation + with + | ex -> Logging.traceWarn ex.Message finally sink.StopFill() } |> Async.Start @@ -36,8 +40,8 @@ module PaketPs = type Add() = inherit PSCmdlet() - [] member val NuGet = "" with get, set - [] member val Version = "" with get, set + [][] member val NuGet = "" with get, set + [] member val Version = "" with get, set [] member val Project = "" with get, set [] member val Force = SwitchParameter() with get, set [] member val Interactive = SwitchParameter() with get, set @@ -47,7 +51,7 @@ type Add() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if String.IsNullOrEmpty x.NuGet = false then yield AddArgs.Nuget x.NuGet if String.IsNullOrEmpty x.Version = false then @@ -62,8 +66,7 @@ type Add() = yield AddArgs.Hard if x.NoInstall.IsPresent then yield AddArgs.No_Install - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.add } |> processWithLogging x @@ -78,13 +81,12 @@ type AutoRestoreCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if x.On.IsPresent then yield AutoRestoreArgs.On if x.Off.IsPresent then yield AutoRestoreArgs.Off - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.autoRestore } |> processWithLogging x @@ -98,11 +100,10 @@ type ConfigCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if String.IsNullOrEmpty x.AddCredentials = false then yield ConfigArgs.AddCredentials x.AddCredentials - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.config } |> processWithLogging x @@ -120,7 +121,7 @@ type ConvertFromNuGetCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if x.Force.IsPresent then yield ConvertFromNugetArgs.Force if x.NoInstall.IsPresent then @@ -129,8 +130,7 @@ type ConvertFromNuGetCmdlet() = yield ConvertFromNugetArgs.No_Auto_Restore if String.IsNullOrEmpty x.CredsMigration = false then yield ConvertFromNugetArgs.Creds_Migration x.CredsMigration - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.convert } |> processWithLogging x @@ -139,16 +139,15 @@ type ConvertFromNuGetCmdlet() = type FindRefsCmdlet() = inherit PSCmdlet() - [] member val NuGet : string[] = Array.empty with get, set + [] member val NuGet : string[] = Array.empty with get, set override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ for p in x.NuGet do yield FindRefsArgs.Packages p - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.findRefs } |> processWithLogging x @@ -157,7 +156,7 @@ type FindRefsCmdlet() = type FindPackagesCmdlet() = inherit PSCmdlet() - [] member val SearchText = "" with get, set + [][] member val SearchText = "" with get, set [] member val Source = "" with get, set [] member val Max = Int32.MinValue with get, set [] member val Silent = SwitchParameter() with get, set @@ -165,7 +164,7 @@ type FindPackagesCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if String.IsNullOrEmpty x.SearchText = false then yield FindPackagesArgs.SearchText x.SearchText if String.IsNullOrEmpty x.Source = false then @@ -174,8 +173,7 @@ type FindPackagesCmdlet() = yield FindPackagesArgs.MaxResults x.Max if x.Silent.IsPresent then yield FindPackagesArgs.Silent - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.findPackages } |> processWithLogging x @@ -184,7 +182,7 @@ type FindPackagesCmdlet() = type FindPackageVersionsCmdlet() = inherit PSCmdlet() - [] member val Name = "" with get, set + [][] member val Name = "" with get, set [] member val Source = "" with get, set [] member val Max = Int32.MinValue with get, set [] member val Silent = SwitchParameter() with get, set @@ -192,7 +190,7 @@ type FindPackageVersionsCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if String.IsNullOrEmpty x.Name = false then yield FindPackageVersionsArgs.Name x.Name if String.IsNullOrEmpty x.Source = false then @@ -201,8 +199,7 @@ type FindPackageVersionsCmdlet() = yield FindPackageVersionsArgs.MaxResults x.Max if x.Silent.IsPresent then yield FindPackageVersionsArgs.Silent - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.findPackageVersions } |> processWithLogging x @@ -230,15 +227,14 @@ type InstallCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if x.Force.IsPresent then yield InstallArgs.Force if x.Hard.IsPresent then yield InstallArgs.Hard if x.Redirects.IsPresent then yield InstallArgs.Redirects - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.install } |> processWithLogging x @@ -253,13 +249,12 @@ type OutdatedCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if x.IgnoreConstraints.IsPresent then yield OutdatedArgs.Ignore_Constraints if x.IncludePrereleases.IsPresent then yield OutdatedArgs.Include_Prereleases - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.outdated } |> processWithLogging x @@ -276,7 +271,7 @@ type PushCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if String.IsNullOrEmpty x.Url = false then yield PushArgs.Url x.Url if String.IsNullOrEmpty x.File = false then @@ -285,8 +280,7 @@ type PushCmdlet() = yield PushArgs.ApiKey x.ApiKey if String.IsNullOrEmpty x.Endpoint = false then yield PushArgs.EndPoint x.Endpoint - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.push } |> processWithLogging x @@ -295,7 +289,7 @@ type PushCmdlet() = type RemoveCmdlet() = inherit PSCmdlet() - [] member val NuGet = "" with get, set + [][] member val NuGet = "" with get, set [] member val Project = "" with get, set [] member val Force = SwitchParameter() with get, set [] member val Interactive = SwitchParameter() with get, set @@ -305,7 +299,7 @@ type RemoveCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if String.IsNullOrEmpty x.NuGet = false then yield RemoveArgs.Nuget x.NuGet if String.IsNullOrEmpty x.Project = false then @@ -318,8 +312,7 @@ type RemoveCmdlet() = yield RemoveArgs.Hard if x.NoInstall.IsPresent then yield RemoveArgs.No_Install - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.remove } |> processWithLogging x @@ -334,13 +327,12 @@ type RestoreCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if x.Force.IsPresent then yield RestoreArgs.Force for rf in x.ReferencesFiles do yield RestoreArgs.References_Files rf - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.restore } |> processWithLogging x @@ -354,11 +346,10 @@ type SimplifyCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if x.Interactive.IsPresent then yield SimplifyArgs.Interactive - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.simplify } |> processWithLogging x @@ -374,15 +365,14 @@ type ShowInstalledPackagesCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if x.All.IsPresent then yield ShowInstalledPackagesArgs.All if String.IsNullOrEmpty x.Project = false then yield ShowInstalledPackagesArgs.Project x.Project if x.Silent.IsPresent then yield ShowInstalledPackagesArgs.Silent - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.showInstalledPackages } |> processWithLogging x @@ -391,8 +381,8 @@ type ShowInstalledPackagesCmdlet() = type UpdateCmdlet() = inherit PSCmdlet() - [] member val NuGet = "" with get, set - [] member val Version = "" with get, set + [][] member val NuGet = "" with get, set + [] member val Version = "" with get, set [] member val Force = SwitchParameter() with get, set [] member val Hard = SwitchParameter() with get, set [] member val Redirects = SwitchParameter() with get, set @@ -400,7 +390,7 @@ type UpdateCmdlet() = override x.ProcessRecord() = async { let parser = UnionArgParser.Create() - seq { + [ if String.IsNullOrEmpty x.NuGet = false then yield UpdateArgs.Nuget x.NuGet if String.IsNullOrEmpty x.Version = false then @@ -411,8 +401,7 @@ type UpdateCmdlet() = yield UpdateArgs.Hard if x.Redirects.IsPresent then yield UpdateArgs.Redirects - } - |> List.ofSeq + ] |> parser.CreateParseResultsOfList |> Program.update } |> processWithLogging x \ No newline at end of file diff --git a/src/Paket.PowerShell/paket.template b/src/Paket.PowerShell/paket.template index 0dce8cbda0..10eab18165 100644 --- a/src/Paket.PowerShell/paket.template +++ b/src/Paket.PowerShell/paket.template @@ -2,8 +2,6 @@ type file id Paket.PowerShell description A package dependency manager for .NET with support for NuGet packages and GitHub repositories. -version - 0.30.0-alpha014 authors Paket team summary @@ -14,7 +12,9 @@ iconurl https://raw.githubusercontent.com/fsprojects/Paket/master/docs/files/img tags nuget, bundler, F# files - ../../bin/merged/Paket.PowerShell.dll ==> tools/Paket.PowerShell + ../../bin/Paket.PowerShell/Paket.PowerShell.dll ==> tools/Paket.PowerShell + ../../bin/Paket.PowerShell/Paket.PowerShell.psd1 ==> tools/Paket.PowerShell + ArgumentTabCompletion.ps1 ==> tools/Paket.PowerShell init.ps1 ==> tools chocolateyInstall.ps1 ==> tools Install-PSModulePath.ps1 ==> tools \ No newline at end of file diff --git a/src/Paket/Program.fs b/src/Paket/Program.fs index aef9207ba6..7bac282878 100644 --- a/src/Paket/Program.fs +++ b/src/Paket/Program.fs @@ -250,54 +250,58 @@ let push (results : ArgParseResults<_>) = ?endPoint = results.TryGetResult <@ PushArgs.EndPoint @>, ?apiKey = results.TryGetResult <@ PushArgs.ApiKey @>) -try +let main() = use consoleTrace = Logging.event.Publish |> Observable.subscribe Logging.traceToConsole use fileTrace = match logFile with | Some lf -> setLogFile lf | None -> null - let parser = UnionArgParser.Create() - let results = - parser.Parse(inputs = args, - ignoreMissing = true, - ignoreUnrecognized = true, - raiseOnUsage = false) - match results.GetAllResults() with - | [ command ] -> - let handler = - match command with - | Add -> processCommand add - | Config -> processWithValidation validateConfig config - | ConvertFromNuget -> processCommand convert - | FindRefs -> processCommand findRefs - | Init -> processCommand init - | AutoRestore -> processWithValidation validateAutoRestore autoRestore - | Install -> processCommand install - | Outdated -> processCommand outdated - | Remove -> processCommand remove - | Restore -> processCommand restore - | Simplify -> processCommand simplify - | Update -> processCommand update - | FindPackages -> processCommand findPackages - | FindPackageVersions -> processCommand findPackageVersions - | ShowInstalledPackages -> processCommand showInstalledPackages - | Pack -> processCommand pack - | Push -> processCommand push - - let args = args.[1..] - - handler command args - | [] -> + try + let parser = UnionArgParser.Create() + let results = + parser.Parse(inputs = args, + ignoreMissing = true, + ignoreUnrecognized = true, + raiseOnUsage = false) + + match results.GetAllResults() with + | [ command ] -> + let handler = + match command with + | Add -> processCommand add + | Config -> processWithValidation validateConfig config + | ConvertFromNuget -> processCommand convert + | FindRefs -> processCommand findRefs + | Init -> processCommand init + | AutoRestore -> processWithValidation validateAutoRestore autoRestore + | Install -> processCommand install + | Outdated -> processCommand outdated + | Remove -> processCommand remove + | Restore -> processCommand restore + | Simplify -> processCommand simplify + | Update -> processCommand update + | FindPackages -> processCommand findPackages + | FindPackageVersions -> processCommand findPackageVersions + | ShowInstalledPackages -> processCommand showInstalledPackages + | Pack -> processCommand pack + | Push -> processCommand push + + let args = args.[1..] + + handler command args + | [] -> + Environment.ExitCode <- 1 + traceError "Command was:" + traceError (" " + String.Join(" ",Environment.GetCommandLineArgs())) + parser.Usage("available commands:") |> traceError + | _ -> failwith "expected only one command" + with + | exn when not (exn :? System.NullReferenceException) -> Environment.ExitCode <- 1 - traceError "Command was:" - traceError (" " + String.Join(" ",Environment.GetCommandLineArgs())) - parser.Usage("available commands:") |> traceError - | _ -> failwith "expected only one command" -with -| exn when not (exn :? System.NullReferenceException) -> - Environment.ExitCode <- 1 - traceErrorfn "Paket failed with:%s\t%s" Environment.NewLine exn.Message - - if verbose then - traceErrorfn "StackTrace:%s %s" Environment.NewLine exn.StackTrace \ No newline at end of file + traceErrorfn "Paket failed with:%s\t%s" Environment.NewLine exn.Message + + if verbose then + traceErrorfn "StackTrace:%s %s" Environment.NewLine exn.StackTrace + +main() \ No newline at end of file