Skip to content
This repository has been archived by the owner on Oct 7, 2020. It is now read-only.

[WIP] Download hlint data-files if they cant be found. #1540

Closed
wants to merge 1 commit into from

Conversation

fendor
Copy link
Collaborator

@fendor fendor commented Jan 2, 2020

Closes #1143
Changes the behaviour in the following way:

  • Introduces a initializeHlint function
  • Introduce HIE_HLINT_DATADIR env variable for the location of the data-files.
  • Download missing data-files with stack or cabal, whatever is available.
  • Copy data-files into XDG_DATA_HOME/hie/hlint
  • Write the data-dir location into the extensible state.

Missing stuff:

To check it out, open a project wait for typecheck, then reopen the project again. Now no data-files should be downloaded and hlint should produce diagnostics. On the first try, it definitely does not produce diagnostics, since I didnt implement After downloading stuff, set the data-dir location in the extensible state. yet.

@fendor fendor requested review from lukel97, alanz and jneira January 2, 2020 21:08
Comment on lines +197 to +198
Cabal -> ["get", hlintName]
Stack -> ["unpack", hlintName]
Copy link
Collaborator Author

@fendor fendor Jan 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the cabal is not updated and doesnt know about the hlint version?
What if the hlint version is not on stackage? (very unlikely, just feels like not good software engineering)

Copy link
Member

@jneira jneira Jan 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmm and what about download the data file directly from https://raw.githubusercontent.com/ndmitchell/hlint/v2.2.5/data/hlint.yaml?
Are the rest of files inside data needed for the hie usage?
Hardcoding the url is not ideal, but it uses fewer moving parts

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is also an option. Just making sure that we get the one as per the version of hlint we are using in the build. Probably the best option.

let hOpts = hlintOpts lintFile (oneHintPos <$> mhint)
getIdeas :: MonadIO m => HlintDataDir -> FilePath -> Maybe OneHint -> ExceptT String m [Idea]
getIdeas dataDir lintFile mhint = do
let hOpts = hlintOpts dataDir lintFile (oneHintPos <$> mhint)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do more locations need to be updates?

Comment on lines +474 to +476
logm "Downloading hlint data-files now."
liftIO ApplyRefact.downloadHlintDatafiles
logm "Finished downloading."
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably be messages to the user.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, progress status messages in the status bar would be great for that

Comment on lines +155 to +159
hlintName :: String
hlintName = "hlint-" ++ VERSION_hlint

hlintDataDirDefaultLocation :: MonadIO m => m FilePath
hlintDataDirDefaultLocation = liftIO $ getXdgDirectory XdgData ("hie" </> "hlint")
Copy link
Collaborator Author

@fendor fendor Jan 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we have to duplicate this code in install.hs, which I think is problematic, especially since we have to VERSION_hlint no access. Any ideas @jneira?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are using the same version of hlint for all ghc versions, right? It is hardcoded in all stack-*.yaml, so maybe it is not a big deal hardcoding it in the script? Not very elegant, though.

Mmm maybe overriding the environment variable hlint_datadir defined by cabal in Paths_hlint.hs before installing hie, so hlint data files will go in that location (not sure it works that way)

liftIO (doesFileExist explicitDir)
>>= \case
True ->
return $ Right explicitDir
Copy link
Collaborator Author

@fendor fendor Jan 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a check if the directory contains any files.

@alanz
Copy link
Collaborator

alanz commented Jan 2, 2020

I am not convinced that this is the right way to do this.

Can we not copy the config file at compile time? Even if we write some sort of helper exe.

And if we do end up doing this, I do not believe the downloading code belongs in the ApplyRefact plugin.

Perhaps we should reach out to @ndmitchell for some ideas around this. I am sure he has a way of installing hlint for CI via a simple download. Rather tap into existing infrastructure.

@fendor
Copy link
Collaborator Author

fendor commented Jan 2, 2020

We discussed this issue in ndmitchell/hlint#620. I took away from it, that it is probably best to use cabal get or stack unpack to get the data-files.
We can do it only at compile-time and handle it like we do with hoogle.
Downloading them at run-time has the advantage that it is viable for users to just download the executable and it works right away. But if you think this is not worth the additional overhead, we can do it only at compile-time.

@alanz
Copy link
Collaborator

alanz commented Jan 2, 2020

The hlint install CI script does

$ curl -sSL https://raw.github.com/ndmitchell/neil/master/misc/run.sh
#!/bin/sh
# This script is invoked from my Travis commands
# It bootstraps to grab the a binary release and run it
set -e # exit on errors

PACKAGE=$1
if [ -z "$PACKAGE" ]; then
    echo No arguments provided, please pass the project name as the first argument
    exit 1
fi
shift

case "$(uname)" in
    "Darwin")
        OS=osx;;
    MINGW64_NT-*|MSYS_NT-*)
        OS=windows;;
    *)
        OS=linux
esac

if [ "$OS" = "windows" ]; then
    EXT=.zip
    ESCEXT=\.zip
else
    EXT=.tar.gz
    ESCEXT=\.tar\.gz
fi

echo Downloading and running $PACKAGE...
# Don't go for the API since it hits the Appveyor GitHub API limit and fails
RELEASES=$(curl --silent --show-error /~https://github.com/ndmitchell/$PACKAGE/releases)
URL=/~https://github.com/$(echo $RELEASES | grep -o '\"[^\"]*-x86_64-'$OS$ESCEXT'\"' | sed s/\"//g | head -n1)
VERSION=$(echo $URL | sed -n 's@.*-\(.*\)-x86_64-'$OS$ESCEXT'@\1@p')
TEMP=$(mktemp -d .$PACKAGE-XXXXXX)

cleanup(){
    rm -r $TEMP
}
trap cleanup EXIT

retry(){
    ($@) && return
    sleep 15
    ($@) && return
    sleep 15
    $@
}

retry curl --progress-bar --location -o$TEMP/$PACKAGE$EXT $URL
if [ "$OS" = "windows" ]; then
    7z x -y $TEMP/$PACKAGE$EXT -o$TEMP -r > /dev/null
else
    tar -xzf $TEMP/$PACKAGE$EXT -C$TEMP
fi
$TEMP/$PACKAGE-$VERSION/$PACKAGE $*

Downloading /~https://github.com/ndmitchell/hlint/releases/download/v2.2.5/hlint-2.2.5-x86_64-linux.tar.gz (from the hlint releases page on github) shows it has the exe and data dir.

Can't we do this at compile time?

@fendor
Copy link
Collaborator Author

fendor commented Jan 2, 2020

We can do all the stuff at compile-time (not sure what the script does, but we can solve the problem at compile-time). @jneira and I just thought that downloading the files at run-time would be more user-friendly.

@alanz
Copy link
Collaborator

alanz commented Jan 2, 2020

@fendor the fewer moving parts the better. I would rather we install it something like the hlint CI images, where you get a platform-specific, ready-to-roll executable, with all its data files.

Otherwise we end up re-implementing a download manager, dealing with security issues, proxies, corporate firewalls, failed downloads, version mismatches, partial downloads and corrupt files, etc.

@jneira
Copy link
Member

jneira commented Jan 2, 2020

@fendor the fewer moving parts the better. I would rather we install it something like the hlint CI images, where you get a platform-specific, ready-to-roll executable, with all its data files.

A zip/tar self-contained with all the data files needed woud work too for precompiled binaries.

Otherwise we end up re-implementing a download manager, dealing with security issues, proxies, corporate firewalls, failed downloads, version mismatches, partial downloads and corrupt files, etc.

Agree it is better to avoid it if possible. To be fair the pr tried to download the data files indirectly using stack or cabal (that have more chances to work if you are already using them)

@jneira
Copy link
Member

jneira commented Jan 3, 2020

Reading the hlint code i've found where it is using the executable path to looking for the data file:

/~https://github.com/ndmitchell/hlint/blob/master/src/CmdLine.hs#L53-L60

It is in the path called by the hlint executable and no the lib (we are using it as a lib, right?) so we would need set hlint_datadir with the value of getExecutablePath ++ "/hlint/data". I dont fully like use env vars but it would be the quick one, although if the api let pass the value of the path we should use it.

I think we still should show an error with a suggesting about how to fix it manually in case the data files would not be there.

@fendor
Copy link
Collaborator Author

fendor commented Jan 3, 2020

Closing in favour of a different solution.

@fendor fendor closed this Jan 3, 2020
@ndmitchell
Copy link

ndmitchell commented Jan 15, 2020

I received a PR to embed the files via Template Haskell, which I'm planning to accept after changes. With that done, you won't have to worry again: ndmitchell/hlint#824

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Hlint data-files can not be easily distributed
5 participants