root / datapacker.hs

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"