Skip to content

Commit 7d3f33e

Browse files
jasagredoKleidukos
andcommitted
Use Base16 hash for script path.
Issue #9334 shows that `%` characters on Windows result in invalid paths, also `/` characters on Linux create invalid paths. This changes from using base64 to using base16 with the same length we use for unit-ids. (cherry picked from commit 97f9917) Co-authored-by: Hécate Moonlight <[email protected]> Co-autohred-by: Javier Sagredo <[email protected]>
1 parent 5d97fcf commit 7d3f33e

File tree

6 files changed

+24
-21
lines changed

6 files changed

+24
-21
lines changed

cabal-install/cabal-install.cabal

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,6 @@ library
207207
async >= 2.0 && < 2.3,
208208
array >= 0.4 && < 0.6,
209209
base16-bytestring >= 0.1.1 && < 1.1.0.0,
210-
base64-bytestring >= 1.0 && < 1.3,
211210
binary >= 0.7.3 && < 0.9,
212211
bytestring >= 0.10.6.0 && < 0.13,
213212
containers >= 0.5.6.2 && < 0.7,

cabal-install/src/Distribution/Client/HashValue.hs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ module Distribution.Client.HashValue (
66
hashValue,
77
truncateHash,
88
showHashValue,
9-
showHashValueBase64,
109
readFileHashValue,
1110
hashFromTUF,
1211
) where
@@ -16,10 +15,9 @@ import Prelude ()
1615

1716
import qualified Hackage.Security.Client as Sec
1817

19-
import qualified Crypto.Hash.SHA256 as SHA256
20-
import qualified Data.ByteString.Base16 as Base16
21-
import qualified Data.ByteString.Base64 as Base64
22-
import qualified Data.ByteString.Char8 as BS
18+
import qualified Crypto.Hash.SHA256 as SHA256
19+
import qualified Data.ByteString.Base16 as Base16
20+
import qualified Data.ByteString.Char8 as BS
2321
import qualified Data.ByteString.Lazy.Char8 as LBS
2422

2523
import System.IO (IOMode (..), withBinaryFile)
@@ -57,9 +55,6 @@ hashValue = HashValue . SHA256.hashlazy
5755
showHashValue :: HashValue -> String
5856
showHashValue (HashValue digest) = BS.unpack (Base16.encode digest)
5957

60-
showHashValueBase64 :: HashValue -> String
61-
showHashValueBase64 (HashValue digest) = BS.unpack (Base64.encode digest)
62-
6358
-- | Hash the content of a file. Uses SHA256.
6459
--
6560
readFileHashValue :: FilePath -> IO HashValue

cabal-install/src/Distribution/Client/ScriptUtils.hs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import Distribution.Client.Config
2727
import Distribution.Client.DistDirLayout
2828
( DistDirLayout(..), DistDirParams(..) )
2929
import Distribution.Client.HashValue
30-
( hashValue, showHashValueBase64 )
30+
( hashValue, showHashValue, truncateHash )
3131
import Distribution.Client.HttpUtils
3232
( HttpTransport, configureTransport )
3333
import Distribution.Client.NixStyleOptions
@@ -131,17 +131,18 @@ import qualified Text.Parsec as P
131131
-- repl to deal with the fact that the repl is relative to the working directory and not
132132
-- the project root.
133133

134-
-- | Get the hash of a script's absolute path)
134+
-- | Get the hash of a script's absolute path.
135135
--
136136
-- Two hashes will be the same as long as the absolute paths
137137
-- are the same.
138138
getScriptHash :: FilePath -> IO String
139-
getScriptHash script
140-
-- Base64 is shorter than Base16, which helps avoid long path issues on windows
141-
-- but it can contain /'s which aren't valid in file paths so replace them with
142-
-- %'s. 26 chars / 130 bits is enough to practically avoid collisions.
143-
= map (\c -> if c == '/' then '%' else c) . take 26
144-
. showHashValueBase64 . hashValue . fromString <$> canonicalizePath script
139+
getScriptHash script =
140+
-- Truncation here tries to help with long path issues on Windows.
141+
showHashValue
142+
. truncateHash 26
143+
. hashValue
144+
. fromString
145+
<$> canonicalizePath script
145146

146147
-- | Get the directory for caching a script build.
147148
--

cabal-testsuite/cabal-testsuite.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ library
6060
, aeson ^>= 1.4.2.0 || ^>=1.5.0.0 || ^>= 2.0.0.0 || ^>= 2.1.0.0 || ^>= 2.2.1.0
6161
, async ^>= 2.2.1
6262
, attoparsec ^>= 0.13.2.2 || ^>=0.14.1
63-
, base64-bytestring ^>= 1.0.0.0 || ^>= 1.1.0.0 || ^>= 1.2.0.0
63+
, base16-bytestring ^>= 0.1.1.5 || ^>= 1.0
6464
, bytestring ^>= 0.10.0.2 || ^>= 0.11.0.0 || ^>= 0.12.0.0
6565
, containers ^>= 0.5.0.0 || ^>= 0.6.0.1
6666
, cryptohash-sha256 ^>= 0.11.101.0

cabal-testsuite/src/Test/Cabal/Prelude.hs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import Control.Monad (unless, when, void, forM_, liftM2, liftM4)
5252
import Control.Monad.Trans.Reader (withReaderT, runReaderT)
5353
import Control.Monad.IO.Class (MonadIO (..))
5454
import qualified Crypto.Hash.SHA256 as SHA256
55-
import qualified Data.ByteString.Base64 as Base64
55+
import qualified Data.ByteString.Base16 as Base16
5656
import qualified Data.ByteString.Char8 as C
5757
import Data.List (isInfixOf, stripPrefix, isPrefixOf, intercalate)
5858
import Data.List.NonEmpty (NonEmpty (..))
@@ -842,8 +842,7 @@ getScriptCacheDirectory :: FilePath -> TestM FilePath
842842
getScriptCacheDirectory script = do
843843
cabalDir <- testCabalDir `fmap` getTestEnv
844844
hashinput <- liftIO $ canonicalizePath script
845-
let hash = map (\c -> if c == '/' then '%' else c) . take 26
846-
. C.unpack . Base64.encode . SHA256.hash . C.pack $ hashinput
845+
let hash = C.unpack . Base16.encode . C.take 26 . SHA256.hash . C.pack $ hashinput
847846
return $ cabalDir </> "script-builds" </> hash
848847

849848
------------------------------------------------------------------------

changelog.d/base16-script-cache

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
synopsis: Script cache dir is the base16 hash of the canonical path of the script.
2+
prs: #9459
3+
packages: cabal-install
4+
5+
description: {
6+
7+
Script cache dir is the base16 hash of the canonical path of the script.
8+
9+
}

0 commit comments

Comments
 (0)