<div dir="ltr">I just want to say thank you for writing this tool.<div><br></div><div>I may not agree with your interpretation of the PVP on this particular issue, and will probably only use it on a couple of smaller packages that have almost no imports, but at least putting code out there to help those who do want to work in that style is a very helpful and valuable thing.</div>
<div><br></div><div>-Edward</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Feb 28, 2014 at 3:10 PM, Henning Thielemann <span dir="ltr"><<a href="mailto:schlepptop@henning-thielemann.de" target="_blank">schlepptop@henning-thielemann.de</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I got distracted by writing a tool that checks consistency of package dependencies and import styles. It's not yet perfect, but usable:<br>

<br>
<a href="https://hackage.haskell.org/package/check-pvp" target="_blank">https://hackage.haskell.org/<u></u>package/check-pvp</a><br>
<br>
<br>
Description:<br>
  Check whether the version ranges used in the @Build-Depends@ field<br>
  matches the style of module imports<br>
  according to the Package Versioning Policy (PVP).<br>
  See <<a href="http://www.haskell.org/haskellwiki/Package_versioning_policy" target="_blank">http://www.haskell.org/<u></u>haskellwiki/Package_<u></u>versioning_policy</a>>.<br>
  The tool essentially looks for any dependency<br>
  like @containers >=0.5 && <0.6@<br>
  that allows the addition of identifiers to modules<br>
  within the version range.<br>
  Then it checks whether all module imports from @containers@<br>
  are protected against name clashes<br>
  that could be caused by addition of identifiers.<br>
  .<br>
  You must run the tool in a directory containing a Cabal package.<br>
  .<br>
  > $ check-pvp<br>
  .<br>
  This requires that the package is configured,<br>
  since only then the association of packages to modules is known.<br>
  If you want to run the tool on a non-configured package<br>
  you may just check all imports for addition-proof style.<br>
  .<br>
  > $ check-pvp --include-all<br>
  .<br>
  It follows a detailed description of the procedure<br>
  and the rationale behind it.<br>
  .<br>
  First the program classifies all dependencies<br>
  in the Cabal file of the package.<br>
  You can show all classifications with the @--classify-dependencies@ option,<br>
  otherwise only problematic dependencies are shown.<br>
  .<br>
  A dependency like @containers >=0.5.0.3 && <0.5.1@<br>
  does not allow changes of the API of @containers@<br>
  and thus the program does not check its imports.<br>
  Clashing import abbreviations are an exception.<br>
  .<br>
  The dependency @containers >=0.5.1 && <0.6@<br>
  requires more care when importing modules from @containers@<br>
  and this is what the program is going to check next.<br>
  This is the main purpose of the program!<br>
  I warmly recommend this kind of dependency range<br>
  since it greatly reduces the work<br>
  to keep your package going together with its imported packages.<br>
  .<br>
  Dependencies like @containers >=0.5@ or @containers >=0.5 && <1@<br>
  are always problematic,<br>
  since within the specified version ranges identifier can disappear.<br>
  There is no import style that protects against removed identifiers.<br>
  .<br>
  An inclusive upper bound as in @containers >=0.5 && <=0.6@<br>
  will also cause a warning, because it is unnecessarily strict.<br>
  If you know that @containers-0.6@ works for you,<br>
  then @containers-0.6.0.1@ or @containers-0.6.1@ will also work,<br>
  depending on your import style.<br>
  A special case of inclusive upper bounds are specific versions<br>
  like in @containers ==0.6@.<br>
  The argument for the warning remains the same.<br>
  .<br>
  Please note that the check of ranges<br>
  is performed entirely on the package description.<br>
  The program will not inspect the imported module contents.<br>
  E.g. if you depend on @containers >=0.5 && <0.6@<br>
  but import in a way that risks name clashes,<br>
  then you may just extend the dependency to @containers >=0.5 && <0.6.1@<br>
  in order to let the checker fall silent.<br>
  If you use the dependency @containers >=0.5 && <0.6.1@<br>
  then the checker expects that you have verified<br>
  that your package works with all versions of kind @0.5.x@<br>
  and the version @0.6.0@.<br>
  Other versions would then work, too,<br>
  due to the constraints imposed by package versioning policy.<br>
  .<br>
  Let us now look at imports<br>
  that must be protected against identifier additions.<br>
  .<br>
  The program may complain about a lax import.<br>
  This means you have imported like<br>
  .<br>
  > import Data.Map as Map<br>
  .<br>
  Additions to @Data.Map@ may clash with other identifiers,<br>
  thus you must import either<br>
  .<br>
  > import qualified Data.Map as Map<br>
  .<br>
  or<br>
  .<br>
  > import Data.Map (Map)<br>
  .<br>
  The program may complain about an open list of constructors as in<br>
  .<br>
  > import Data.Sequence (ViewL(..))<br>
  .<br>
  Additions of constructors to @ViewL@ may also conflict with other identifiers.<br>
  You must instead import like<br>
  .<br>
  > import Data.Sequence (ViewL(EmptyL, (:<)))<br>
  .<br>
  or<br>
  .<br>
  > import qualified Data.Sequence as Seq<br>
  .<br>
  The program emits an error on clashing module abbreviations like<br>
  .<br>
  > import qualified Data.Map.Lazy as Map<br>
  > import qualified Data.Map.Strict as Map<br>
  .<br>
  This error is raised<br>
  whenever multiple modules are imported with the same abbreviation,<br>
  where at least one module is open for additions.<br>
  Our test is overly strict in the sense that it also blames<br>
  .<br>
  > import qualified Data.Map as Map<br>
  > import qualified Data.Map as Map<br>
  .<br>
  but I think it is good idea to avoid redundant imports anyway.<br>
  .<br>
  Additionally you can enable a test for hiding imports<br>
  with the @--pedantic@ option.<br>
  The import<br>
  .<br>
  > import Data.Map hiding (insert)<br>
  .<br>
  is not bad in the sense of the PVP,<br>
  but this way you depend on the existence of the identifier @insert@<br>
  although you do not need it.<br>
  If it is removed in a later version of @containers@,<br>
  then your import breaks although you did not use the identifier.<br>
  .<br>
  Finally you can control what items are checked.<br>
  First of all you can select the imports that are checked.<br>
  Normally the imports are checked that belong to lax dependencies<br>
  like @containers >=0.5 && <0.6@.<br>
  However this requires the package to be configured<br>
  in order to know which import belongs to which dependency.<br>
  E.g. @Data.Map@ belongs to @containers@.<br>
  You can just check all imports for being addition-proof<br>
  using the @--include-all@ option.<br>
  Following you can write the options<br>
  @--include-import@,<br>
  @--exclude-import@,<br>
  @--include-dependency@,<br>
  @--exclude-dependency@<br>
  that allow to additionally check or ignore imports<br>
  from certain modules or packages.<br>
  These modifiers are applied from left to right.<br>
  E.g. @--exclude-import=Prelude@ will accept any import style for @Prelude@<br>
  and @--exclude-dependency=foobar@ will ignore the package @foobar@,<br>
  say, because it does not conform to the PVP.<br>
  .<br>
  Secondly, you may ignore certain modules or components of the package<br>
  using the options<br>
  @--exclude-module@,<br>
  @--exclude-library@,<br>
  @--exclude-executables@,<br>
  @--exclude-testsuites@,<br>
  @--exclude-benchmarks@.<br>
  E.g. @--exclude-module=Paths_PKG@ will exclude the Paths module<br>
  that is generated by Cabal.<br>
  I assume that it will always be free of name clashes.<br>
  .<br>
  Known problems:<br>
  .<br>
  * The program cannot automatically filter out the @Paths@ module.<br>
  .<br>
  * The program cannot find and check preprocessed modules.<br>
  .<br>
  * The program may yield wrong results in the presence of Cabal conditions.<br>
  .<br>
  If this program proves to be useful<br>
  it might eventually be integrated in the @check@ command of @cabal-install@.<br>
  See <<a href="https://github.com/haskell/cabal/issues/1703" target="_blank">https://github.com/haskell/<u></u>cabal/issues/1703</a>>.<br>
  .<br>
  Alternative:<br>
  If you want to allow exclusively large version ranges, i.e. @>=x.y && <x.y+1@,<br>
  then you may also add the option @-fwarn-missing-import-lists@<br>
  to the @GHC-Options@ fields of your Cabal file.<br>
  See <<a href="https://ghc.haskell.org/trac/ghc/ticket/4977" target="_blank">https://ghc.haskell.org/trac/<u></u>ghc/ticket/4977</a>>.<br>
  Unfortunately there is no GHC warning on clashing module abbreviations.<br>
  See <<a href="https://ghc.haskell.org/trac/ghc/ticket/4980" target="_blank">https://ghc.haskell.org/trac/<u></u>ghc/ticket/4980</a>>.<div class="HOEnZb"><div class="h5"><br>
<br>
______________________________<u></u>_________________<br>
Libraries mailing list<br>
<a href="mailto:Libraries@haskell.org" target="_blank">Libraries@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/libraries" target="_blank">http://www.haskell.org/<u></u>mailman/listinfo/libraries</a><br>
</div></div></blockquote></div><br></div>