Skip to content

Commit

Permalink
Patch to generate unique IPID from source
Browse files Browse the repository at this point in the history
  • Loading branch information
fugyk committed Aug 22, 2015
1 parent 6627c7d commit 9833a34
Show file tree
Hide file tree
Showing 16 changed files with 246 additions and 23 deletions.
14 changes: 13 additions & 1 deletion Cabal/Cabal.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ extra-source-files:
tests/PackageTests/BuildDeps/TargetSpecificDeps3/MyLibrary.hs
tests/PackageTests/BuildDeps/TargetSpecificDeps3/lemon.hs
tests/PackageTests/BuildDeps/TargetSpecificDeps3/my.cabal
tests/PackageTests/BuildTestSuiteDetailedV09/Dummy2.hs
tests/PackageTests/CMain/Bar.hs
tests/PackageTests/CMain/Setup.hs
tests/PackageTests/CMain/foo.c
Expand All @@ -94,6 +95,9 @@ extra-source-files:
tests/PackageTests/PreProcess/Foo.hsc
tests/PackageTests/PreProcess/Main.hs
tests/PackageTests/PreProcess/my.cabal
tests/PackageTests/PreProcessExtraSources/Foo.hsc
tests/PackageTests/PreProcessExtraSources/Main.hs
tests/PackageTests/PreProcessExtraSources/my.cabal
tests/PackageTests/ReexportedModules/ReexportedModules.cabal
tests/PackageTests/TemplateHaskell/dynamic/Exe.hs
tests/PackageTests/TemplateHaskell/dynamic/Lib.hs
Expand All @@ -113,10 +117,17 @@ extra-source-files:
tests/PackageTests/TestSuiteTests/ExeV10/Foo.hs
tests/PackageTests/TestSuiteTests/ExeV10/my.cabal
tests/PackageTests/TestSuiteTests/ExeV10/tests/test-Foo.hs
tests/PackageTests/TestSuiteTests/LibV09/LibV09.cabal
tests/PackageTests/TestSuiteTests/LibV09/Lib.hs
tests/PackageTests/TestSuiteTests/LibV09/LibV09.cabal
tests/PackageTests/TestSuiteTests/LibV09/tests/Deadlock.hs
tests/PackageTests/UniqueIPID/P1/M.hs
tests/PackageTests/UniqueIPID/P1/my.cabal
tests/PackageTests/UniqueIPID/P2/M.hs
tests/PackageTests/UniqueIPID/P2/my.cabal
tests/Setup.hs
tests/Test/Distribution/Version.hs
tests/Test/Laws.hs
tests/Test/QuickCheck/Utils.hs
tests/hackage/check.sh
tests/hackage/download.sh
tests/hackage/unpack.sh
Expand Down Expand Up @@ -309,6 +320,7 @@ test-suite package-tests
PackageTests.TestStanza.Check
PackageTests.TestSuiteTests.ExeV10.Check
PackageTests.TestSuiteTests.LibV09.Check
PackageTests.UniqueIPID.Check
Test.Distribution.Version
Test.Laws
Test.QuickCheck.Utils
Expand Down
3 changes: 2 additions & 1 deletion Cabal/Distribution/Simple/Build.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import qualified Distribution.Simple.Build.PathsModule as Build.PathsModule
import Distribution.Package
( Package(..), PackageName(..), PackageIdentifier(..)
, Dependency(..), thisPackageVersion, PackageKey(..), packageName
, LibraryName(..) )
, LibraryName(..), InstalledPackageId(..) )
import Distribution.Simple.Compiler
( Compiler, CompilerFlavor(..), compilerFlavor
, PackageDB(..), PackageDBStack )
Expand Down Expand Up @@ -408,6 +408,7 @@ testSuiteLibV09AsLibAndExe pkg_descr
{ componentPackageDeps = componentPackageDeps clbi
, componentPackageRenaming = componentPackageRenaming clbi
, componentLibraryName = LibraryName (testName test)
, componentIPID = InstalledPackageId $ display (package pkg_descr) ++ "-inplace"
, componentExposedModules = [IPI.ExposedModule m Nothing Nothing]
, componentPackageKey = OldPackageKey (PackageIdentifier (PackageName (testName test)) (pkgVersion (package pkg_descr)))
}
Expand Down
56 changes: 50 additions & 6 deletions Cabal/Distribution/Simple/Configure.hs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import Distribution.Simple.Compiler
, showCompilerId, unsupportedLanguages, unsupportedExtensions
, PackageDB(..), PackageDBStack, reexportedModulesSupported
, packageKeySupported, renamingPackageFlagsSupported )
import Distribution.Simple.PreProcess ( platformDefines )
import Distribution.Simple.PreProcess ( platformDefines, knownSuffixHandlers )
import Distribution.Package
( PackageName(PackageName), PackageIdentifier(..), PackageId
, packageName, packageVersion, Package(..)
Expand All @@ -72,7 +72,7 @@ import Distribution.PackageDescription as PD
, Library(..), hasLibs, Executable(..), BuildInfo(..), allExtensions
, HookedBuildInfo, updatePackageDescription, allBuildInfo
, Flag(flagName), FlagName(..), TestSuite(..), Benchmark(..)
, ModuleReexport(..) , defaultRenaming )
, ModuleReexport(..) , defaultRenaming, FlagAssignment )
import Distribution.ModuleName
( ModuleName )
import Distribution.PackageDescription.Configuration
Expand All @@ -97,6 +97,7 @@ import Distribution.Simple.LocalBuildInfo
, absoluteInstallDirs, prefixRelativeInstallDirs, inplacePackageId
, ComponentName(..), showComponentName, pkgEnabledComponents
, componentBuildInfo, componentName, checkComponentsCyclic )
import Distribution.Simple.SrcDist ( listPackageSources )
import Distribution.Simple.BuildPaths
( autogenModulesDir )
import Distribution.Simple.Utils
Expand All @@ -110,7 +111,7 @@ import Distribution.System
import Distribution.Version
( Version(..), anyVersion, orLaterVersion, withinRange, isAnyVersion )
import Distribution.Verbosity
( Verbosity, lessVerbose )
( Verbosity, lessVerbose, silent )

