haskell / cabal

Official upstream development repository for Cabal and cabal-install
https://haskell.org/cabal
Other
1.61k stars 691 forks source link

Allow executables to also be scripts #10324

Open philderbeast opened 1 week ago

philderbeast commented 1 week ago

... offer the option to install each standalone *.hs script by listing them as executables in the package.

Originally posted by @philderbeast in https://github.com/haskell/cabal/issues/10317#issuecomment-2332379427

Please allow at least single file, self contained executables to be run as scripts. I tried this with #10320 but was rebuffed with:

$ ./cabal-validate/main/Main.hs
Warning: this is a debug build of cabal-install with assertions enabled.
Resolving dependencies...
Error: [Cabal-7070]
The run command can only run an executable as a whole, not files or modules within them,
but the target 'main/Main.hs' refers to the file main/Main.hs in the executable cabal-validate.
philderbeast commented 1 week ago

If I change the main module in the package, effectively removing the script I want to run from the package, then I can run it:

$ git diff
diff --git a/cabal-validate/cabal-validate.cabal b/cabal-validate/cabal-validate.cabal
index 37a6f5263..1f0e0465a 100644
--- a/cabal-validate/cabal-validate.cabal
+++ b/cabal-validate/cabal-validate.cabal
@@ -14,15 +14,9 @@ common warnings
 executable cabal-validate
     import: warnings
     default-language: Haskell2010
-    default-extensions:
-        OverloadedStrings
-        , NoFieldSelectors
-        , DuplicateRecordFields
-        , OverloadedRecordDot
-        , TypeApplications
     ghc-options: -O -threaded -rtsopts -with-rtsopts=-N

-    main-is: Main.hs
+    main-is: Non-Existant-Main.hs
     hs-source-dirs: main

     build-depends:
diff --git a/cabal-validate/main/Main.hs b/cabal-validate/main/Main.hs
old mode 100644
new mode 100755
index 6f2847819..1026103b7
--- a/cabal-validate/main/Main.hs
+++ b/cabal-validate/main/Main.hs
@@ -1,4 +1,22 @@
-module Main where
+#!/usr/bin/env cabal
+{- cabal:
+build-depends:
+        base >=4 && <5
+        , ansi-terminal >=1 && <2
+        , turtle >=1 && <2
+        , optparse-applicative >=0.18 && <1
+        , containers >=0.6 && <1
+        , directory >=1.0 && <2
+        , text >=2 && <3
+        , terminal-size >=0.3 && <1
+        , time >=1 && <2
+-}
+
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoFieldSelectors #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE OverloadedRecordDot #-}
+{-# LANGUAGE TypeApplications #-}

 import Control.Applicative (Alternative (many, (<|>)), (<**>))
 import Control.Monad (forM_, unless)
$ ./cabal-validate/main/Main.hs
Warning: this is a debug build of cabal-install with assertions enabled.
Warning: this is a debug build of cabal-install with assertions enabled.
═══ print-config ═════════════════════════════════════════════════════════════════════════════════════════════
compiler:          ghc
cabal-install:     cabal
jobs:              1
steps:             print-config print-tool-versions build lib-tests cli-tests
Hackage tests:     NoHackageTests
verbose:           False
extra compilers:   
extra RTS options: 

═══ print-tool-versions ══════════════════════════════════════════════════════════════════════════════════════
$ ghc-9.10.1 --version
The Glorious Glasgow Haskell Compilation System, version 9.10.1
Finished: ghc-9.10.1 --version (0.02 this step, 0.04 cumulative)
$ cabal --version
cabal-install version 3.13.0.0
compiled using version 3.13.0.0 of the Cabal library
Finished: cabal --version (0.00 this step, 0.04 cumulative)

═══ build ════════════════════════════════════════════════════════════════════════════════════════════════════
cabal-script-Main.hs: TODO
CallStack (from HasCallStack):
  error, called at /.../cabal/cabal-validate/main/Main.hs:455:12 in fake-package-0-inplace-script-Main.hs:Main
HasCallStack backtrace:
  collectBacktraces, called at libraries/ghc-internal/src/GHC/Internal/Exception.hs:92:13 in ghc-internal:GHC.Internal.Exception
  toExceptionWithBacktrace, called at libraries/ghc-internal/src/GHC/Internal/Exception.hs:128:3 in ghc-internal:GHC.Internal.Exception