Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile .fsx #1780

Merged
merged 6 commits into from
Mar 19, 2019
Merged

Compile .fsx #1780

merged 6 commits into from
Mar 19, 2019

Conversation

alfonsogarciacaro
Copy link
Member

@alfonsogarciacaro alfonsogarciacaro commented Mar 8, 2019

Alternative to #1728

See discussion: f56e3f3#commitcomment-32633830

@nojaf
Copy link
Member

nojaf commented Mar 11, 2019

@alfonsogarciacaro could you tell me again why the dlls should be coming form the nuget cache (C:\Users\me.nuget\packages\microsoft.netcore.app\2.1.6) instead of the dotnet install location (C:\Program Files\dotnet\sdk\2.1.503)?

Because this scenario would fail when using a clean install of dotnet (C:\Users\me.nuget\packages is empty). A dockerbased build would have this issue for example.

@alfonsogarciacaro
Copy link
Member Author

@nojaf You tell me :) I don't know why but in my machine (macOS) the parsing wasn't working when using "usr/local/share/dotnet/shared/Microsoft.NETCore.App/2.1.6" (see first comment of the thread). Not sure if that's the equivalent of "C:\Program Files\dotnet\sdk\2.1.503" on Windows. If it's not, we can change it but we need a cross platform way to find the dotnet SDK location (taking into account it may be a custom path not a global installation).

@nojaf
Copy link
Member

nojaf commented Mar 11, 2019

As requested a while ago, my project options in my fsx fork
image

image

image

@alfonsogarciacaro
Copy link
Member Author

Thanks @nojaf! So in your case you're referencing .NET Framework assemblies. Interesting, although this will likely not work in non-Windows machines without mono installed 🤔

BTW, sorry I forgot to tell you, but you can pass the verbose option to see the options in the command line.

                use: {
                    loader: "fable-loader",
                    options: {
                        cli: { verbose: true }
                    }
                }

@nojaf
Copy link
Member

nojaf commented Mar 12, 2019

    let getNetcoreAssembliesDir() =
        let matchProcessOutput exe args regexPattern =
            let _, logOut, _ =
                runProcess "." exe args
            Regex.Match(String.concat " " logOut, regexPattern)
        let nugetCache =
            matchProcessOutput "dotnet" "nuget locals global-packages --list"
                               @"info\s*:\s*global-packages\s*:\s*(.+)"
            |> fun m -> m.Groups.[1].Value.Trim()
        let hostVersion =
            matchProcessOutput "dotnet" "--info"
                               @"Host[\s\S]*?Version\s*:\s*([\d.]+)"
            |> fun m -> m.Groups.[1].Value
        let v = hostVersion.Split('.')
        let netCoreAssembliesDir = Path.Combine(nugetCache, "microsoft.netcore.app", hostVersion, "ref", "netcoreapp" + v.[0] + "." + v.[1])
        if not(Directory.Exists(netCoreAssembliesDir)) then
            failwith "NET core assemblies cannot be found in cache."
            
        netCoreAssembliesDir

The netCoreAssembliesDir does not exist for me on Windows (2.2.103). Workaround there is Path.GetDirectoryName(typeof<int>.GetTypeInfo().Assembly.Location).

Then the InteractiveChecker can figure out everything for me, however I hit a wall in Agent.fs.

In

let checkProject (msg: Parser.Message)
                 (opts: FSharpProjectOptions)
                 (fableLibraryDir: string)
                 (triggerFile: string)
                 (srcFiles: File[])
                 (checker: InteractiveChecker) =
    Log.logAlways(sprintf "Parsing %s..." (getRelativePath opts.ProjectFileName))
    let checkedProject =
        let fileDic = srcFiles |> Seq.map (fun f -> f.NormalizedFullPath, f) |> dict
        let sourceReader f = fileDic.[f].ReadSource()
        let filePaths = srcFiles |> Array.map (fun file -> file.NormalizedFullPath)
        checker.ParseAndCheckProject(opts.ProjectFileName, filePaths, sourceReader)
    // checkFableCoreVersion checkedProject
    let optimized = GlobalParams.Singleton.Experimental.Contains("optimize-fcs")
    let implFiles =
        if not optimized
        then checkedProject.AssemblyContents.ImplementationFiles
        else checkedProject.GetOptimizedAssemblyContents().ImplementationFiles
    if List.isEmpty implFiles then
        Log.logAlways "The list of files returned by F# compiler is empty"
    let implFilesMap =
        implFiles |> Seq.map (fun file -> Path.normalizePathAndEnsureFsExtension file.FileName, file) |> dict
    tryGetOption "saveAst" msg.extra |> Option.iter (fun outDir ->
        Printers.printAst outDir implFiles)
    Project(opts, implFilesMap, checkedProject.Errors)
    |> ProjectExtra.Create checker srcFiles triggerFile fableLibraryDir