import qualified Distribution.Simple.GHC as GHC
import qualified Distribution.Simple.GHCJS as GHCJS
Expand All @@ -126,11 +127,16 @@ import Control.Exception
import Control.Monad
( liftM, when, unless, foldM, filterM )
import Distribution.Compat.Binary ( decodeOrFailIO, encode )
import GHC.Fingerprint ( Fingerprint(..), fingerprintString
#if __GLASGOW_HASKELL__ >= 710
, getFileHash
#endif
)
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy.Char8 as BLC8
import Data.List
( (\\), nub, partition, isPrefixOf, inits, stripPrefix )
( (\\), nub, partition, isPrefixOf, inits, stripPrefix, sort )
import Data.Maybe
( isNothing, catMaybes, fromMaybe, isJust )
import Data.Either
Expand All @@ -145,6 +151,9 @@ import Data.Map (Map)
import Data.Traversable
( mapM )
import Data.Typeable
import Data.Char ( chr )
import Numeric ( showIntAtBase, showHex )
import Data.Bits ( shift )
import System.Directory
( doesFileExist, createDirectoryIfMissing, getTemporaryDirectory )
import System.FilePath
Expand Down Expand Up @@ -615,7 +624,7 @@ configure (pkg_descr0, pbi) cfg
mkComponentsLocalBuildInfo comp packageDependsIndex pkg_descr
internalPkgDeps externalPkgDeps holeDeps
(Map.fromList hole_insts)
components
components (configConfigurationsFlags cfg)

