kit 0.3 → 0.4
raw patch · 7 files changed
+282/−96 lines, 7 filesdep ~cmdargs
Dependency ranges changed: cmdargs
Files
- Kit/Main.hs +63/−44
- Kit/Project.hs +37/−22
- Kit/XCode/OldPList.hs +42/−0
- Kit/XCode/PBXProject.hs +72/−0
- Kit/XCode/ProjectFile.hs +11/−12
- Main.hs +4/−2
- kit.cabal +53/−16
Kit/Main.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DeriveDataTypeable #-} module Kit.Main where import qualified Data.ByteString as BS @@ -10,25 +11,32 @@ import Kit.Project import Kit.Repository import Kit.Spec- import Kit.Util + import Kit.Util import Kit.XCode.Builder import qualified Data.Traversable as T import System.Cmd import System.Environment import Text.JSON+ import System.Console.CmdArgs+ import System.Console.CmdArgs as CA + import Data.Data+ import Data.Typeable++ appVersion = "0.3"+ defaultLocalRepoPath = do home <- getHomeDirectory return $ home </> ".kit" </> "repository" defaultLocalRepository = fmap fileRepo defaultLocalRepoPath- + handleFails (Left e) = do print e return () handleFails (Right _) = return ()- - update :: IO ()- update = unKitIO g >>= handleFails++ doUpdate :: IO ()+ doUpdate = unKitIO g >>= handleFails where g = do repo <- liftIO defaultLocalRepository deps <- getMyDeps repo@@ -39,22 +47,22 @@ puts "Kit complete. You may need to restart XCode for it to pick up any changes." where p x = liftIO $ print x puts x = liftIO $ putStrLn x- - packageKit :: IO ()- packageKit = do++ doPackageKit :: IO ()+ doPackageKit = do mySpec <- unKitIO myKitSpec T.for mySpec package return ()- - deployLocal :: IO ()- deployLocal = do++ doDeployLocal :: IO ()+ doDeployLocal = do mySpec <- unKitIO myKitSpec T.for mySpec package T.for mySpec x handleFails mySpec where x :: KitSpec -> IO ()- x spec = let + x spec = let k = specKit spec kf = kitFileName . specKit $ spec pkg = (kf ++ ".tar.gz")@@ -64,15 +72,15 @@ mkdir_p thisKitDir copyFile pkg $ thisKitDir </> pkg copyFile "KitSpec" $ thisKitDir </> "KitSpec"- - verify :: Maybe String -> IO ()- verify sdk = (unKitIO f >>= handleFails)++ doVerify :: String -> IO ()+ doVerify sdk = (unKitIO f >>= handleFails) where f = do mySpec <- myKitSpec puts "Checking that the kit can be depended upon..." puts " #> Deploying locally"- liftIO deployLocal+ liftIO doDeployLocal puts " #> Building temporary parent project" tmp <- liftIO getTemporaryDirectory liftIO $ inDirectory tmp $ do@@ -80,46 +88,57 @@ cleanOrCreate kitVerifyDir inDirectory kitVerifyDir $ do writeFile "KitSpec" $ encode (KitSpec (Kit "verify-kit" "1.0") $ defaultConfiguration{kitConfigDependencies=[specKit mySpec]})- update+ doUpdate inDirectory "Kits" $ do- system $ "xcodebuild -sdk " ++ (fromMaybe "iphonesimulator4.0" sdk)+ system $ "xcodebuild -sdk " ++ sdk putStrLn "OK." puts "End checks." puts = liftIO . putStrLn- - createSpec :: String -> String -> IO ()- createSpec name version = do++ doCreateSpec :: String -> String -> IO ()+ doCreateSpec name version = do let kit =(Kit name version) let spec = KitSpec kit defaultConfiguration writeFile "KitSpec" $ encode spec putStrLn $ "Created KitSpec for " ++ kitFileName kit return ()- - handleArgs :: [String] -> IO ()- handleArgs ["update"] = update- handleArgs ["package"] = packageKit- handleArgs ["publish-local"] = deployLocal- handleArgs ["verify"] = verify Nothing- handleArgs ["verify", sdk] = verify $ Just sdk- handleArgs ["create-spec", name, version] = createSpec name version- - handleArgs _ = putStrLn f where- f = "Usage: kit command [arguments]" `nl`- "Commands:" `nl`- "\tupdate\t\t\t\tCreate an Xcode project to wrap the dependencies defined in ./KitSpec" `nl`- "\tcreate-spec NAME VERSION\tWrite out a KitSpec file using the given name and version." `nl`- "\tpackage\t\t\t\tCreate a tar.gz wrapping this kit" `nl`- "\tverify [SDK]\t\t\tPackage this kit, then attempt to use it as a dependency in an empty project." `nl`- "\tpublish-local\t\t\tPackage this kit, then deploy it to the local repository (~/.kit/repository)" - nl a b = a ++ "\n" ++ b- ++ data KitCmdArgs = Update+ | Package+ | PublishLocal+ | Verify { sdk :: String }+ | CreateSpec { name :: String, version :: String } deriving (Show, Data, Typeable)++ parseArgs = cmdArgs $ modes [+ Update &= help "Create an Xcode project to wrap the dependencies defined in `KitSpec`"+ &= auto -- The default mode to run. This is most common usage.+ , (CreateSpec { Kit.Main.name = (def &= typ "NAME") &= argPos 0, version = (def &= typ "VERSION") &= argPos 1 }) &=+ explicit &=+ CA.name "create-spec" &=+ help "Write out a KitSpec file using the given name and version."+ , Package &=+ help "Create a tar.gz wrapping this kit"+ , PublishLocal &= explicit &= CA.name "publish-local" &=+ help "Package this kit, then deploy it to the local repository (~/.kit/repository)"+ , Verify { sdk = "iphonesimulator4.0" &= typ "SDK" &= help "iphoneos3.1, iphonesimulator4.0, etc."} &=+ help "Package this kit, then attempt to use it as a dependency in an empty project. This will assert that the kit and all its dependencies can be compiled together."+ ] &= program "kit"+ &= summary ("Kit v" ++ appVersion ++ ". It's a dependency manager for Objective-C projects built with XCode.")++ handleArgs :: KitCmdArgs -> IO ()+ handleArgs Update = doUpdate+ handleArgs Package = doPackageKit+ handleArgs PublishLocal = doDeployLocal+ handleArgs (Verify sdk) = doVerify sdk+ handleArgs (CreateSpec name version) = doCreateSpec name version+ kitMain :: IO () kitMain = do localRepo <- defaultLocalRepository path <- defaultLocalRepoPath mkdir_p path- args <- getArgs- handleArgs args+ handleArgs =<< parseArgs -- =<< getArgs - - +++
Kit/Project.hs view
@@ -1,17 +1,17 @@ module Kit.Project (- getDeps, getMyDeps, installKit, generateXCodeProject, myKitSpec) where- + import Control.Monad.Trans import Control.Monad import Control.Applicative- import Data.Foldable+ import qualified Data.Foldable as F import Data.Maybe import Data.List+ import Data.Tree import Data.Monoid import System.Cmd import Kit.Kit@@ -23,22 +23,22 @@ import Text.JSON import Kit.JSON import qualified Data.Traversable as T- + -- Paths kitDir = "." </> "Kits" projectDir = "KitDeps.xcodeproj" prefixFile = "KitDeps_Prefix.pch" projectFile = projectDir </> "project.pbxproj" xcodeConfigFile = "Kit.xcconfig"- + prefixDefault = "#ifdef __OBJC__\n" ++ " #import <Foundation/Foundation.h>\n #import <UIKit/UIKit.h>\n" ++ "#endif\n"- + -- Represents an extracted project -- Headers, Sources, Config, Prefix content data KitContents = KitContents { contentHeaders :: [String], contentSources :: [String], contentConfig :: Maybe XCConfig, contentPrefix :: Maybe String }- + readKitContents :: Kit -> IO KitContents- readKitContents kit = + readKitContents kit = let kitDir = kitFileName kit find tpe = glob ((kitDir </> "src/**/*") ++ tpe) headers = find ".h"@@ -46,7 +46,7 @@ config = readConfig kit prefix = readHeader kit in KitContents <$> headers <*> sources <*> config <*> prefix- + generateXCodeProject :: [Kit] -> IO () generateXCodeProject deps = do mkdir_p kitDir@@ -64,13 +64,13 @@ createHeader cs = do let headers = catMaybes $ cs |> contentPrefix let combinedHeader = stringJoin "\n" headers- writeFile prefixFile $ prefixDefault ++ combinedHeader ++ "\n" + writeFile prefixFile $ prefixDefault ++ combinedHeader ++ "\n" createConfig cs = do let configs = catMaybes $ cs |> contentConfig let combinedConfig = multiConfig "KitConfig" configs let kitHeaders = "HEADER_SEARCH_PATHS = $(HEADER_SEARCH_PATHS) " ++ (stringJoin " " $ kitFileNames >>= (\x -> [kitDir </> x </> "src", x </> "src"])) ++ "\n" ++ "GCC_PRECOMPILE_PREFIX_HEADER = YES\nGCC_PREFIX_HEADER = $(SRCROOT)/KitDeps_Prefix.pch\n" writeFile xcodeConfigFile $ kitHeaders ++ "\n" ++ configToString combinedConfig- + kitPrefixFile = "Prefix.pch" readHeader :: Kit -> IO (Maybe String)@@ -79,24 +79,39 @@ exists <- doesFileExist fp contents <- T.sequence (fmap readFile $ justTrue exists fp) return contents- + readConfig :: Kit -> IO (Maybe XCConfig) readConfig kit = do let fp = kitConfigFile kit exists <- doesFileExist fp contents <- T.sequence (fmap readFile $ justTrue exists fp) return $ fmap (fileContentsToXCC $ kitName kit) contents- + depsForSpec :: KitRepository -> KitSpec -> KitIO [Kit] depsForSpec kr spec = do deps <- mapM (getDeps kr) (specDependencies spec) return . nub . sort $ specDependencies spec ++ join deps -- TODO Check for conflicting versions- - getDeps :: KitRepository -> Kit -> KitIO [Kit]- getDeps kr kit = getKitSpec kr kit >>= depsForSpec kr+ where getDeps kr kit = getKitSpec kr kit >>= depsForSpec kr ++ refineDeps :: Tree Kit -> [Kit]+ refineDeps = nub . concat . reverse . drop 1 . levels++ depsForSpec' :: KitRepository -> KitSpec -> KitIO [Kit]+ depsForSpec' kr spec = do+ tree <- unfoldTreeM (unfoldDeps kr) spec+ -- todo: check for dups, check for conflicts+ return $ refineDeps tree++ unfoldDeps :: KitRepository -> KitSpec -> KitIO (Kit, [KitSpec])+ unfoldDeps kr ks = do+ let kit = specKit ks+ let depKits = specDependencies ks+ specs <- mapM (getKitSpec kr) depKits+ return (kit, specs)+ getMyDeps :: KitRepository -> KitIO [Kit]- getMyDeps kr = myKitSpec >>= depsForSpec kr+ getMyDeps kr = myKitSpec >>= depsForSpec' kr installKit :: KitRepository -> Kit -> IO () installKit kr kit = do@@ -112,7 +127,7 @@ readSpec :: FilePath -> KitIO KitSpec readSpec kitSpecPath = readSpecContents kitSpecPath >>= KitIO . return . parses- + myKitSpec :: KitIO KitSpec myKitSpec = readSpec "KitSpec" @@ -121,12 +136,12 @@ checkExists kitSpecPath = do doesExist <- liftIO $ doesFileExist kitSpecPath maybeToKitIO ("Couldn't find the spec at " ++ kitSpecPath) (justTrue doesExist kitSpecPath)- + readSpecContents :: FilePath -> KitIO String readSpecContents kitSpecPath = checkExists kitSpecPath >>= liftIO . readFile- + parses :: String -> Either [KitError] KitSpec- parses contents = case (decode contents) of + parses contents = case (decode contents) of Ok a -> Right a Error a -> Left [a]- +
+ Kit/XCode/OldPList.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE TypeSynonymInstances #-}+module Kit.XCode.OldPList where++import Data.List++class AsPListType a where+ asPListType :: a -> PListType++instance AsPListType PListType where+ asPListType = id++data PListType = PListValue String+ | PListArray [PListType]+ | PListObject [(String, PListType)]++val = PListValue+arr = PListArray+obj = PListObject++data PListFile = PListFile { pListFileCharset :: String, pListFileValue :: PListType }++quote s = "\"" ++ s ++ "\""+quotable s = or $ map (\x -> x `isInfixOf` s) ["-", "<", ">", " "]+++instance Show PListType where++ show (PListValue a) = if (quotable a) then quote a else a+ show (PListArray xs) = "(" ++ (map ((++ ",") . show) xs >>= id) ++ ")"+ show (PListObject kvs) = "{" ++ (kvs >>= f) ++ "}"+ where f (k, v) = k ++ " = " ++ show v ++ ";"++(~=~) = (,)+++projectFile = PListFile "!$*UTF8*$!" $ PListObject [+ "archiveVersion" ~=~ PListValue "1",+ "classes" ~=~ PListObject [],+ "objectVersion" ~=~ PListValue "45",+ "objects" ~=~ PListObject []+ ]+
+ Kit/XCode/PBXProject.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+module Kit.XCode.PBXProject where++import Kit.XCode.OldPList+import Control.Monad.State+import Control.Monad.Writer++type UUID = String++data PBXProject = PBXProject {+ projectConfigurationList :: XCConfigurationList+ , projectGroups :: [PBXGroup]+ , projectName :: String+}++data XCConfigurationList = XCConfigurationList {+ configurationsList :: [XCBuildConfiguration]+}++data PBXGroup = PBXGroup {+ groupChildren :: [PBXGroup]+ , groupChildrenExtra :: [UUID]+ , groupName :: String+ , groupSourceTree :: String+}++data XCBuildConfiguration = XCBuildConfiguration++instance ProjectPListItem PBXGroup where+ writeEntry group = do+ childUUIDs <- mapM writeEntry (groupChildren group)+ write $ obj [+ "isa" ~=~ val "PBXGroup"+ , "name" ~=~ (val . groupName) group+ , "sourceTree" ~=~ (val . groupSourceTree) group+ , "children" ~=~ (arr $ map val (childUUIDs ++ groupChildrenExtra group))+ ]++type PLObjects = [(UUID, PListType)]+-- Consume UUIDs from state, write out other objects to be added to the plist+newtype PL a = PL { unPL :: WriterT PLObjects (State [UUID]) a }+ deriving (Monad, MonadState [UUID], MonadWriter PLObjects)++class ProjectPListItem a where+ writeEntry :: a -> PL UUID++popS = do+ (x:xs) <- get+ put xs+ return x++write blah = do+ uuid <- popS+ tell [(uuid, blah)]+ return uuid++instance ProjectPListItem PBXProject where+ writeEntry project = do+ config <- write $ val "TODO"+ productGroupUUID <- writeEntry (PBXGroup [] [] "Products" "<group>")+ mainGroupUUID <- writeEntry (PBXGroup [] [productGroupUUID] (projectName project) "<group>")+ write $ obj [+ "isa" ~=~ val "PBXProject"+ , "buildConfigurationList" ~=~ val config+ , "compatibilityVersion" ~=~ val "Xcode 3.1"+ , "hasScannedForEncodings" ~=~ val "1"+ , "mainGroup" ~=~ val mainGroupUUID+ , "productRefGroup" ~=~ val productGroupUUID+ , "projectDirPath" ~=~ val ""+ , "projectRoot" ~=~ val ""+ , "targets" ~=~ arr []+ ]
Kit/XCode/ProjectFile.hs view
@@ -3,20 +3,19 @@ Constant sections of the project file -} module Kit.XCode.ProjectFile (projectPbxProj) where- - nl a b = a ++ "\n" ++ b - - projectPbxProj bfs fileRefsSection classes headers sources = + nl a b = a ++ "\n" ++ b++ projectPbxProj bfs fileRefsSection classes headers sources = top `nl` bfs `nl` fileRefsSection `nl` next1 `nl` classes `nl` next2 `nl` headers `nl` next3 `nl` sources `nl` bottom- - top = "// !$*UTF8*$!" `nl` ++ top = "// !$*UTF8*$!" `nl` "{" `nl` " archiveVersion = 1;" `nl` " classes = {" `nl` " };" `nl` " objectVersion = 45;" `nl` " objects = {"- + next1 = "/* Begin PBXFrameworksBuildPhase section */" `nl` "D2AAC07C0554694100DB518D /* Frameworks */ = {" `nl` "isa = PBXFrameworksBuildPhase;" `nl`@@ -67,7 +66,7 @@ "sourceTree = \"<group>\";" `nl` "};" `nl` "/* End PBXGroup section */"- + next3 = "/* Begin PBXNativeTarget section */" `nl` "D2AAC07D0554694100DB518D /* KitDeps */ = {" `nl` "isa = PBXNativeTarget;" `nl`@@ -103,7 +102,7 @@ ");" `nl` "};" `nl` "/* End PBXProject section */"- + bottom = "/* Begin XCBuildConfiguration section */" `nl` "1DEB921F08733DC00010E9CD /* Debug */ = {" `nl` "isa = XCBuildConfiguration;" `nl`@@ -191,8 +190,8 @@ "};" `nl` "rootObject = 0867D690FE84028FC02AAC07 /* Project object */;" `nl` "}"- - ++ main = do putStrLn $ projectPbxProj "" "" "" "" ""- +
Main.hs view
@@ -2,9 +2,11 @@ import Kit.Main import qualified Data.Map as M import Kit.XCode.XCConfig- + import Kit.XCode.OldPList+ import Kit.XCode.PBXProject+ conf1 = XCC "conf1" (M.fromList [("A", "1")]) [] conf2 = XCC "conf2" (M.fromList [("A", "2")]) []- + --main = putStrLn $ show $ multiConfig "combo" [conf1, conf2] main = kitMain
kit.cabal view
@@ -1,16 +1,53 @@-Name: kit-Version: 0.3-Synopsis: A dependency manager for XCode (Objective-C) projects-Description: A dependency manager for XCode (Objective-C) projects-Category: Development-License: BSD3-License-file: LICENSE-Author: Nick Partridge-Maintainer: nkpart@gmail.com-Build-Type: Simple-Cabal-Version: >=1.2-Executable kit- Main-is: Main.hs- Other-Modules: Kit.JSON, Kit.Kit, Kit.Main, Kit.Package, Kit.Project, Kit.Repository, Kit.Spec, Kit.Util, Kit.XCode.Builder, Kit.XCode.Common, Kit.XCode.ProjectFile, Kit.XCode.XCConfig- Build-Depends: base >= 3 && < 5, HTTP >= 4000.0.9, network, bytestring, filepath, directory, process, json, mtl, cmdargs, MissingH, containers, QuickCheck- +name: kit+version: 0.4+cabal-version: >=1.2+build-type: Simple+license: BSD3+license-file: LICENSE+copyright:+maintainer: nkpart@gmail.com+build-depends: HTTP >=4000.0.9, MissingH -any, QuickCheck -any,+ base >=3 && <5, bytestring -any, cmdargs >=0.3, containers -any,+ directory -any, filepath -any, json -any, mtl -any, network -any,+ process -any+stability:+homepage:+package-url:+bug-reports:+synopsis: A dependency manager for XCode (Objective-C) projects+description: A dependency manager for XCode (Objective-C) projects+category: Development+author: Nick Partridge+tested-with:+data-files:+data-dir: ""+extra-source-files:+extra-tmp-files:+ +executable: kit+main-is: Main.hs+buildable: True+build-tools:+cpp-options:+cc-options:+ld-options:+pkgconfig-depends:+frameworks:+c-sources:+extensions:+extra-libraries:+extra-lib-dirs:+includes:+install-includes:+include-dirs:+hs-source-dirs: .+other-modules: Kit.JSON Kit.Kit Kit.Main Kit.Package Kit.Project+ Kit.Repository Kit.Spec Kit.Util Kit.XCode.Builder Kit.XCode.Common+ Kit.XCode.OldPList Kit.XCode.PBXProject Kit.XCode.ProjectFile+ Kit.XCode.XCConfig+ghc-prof-options:+ghc-shared-options:+ghc-options:+hugs-options:+nhc98-options:+jhc-options: