cblrepo (empty) → 0.2.0
raw patch · 19 files changed
+1304/−0 lines, 19 filesdep +Cabaldep +HUnitdep +Unixutilsbuild-type:Customsetup-changed
Dependencies added: Cabal, HUnit, Unixutils, ansi-wl-pprint, base, bytestring, cmdargs, directory, filepath, json, mtl, process, tar, test-framework, test-framework-hunit, test-framework-th, unix, zlib
Files
- LICENSE-2.0 +202/−0
- Setup.hs +21/−0
- cblrepo.cabal +47/−0
- src/AddBase.hs +50/−0
- src/AddCabal.hs +87/−0
- src/BuildPkgs.hs +32/−0
- src/BumpPkgs.hs +41/−0
- src/IdxSync.hs +28/−0
- src/IdxVersion.hs +56/−0
- src/ListPkgs.hs +38/−0
- src/Main.hs +135/−0
- src/PkgDB.hs +145/−0
- src/PkgDB.hs-boot +9/−0
- src/Updates.hs +70/−0
- src/Urls.hs +28/−0
- src/Util/Misc.hs +204/−0
- tst/TestPkgDB.hs +52/−0
- tst/TestSystem.hs +31/−0
- tst/tst.hs +28/−0
+ LICENSE-2.0 view
@@ -0,0 +1,202 @@++ Apache License+ Version 2.0, January 2004+ http://www.apache.org/licenses/++ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++ 1. Definitions.++ "License" shall mean the terms and conditions for use, reproduction,+ and distribution as defined by Sections 1 through 9 of this document.++ "Licensor" shall mean the copyright owner or entity authorized by+ the copyright owner that is granting the License.++ "Legal Entity" shall mean the union of the acting entity and all+ other entities that control, are controlled by, or are under common+ control with that entity. For the purposes of this definition,+ "control" means (i) the power, direct or indirect, to cause the+ direction or management of such entity, whether by contract or+ otherwise, or (ii) ownership of fifty percent (50%) or more of the+ outstanding shares, or (iii) beneficial ownership of such entity.++ "You" (or "Your") shall mean an individual or Legal Entity+ exercising permissions granted by this License.++ "Source" form shall mean the preferred form for making modifications,+ including but not limited to software source code, documentation+ source, and configuration files.++ "Object" form shall mean any form resulting from mechanical+ transformation or translation of a Source form, including but+ not limited to compiled object code, generated documentation,+ and conversions to other media types.++ "Work" shall mean the work of authorship, whether in Source or+ Object form, made available under the License, as indicated by a+ copyright notice that is included in or attached to the work+ (an example is provided in the Appendix below).++ "Derivative Works" shall mean any work, whether in Source or Object+ form, that is based on (or derived from) the Work and for which the+ editorial revisions, annotations, elaborations, or other modifications+ represent, as a whole, an original work of authorship. For the purposes+ of this License, Derivative Works shall not include works that remain+ separable from, or merely link (or bind by name) to the interfaces of,+ the Work and Derivative Works thereof.++ "Contribution" shall mean any work of authorship, including+ the original version of the Work and any modifications or additions+ to that Work or Derivative Works thereof, that is intentionally+ submitted to Licensor for inclusion in the Work by the copyright owner+ or by an individual or Legal Entity authorized to submit on behalf of+ the copyright owner. For the purposes of this definition, "submitted"+ means any form of electronic, verbal, or written communication sent+ to the Licensor or its representatives, including but not limited to+ communication on electronic mailing lists, source code control systems,+ and issue tracking systems that are managed by, or on behalf of, the+ Licensor for the purpose of discussing and improving the Work, but+ excluding communication that is conspicuously marked or otherwise+ designated in writing by the copyright owner as "Not a Contribution."++ "Contributor" shall mean Licensor and any individual or Legal Entity+ on behalf of whom a Contribution has been received by Licensor and+ subsequently incorporated within the Work.++ 2. Grant of Copyright License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ copyright license to reproduce, prepare Derivative Works of,+ publicly display, publicly perform, sublicense, and distribute the+ Work and such Derivative Works in Source or Object form.++ 3. Grant of Patent License. Subject to the terms and conditions of+ this License, each Contributor hereby grants to You a perpetual,+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable+ (except as stated in this section) patent license to make, have made,+ use, offer to sell, sell, import, and otherwise transfer the Work,+ where such license applies only to those patent claims licensable+ by such Contributor that are necessarily infringed by their+ Contribution(s) alone or by combination of their Contribution(s)+ with the Work to which such Contribution(s) was submitted. If You+ institute patent litigation against any entity (including a+ cross-claim or counterclaim in a lawsuit) alleging that the Work+ or a Contribution incorporated within the Work constitutes direct+ or contributory patent infringement, then any patent licenses+ granted to You under this License for that Work shall terminate+ as of the date such litigation is filed.++ 4. Redistribution. You may reproduce and distribute copies of the+ Work or Derivative Works thereof in any medium, with or without+ modifications, and in Source or Object form, provided that You+ meet the following conditions:++ (a) You must give any other recipients of the Work or+ Derivative Works a copy of this License; and++ (b) You must cause any modified files to carry prominent notices+ stating that You changed the files; and++ (c) You must retain, in the Source form of any Derivative Works+ that You distribute, all copyright, patent, trademark, and+ attribution notices from the Source form of the Work,+ excluding those notices that do not pertain to any part of+ the Derivative Works; and++ (d) If the Work includes a "NOTICE" text file as part of its+ distribution, then any Derivative Works that You distribute must+ include a readable copy of the attribution notices contained+ within such NOTICE file, excluding those notices that do not+ pertain to any part of the Derivative Works, in at least one+ of the following places: within a NOTICE text file distributed+ as part of the Derivative Works; within the Source form or+ documentation, if provided along with the Derivative Works; or,+ within a display generated by the Derivative Works, if and+ wherever such third-party notices normally appear. The contents+ of the NOTICE file are for informational purposes only and+ do not modify the License. You may add Your own attribution+ notices within Derivative Works that You distribute, alongside+ or as an addendum to the NOTICE text from the Work, provided+ that such additional attribution notices cannot be construed+ as modifying the License.++ You may add Your own copyright statement to Your modifications and+ may provide additional or different license terms and conditions+ for use, reproduction, or distribution of Your modifications, or+ for any such Derivative Works as a whole, provided Your use,+ reproduction, and distribution of the Work otherwise complies with+ the conditions stated in this License.++ 5. Submission of Contributions. Unless You explicitly state otherwise,+ any Contribution intentionally submitted for inclusion in the Work+ by You to the Licensor shall be under the terms and conditions of+ this License, without any additional terms or conditions.+ Notwithstanding the above, nothing herein shall supersede or modify+ the terms of any separate license agreement you may have executed+ with Licensor regarding such Contributions.++ 6. Trademarks. This License does not grant permission to use the trade+ names, trademarks, service marks, or product names of the Licensor,+ except as required for reasonable and customary use in describing the+ origin of the Work and reproducing the content of the NOTICE file.++ 7. Disclaimer of Warranty. Unless required by applicable law or+ agreed to in writing, Licensor provides the Work (and each+ Contributor provides its Contributions) on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+ implied, including, without limitation, any warranties or conditions+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+ PARTICULAR PURPOSE. You are solely responsible for determining the+ appropriateness of using or redistributing the Work and assume any+ risks associated with Your exercise of permissions under this License.++ 8. Limitation of Liability. In no event and under no legal theory,+ whether in tort (including negligence), contract, or otherwise,+ unless required by applicable law (such as deliberate and grossly+ negligent acts) or agreed to in writing, shall any Contributor be+ liable to You for damages, including any direct, indirect, special,+ incidental, or consequential damages of any character arising as a+ result of this License or out of the use or inability to use the+ Work (including but not limited to damages for loss of goodwill,+ work stoppage, computer failure or malfunction, or any and all+ other commercial damages or losses), even if such Contributor+ has been advised of the possibility of such damages.++ 9. Accepting Warranty or Additional Liability. While redistributing+ the Work or Derivative Works thereof, You may choose to offer,+ and charge a fee for, acceptance of support, warranty, indemnity,+ or other liability obligations and/or rights consistent with this+ License. However, in accepting such obligations, You may act only+ on Your own behalf and on Your sole responsibility, not on behalf+ of any other Contributor, and only if You agree to indemnify,+ defend, and hold each Contributor harmless for any liability+ incurred by, or claims asserted against, such Contributor by reason+ of your accepting any such warranty or additional liability.++ END OF TERMS AND CONDITIONS++ APPENDIX: How to apply the Apache License to your work.++ To apply the Apache License to your work, attach the following+ boilerplate notice, with the fields enclosed by brackets "[]"+ replaced with your own identifying information. (Don't include+ the brackets!) The text should be enclosed in the appropriate+ comment syntax for the file format. We also recommend that a+ file or class name and description of purpose be included on the+ same "printed page" as the copyright notice for easier+ identification within third-party archives.++ Copyright [yyyy] [name of copyright owner]++ Licensed under the Apache License, Version 2.0 (the "License");+ you may not use this file except in compliance with the License.+ You may obtain a copy of the License at++ http://www.apache.org/licenses/LICENSE-2.0++ Unless required by applicable law or agreed to in writing, software+ distributed under the License is distributed on an "AS IS" BASIS,+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ See the License for the specific language governing permissions and+ limitations under the License.
+ Setup.hs view
@@ -0,0 +1,21 @@+#! /usr/bin/env runhaskell++{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++import Distribution.Simple++main = defaultMain
+ cblrepo.cabal view
@@ -0,0 +1,47 @@+name: cblrepo+version: 0.2.0+cabal-version: >= 1.6+license: OtherLicense+license-file: LICENSE-2.0+copyright: Copyright (c) 2011 Magnus Therning+author: Magnus Therning+maintainer: Magnus Therning <magnus@therning.org>+stability: experimental+bug-reports: mailto:magnus@therning.org+synopsis: Tool to maintain a database of CABAL packages and their dependencies+description:+ Helper tool for people maintaining a set of CABAL packages for their+ distribution. It maintains a database of packages and verifies+ dependencies of the entire set as packages are added or updated. It also+ makes it trivial to track packages as new versions are released on Hackage.++ It can also be used to build source packages for the ArchLinux distribution.+category: Utils, Distribution+build-type: Custom++flag BuildTests+ Description: Build tests+ Default: False++executable cblrepo+ hs-source-dirs: src+ main-is: Main.hs+ other-modules: Util.Misc PkgDB AddBase AddCabal BumpPkgs BuildPkgs IdxSync+ IdxVersion Updates ListPkgs Urls+ build-depends: base ==4.3.*, cmdargs ==0.7.*, filepath ==1.2.*,+ directory ==1.1.*, Cabal ==1.10.*, json ==0.4.*,+ bytestring ==0.9.*, tar ==0.3.*, zlib ==0.5.*, mtl ==2.0.*,+ process ==1.0.*, Unixutils ==1.36.*, unix ==2.4.*,+ ansi-wl-pprint ==0.6.*++executable tests+ hs-source-dirs: tst src+ main-is: tst.hs+ other-modules: TestSystem TestPkgDB+ if flag(BuildTests)+ build-depends: base ==4.3.*, test-framework-th ==0.1.*, HUnit ==1.2.*,+ test-framework-hunit ==0.2.*, test-framework ==0.3.*+ else+ buildable: False++-- vim: set tw=0 :
+ src/AddBase.hs view
@@ -0,0 +1,50 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module AddBase where++import PkgDB+import Util.Misc++import Control.Monad+import Control.Monad.Reader+import Data.List+import Data.Maybe+import Distribution.Text+import Distribution.Version+import System.FilePath++addBase :: ReaderT Cmds IO ()+addBase = do+ pkgs <- cfgGet pkgVers+ dR <- cfgGet dryRun+ guard $ isJust $ (sequence $ map (simpleParse . snd) pkgs :: Maybe [Version])+ let ps = map (\ (n, v) -> (n, fromJust $ simpleParse v)) pkgs+ dbFn <- cfgGet dbFile+ db <- liftIO $ readDb dbFn+ case doAddBase db ps of+ Left brkOthrs -> liftIO $ mapM_ printBrksOth brkOthrs+ Right newDb -> liftIO $ unless dR $ saveDb newDb dbFn++doAddBase db pkgs = let+ (_, fails) = partition (\ (n, v) -> canBeAdded db n v) pkgs+ newDb = foldl (\ d (n, v) -> addBasePkg d n v) db pkgs+ brkOthrs = map (\ (n, v) -> ((n, v), checkDependants db n v)) fails+ in if null fails+ then Right newDb+ else Left brkOthrs++canBeAdded db n v = null $ checkDependants db n v
+ src/AddCabal.hs view
@@ -0,0 +1,87 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module AddCabal where++import PkgDB+import Util.Misc++import Codec.Archive.Tar as Tar+import Codec.Compression.GZip as GZip+import Control.Monad+import Control.Monad.Error+import Control.Monad.Reader+import Data.List+import Data.Maybe+import Data.Version+import Distribution.Compiler+import Distribution.PackageDescription+import Distribution.PackageDescription.Configuration+import Distribution.PackageDescription.Parse+import Distribution.System+import Distribution.Text+import Distribution.Verbosity+import Distribution.Version+import System.Directory+import System.FilePath+import qualified Data.ByteString.Lazy.Char8 as BS+import qualified Distribution.Package as P+import System.Posix.Files+import System.Unix.Directory+import System.Process+import System.Exit+import System.IO++addCabal :: ReaderT Cmds IO ()+addCabal = do+ dbFn <- cfgGet dbFile+ db <- liftIO $ readDb dbFn+ pD <- cfgGet patchDir+ cbls <- cfgGet cbls+ dR <- cfgGet dryRun+ genPkgs <- liftIO $ mapM (\ c -> withTemporaryDirectory "/tmp/cblrepo." (readCabal pD c)) cbls+ let pkgNames = map ((\ (P.PackageName n) -> n ) . P.pkgName . package . packageDescription) genPkgs+ let tmpDb = filter (\ p -> not $ pkgName p `elem` pkgNames) db+ case doAddCabal tmpDb genPkgs of+ Left (unSats, brksOthrs) -> liftIO (mapM_ printUnSat unSats >> mapM_ printBrksOth brksOthrs)+ Right newDb -> liftIO $ unless dR $ saveDb newDb dbFn++doAddCabal db pkgs = let+ (succs, fails) = partition (canBeAdded db) pkgs+ newDb = foldl addPkg2 db (map (fromJust . finalizeToCblPkg db) succs)+ unSats = catMaybes $ map (finalizeToDeps db) fails+ genPkgName = ((\ (P.PackageName n) -> n ) . P.pkgName . package . packageDescription)+ genPkgVer = P.pkgVersion . package . packageDescription+ brksOthrs = filter (not . null . snd) $ map (\ p -> ((genPkgName p, genPkgVer p), checkDependants db (genPkgName p) (genPkgVer p))) fails+ in case (succs, fails) of+ (_, []) -> Right newDb+ ([], _) -> Left (unSats, brksOthrs)+ (_, _) -> doAddCabal newDb fails++canBeAdded db p = let+ finable = either (const False) (const True) (finalizePkg db p)+ n = ((\ (P.PackageName n) -> n ) . P.pkgName . package . packageDescription) p+ v = P.pkgVersion $ package $ packageDescription p+ depsOK = null $ checkDependants db n v+ in finable && depsOK++finalizeToCblPkg db p = case finalizePkg db p of+ Right (pd, _) -> Just $ createCblPkg pd+ _ -> Nothing++finalizeToDeps db p = case finalizePkg db p of+ Left ds -> Just $ (((\ (P.PackageName n) -> n ) . P.pkgName . package . packageDescription) p, ds)+ _ -> Nothing
+ src/BuildPkgs.hs view
@@ -0,0 +1,32 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module BuildPkgs where++import PkgDB+import Util.Misc++import Control.Monad+import Control.Monad.Reader+import Data.List+import Data.Maybe+import System.FilePath++buildPkgs :: ReaderT Cmds IO ()+buildPkgs = do+ db <- cfgGet dbFile >>= liftIO . readDb+ pkgs <- cfgGet pkgs+ liftIO $ mapM_ putStrLn $ transitiveDependants db pkgs
+ src/BumpPkgs.hs view
@@ -0,0 +1,41 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module BumpPkgs where++import PkgDB+import Util.Misc++import Control.Monad+import Control.Monad.Reader+import Data.List+import Data.Maybe+import System.FilePath++bumpPkgs :: ReaderT Cmds IO ()+bumpPkgs = do+ dbFn <- cfgGet dbFile+ db <- liftIO $ readDb dbFn+ dR <- cfgGet dryRun+ pkgs <- cfgGet pkgs+ incl <- cfgGet inclusive+ let bpkgs = transDependants db incl pkgs+ let newDb = foldl (\ db p -> bumpRelease db p) db bpkgs+ if dR+ then liftIO $ putStrLn "Would bump:" >> mapM_ putStrLn bpkgs+ else liftIO $ saveDb newDb dbFn++transDependants db i pkgs = filter ((||) i . (not . flip elem pkgs)) $ transitiveDependants db pkgs
+ src/IdxSync.hs view
@@ -0,0 +1,28 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module IdxSync where++import Util.Misc++import Control.Monad.Reader+import System.FilePath+import Control.Monad.Error++idxSync :: ReaderT Cmds IO ()+idxSync = do+ aD <- cfgGet appDir+ liftIO $ getFromURL "http://hackage.haskell.org/packages/archive/00-index.tar.gz" (aD </> "00-index.tar.gz")
+ src/IdxVersion.hs view
@@ -0,0 +1,56 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module IdxVersion where++import Util.Misc++import Codec.Archive.Tar as Tar+import Codec.Compression.GZip as GZip+import Control.Monad+import Control.Monad.Reader+import Data.List+import Data.Maybe+import Distribution.Text+import Distribution.Version+import System.FilePath+import qualified Data.ByteString.Lazy.Char8 as BS++idxVersion :: ReaderT Cmds IO ()+idxVersion = do+ aD <- cfgGet appDir+ pkgs <- cfgGet pkgs+ liftIO $ do+ es <- liftM (Tar.read . GZip.decompress) (BS.readFile $ aD </> "00-index.tar.gz")+ mapM_ (printVersions . findVersions es) pkgs++findVersions es p = (p, findV p es [])+ where+ findV pkgName (Next e es) acc = let+ eP = entryPath e+ (ePkg:v:_) = splitDirectories eP+ in if ('/' `elem` eP) && (pkgName == ePkg)+ then findV pkgName es (v:acc)+ else findV pkgName es acc++ findV _ Done acc = let+ vs :: [Version]+ vs = map (fromJust . simpleParse) acc+ in map display $ sort vs++printVersions (p, vs) = do+ putStr $ p ++ " : "+ putStrLn $ unwords vs
+ src/ListPkgs.hs view
@@ -0,0 +1,38 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module ListPkgs where++import Util.Misc+import PkgDB++import Control.Monad+import Control.Monad.Reader+import Data.Maybe+import Distribution.Text+import System.FilePath++listPkgs :: ReaderT Cmds IO ()+listPkgs = do+ iB <- cfgGet incBase+ db <- cfgGet dbFile >>= liftIO . readDb+ let pkgs = if not iB+ then filter (not . isBasePkg) db+ else db+ liftIO $ mapM_ printCblPkgShort pkgs++printCblPkgShort (p, (v, _, r)) =+ putStrLn $ p ++ " ==" ++ (display v) ++ " (" ++ (show r) ++")"
+ src/Main.hs view
@@ -0,0 +1,135 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module Main where++import AddBase+import AddCabal+import BuildPkgs+import BumpPkgs+import IdxSync+import IdxVersion+import ListPkgs+import Updates+import Util.Misc+import Urls+import PkgBuild++import Paths_cblrepo++import Control.Monad+import Control.Monad.Reader+import Distribution.Text+import System.Console.CmdArgs+import System.Directory+import System.FilePath++-- {{{1 command line arguments+argAppDir = appDir := def += explicit += name "appdir" += help "application data directory" += typDir+argDbFile = dbFile := "cblrepo.db" += explicit += name "db" += help "package database" += typFile+argDryRun = dryRun := False += explicit += name "n" += help "dry run"++cmdAddBasePkg = record defAddBasePkg+ [ argAppDir, argDbFile, argDryRun+ , pkgVers := def += args += typ "STRING,STRING"+ ] += name "addbasepkg" += help "add base packages" += details+ [ "The format for a package is <name>,<version>." ]++cmdAddPkg = record defAddPkg+ [ argAppDir, argDbFile+ , patchDir := "patches" += explicit += name "patchdir" += help "location of patches" += typDir+ , argDryRun+ , cbls := def += args += typ "CABAL"+ ] += name "add" += help "add a package from a Cabal file" += details+ [ "There are three ways to specify the location of the Cabal file:"+ , " 1. The filename of the Cabal file."+ , " 2. A URL where the Cabal can be found (for file:// URLs the full absolute path is required)."+ , " 3. A pair, <name>,<version>, will load the Cabal file out of an index file (see idxupdate)"+ , "All three format may be mixed on the command line."+ ]++cmdBumpPkgs = record defBumpPkgs+ [ argAppDir, argDbFile+ , argDryRun+ , inclusive := False += explicit += name "inclusive" += help "include listed packages"+ , pkgs := def += args += typ "PKG"+ ] += name "bump" += help "bump packages that need it after updating the named packages"++cmdBuildPkgs = record defBuildPkgs+ [ argAppDir, argDbFile+ , pkgs := def += args += typ "PKG"+ ] += name "build" += help "list packages that need rebuilding, in order"++cmdIdxSync = record defIdxSync [ argAppDir ] += help "update the index"++cmdIdxVersion = record defIdxVersion+ [ argAppDir+ , pkgs := def += args += typ "PKG"+ ] += help "list available versions"++cmdUpdates = record defUpdates [ argAppDir , argDbFile ] += name "updates" += help "check for availabale updates"++cmdListPkgs = record defListPkgs+ [ argAppDir, argDbFile+ , incBase := False += help "include base packages in listing"+ ] += name "list" += help "list packages in repo"++cmdUrls = record defUrls+ [ argAppDir+ , pkgVers := def += args += typ "STRING,STRING"+ ] += help "list urls of cabal files for the given packages" += details+ [ "The format for a package is <name>,<version>." ]++cmdPkgBuild = record defPkgBuild+ [ argAppDir, argDbFile+ , patchDir := "patches" += explicit += name "patchdir" += help "location of patches (patches)" += typDir+ , pkgs := def += args += typ "PKG"+ ] += help "create a PKGBUILD, and other files necessary for an Arch package"++cmds = cmdArgsMode_ $ modes_+ [ cmdAddBasePkg+ , cmdAddPkg+ , cmdBuildPkgs+ , cmdBumpPkgs+ , cmdIdxSync+ , cmdIdxVersion+ , cmdListPkgs+ , cmdUpdates+ , cmdUrls+ , cmdPkgBuild+ ]+ += program progName+ += summary (progName ++ " v" ++ (display version))+ += help "maintain a database of dependencies of CABAL packages"++-- {{{1 main+main = do+ defAppDir <- getAppUserDataDirectory progName+ cmdArgsRun cmds >>= \ c -> do+ let aD = if null (appDir c) then defAppDir else (appDir c)+ let c' = c { appDir = aD }+ createDirectoryIfMissing True (aD)+ case c' of+ AddBasePkg {} -> runReaderT addBase c'+ AddPkg {} -> runReaderT addCabal c'+ BuildPkgs {} -> runReaderT buildPkgs c'+ BumpPkgs {} -> runReaderT bumpPkgs c'+ IdxSync {} -> runReaderT idxSync c'+ IdxVersion {} -> runReaderT idxVersion c'+ ListPkgs {} -> runReaderT listPkgs c'+ Updates {} -> runReaderT updates c'+ Urls {} -> runReaderT urls c'+ PkgBuild {} -> runReaderT pkgBuild c'
+ src/PkgDB.hs view
@@ -0,0 +1,145 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module PkgDB where++import Util.Misc++import Control.Exception as CE+import Data.List+import Data.Maybe+import Data.Maybe+import Distribution.PackageDescription+import Distribution.Text+import Distribution.Version+import System.IO.Error+import Text.JSON+import qualified Distribution.Package as P+import qualified Distribution.Version as V++type CblPkg = (String, (V.Version, [P.Dependency], Int))+type CblDB = [CblPkg]++pkgName :: CblPkg -> String+pkgName (n, _) = n++pkgVersion :: CblPkg -> V.Version+pkgVersion (_, (v, _, _)) = v++pkgDeps :: CblPkg -> [P.Dependency]+pkgDeps (_, (_, ds, _)) = ds++pkgRelease :: CblPkg -> Int+pkgRelease (_, (_, _, i)) = i++createCblPkg :: PackageDescription -> CblPkg+createCblPkg pd = (name, (version, deps, 1))+ where+ name = (\ (P.PackageName n) -> n) (P.pkgName $ package pd)+ version = P.pkgVersion $ package pd+ deps = buildDepends pd++getDependencyOn :: String -> CblPkg -> Maybe P.Dependency+getDependencyOn n p = find (\ d -> depName d == n) (pkgDeps p)++isBasePkg (_, (_, ds, _)) = null ds++emptyPkgDB :: CblDB+emptyPkgDB = []++addPkg :: CblDB -> String -> V.Version -> [P.Dependency] -> Int -> CblDB+addPkg db n v ds r = nubBy cmp newdb+ where+ cmp (n1, _) (n2, _) = n1 == n2+ newdb = (n, (v, ds, r)) : db++addPkg2 db (n, (v, ds, r)) = addPkg db n v ds r++addBasePkg db n v = addPkg db n v [] 0++delPkg :: CblDB -> String -> CblDB+delPkg db n = filter (\ p -> n /= pkgName p) db++lookupPkg :: CblDB -> String -> Maybe CblPkg+lookupPkg db n = maybe Nothing (\ s -> Just (n, s)) (lookup n db)++lookupDependencies :: CblDB -> String -> Maybe [String]+lookupDependencies db n =+ case lookupPkg db n of+ Nothing -> Nothing+ Just p -> let+ ds = pkgDeps p+ in Just $ map depName ds++lookupDependants :: CblDB -> String -> [String]+lookupDependants db n = map pkgName $ filter (\ p -> doesDependOn p n) db+ where+ doesDependOn p n = n `elem` (map depName $ pkgDeps p)++checkDependants db n v = let+ d1 = catMaybes $ map (lookupPkg db) (lookupDependants db n)+ d2 = map (\ p -> (pkgName p, getDependencyOn n p)) d1+ fails = filter (not . withinRange v . depVersionRange . fromJust . snd) d2+ in fails++transitiveDependants db pkgs = keepLast $ concat $ map transUsersOfOne pkgs+ where+ transUsersOfOne pkg = pkg : (keepLast $ concat $ map (transUsersOfOne) (lookupDependants db pkg))+ keepLast = reverse . nub . reverse++lookupRelease :: CblDB -> String -> Maybe Int+lookupRelease db n = lookupPkg db n >>= return . pkgRelease++bumpRelease db n = let+ bump (n', (v', d', r')) = (n', (v', d', r' + 1))+ in maybe db (addPkg2 db . bump) (lookupPkg db n)+readDb :: FilePath -> IO CblDB+readDb fp = (flip CE.catch)+ (\ e -> if isDoesNotExistError e+ then return emptyPkgDB+ else throwIO e)+ $ do+ r <- readFile fp >>= return . sequence . map decode . lines+ case r of+ Ok a -> return a+ Error s -> fail s++saveDb :: CblDB -> FilePath -> IO ()+saveDb db fp = writeFile fp s+ where+ s = unlines $ map (encode . showJSON) db++instance JSON V.Version where+ showJSON v = makeObj [ ("Version", showJSON $ display v) ]+ readJSON (JSObject o) = let+ jAssoc = fromJSObject o+ resultToMaybe (Ok a) = Just a+ resultToMaybe _ = Nothing+ version = lookup "Version" jAssoc >>= resultToMaybe . readJSON >>= simpleParse+ in+ maybe (fail "Not a version object") return version+ readJSON _ = fail "Not a version object"++instance JSON P.Dependency where+ showJSON d = makeObj [ ("Dependency", showJSON $ display d) ]+ readJSON (JSObject o) = let+ jAssoc = fromJSObject o+ resultToMaybe (Ok a) = Just a+ resultToMaybe _ = Nothing+ dependency = lookup "Dependency" jAssoc >>= resultToMaybe . readJSON >>= simpleParse+ in+ maybe (fail "Not a dependency object") return dependency+ readJSON _ = fail "Not a version object"
+ src/PkgDB.hs-boot view
@@ -0,0 +1,9 @@+module PkgDB where++import qualified Distribution.Package as P+import qualified Distribution.Version as V++type CblPkg = (String, (V.Version, [P.Dependency], Int))+type CblDB = [CblPkg]++lookupPkg :: CblDB -> String -> Maybe CblPkg
+ src/Updates.hs view
@@ -0,0 +1,70 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module Updates where++import PkgDB+import Util.Misc++import Codec.Archive.Tar as Tar+import Codec.Compression.GZip as GZip+import Control.Monad+import Control.Monad.Reader+import Data.Maybe+import Distribution.Text+import Distribution.Version+import System.FilePath+import qualified Data.ByteString.Lazy.Char8 as BS++updates :: ReaderT Cmds IO ()+updates = do+ db <- cfgGet dbFile >>= liftIO . readDb+ aD <- cfgGet appDir+ entries <- liftIO $ liftM (Tar.read . GZip.decompress)+ (BS.readFile $ aD </> "00-index.tar.gz")+ let nonBasePkgs = filter (\ (_, (_, ds, _)) -> not $ null ds) db+ let pkgsNVers = map (\ (p, (v, _, _)) -> (p, v)) nonBasePkgs+ let availPkgs = catMaybes $ eMap extractPkgVer entries+ let outdated = filter+ (\ (p, v) -> maybe False (> v) (latestVer p availPkgs))+ pkgsNVers+ liftIO $ mapM_ (flip printOutdated availPkgs) outdated++type PkgVer = (String, Version)++extractPkgVer :: Entry -> Maybe PkgVer+extractPkgVer e = let+ ep = entryPath e+ isCabal = '/' `elem` ep+ (pkg:ver':_) = map dropTrailingPathSeparator $ splitPath ep+ ver = simpleParse ver'+ in if isCabal && isJust ver+ then Just $ (pkg, (fromJust ver))+ else Nothing++latestVer p pvs = let+ vs = map snd $ filter ((== p) . fst) pvs+ in if null vs+ then Nothing+ else Just $ maximum vs++eMap _ Done = []+eMap f (Next e es) = (f e):(eMap f es)++printOutdated (p, v) avail = let+ l = fromJust $ latestVer p avail+ in+ putStrLn $ p ++ ": " ++ (display v) ++ " (" ++ (display l) ++ ")"
+ src/Urls.hs view
@@ -0,0 +1,28 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module Urls where++import Util.Misc++import Control.Monad.Reader++urls :: ReaderT Cmds IO ()+urls = do+ pkgs <- cfgGet pkgVers+ liftIO $ mapM_ (putStrLn . createUrl) pkgs++createUrl (pkg, ver) = "http://hackage.haskell.org/packages/archive/" ++ pkg ++ "/" ++ ver ++ "/" ++ pkg ++ ".cabal"
+ src/Util/Misc.hs view
@@ -0,0 +1,204 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module Util.Misc where++import {-# SOURCE #-} PkgDB++import Codec.Archive.Tar as Tar+import Codec.Compression.GZip as GZip+import Control.Concurrent+import Control.Monad+import Control.Monad.Error+import Control.Monad.Reader+import Data.Data+import Data.List+import Data.Typeable+import Distribution.Compiler+import Distribution.Package+import Distribution.PackageDescription+import Distribution.PackageDescription.Configuration+import Distribution.PackageDescription.Parse+import Distribution.System+import Distribution.Text+import Distribution.Verbosity+import Distribution.Version+import System.Directory+import System.Exit+import System.FilePath+import System.IO+import System.Posix.Files+import System.Process+import qualified Control.Exception as CE+import qualified Data.ByteString.Lazy.Char8 as BS++-- {{{1 Dependency+depName (Dependency (PackageName n) _) = n+depVersionRange (Dependency _ vr) = vr++-- {{{ print functions+printUnSat (n, ds) = do+ putStrLn $ "Failed to satisfy the following dependencies for " ++ n ++ ":"+ mapM_ (putStrLn . (" " ++) . display) ds++printBrksOth ((n, v), brks) = do+ putStrLn $ "Adding " ++ n ++ " " ++ (display v) ++ " would break:"+ mapM_ (\ (bN, (Just bD)) -> putStrLn $ " " ++ bN ++ " : " ++ (display bD)) brks++-- {{{1 program variables+progName = "cblrepo"+dbName = progName ++ ".db"++-- {{{1 command line argument type+data Cmds+ = AddBasePkg { appDir :: FilePath, dbFile :: FilePath, dryRun :: Bool, pkgVers :: [(String, String)] }+ | AddPkg { appDir :: FilePath, dbFile :: FilePath, patchDir :: FilePath, dryRun :: Bool, cbls :: [FilePath] }+ | BuildPkgs { appDir :: FilePath, dbFile :: FilePath, pkgs :: [String] }+ | BumpPkgs { appDir :: FilePath, dbFile :: FilePath, dryRun :: Bool, inclusive :: Bool, pkgs :: [String] }+ | IdxSync { appDir :: FilePath }+ | IdxVersion { appDir :: FilePath, pkgs :: [String] }+ | ListPkgs { appDir :: FilePath, dbFile :: FilePath, incBase :: Bool }+ | Updates { appDir :: FilePath, dbFile :: FilePath }+ | Urls { appDir :: FilePath, pkgVers :: [(String, String)] }+ | PkgBuild { appDir :: FilePath, dbFile :: FilePath, patchDir :: FilePath, pkgs :: [String] }+ deriving (Show, Data, Typeable)++defAddBasePkg = AddBasePkg "" "" True []+defAddPkg = AddPkg "" "" "" True []+defBuildPkgs = BuildPkgs "" "" []+defBumpPkgs = BumpPkgs "" "" False False []+defIdxSync = IdxSync ""+defIdxVersion = IdxVersion "" []+defListPkgs = ListPkgs "" "" True+defUpdates = Updates "" ""+defUrls = Urls "" []+defPkgBuild = PkgBuild "" "" "" []++cfgGet f = liftM f ask++-- {{{1 getFromURL+getFromURL url fn = do+ (ec, _, er) <- readProcessWithExitCode "curl" ["-f", "-o", fn, url] ""+ case ec of+ ExitSuccess -> return ()+ ExitFailure _ -> do+ hPutStrLn stderr ("Failed downloading " ++ url)+ hPutStrLn stderr er+ exitFailure++-- {{{1 applyPatchIfExist+applyPatch origFilename patchFilename = do+ (ec, _, err) <- readProcessWithExitCode "patch" [origFilename, patchFilename] ""+ case ec of+ ExitSuccess -> return ()+ ExitFailure _ ->+ hPutStrLn stderr "Failed patching the .cabal file" >> exitFailure++applyPatchIfExist origFilename patchFilename =+ fileExist patchFilename >>= flip when (applyPatch origFilename patchFilename)++-- {{{1 package descriptions+-- {{{2 readCabal+data LocType = Url | Idx | File++-- | Read in a Cabal file.+readCabal patchDir loc tmpDir = let+ locType+ | isInfixOf "://" loc = Url+ | ',' `elem` loc = Idx+ | otherwise = File++ copyCabal tmpDir loc = copyFile loc fn >> return fn+ where fn = tmpDir </> takeFileName loc++ downloadCabal tmpDir loc = getFromURL loc fn >> return fn+ where+ fn = tmpDir </> takeFileName loc++ extractCabal tmpDir loc = let+ (p, (_: v)) = span (/= ',') loc+ path = p </> v </> p ++ ".cabal"+ pkgStr = p ++ " " ++ v+ fn = tmpDir </> (p ++ ".cabal")++ esFindEntry p (Next e es) = if p == (entryPath e)+ then Just e+ else esFindEntry p es+ esFindEntry _ _ = Nothing++ eGetContent e = let+ ec = entryContent e+ in case ec of+ NormalFile c _ -> Just $ BS.unpack c+ _ -> Nothing++ in do+ fp <- getAppUserDataDirectory "cblrepo"+ es <- liftM (Tar.read . GZip.decompress)+ (BS.readFile $ fp </> "00-index.tar.gz")+ e <- maybe (error $ "No entry for " ++ pkgStr)+ return+ (esFindEntry path es)+ cbl <- maybe (error $ "Failed to extract contents for " ++ pkgStr)+ return+ (eGetContent e)+ writeFile fn cbl+ return fn++ extractName fn = liftM name $ readPackageDescription silent fn+ where+ packageName (PackageName s) = s+ name = packageName . pkgName . package . packageDescription++ in do+ cblFn <- case locType of+ File -> copyCabal tmpDir loc+ Idx -> extractCabal tmpDir loc+ Url -> downloadCabal tmpDir loc+ pn <- extractName cblFn+ let patchFn = patchDir </> pn <.> "cabal"+ return patchFn+ applyPatchIfExist cblFn patchFn+ readPackageDescription silent cblFn++-- {{{2 finalising+finalizePkg db = finalizePackageDescription+ [] -- no flags+ (checkAgainstDb db)+ (Platform X86_64 buildOS) -- platform+ (CompilerId GHC (Version [7,0,2] [])) -- compiler version+ [] -- no additional constraints++checkAgainstDb db dep = let+ dN = depName dep+ dVR = depVersionRange dep+ in case lookupPkg db dN of+ Nothing -> False+ Just (_, (v, _, _)) -> withinRange v dVR++-- {{{1 allPatches+allPatches pn patchDir = let+ cblPatch = patchDir </> pn <.> "cabal"+ pkgPatch = patchDir </> pn <.> "pkgbuild"+ bldPatch = patchDir </> pn <.> "build"+ in do+ cE <- fileExist cblPatch+ pE <- fileExist pkgPatch+ bE <- fileExist bldPatch+ return (if cE then Just cblPatch else Nothing,+ if pE then Just pkgPatch else Nothing,+ if bE then Just bldPatch else Nothing)
+ tst/TestPkgDB.hs view
@@ -0,0 +1,52 @@+{-# OPTIONS_GHC -XTemplateHaskell #-}+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module TestPkgDB+ ( testGroup+ ) where++import PkgDB++import Data.Maybe+import Distribution.Text+import Test.Framework.Providers.HUnit+import Test.Framework.TH+import Test.HUnit++-- {{{1 transitiveDependants+theDb :: CblDB+theDb =+ [ ("pkgA", (fromJust $ simpleParse "1.0", [])) -- nothing depends on this pkg+ -- a chain of two+ , ("pkgB", (fromJust $ simpleParse "1.0", []))+ , ("pkgC", (fromJust $ simpleParse "1.0", map (fromJust . simpleParse) ["pkgB"]))+ -- a chain of three+ , ("pkgD", (fromJust $ simpleParse "1.0", []))+ , ("pkgE", (fromJust $ simpleParse "1.0", map (fromJust . simpleParse) ["pkgD"]))+ , ("pkgF", (fromJust $ simpleParse "1.0", map (fromJust . simpleParse) ["pkgE"]))+ ]++case_TD_one = do transitiveDependants theDb ["pkgA"] @=? ["pkgA"]+case_TD_two = do transitiveDependants theDb ["pkgB"] @=? ["pkgB", "pkgC"]+case_TD_three = do transitiveDependants theDb ["pkgD"] @=? ["pkgD", "pkgE", "pkgF"]+-- pass in packages in correct order+case_TD_ordering1 = do transitiveDependants theDb ["pkgD", "pkgF"] @=? ["pkgD", "pkgE", "pkgF"]+-- pass in packages in reverse order+case_TD_ordering2 = do transitiveDependants theDb ["pkgF", "pkgD"] @=? ["pkgD", "pkgE", "pkgF"]++-- {{{1 testGroup+testGroup = $(testGroupGenerator)
+ tst/TestSystem.hs view
@@ -0,0 +1,31 @@+{-# OPTIONS_GHC -XTemplateHaskell #-}+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module TestSystem+ ( testGroup+ ) where++import Data.List+import Test.Framework.Providers.HUnit+import Test.Framework.TH+import Test.HUnit++-- {{{1 nub works as expected+case_nub_order = do nub [1,2,1,3,1] @=? [1,2,3]++-- {{{1 testGroup+testGroup = $(testGroupGenerator)
+ tst/tst.hs view
@@ -0,0 +1,28 @@+{-+ - Copyright 2011 Per Magnus Therning+ -+ - Licensed under the Apache License, Version 2.0 (the "License");+ - you may not use this file except in compliance with the License.+ - You may obtain a copy of the License at+ -+ - http://www.apache.org/licenses/LICENSE-2.0+ -+ - Unless required by applicable law or agreed to in writing, software+ - distributed under the License is distributed on an "AS IS" BASIS,+ - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+ - See the License for the specific language governing permissions and+ - limitations under the License.+ -}++module Main where++import qualified TestPkgDB+import qualified TestSystem++import Test.Framework++main = defaultMain+ [ TestPkgDB.testGroup+ , TestSystem.testGroup+ ]+