multi-cabal (empty) → 0.1.0.0
raw patch · 15 files changed
+519/−0 lines, 15 filesdep +AAIdep +HUnitdep +aesonsetup-changed
Dependencies added: AAI, HUnit, aeson, base, bytestring, directory, filepath, mtl, multi-cabal, process, strict, test-framework, test-framework-hunit
Files
- LICENSE +20/−0
- README.md +1/−0
- Setup.hs +2/−0
- changelog.md +4/−0
- multi-cabal.cabal +58/−0
- src-lib/Data/Model/Project.hs +43/−0
- src-lib/Data/Model/Utility.hs +27/−0
- src-lib/Logic/Dependency/Resolution.hs +87/−0
- src-test/Main.hs +28/−0
- src/Main.hs +38/−0
- src/MultiCabal/Commands.hs +42/−0
- src/MultiCabal/Commands/Help.hs +41/−0
- src/MultiCabal/Commands/Install.hs +69/−0
- src/MultiCabal/Commands/Version.hs +32/−0
- src/MultiCabal/Instruction.hs +27/−0
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2015 Nils 'bash0r' Jonsson++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ README.md view
@@ -0,0 +1,1 @@+# multi-cabal
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ changelog.md view
@@ -0,0 +1,4 @@+# v0.1.0.0++Initial release.+
+ multi-cabal.cabal view
@@ -0,0 +1,58 @@+name: multi-cabal+version: 0.1.0.0+synopsis: A tool supporting multi cabal project builds.+description: A tool supporting multi cabal project builds.+homepage: https://github.com/aka-bash0r/multi-cabal+license: MIT+license-file: LICENSE+author: Nils 'bash0r' Jonsson+maintainer: aka.bash0r@gmail.com+-- copyright: +category: Development+build-type: Simple+extra-source-files: LICENSE+ , README.md+ , changelog.md+cabal-version: >=1.10++library+ exposed-modules: Data.Model.Project+ , Data.Model.Utility+ , Logic.Dependency.Resolution+ build-depends: base >=4.8 && <4.9+ , aeson >=0.9 && <0.10+ , filepath >=1.4 && <1.5+ , mtl >=2.2 && <2.3+ hs-source-dirs: src-lib+ default-language: Haskell2010 ++executable multi-cabal+ main-is: Main.hs+ other-modules: MultiCabal.Commands+ , MultiCabal.Commands.Help+ , MultiCabal.Commands.Install+ , MultiCabal.Commands.Version+ , MultiCabal.Instruction+ , Paths_multi_cabal+ build-depends: base >=4.8 && <4.9+ , aeson >=0.9 && <0.10+ , filepath >=1.4 && <1.5+ , directory >=1.2 && <1.3+ , bytestring >=0.10 && <0.11+ , process >=1.2 && <1.3+ , strict >=0.3 && <0.4+ , AAI >=0.2 && <0.3+ , multi-cabal+ hs-source-dirs: src+ default-language: Haskell2010++Test-Suite multi-cabal-tests+ type: exitcode-stdio-1.0+ main-is: Main.hs+ hs-source-dirs: src-test+ build-depends: base >=4.8 && <4.9+ , test-framework+ , test-framework-hunit+ , HUnit+ , multi-cabal+
+ src-lib/Data/Model/Project.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE OverloadedStrings #-}++{- |+Module : $Header$+Description : ADT describing a project.+Author : Nils 'bash0r' Jonsson+Copyright : (c) 2015 Nils 'bash0r' Jonsson+License : MIT++Maintainer : aka.bash0r@gmail.com+Stability : unstable+Portability : non-portable (Portability is untested.)++A simple ADT describing a project.+-}+module Data.Model.Project+( Project (..)+) where++import Data.Aeson+import Data.Model.Utility+++-- | A representation of a project.+data Project+ -- | A basic representation of a project. + = Project ProjectName ProjectRoot [ProjectName]+ deriving (Show, Eq)+++instance ToJSON Project where+ toJSON (Project pName pDirectory pDependencies) =+ object [ "name" .= pName+ , "root" .= pDirectory+ , "dependencies" .= pDependencies+ ]++instance FromJSON Project where+ parseJSON = withObject "Project Description" $ \o ->+ Project <$> o .: "name"+ <*> o .: "root"+ <*> o .: "dependencies"+
+ src-lib/Data/Model/Utility.hs view
@@ -0,0 +1,27 @@+{- |+Module : $Header$+Description : A collection of utility declarations.+Author : Nils 'bash0r' Jonsson+Copyright : (c) 2015 Nils 'bash0r' Jonsson+License : MIT++Maintainer : aka.bash0r@gmail.com+Stability : unstable+Portability : non-portable (Portability is untested.)++A collection of utility declarations.+-}+module Data.Model.Utility+( ProjectName+, ProjectRoot+) where++import System.FilePath.Posix+++-- | The name of a project.+type ProjectName = String++-- | The root directory of the project.+type ProjectRoot = FilePath+
+ src-lib/Logic/Dependency/Resolution.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE FlexibleContexts #-}++{- |+Module : $Header$+Description : Contains dependency resolution algorithms.+Author : Nils 'bash0r' Jonsson+Copyright : (c) 2015 Nils 'bash0r' Jonsson+License : MIT++Maintainer : aka.bash0r@gmail.com+Stability : unstable+Portability : non-portable (Portability is untested.)++This module contains all dependency resolution algorithms.+-}+module Logic.Dependency.Resolution+( resolve+) where++import Control.Applicative+import Control.Monad+import Control.Monad.State.Lazy++import Data.List+import Data.Model.Project+import Data.Model.Utility+++resolve :: [Project] -> Maybe [Project]+resolve =+ evalState resolver++resolver =+ findRootProjects >>= (resolveProjects . reverse)++findRootProjects :: State [Project] [Project]+findRootProjects = do+ xs <- get+ let (rootProjects,remaining) = findRootProjects' xs [] []+ put remaining+ return rootProjects+ where+ hasDependencies (Project _ _ []) =+ False+ hasDependencies (Project {} ) =+ True++ findRootProjects' [] rp rem =+ (reverse rp, reverse rem)+ findRootProjects' (x:xs) rp rem =+ if hasDependencies x+ then findRootProjects' xs rp (x:rem)+ else findRootProjects' xs (x:rp) rem++resolveProjects :: [Project] -> State [Project] (Maybe [Project])+resolveProjects rs =+ resolveProjects' rs >>= \res -> return (fmap reverse res)+ where+ resolveProjects' :: [Project] -> State [Project] (Maybe [Project])+ resolveProjects' rs = do+ xs <- get+ if null xs+ then (return . return) rs+ else do+ let (rs', xs') = traverse xs rs []+ put xs'+ if genericLength xs == genericLength xs'+ then return empty+ else resolveProjects' rs'++ traverse [] rs rem =+ (rs, rem)+ traverse (x@(Project name _ ds):xs) rs rem =+ if rs `hasDependencies` ds+ then traverse xs (x:rs) rem+ else traverse xs rs (x:rem)++ hasDependencies _ [] =+ True+ hasDependencies rs (d:ds) =+ d `isContainedIn` rs && rs `hasDependencies` ds++ isContainedIn d [] =+ False+ isContainedIn d (Project name _ _ :xs) =+ d == name || d `isContainedIn` xs+
+ src-test/Main.hs view
@@ -0,0 +1,28 @@+{- |+Module : $Header$+Description : Entrypoint of the application.+Author : Nils 'bash0r' Jonsson+Copyright : (c) 2015 Nils 'bash0r' Jonsson+License : MIT++Maintainer : aka.bash0r@gmail.com+Stability : unstable+Portability : non-portable (Portability is untested.)++The 'Main' module is the entrypoint of the application.+-}+module Main+( main+) where++import Test.HUnit+import Test.Framework+import Test.Framework.Providers.HUnit++import qualified Tests.Dependencies as TD++main :: IO ()+main = defaultMainWithOpts tests mempty++tests = [ TD.tests ]+
+ src/Main.hs view
@@ -0,0 +1,38 @@+{- |+Module : $Header$+Description : Entrypoint of the application.+Author : Nils 'bash0r' Jonsson+Copyright : (c) 2015 Nils 'bash0r' Jonsson+License : MIT++Maintainer : aka.bash0r@gmail.com+Stability : unstable+Portability : non-portable (Portability is untested.)++The 'Main' module is the entrypoint of the application.+-}+module Main+( main+) where++import Control.Applicative+import Control.Command+import Control.Monad+import Control.Router++import System.Environment++import MultiCabal.Instruction+import MultiCabal.Commands+++main :: IO ()+main = getArgs >>= invoke >> return ()+ where+ invoke [] =+ execute Help []+ invoke (cmd:args) =+ case route availableCommands cmd of+ Just a -> execute a args+ Nothing -> putStrLn ("Command " ++ cmd ++ " is not available.\n")+
+ src/MultiCabal/Commands.hs view
@@ -0,0 +1,42 @@+{- |+Module : $Header$+Description : A simple data type representing commands.+Author : Nils 'bash0r' Jonsson+Copyright : (c) 2015 Nils 'bash0r' Jonsson+License : MIT++Maintainer : aka.bash0r@gmail.com+Stability : unstable+Portability : non-portable (Portability is untested.)++A simple data type representing commands in the application.+-}+module MultiCabal.Commands+(+) where++import Control.Command+import Control.Router++import MultiCabal.Instruction++import qualified MultiCabal.Commands.Help as CH+import qualified MultiCabal.Commands.Install as CI+import qualified MultiCabal.Commands.Version as CV+++instance Command Instruction where+ execute Install xs = CI.invokeExec xs+ execute Version xs = CV.invokeExec xs+ execute Help xs = CH.invokeExec xs+ + help Install = CI.invokeHelp+ help Version = CV.invokeHelp+ help Help = CH.invokeHelp++instance Router Instruction where+ routes Help "help" = True+ routes Install "install" = True+ routes Version "version" = True+ routes _ _ = False+
+ src/MultiCabal/Commands/Help.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE FlexibleContexts #-}++{- |+Module : $Header$+Description : A simple help command.+Author : Nils 'bash0r' Jonsson+Copyright : (c) 2015 Nils 'bash0r' Jonsson+License : MIT++Maintainer : aka.bash0r@gmail.com+Stability : unstable+Portability : non-portable (Portability is untested.)++A simple help command.+-}+module MultiCabal.Commands.Help+( invokeExec+, invokeHelp+) where++import Control.Applicative+import Control.Monad++import Control.Command+import Control.Router++import MultiCabal.Instruction++invokeExec :: (Command Instruction, Router Instruction) => [String] -> IO ()+invokeExec [cmd] = case route availableCommands cmd of+ Just a -> putStrLn (help a)+ Nothing -> putStrLn ("The command " ++ cmd ++ " does not exist.")+invokeExec _ = mapM_ putStrLn (fmap help availableCommands) >> putStrLn ""++invokeHelp :: String+invokeHelp =+ "multi-cabal help\n" +++ " shows a general help dialog\n" +++ "multi-cabal help COMMAND\n" +++ " shows the specific help dialog of COMMAND"+
+ src/MultiCabal/Commands/Install.hs view
@@ -0,0 +1,69 @@+{- |+Module : $Header$+Description : A simple installation command.+Author : Nils 'bash0r' Jonsson+Copyright : (c) 2015 Nils 'bash0r' Jonsson+License : MIT++Maintainer : aka.bash0r@gmail.com+Stability : unstable+Portability : non-portable (Portability is untested.)++A simple installation command.+-}+module MultiCabal.Commands.Install+( invokeExec+, invokeHelp+) where++import Data.Aeson++import qualified Data.ByteString.Lazy as BS++import System.Directory+import System.FilePath.Posix+import System.IO hiding (hGetContents)+import System.IO.Strict (hGetContents)+import System.Process+++import Data.Model.Project+import Data.Model.Utility++import Logic.Dependency.Resolution+++invokeExec :: [String] -> IO ()+invokeExec [] = do+ cwd <- getCurrentDirectory+ let projectFile = cwd </> "project.json"+ exists <- doesFileExist projectFile+ if exists+ then do+ h <- openFile projectFile ReadMode+ c <- BS.hGetContents h+ let result = decode c >>= resolve+ case result of+ Just a -> do+ mapM_ installProject a+ return ()+ Nothing ->+ putStrLn "Your project.json is corrupt or contains circular dependencies."+ hClose h+ else do+ putStrLn "No project.json in the current working directory."+ putStrLn "Create a project.json and try again."+ where+ installProject (Project name dir _) = do+ putStrLn ("Installing project " ++ name ++ "...")+ cwd <- getCurrentDirectory+ (_, Just hout, _, _) <- createProcess_ "" (proc "cabal" ["install", cwd </> dir]){ std_out = CreatePipe }+ putStrLn =<< hGetContents hout+invokeExec _ =+ putStrLn invokeHelp++invokeHelp :: String+invokeHelp =+ "multi-cabal install\n" +++ " installs the multi cabal project"+
+ src/MultiCabal/Commands/Version.hs view
@@ -0,0 +1,32 @@+{- |+Module : $Header$+Description : A simple version output command.+Author : Nils 'bash0r' Jonsson+Copyright : (c) 2015 Nils 'bash0r' Jonsson+License : MIT++Maintainer : aka.bash0r@gmail.com+Stability : unstable+Portability : non-portable (Portability is untested.)++Prints the version to the standard output.+-}+module MultiCabal.Commands.Version+( invokeExec+, invokeHelp+) where++import Data.Version++import Paths_multi_cabal (version)+++invokeExec :: [String] -> IO ()+invokeExec [] = (putStrLn . showVersion) version+invokeExec _ = putStrLn invokeHelp++invokeHelp :: String+invokeHelp =+ "multi-cabal version\n" +++ " shows the version string of the application"+
+ src/MultiCabal/Instruction.hs view
@@ -0,0 +1,27 @@+{- |+Module : $Header$+Description : Basic instruction definitions.+Author : Nils 'bash0r' Jonsson+Copyright : (c) 2015 Nils 'bash0r' Jonsson+License : MIT++Maintainer : aka.bash0r@gmail.com+Stability : unstable+Portability : non-portable (Portability is untested.)++The basic definition of instructions exposed by this application.+-}+module MultiCabal.Instruction+( Instruction (..)+, availableCommands+) where++-- | A simple instruction collection+data Instruction+ = Help+ | Install+ | Version+ deriving (Show, Eq)++availableCommands = [Install, Version, Help]+