implFilesMap only contains a single file, however my script.fsx contains:

#load @".paket\load\netstandard2.0\main.group.fsx"

open Fable.Helpers.React
open Fable.Import

let view = div [] [str "dev server_ ziggy"]

ReactDom.render(view, Browser.document.getElementById "app")

main.fsx is part of the Map, but the entry script.fsx is not.
checkedProject.AssemblyContents.ImplementationFiles only contains one file (main.fsx).

@alfonsogarciacaro
Copy link
Member Author

I already tried Path.GetDirectoryName(typeof<int>.GetTypeInfo().Assembly.Location) to get the location of the system assemblies but with my mac I had an issue similar to you, just a bit worse because the implFilesMap was totally empty.

Did I already say I hate dotnet assembly resolution? 😉

We could try going back to your PR though I'd prefer to remove most of the code we don't need (locating MSBuild exe, NET Framework installation, etc).

@nojaf
Copy link
Member

nojaf commented Mar 12, 2019

Interesting, pointing to a location that does exist in my global nuget cache (C:\Users\nojaf\.nuget\packages\microsoft.netcore.app\2.1.6\ref\netcoreapp2.1) gives me two implementation files.

Compilation fails now because

C:/Temp/fsx-sample/script.fsx(6,19): (6,42) error FABLE: Cannot resolve Fable.Helpers.React.str
C:/Temp/fsx-sample/script.fsx(6,11): (6,43) error FABLE: Cannot resolve Fable.Helpers.React.div

I guess the ref to packages\Fable.React\fable\Fable.React.fsproj is now missing.

@nojaf
Copy link
Member

nojaf commented Mar 12, 2019

Added some code that resolve the Fable projects, back to resolving dlls now ;)

@nojaf
Copy link
Member

nojaf commented Mar 12, 2019

A workaround might be the following:

        if not(Directory.Exists(netCoreAssembliesDir)) then
            let netappCore = sprintf "%s.%s" v.[0] v.[1]
            let proj = sprintf """<?xml version="1.0" encoding="utf-8"?>
                                    <Project Sdk="Microsoft.NET.Sdk">
                                      <PropertyGroup>
                                        <TargetFramework>netcoreapp%s</TargetFramework>
                                      </PropertyGroup>
                                      <ItemGroup>
                                        <PackageReference Include="Microsoft.NETCore.App" Version="%s" />
                                      </ItemGroup>
                                    </Project>
                                    """ netappCore hostVersion
                                    
            let tempFolder = Path.GetTempPath()
            let tempProj = System.IO.Path.Combine(tempFolder, (sprintf "%s.proj" (System.Guid.NewGuid().ToString("N"))))
            System.IO.File.WriteAllText(tempProj, proj)
            let restoreCode = runProcess tempFolder "dotnet" (sprintf "restore \"%s\"" tempProj)
            System.IO.File.Delete(tempProj)

Although that is not really the nicest solution, won't commit that part without any approval 😋

@alfonsogarciacaro
Copy link
Member Author

I actually thought of the temp project solution too at one point :) I'm not opposed to it if it's something temporary, works cross platform and it's conveniently encapsulated 👍

@nojaf nojaf mentioned this pull request Mar 15, 2019
3 tasks
@nojaf
Copy link
Member

nojaf commented Mar 15, 2019

@alfonsogarciacaro @ncave I think this is ready for review.
I've created a sample that uses Paket load file to get all the dependencies. Webpack-dev-server works, reload on file change.

Let me know if anything is still missing.

@alfonsogarciacaro
Copy link
Member Author

I've tested this on my computer and it's working. We will soon release fable-compiler 2.2 with .fsx compatibility :) Thanks a lot for your hard work @nojaf!

@alfonsogarciacaro alfonsogarciacaro merged commit a6b645a into master Mar 19, 2019
@alfonsogarciacaro alfonsogarciacaro restored the fsx branch July 2, 2020 05:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants