Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/languages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ jobs:
echo 'C:\Strawberry\c\bin' >> "$GITHUB_PATH"
shell: bash
if: matrix.os == 'windows-latest' && matrix.language == 'perl'
- uses: haskell/actions/setup@v2
if: matrix.language == 'haskell'

- name: install deps
run: python -mpip install -e . -r requirements-dev.txt
Expand Down
2 changes: 2 additions & 0 deletions pre_commit/all_languages.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from pre_commit.languages import dotnet
from pre_commit.languages import fail
from pre_commit.languages import golang
from pre_commit.languages import haskell
from pre_commit.languages import lua
from pre_commit.languages import node
from pre_commit.languages import perl
Expand All @@ -31,6 +32,7 @@
'dotnet': dotnet,
'fail': fail,
'golang': golang,
'haskell': haskell,
'lua': lua,
'node': node,
'perl': perl,
Expand Down
56 changes: 56 additions & 0 deletions pre_commit/languages/haskell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from __future__ import annotations

import contextlib
import os.path
from typing import Generator
from typing import Sequence

from pre_commit import lang_base
from pre_commit.envcontext import envcontext
from pre_commit.envcontext import PatchesT
from pre_commit.envcontext import Var
from pre_commit.errors import FatalError
from pre_commit.prefix import Prefix

ENVIRONMENT_DIR = 'hs_env'
get_default_version = lang_base.basic_get_default_version
health_check = lang_base.basic_health_check
run_hook = lang_base.basic_run_hook


def get_env_patch(target_dir: str) -> PatchesT:
bin_path = os.path.join(target_dir, 'bin')
return (('PATH', (bin_path, os.pathsep, Var('PATH'))),)


@contextlib.contextmanager
def in_env(prefix: Prefix, version: str) -> Generator[None, None, None]:
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)
with envcontext(get_env_patch(envdir)):
yield


def install_environment(
prefix: Prefix,
version: str,
additional_dependencies: Sequence[str],
) -> None:
lang_base.assert_version_default('haskell', version)
envdir = lang_base.environment_dir(prefix, ENVIRONMENT_DIR, version)

pkgs = [*prefix.star('.cabal'), *additional_dependencies]
if not pkgs:
raise FatalError('Expected .cabal files or additional_dependencies')

bindir = os.path.join(envdir, 'bin')
os.makedirs(bindir, exist_ok=True)
lang_base.setup_cmd(prefix, ('cabal', 'update'))
lang_base.setup_cmd(
prefix,
(
'cabal', 'install',
'--install-method', 'copy',
'--installdir', bindir,
*pkgs,
),
)
50 changes: 50 additions & 0 deletions tests/languages/haskell_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from __future__ import annotations

import pytest

from pre_commit.errors import FatalError
from pre_commit.languages import haskell
from pre_commit.util import win_exe
from testing.language_helpers import run_language


def test_run_example_executable(tmp_path):
example_cabal = '''\
cabal-version: 2.4
name: example
version: 0.1.0.0

executable example
main-is: Main.hs

build-depends: base >=4
default-language: Haskell2010
'''
main_hs = '''\
module Main where

main :: IO ()
main = putStrLn "Hello, Haskell!"
'''
tmp_path.joinpath('example.cabal').write_text(example_cabal)
tmp_path.joinpath('Main.hs').write_text(main_hs)

result = run_language(tmp_path, haskell, 'example')
assert result == (0, b'Hello, Haskell!\n')

# should not symlink things into environments
exe = tmp_path.joinpath(win_exe('hs_env-default/bin/example'))
assert exe.is_file()
assert not exe.is_symlink()


def test_run_dep(tmp_path):
result = run_language(tmp_path, haskell, 'hello', deps=['hello'])
assert result == (0, b'Hello, World!\n')


def test_run_empty(tmp_path):
with pytest.raises(FatalError) as excinfo:
run_language(tmp_path, haskell, 'example')
msg, = excinfo.value.args
assert msg == 'Expected .cabal files or additional_dependencies'