epub-tools 2.8 → 2.9
raw patch · 9 files changed
+406/−32 lines, 9 files
Files
- LICENSE +1/−1
- README.md +19/−13
- changelog.md +9/−0
- epub-tools.cabal +31/−6
- src/EpubTools/epubname.hs +1/−1
- stack.yaml +4/−0
- util/install.hs +329/−0
- util/prefs/boring +6/−5
- util/win-dist.sh +6/−6
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2008-2015 Dino Morelli+Copyright (c) 2008-2016 Dino Morelli All rights reserved. Redistribution and use in source and binary forms, with or without
README.md view
@@ -67,26 +67,32 @@ epubzip is a handy utility for zipping up the files that comprise an epub into an .epub zip file. Using the same technology as epubname, it can try to make a meaningful filename for the book. -## Getting source+## Getting this software -- Download the cabalized source package [from Hackage](http://hackage.haskell.org/package/epub-tools)+Binaries+ - epub-tools is available for Arch Linux [from the AUR](http://aur.archlinux.org/packages/epub-tools/)-- Download [binaries for Windows](http://ui3.info/d/proj/epub-tools/epub-tools-2.7-win.zip)-- Get the source with darcs: `$ darcs get http://hub.darcs.net/dino/epub-tools`-- If you're just looking, [browse the source](http://hub.darcs.net/dino/epub-tools)+- Download [binaries for Windows](http://ui3.info/d/proj/epub-tools/epub-tools-2.9-win.zip) -And once you have it, building the usual way: - $ cabal configure --enable-tests- $ cabal build- $ cabal test- $ cabal install+Building and installing from source with cabal-install: + $ cabal update ; cabal install epub-tools -## Installing -Build and install with cabal-install:- `$ cabal update ; cabal install epub-tools`+Getting source for development++- Download the cabalized source package [from Hackage](http://hackage.haskell.org/package/epub-tools)+- Get the source with darcs: `$ darcs clone http://hub.darcs.net/dino/epub-tools`+- Get the source with stack: `$ stack unpack epub-tools`+- If you're just looking, [browse the source](http://hub.darcs.net/dino/epub-tools)+++Once you have source, building the usual way:++ $ stack build+ $ stack test+ $ stack haddock ## Contact
changelog.md view
@@ -1,3 +1,12 @@+2.9 (2016-10-19)++ * Switched build to stack+ * Added hsinstall installation script and updated windows dist script+ * Various cabal file updates+ * Moved copyright date up to 2016+ * Updated README with better instructions for getting this software++ 2.8 (2015-09-18) * Fixed some magazine and anthology naming rules
epub-tools.cabal view
@@ -1,28 +1,29 @@ name: epub-tools-cabal-version: >= 1.8-version: 2.8+cabal-version: >= 1.10+version: 2.9 build-type: Simple license: BSD3 license-file: LICENSE-copyright: 2008-2015 Dino Morelli+copyright: 2008-2016 Dino Morelli author: Dino Morelli maintainer: Dino Morelli <dino@ui3.info>-stability: stable homepage: http://hub.darcs.net/dino/epub-tools synopsis: Command line utilities for working with epub files description: A suite of command-line utilities for creating and manipulating epub book files. Included are: epubmeta, epubname, epubzip category: Application, Console-tested-with: GHC >= 7.10.1+tested-with: GHC >= 8.0.1 extra-source-files: changelog.md doc/dev/notes.md doc/hcar/epubtoolsCommandlineepubU-De.tex doc/INSTALL README.md+ stack.yaml testsuite/EpubTools/*.hs testsuite/EpubTools/Test/EpubName/*.hs TODO.md util/all-books.hs+ util/install.hs util/prefs/boring util/win-dist.sh @@ -43,6 +44,7 @@ EpubTools.EpubMeta.Opts EpubTools.EpubMeta.Util ghc-options: -Wall -rtsopts -with-rtsopts=-K32m+ default-language: Haskell2010 executable epubname main-is: EpubTools/epubname.hs@@ -61,6 +63,7 @@ EpubTools.EpubName.Prompt EpubTools.EpubName.Util ghc-options: -Wall -rtsopts -with-rtsopts=-K32m+ default-language: Haskell2010 test-suite epubname-tests type: exitcode-stdio-1.0@@ -68,12 +71,34 @@ build-depends: base, directory, epub-metadata >= 4.0, filepath, HUnit, mtl, parsec, regex-compat hs-source-dirs: src testsuite+ other-modules: EpubTools.EpubName.Doc.Rules+ EpubTools.EpubName.Format.Author+ EpubTools.EpubName.Format.Compile+ EpubTools.EpubName.Format.Format+ EpubTools.EpubName.Format.PubYear+ EpubTools.EpubName.Format.Util+ EpubTools.EpubName.Main+ EpubTools.EpubName.Opts+ EpubTools.EpubName.Util+ EpubTools.Test.EpubName.Format+ EpubTools.Test.EpubName.PubYear ghc-options: -Wall -rtsopts -with-rtsopts=-K32m+ default-language: Haskell2010 executable epubzip main-is: EpubTools/epubzip.hs build-depends: base >= 3 && < 5, directory, epub-metadata >= 4.0, filepath, mtl, parsec, regex-compat hs-source-dirs: src- other-modules: EpubTools.EpubZip.Opts+ other-modules: EpubTools.EpubName.Doc.Rules+ EpubTools.EpubName.Format.Author+ EpubTools.EpubName.Format.Compile+ EpubTools.EpubName.Format.Format+ EpubTools.EpubName.Format.PubYear+ EpubTools.EpubName.Format.Util+ EpubTools.EpubName.Main+ EpubTools.EpubName.Opts+ EpubTools.EpubName.Util+ EpubTools.EpubZip.Opts ghc-options: -Wall+ default-language: Haskell2010
src/EpubTools/epubname.hs view
@@ -45,7 +45,7 @@ {- Format and display output for a book that was processed -}-displayResults :: (MonadError String m, MonadIO m) => Options+displayResults :: MonadIO m => Options -> FilePath -> FilePath -> String -> Package -> Metadata -> m () displayResults opts oldPath newPath fmtUsed pkg md = liftIO $ printf "%s -> %s%s\n" oldPath newPath
+ stack.yaml view
@@ -0,0 +1,4 @@+resolver: nightly-2016-10-18++packages:+- .
+ util/install.hs view
@@ -0,0 +1,329 @@+#! /usr/bin/env stack+{- stack runghc -}++{-# LANGUAGE ScopedTypeVariables #-}++import Control.Exception+import Control.Monad+import Data.List+import Data.Version+import Distribution.Package+import Distribution.PackageDescription hiding ( error, options )+import Distribution.PackageDescription.Parse+import Distribution.Verbosity+import Distribution.Version+import System.Console.GetOpt+import System.Directory+import System.Environment+import System.Exit+import System.FilePath+import System.Process+import Text.Printf+import Text.Read+++defaultOptions :: Options+defaultOptions = Options+ { optClean = False+ , optDelete = False+ , optHelp = False+ , optLink = False+ , optPrefix = "/opt"+ , optRsrcCpVerbose = True+ , optInstType = FHS+ , optVersion = True+ }++data InstallType = Bundle | FHS deriving Eq+++main :: IO ()+main = do+ -- Parse args+ (opts, _) <- parseOpts =<< getArgs++ -- User asked for help+ when (optHelp opts) $ putStrLn usageText >> exitSuccess++ -- Locate cabal file+ cabalFiles <- (filter $ isSuffixOf ".cabal") <$> getDirectoryContents "."++ when (null cabalFiles) $ do+ die "Can't continue because no cabal files were found in ."++ -- Parse the cabal file and extract things we need from it+ -- then pass a pile of what we know to a function to create the+ -- installation dirs+ dirs <- constructDirs opts . package . packageDescription+ <$> readPackageDescription normal (head cabalFiles)+++ -- Perform the installation++ -- Remove existing install directory+ appDirExists <- doesDirectoryExist $ appDir dirs+ when (optDelete opts && appDirExists) $ do+ putStrLn $ "Removing existing directory " ++ (appDir dirs)+ removeDirectoryRecursive $ appDir dirs++ -- Clean before building+ when (optClean opts) $ system "stack clean" >> return ()++ -- Copy the binaries+ createDirectoryIfMissing True $ binDir dirs+ installExitCode <- system $ "stack install --local-bin-path=" ++ (binDir dirs)+ unless (ok installExitCode) $ die "Can't continue because stack install failed"++ -- Copy additional scripts+ {-+ putStrLn "Copying additional scripts"+ mapM_ (\f -> copyFile ("util" </> f) (binDir dirs </> f))+ [ "script1.sh", "script2.hs" ]+ -}++ -- Copy the license+ putStrLn "\nCopying LICENSE"+ createDirectoryIfMissing True $ docDir dirs+ copyFile "LICENSE" (docDir dirs </> "LICENSE")++ -- Copy the resources+ let rsrcDirSrc = "." </> "resources"+ rsrcsExist <- doesDirectoryExist rsrcDirSrc+ when rsrcsExist $ do+ putStrLn $ "\nCopying resources"+ copyTree (optRsrcCpVerbose opts) rsrcDirSrc (rsrcDir dirs)+ return ()++ -- Make the symlink+ when (optLink opts) $ do+ if (optInstType opts == FHS) then+ putStrLn "No link will be made because installation type is fhs"+ else if (not . optVersion $ opts) then+ putStrLn "No link will be made because the app dir already has no version part"+ else do+ printf "Making symbolic link now %s -> %s\n" (linkPath dirs) (appDir dirs)+ system $ printf "rm %s" (linkPath dirs)+ system $ printf "ln -s %s %s" (appDir dirs) (linkPath dirs)+ return ()++ exitSuccess+++data Dirs = Dirs+ { appDir :: FilePath+ , linkPath :: FilePath+ , binDir :: FilePath+ , docDir :: FilePath+ , rsrcDir :: FilePath+ }+++constructDirs :: Options -> PackageId -> Dirs+constructDirs opts pkgId =+ Dirs appDir' linkPath' binDir' (appDir' </> "doc") (appDir' </> "resources")++ where+ project = unPackageName . pkgName $ pkgId+ version = showVersion . pkgVersion $ pkgId+ versionPart = if optVersion opts then "-" ++ version else ""+ appDir' = case (optInstType opts) of+ Bundle -> optPrefix opts </> (project ++ versionPart)+ FHS -> optPrefix opts </> "share" </> (project ++ versionPart)+ linkPath' = optPrefix opts </> project+ binDir' = case (optInstType opts) of+ Bundle -> appDir' </> "bin"+ FHS -> optPrefix opts </> "bin"+++{- Turn an exit code (say, from system) into a Bool+-}+ok :: ExitCode -> Bool+ok ExitSuccess = True+ok _ = False+++{-+ Argument parsing code+-}++data Options = Options+ { optClean :: Bool+ , optDelete :: Bool+ , optHelp :: Bool+ , optLink :: Bool+ , optPrefix :: FilePath+ , optRsrcCpVerbose :: Bool+ , optInstType :: InstallType+ , optVersion :: Bool+ }+++instance Read InstallType where+ readsPrec _ "bundle" = [(Bundle, "")]+ readsPrec _ "fhs" = [(FHS, "")]+ readsPrec _ _ = []++instance Show InstallType where+ show Bundle = "bundle"+ show FHS = "fhs"+++readInstallType :: String -> InstallType+readInstallType s =+ case (readEither s) of+ Left _ -> error $ printf "Can't continue because %s is not a valid install type\n\n%s" s usageText+ Right t -> t+++options :: [OptDescr (Options -> Options)]+options =+ [ Option ['c'] ["clean"]+ (NoArg (\opts -> opts { optClean = True } ))+ ("Do 'stack clean' first." ++ (defaultText . optClean $ defaultOptions))+ , Option ['C'] ["no-clean"]+ (NoArg (\opts -> opts { optClean = False } ))+ ("Do not 'stack clean' first."+ ++ (defaultText . not . optClean $ defaultOptions))+ , Option ['d'] ["delete"]+ (NoArg (\opts -> opts { optDelete = True } ))+ ("Delete the app directory before copying files."+ ++ (defaultText . optDelete $ defaultOptions))+ , Option ['D'] ["no-delete"]+ (NoArg (\opts -> opts { optDelete = False } ))+ ("Do not delete the app directory before copying files."+ ++ (defaultText . not . optDelete $ defaultOptions))+ , Option ['h'] ["help"]+ (NoArg (\opts -> opts { optHelp = True } ))+ "This help information."+ , Option ['l'] ["link"]+ (NoArg (\opts -> opts { optLink = True } ))+ ("Create symlink PROJECT -> PROJECT-VERSION in PREFIX dir. Only useful for bundle installations. Does not work on Windows."+ ++ (defaultText . optLink $ defaultOptions))+ , Option ['L'] ["no-link"]+ (NoArg (\opts -> opts { optLink = True } ))+ ("Do not create symlink PROJECT -> PROJECT-VERSION in PREFIX dir."+ ++ (defaultText . not . optLink $ defaultOptions))+ , Option ['p'] ["prefix"]+ (ReqArg (\s opts -> opts { optPrefix = s } ) "PREFIX" )+ (printf "Install prefix directory. Defaults to %s so what you'll end up with is %s/PROJECT-VERSION"+ (optPrefix defaultOptions) (optPrefix defaultOptions))+ , Option ['r'] ["resource-copy-verbose"]+ (NoArg (\opts -> opts { optRsrcCpVerbose = True } ))+ ("Be chatty when copying the resources directory."+ ++ (defaultText . optRsrcCpVerbose $ defaultOptions))+ , Option ['R'] ["no-resource-copy-verbose"]+ (NoArg (\opts -> opts { optRsrcCpVerbose = False } ))+ ("Don't be chatty when copying the resources directory. Useful when there are a LOT of resources."+ ++ (defaultText . not . optRsrcCpVerbose $ defaultOptions))+ , Option ['t'] ["type"]+ (ReqArg (\s opts -> opts { optInstType = readInstallType s } ) "INST_TYPE" )+ (printf "Installation type, see INSTALLATION TYPE below for details. Default: %s"+ (show . optInstType $ defaultOptions))+ , Option ['v'] ["version"]+ (NoArg (\opts -> opts { optVersion = True } ))+ (printf "Include version in installation path, meaning: %s/PROJECT-VERSION %s"+ (optPrefix defaultOptions) (defaultText . optVersion $ defaultOptions))+ , Option ['V'] ["no-version"]+ (NoArg (\opts -> opts { optVersion = False } ))+ (printf "Do not include version in installation path, meaning: %s/PROJECT %s"+ (optPrefix defaultOptions) (defaultText . not . optVersion $ defaultOptions))+ ]+++defaultText :: Bool -> String+defaultText True = " Default"+defaultText False = ""+++parseOpts :: [String] -> IO (Options, [String])+parseOpts args =+ case getOpt Permute options args of+ (o,n,[] ) -> return (foldl (flip id) defaultOptions o, n)+ (_,_,errs) -> ioError $ userError (concat errs ++ usageText)+++usageText :: String+usageText = (usageInfo header options) ++ "\n" ++ footer+ where+ header = init $ unlines+ [ "Usage: install.hs [OPTIONS]"+ , ""+ , "options:"+ ]+ footer = init $ unlines+ [ "INSTALLATION TYPE"+ , ""+ , "This is the topology used when copying files, one of: bundle, fhs"+ , ""+ , "bundle is sort-of a self-contained structure like this:"+ , ""+ , " $PREFIX/"+ , " $PROJECT -> $PROJECT-$VERSION <-- if --link was specified"+ , " $PROJECT-$VERSION/ <-- this is the \"app directory\""+ , " bin/..."+ , " doc/LICENSE"+ , " resources/..."+ , ""+ , "fhs is the more traditional UNIX structure like this:"+ , ""+ , " $PREFIX/"+ , " bin/..."+ , " share/"+ , " $PROJECT-$VERSION/ <-- this is the \"app directory\""+ , " doc/LICENSE"+ , " resources/..."+ , ""+ , "Be aware that when the --delete switch is used along with fhs type, the binaries WILL NOT be deleted, only the \"app directory\"."+ , ""+ , "COMPILING"+ , ""+ , "install.hs was intentionally left as a script, but if you would prefer to compile it, do this:"+ , ""+ , " $ stack ghc -- -o util/install util/install.hs"+ , ""+ , ""+ , "This script is part of the hsinstall package by Dino Morelli <dino@ui3.info>"+ ]+++{-+ Recursive file copying code++ It was desireable to have a standalone recursive file copy in+ this script for maximum cross-platform compatibility and to+ avoid Haskell library dependencies.++ Many thanks to [abuzittin gillifirca](https://codereview.stackexchange.com/users/20251/abuzittin-gillifirca) for the StackOverflow post [Copying files in Haskell](https://codereview.stackexchange.com/questions/68908/copying-files-in-haskell) where the following code was lifted.+-}++copyTree :: Bool -> FilePath -> FilePath -> IO ()+copyTree chatty s t = do+ createDirectoryIfMissing True t+ subItems <- getSubitems s+ mapM_ (copyItem chatty s t) subItems+++getSubitems :: FilePath -> IO [(Bool, FilePath)]+getSubitems path = getSubitems' ""+ where+ getChildren path = (\\ [".", ".."]) <$> getDirectoryContents path++ getSubitems' relPath = do+ let absPath = path </> relPath+ isDir <- doesDirectoryExist absPath+ children <- if isDir then getChildren absPath else return []+ let relChildren = [relPath </> p | p <- children]+ ((isDir, relPath) :) . concat <$> mapM getSubitems' relChildren+++copyItem :: Bool -> FilePath -> FilePath -> (Bool, FilePath) -> IO ()+copyItem chatty baseSourcePath baseTargetPath (isDir, relativePath) = do+ let sourcePath = baseSourcePath </> relativePath+ let targetPath = baseTargetPath </> relativePath++ when chatty $+ putStrLn $ "Copying " ++ sourcePath ++ " to " ++ targetPath++ if isDir+ then createDirectoryIfMissing False targetPath+ else copyFile sourcePath targetPath
util/prefs/boring view
@@ -1,7 +1,7 @@ # This file contains a list of extended regular expressions, one per # line. A file path matching any of these expressions will be filtered # out during `darcs add', or when the `--look-for-adds' flag is passed-# to `darcs whatsnew' and `record'. The entries in ~/.darcs/boring (if+# to `darcs whatsnew' and `record'. The entries in ~/.darcs/boring (if # it exists) supplement those in this file. # # Blank lines, and lines beginning with an octothorpe (#) are ignored.@@ -45,11 +45,8 @@ # cabal intermediates \.installed-pkg-config \.setup-config-# cabal sandbox-^\.cabal-sandbox(/|$)-cabal\.sandbox\.config # standard cabal build dir, might not be boring for everybody-^dist(/|$)+# ^dist(/|$) # autotools (^|/)autom4te\.cache($|/) (^|/)config\.(log|status)$@@ -121,3 +118,7 @@ (^|/)\.lock-wscript$ # mac os finder (^|/)\.DS_Store$+# emacs saved sessions (desktops)+(^|.*/)\.emacs\.desktop(\.lock)?$++(^|/).stack-work($|/)
util/win-dist.sh view
@@ -2,14 +2,14 @@ version=$(awk '/^[Vv]ersion/ { print $2 }' epub-tools.cabal) -buildDir="dist/build"--binaries="$buildDir/epubmeta/epubmeta.exe $buildDir/epubname/epubname.exe $buildDir/epubzip/epubzip.exe"+buildDir="dist" -strip $binaries+./util/install.hs -p $buildDir -t bundle -zipFile="dist/epub-tools-$version-win.zip"+zipFile="epub-tools-$version-win.zip" rm $zipFile -zip -j $zipFile doc/INSTALL $binaries+cd $buildDir++zip -r ../$zipFile *