| 1 |
1121cc70 |
John |
{-
|
| 2 |
1121cc70 |
John |
Copyright (C) 2006-2008 John Goerzen <jgoerzen@complete.org>
|
| 3 |
1121cc70 |
John |
|
| 4 |
1121cc70 |
John |
This program is distributed in the hope that it will be useful, but
|
| 5 |
1121cc70 |
John |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 6 |
1121cc70 |
John |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 7 |
1121cc70 |
John |
General Public License for more details.
|
| 8 |
1121cc70 |
John |
-}
|
| 9 |
1121cc70 |
John |
|
| 10 |
1121cc70 |
John |
{- |
|
| 11 |
1121cc70 |
John |
Module : Main
|
| 12 |
1121cc70 |
John |
Copyright : Copyright (C) 2008 John Goerzen
|
| 13 |
1121cc70 |
John |
License : GNU GPL, version 3 or above; see COPYRIGHT for details
|
| 14 |
1121cc70 |
John |
|
| 15 |
1121cc70 |
John |
Maintainer : John Goerzen <jgoerzen@complete.org>
|
| 16 |
1121cc70 |
John |
Stability : provisional
|
| 17 |
1121cc70 |
John |
Portability: portable
|
| 18 |
1121cc70 |
John |
|
| 19 |
1121cc70 |
John |
Written by John Goerzen, jgoerzen\@complete.org
|
| 20 |
1121cc70 |
John |
|
| 21 |
1121cc70 |
John |
-}
|
| 22 |
1121cc70 |
John |
|
| 23 |
39fbfa62 |
John |
import System.Log.Logger
|
| 24 |
39fbfa62 |
John |
import System.Log.Handler.Simple
|
| 25 |
edd556aa |
John |
import System.IO(stderr)
|
| 26 |
1121cc70 |
John |
import System.Console.GetOpt.Utils
|
| 27 |
1121cc70 |
John |
import System.Console.GetOpt
|
| 28 |
edd556aa |
John |
import System.Environment
|
| 29 |
edd556aa |
John |
import Data.Quantity
|
| 30 |
1121cc70 |
John |
import Data.List
|
| 31 |
1121cc70 |
John |
import System.Exit
|
| 32 |
1121cc70 |
John |
import Control.Monad
|
| 33 |
0a9dfbf4 |
John |
import Types
|
| 34 |
edd556aa |
John |
import Scan
|
| 35 |
5310f5df |
John |
import Data.List.Utils(split)
|
| 36 |
ef1c9d6f |
John |
import Actions
|
| 37 |
1121cc70 |
John |
|
| 38 |
791855a4 |
John |
main :: IO ()
|
| 39 |
1121cc70 |
John |
main =
|
| 40 |
39fbfa62 |
John |
do updateGlobalLogger "" (setLevel INFO)
|
| 41 |
39fbfa62 |
John |
argv <- getArgs
|
| 42 |
1121cc70 |
John |
case getOpt RequireOrder options argv of
|
| 43 |
1121cc70 |
John |
(o, n, []) -> worker o n
|
| 44 |
1121cc70 |
John |
(_, _, errors) -> usageerror (concat errors) -- ++ usageInfo header options)
|
| 45 |
791855a4 |
John |
|
| 46 |
791855a4 |
John |
options :: [OptDescr (String, String)]
|
| 47 |
4a3147c3 |
John |
options = [
|
| 48 |
5310f5df |
John |
Option "0" ["null"] (NoArg ("0", ""))
|
| 49 |
5310f5df |
John |
"Input items terminated by null character",
|
| 50 |
93c1d21c |
John |
Option "a" ["action"] (ReqArg (stdRequired "a") "ACTION")
|
| 51 |
93c1d21c |
John |
"Give action for output. Options are:\n\
|
| 52 |
bd4b204d |
John |
\print print each record with a newline\n\
|
| 53 |
bd4b204d |
John |
\ after [default]\n\
|
| 54 |
93c1d21c |
John |
\printfull print one line for each bin\n\
|
| 55 |
93c1d21c |
John |
\print0 print each record with NULL after\n\
|
| 56 |
bd4b204d |
John |
\exec:CMD Execute CMD in the shell for each\n\
|
| 57 |
bd4b204d |
John |
\record\n\
|
| 58 |
93c1d21c |
John |
\hardlink Hard link items into bins\n\
|
| 59 |
93c1d21c |
John |
\symlink Symlink items into bins",
|
| 60 |
4d1bfa52 |
John |
Option "b" ["binfmt"] (ReqArg (stdRequired "b") "FORMAT")
|
| 61 |
4d1bfa52 |
John |
"Gives bin name format in printf style.\n\
|
| 62 |
4d1bfa52 |
John |
\Tip: this can include a directory.\n\
|
| 63 |
4d1bfa52 |
John |
\default: %03d",
|
| 64 |
4a3147c3 |
John |
Option "d" ["debug"] (NoArg ("d", "")) "Enable debugging",
|
| 65 |
a8d0ef6f |
John |
Option "D" ["deep-links"] (NoArg ("D", "")) "Enable deep bin directories",
|
| 66 |
4a3147c3 |
John |
Option "p" ["preserve-order"] (NoArg ("p", ""))
|
| 67 |
4a3147c3 |
John |
"Don't reorder files for maximum packing",
|
| 68 |
4a3147c3 |
John |
Option "s" ["size"] (ReqArg (stdRequired "s") "SIZE")
|
| 69 |
4a3147c3 |
John |
"Size of each output bin",
|
| 70 |
4a3147c3 |
John |
Option "S" ["size-first"] (ReqArg (stdRequired "S") "SIZE")
|
| 71 |
4a3147c3 |
John |
"Override size of first output bin",
|
| 72 |
8763ec66 |
John |
Option "" ["sort"] (NoArg ("sort", "")) "Sort input; useless without -p",
|
| 73 |
1121cc70 |
John |
Option "" ["help"] (NoArg ("help", "")) "Display this help"]
|
| 74 |
1121cc70 |
John |
|
| 75 |
791855a4 |
John |
worker :: [(String, String)] -> [FilePath] -> IO ()
|
| 76 |
dd457c25 |
John |
worker args files =
|
| 77 |
dd457c25 |
John |
do when (lookup "help" args == Just "") $ usageerror ""
|
| 78 |
39fbfa62 |
John |
when (lookup "d" args == Just "")
|
| 79 |
39fbfa62 |
John |
(updateGlobalLogger "" (setLevel DEBUG))
|
| 80 |
0a9dfbf4 |
John |
handler <- streamHandler stderr DEBUG
|
| 81 |
39fbfa62 |
John |
updateGlobalLogger "" (setHandlers [handler])
|
| 82 |
39fbfa62 |
John |
|
| 83 |
791855a4 |
John |
runinfo <- case parseArgs args of
|
| 84 |
dd457c25 |
John |
Left x -> usageerror x
|
| 85 |
d8035ee7 |
John |
Right x -> return x
|
| 86 |
0a9dfbf4 |
John |
|
| 87 |
7f5ebe0d |
John |
when (files == [])
|
| 88 |
7f5ebe0d |
John |
(usageerror "One or more files, or \"-\", must be specified")
|
| 89 |
7f5ebe0d |
John |
|
| 90 |
5310f5df |
John |
files_scan <- if files == ["-"]
|
| 91 |
5310f5df |
John |
then readFileList (readNull runinfo)
|
| 92 |
5310f5df |
John |
else return files
|
| 93 |
5310f5df |
John |
|
| 94 |
8763ec66 |
John |
let listToProc = if sortFiles runinfo then sort files_scan else files_scan
|
| 95 |
8763ec66 |
John |
|
| 96 |
8763ec66 |
John |
results <- scan runinfo listToProc
|
| 97 |
77198ea6 |
John |
let numberedResults = zip [1..] (map (map snd) results)
|
| 98 |
ef1c9d6f |
John |
runAction runinfo numberedResults
|
| 99 |
0a9dfbf4 |
John |
|
| 100 |
5310f5df |
John |
readFileList :: Bool -> IO [FilePath]
|
| 101 |
5310f5df |
John |
readFileList nullsep =
|
| 102 |
5310f5df |
John |
do c <- getContents
|
| 103 |
5310f5df |
John |
return (splitfunc c)
|
| 104 |
5310f5df |
John |
where splitfunc
|
| 105 |
c27a930c |
John |
| nullsep = filter (/= "") . split "\0"
|
| 106 |
5310f5df |
John |
| otherwise = lines
|
| 107 |
5310f5df |
John |
|
| 108 |
791855a4 |
John |
parseArgs :: [(String, String)] -> Either String RunInfo
|
| 109 |
791855a4 |
John |
parseArgs args =
|
| 110 |
a5096e91 |
John |
do size <- case lookup "s" args of
|
| 111 |
d8035ee7 |
John |
Nothing -> fail "Missing required argument --size"
|
| 112 |
a5096e91 |
John |
Just x -> parseNumInt binaryOpts True x
|
| 113 |
dd457c25 |
John |
first <- case lookup "S" args of
|
| 114 |
d8035ee7 |
John |
Nothing -> return size
|
| 115 |
d8035ee7 |
John |
Just x -> parseNumInt binaryOpts True x
|
| 116 |
dd457c25 |
John |
let po = case lookup "p" args of
|
| 117 |
dd457c25 |
John |
Nothing -> False
|
| 118 |
dd457c25 |
John |
Just _ -> True
|
| 119 |
5310f5df |
John |
let n = case lookup "0" args of
|
| 120 |
5310f5df |
John |
Nothing -> False
|
| 121 |
5310f5df |
John |
Just _ -> True
|
| 122 |
4d1bfa52 |
John |
let b = case lookup "b" args of
|
| 123 |
4d1bfa52 |
John |
Nothing -> "%03d"
|
| 124 |
4d1bfa52 |
John |
Just x -> x
|
| 125 |
a8d0ef6f |
John |
let deeplinks = case lookup "D" args of
|
| 126 |
8763ec66 |
John |
Nothing -> False
|
| 127 |
8763ec66 |
John |
Just _ -> True
|
| 128 |
8763ec66 |
John |
let dosort = case lookup "sort" args of
|
| 129 |
8763ec66 |
John |
Nothing -> False
|
| 130 |
8763ec66 |
John |
Just _ -> True
|
| 131 |
bd4b204d |
John |
a <- case lookup "a" args of
|
| 132 |
bd4b204d |
John |
Nothing -> return Print
|
| 133 |
bd4b204d |
John |
Just "print" -> return Print
|
| 134 |
bd4b204d |
John |
Just "printfull" -> return PrintFull
|
| 135 |
bd4b204d |
John |
Just "print0" -> return Print0
|
| 136 |
bd4b204d |
John |
Just "hardlink" -> return Hardlink
|
| 137 |
bd4b204d |
John |
Just "symlink" -> return Symlink
|
| 138 |
bd4b204d |
John |
Just x ->
|
| 139 |
bd4b204d |
John |
if "exec:" `isPrefixOf` x
|
| 140 |
bd4b204d |
John |
then return (Exec (drop 5 x))
|
| 141 |
bd4b204d |
John |
else fail $ "Unknown action: " ++ show x
|
| 142 |
dd457c25 |
John |
return $ RunInfo {binSize = size, firstBinSize = first,
|
| 143 |
bd4b204d |
John |
preserveOrder = po, readNull = n, binFmt = b,
|
| 144 |
a8d0ef6f |
John |
action = a, deepLinks = deeplinks, sortFiles = dosort}
|
| 145 |
791855a4 |
John |
|
| 146 |
791855a4 |
John |
usageerror :: String -> IO t
|
| 147 |
1121cc70 |
John |
usageerror errormsg =
|
| 148 |
1121cc70 |
John |
do putStrLn errormsg
|
| 149 |
1121cc70 |
John |
putStrLn (usageInfo header options)
|
| 150 |
5310f5df |
John |
putStrLn "If the single value \"-\" is given for inputfiles, the list of files"
|
| 151 |
5310f5df |
John |
putStrLn "is read from stdin."
|
| 152 |
1121cc70 |
John |
exitFailure
|
| 153 |
1121cc70 |
John |
|
| 154 |
791855a4 |
John |
header :: String
|
| 155 |
5310f5df |
John |
header = "\nUsage: datapacker [options] --size=n inputfiles\n\n\
|
| 156 |
1121cc70 |
John |
\Available options are:\n" |