split_objs <-
if not (fromFlag $ configSplitObjs cfg)
Expand Down Expand Up @@ -1294,11 +1303,12 @@ mkComponentsLocalBuildInfo :: Compiler
-> [InstalledPackageInfo] -- hole package deps
-> Map ModuleName (InstalledPackageInfo, ModuleName)
-> [(Component, [ComponentName])]
-> FlagAssignment
-> IO [(ComponentName, ComponentLocalBuildInfo,
[ComponentName])]
mkComponentsLocalBuildInfo comp installedPackages pkg_descr
internalPkgDeps externalPkgDeps holePkgDeps hole_insts
graph =
graph flagAssignment =
sequence
[ do clbi <- componentLocalBuildInfo c
return (componentName c, clbi, cdeps)
Expand Down Expand Up @@ -1333,9 +1343,33 @@ mkComponentsLocalBuildInfo comp installedPackages pkg_descr
(map Installed.libraryName externalPkgs)
version_hash = packageKeyLibraryName (package pkg_descr) pkg_key

-- Calculate IPID
ipid <- do
-- sdist produces too much noise, so silent
(ordfiles, exefiles) <-
listPackageSources silent pkg_descr knownSuffixHandlers
let files = sort $ ordfiles ++ exefiles
fileHashes <-
#if __GLASGOW_HASKELL__ >= 710
mapM getFileHash files
#else
mapM (\x -> readFile x >>= (return . fingerprintString)) files
#endif
-- show is found to be faster than intercalate and then replacement of
-- special character used in intercalating. We cannot simply hash by
-- doubly concating list, as it just flatten out the nested list, so
-- different sources can produce same hash
return $ InstalledPackageId $ (display (package pkg_descr)) ++ "-" ++
(hashToBase62 $
(show $ map Installed.installedPackageId externalPkgs)
++ show (zip files $
map (flip showHex "" . fpToInteger) fileHashes)
++ show flagAssignment)

return LibComponentLocalBuildInfo {
componentPackageDeps = cpds,
componentPackageKey = pkg_key,
componentIPID = ipid,
componentLibraryName = version_hash,
componentPackageRenaming = cprns,
componentExposedModules = exports ++ reexports ++ esigs
Expand Down Expand Up @@ -1388,6 +1422,16 @@ mkComponentsLocalBuildInfo comp installedPackages pkg_descr

names bi = [ name | Dependency name _ <- targetBuildDepends bi ]

representBase62 x
| x < 10 = chr (48 + x)
| x < 36 = chr (65 + x - 10)
| x < 62 = chr (97 + x - 36)
| otherwise = '@'
fpToInteger (Fingerprint a b) =
toInteger a * (shift (1 :: Integer) 64) + toInteger b
hashToBase62 s = showIntAtBase 62 representBase62
(fpToInteger $ fingerprintString s) ""

-- | Given the author-specified re-export declarations from the .cabal file,
-- resolve them to the form that we need for the package database.
--
Expand Down
12 changes: 12 additions & 0 deletions Cabal/Distribution/Simple/LocalBuildInfo.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ module Distribution.Simple.LocalBuildInfo (
inplacePackageId,
localPackageKey,
localLibraryName,
localIPID,

-- * Buildable package components
Component(..),
Expand Down Expand Up @@ -172,6 +173,16 @@ localLibraryName lbi =
LibComponentLocalBuildInfo { componentLibraryName = n } -> n
_ -> old_n

-- | Extract the 'IPID' from the library component of a
-- 'LocalBuildInfo' if it exists
localIPID :: LocalBuildInfo -> Maybe InstalledPackageId
localIPID lbi =
foldr go Nothing (componentsConfigs lbi)
where go (_, clbi, _) old_ipid = case clbi of
LibComponentLocalBuildInfo { componentIPID = ipid } -> Just ipid
_ -> old_ipid


-- | External package dependencies for the package as a whole. This is the
-- union of the individual 'componentPackageDeps', less any internal deps.
externalPackageDeps :: LocalBuildInfo -> [(InstalledPackageId, PackageId)]
Expand Down Expand Up @@ -223,6 +234,7 @@ data ComponentLocalBuildInfo
-- to the specific versions available on this machine for this compiler.
componentPackageDeps :: [(InstalledPackageId, PackageId)],
componentPackageKey :: PackageKey,
componentIPID :: InstalledPackageId,
componentLibraryName :: LibraryName,
componentExposedModules :: [Installed.ExposedModule],
componentPackageRenaming :: Map PackageName ModuleRenaming
Expand Down
19 changes: 5 additions & 14 deletions Cabal/Distribution/Simple/Register.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module Distribution.Simple.Register (
import Distribution.Simple.LocalBuildInfo
( LocalBuildInfo(..), ComponentLocalBuildInfo(..)
, ComponentName(..), getComponentLocalBuildInfo
, InstallDirs(..), absoluteInstallDirs )
, InstallDirs(..), absoluteInstallDirs, localIPID )
import Distribution.Simple.BuildPaths (haddockName)

import qualified Distribution.Simple.GHC as GHC
Expand All @@ -49,7 +49,7 @@ import qualified Distribution.Simple.UHC as UHC
import qualified Distribution.Simple.HaskellSuite as HaskellSuite

import Distribution.Simple.Compiler
( compilerVersion, Compiler, CompilerFlavor(..), compilerFlavor
( Compiler, CompilerFlavor(..), compilerFlavor
, PackageDB, PackageDBStack, absolutePackageDBPaths
, registrationPackageDB )
import Distribution.Simple.Program
Expand Down Expand Up @@ -77,7 +77,6 @@ import Distribution.System
( OS(..), buildOS )
import Distribution.Text
( display )
import Distribution.Version ( Version(..) )
import Distribution.Verbosity as Verbosity
( Verbosity, normal )

Expand Down Expand Up @@ -168,17 +167,9 @@ generateRegistrationInfo verbosity pkg lib lbi clbi inplace reloc distPref packa

--TODO: the method of setting the InstalledPackageId is compiler specific
-- this aspect should be delegated to a per-compiler helper.
let comp = compiler lbi
ipid <-
case compilerFlavor comp of
GHC | compilerVersion comp >= Version [6,11] [] -> do
s <- GHC.libAbiHash verbosity pkg lbi lib clbi
return (InstalledPackageId (display (packageId pkg) ++ '-':s))
GHCJS -> do
s <- GHCJS.libAbiHash verbosity pkg lbi lib clbi
return (InstalledPackageId (display (packageId pkg) ++ '-':s))
_other -> do
return (InstalledPackageId (display (packageId pkg)))
let ipid = case localIPID lbi of
Just i -> i
_ -> error "No library found"

installedPkgInfo <-
if inplace
Expand Down
2 changes: 1 addition & 1 deletion Cabal/Distribution/Simple/Setup.hs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ import qualified Text.PrettyPrint as Disp
import Distribution.ModuleName
import Distribution.Package ( Dependency(..)
, PackageName
, InstalledPackageId )
, InstalledPackageId(..) )
import Distribution.PackageDescription
( FlagName(..), FlagAssignment )
import Distribution.Simple.Command hiding (boolOpt, boolOpt')
Expand Down
39 changes: 39 additions & 0 deletions Cabal/doc/installing-packages.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,45 @@ This command takes the following options:
any supplemental files installed --- plain Haskell libraries should
be fine.

### Package Identifiers ###

When a package is registered in a DB, it is registered with various identifiers
for identifying it. Currently there are following identifiers:

#### Package name ####

The name of package like "bytestring". It is fully specified in package
description file.

#### Package version ####

The version of the package like "0.10.6.0". It is fully specified in package
description file.

#### Package ID ####

Concatenation of package name and package version with `-` in between. It can be
calculated from package description file.

#### Package Key ####

It is required for doing full recompilation if any of its direct or indirect
dependencies is changed. It is a merkle tree of package IDs, meaning it is
calculated by hashing the package ID of the package plus the package key of all
its dependencies. A change in Package Key implies that there is a change in
dependency tree, but same package key can produce different builds as its hash
does not include source or output. It is calculated in configure step.

#### Installed Package ID ####

This identifier uniquely identifies the package. Same Installed Package ID means
a package will behave exactly the same way. Currently it is calculated by
hashing the source of the package, flag assignments passed and Installed Package
ID of all dependencies in configure step. Earlier it was calculated by taking
GHC ABI hash of the library (meaning it can be replaced with other package with
same Installed package ID but does not guarantee same behaviour) in the register
step.

## setup unregister ##

Deregister this package with the compiler.
Expand Down
3 changes: 3 additions & 0 deletions Cabal/tests/PackageTests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import PackageTests.TestSuiteTests.ExeV10.Check
import PackageTests.TestSuiteTests.LibV09.Check
import PackageTests.OrderFlags.Check
import PackageTests.ReexportedModules.Check
import PackageTests.UniqueIPID.Check

import Distribution.Simple.Configure
( ConfigStateFileError(..), findDistPrefOrDefault, getConfigStateFile )
Expand Down Expand Up @@ -109,6 +110,8 @@ tests config version =
(PackageTests.TemplateHaskell.Check.dynamic config)
, testCase "ReexportedModules"
(PackageTests.ReexportedModules.Check.suite config)
, testCase "UniqueIPID"
(PackageTests.UniqueIPID.Check.suite config)
] ++
-- These tests are only required to pass on cabal version >= 1.7
(if version >= Version [1, 7] []
Expand Down
Loading

0 comments on commit 9833a34

Please sign in to comment.