diff --git a/src/Paket.Bootstrapper/WindowsProcessArguments.cs b/src/Paket.Bootstrapper/WindowsProcessArguments.cs index e1b9df7e51..3912aea55e 100644 --- a/src/Paket.Bootstrapper/WindowsProcessArguments.cs +++ b/src/Paket.Bootstrapper/WindowsProcessArguments.cs @@ -3,7 +3,7 @@ namespace Paket.Bootstrapper { - static class WindowsProcessArguments + public static class WindowsProcessArguments { static void AddBackslashes(StringBuilder builder, int backslashes, bool beforeQuote) { diff --git a/src/Paket.CmdLineHelpers/Paket.CmdLineHelpers.csproj b/src/Paket.CmdLineHelpers/Paket.CmdLineHelpers.csproj new file mode 100644 index 0000000000..84184ed101 --- /dev/null +++ b/src/Paket.CmdLineHelpers/Paket.CmdLineHelpers.csproj @@ -0,0 +1,11 @@ + + + + netcoreapp2.1 + + + + + + + diff --git a/src/Paket.CmdLineHelpers/paket.references b/src/Paket.CmdLineHelpers/paket.references new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Paket/Paket.fsproj b/src/Paket/Paket.fsproj index 56ac8eb56a..88d0d0dcaf 100644 --- a/src/Paket/Paket.fsproj +++ b/src/Paket/Paket.fsproj @@ -1,7 +1,8 @@  Exe - net461;netcoreapp2.1 + netcoreapp2.1;net461 + 5.239.0-beta-0001 false Paket paket @@ -11,10 +12,14 @@ https://raw.githubusercontent.com/fsprojects/Paket/master/docs/files/img/logo.png nuget;bundler;F# + + PAKET_GLOBAL_LOCAL;$(DefineConstants) + netcoreapp2.1 + PAKET_GLOBAL_LOCAL;$(DefineConstants) @@ -25,14 +30,38 @@ - + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Paket/Program.fs b/src/Paket/Program.fs index 56d142682a..fcb0ef69e1 100644 --- a/src/Paket/Program.fs +++ b/src/Paket/Program.fs @@ -37,10 +37,11 @@ let processWithValidationEx printUsage silent validateF commandF result = traceError (" " + String.Join(" ",Environment.GetCommandLineArgs())) printUsage result - Environment.ExitCode <- 1 + 1 else try commandF result + 0 finally sw.Stop() if not silent then @@ -866,6 +867,97 @@ let handleCommand silent command = | Version | Log_File _ -> failwithf "internal error: this code should never be reached." +#if PAKET_GLOBAL_LOCAL + +(* +#load @"..\Paket.Core\Common\Domain.fs" +#load @"..\Paket.Core\Common\Logging.fs" +#load @"..\Paket.Core\Common\Constants.fs" +open System +open System.IO +open Paket +*) + +let rec findRootInHierarchyFrom (dir: DirectoryInfo) = + if not (dir.Exists) then + None + else + let dotPaketDir = + Path.Combine(dir.FullName, Constants.PaketFolderName) + |> DirectoryInfo + if dotPaketDir.Exists then + Some dir + else + match dir.Parent with + | null -> None + | root -> findRootInHierarchyFrom root + +let findRootInHierarchy () = + (Directory.GetCurrentDirectory() |> DirectoryInfo) + |> findRootInHierarchyFrom + +let runIt exeName exeArgs = + use p = new Process() + + // let argString : string = Paket.Bootstrapper.WindowsProcessArguments.ToString(exeArgs) + // let psi = ProcessStartInfo(FileName = exeName, Arguments = argString, UseShellExecute = false) + // printfn "Running: %s %A" exeName (psi.Arguments) + + let psi = ProcessStartInfo(FileName = exeName, Arguments = "", UseShellExecute = false) + for arg in exeArgs do + psi.ArgumentList.Add(arg) + printfn "Running: %s %A" exeName (psi.ArgumentList |> Seq.toList) + + p.StartInfo <- psi + + p.Start() |> ignore + p.WaitForExit() + p.ExitCode + + +[] +type GlobalCommand = + // global options + | [] Silent + | [] Verbose + // subcommands + | [] Init of ParseResults +with + interface IArgParserTemplate with + member this.Usage = + match this with + | Init _ -> "create an empty paket.dependencies file in the current working directory" + | Silent -> "suppress console output" + | Verbose -> "print detailed information to the console" + +let globalCommandParser = ArgumentParser.Create(programName = "paket", errorHandler = new ProcessExiter(), checkStructure = false) + +let dotnetToolManifestPath (dir: DirectoryInfo) = + Path.Combine(dir.FullName, ".config", "dotnet-tools.json") + |> FileInfo + +open System.Reflection + +let isToolLocal () = + let x = typeof.Assembly.Location + // printfn "%s" x + + // local is like + // C:\Users\e0s01ao\.nuget\packages\paket\5.239.0-beta-0001\tools\netcoreapp2.1\any\paket.dll + + // global is like + // C:\Users\e0s01ao\.dotnet\tools\.store\paket\5.239.0-beta-0001\paket\5.239.0-beta-0001\tools\netcoreapp2.1\any\paket.dll + + let isToolGlobal = x.Contains(".store") + + // printfn "tg %O" isToolGlobal + + let isToolLocal = not isToolGlobal + + isToolLocal + +#endif + let main() = let waitDebuggerEnvVar = Environment.GetEnvironmentVariable ("PAKET_WAIT_DEBUGGER") if waitDebuggerEnvVar = "1" then @@ -932,12 +1024,91 @@ let main() = | None -> null handleCommand silent (results.GetSubCommand()) + else + 0 with | exn when not (exn :? System.NullReferenceException) -> - Environment.ExitCode <- 1 traceErrorfn "Paket failed with" if Environment.GetEnvironmentVariable "PAKET_DETAILED_ERRORS" = "true" then printErrorExt true true true exn else printError exn + 1 + +#if PAKET_GLOBAL_LOCAL + +let handleGlobalCommand silent command = + match command with + | GlobalCommand.Init r -> processCommand silent (init) r + // global options; list here in order to maintain compiler warnings + // in case of new subcommands added + | GlobalCommand.Verbose + | GlobalCommand.Silent -> failwithf "internal error: this code should never be reached." -main() +let mainGlobal () = + let waitDebuggerEnvVar = Environment.GetEnvironmentVariable ("PAKET_WAIT_DEBUGGER") + if waitDebuggerEnvVar = "1" then + waitForDebugger() + + Logging.verboseWarnings <- Environment.GetEnvironmentVariable "PAKET_DETAILED_WARNINGS" = "true" + use consoleTrace = Logging.event.Publish |> Observable.subscribe Logging.traceToConsole + + // TODO ^--- no need to duplicate these, move in entrypoint + + try + let parser = ArgumentParser.Create(programName = "paket", + helpTextMessage = sprintf "Paket version %s%sHelp was requested:" paketVersion Environment.NewLine, + errorHandler = new PaketExiter(), + checkStructure = false) + + let results = parser.ParseCommandLine(raiseOnUsage = true) + let silent = results.Contains <@ GlobalCommand.Silent @> + tracePaketVersion silent + + if results.Contains <@ GlobalCommand.Verbose @> then + Logging.verbose <- true + Logging.verboseWarnings <- true + + handleGlobalCommand silent (results.GetSubCommand()) + + //TODO v---- no need to duplicate, move in entrypoint? or not + with + | exn when not (exn :? System.NullReferenceException) -> + traceErrorfn "Paket failed with" + if Environment.GetEnvironmentVariable "PAKET_DETAILED_ERRORS" = "true" then + printErrorExt true true true exn + else printError exn + 1 + +#endif + +[] +let theMain argv = +#if PAKET_GLOBAL_LOCAL + let isToolLocal = isToolLocal () + + if isToolLocal then + main () + else + let paketRoot = findRootInHierarchy () + match paketRoot with + | None -> + // act as global tool (subset of commands) + mainGlobal () + | Some dir -> + let manifestToolPath = dotnetToolManifestPath dir + if manifestToolPath.Exists then + // paket as local tool => `dotnet paket` + + //TODO check if paket is installed in manifest! otherwise tell to user! + + runIt "dotnet" [| yield "paket"; yield! argv |] + else + // old paket => `.paket/paket` + let paketExePath = + Path.Combine(dir.FullName, Constants.PaketFolderName, Constants.PaketFileName) + |> Path.GetFullPath + runIt paketExePath argv + +#else + main () +#endif