rewrite (empty) → 0.2
raw patch · 4 files changed
+181/−0 lines, 4 filesdep +basedep +directorydep +multiargsetup-changed
Dependencies added: base, directory, multiarg, process, temporary
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- rewrite.cabal +37/−0
- rewrite.hs +112/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, Omari Norman++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Omari Norman nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ rewrite.cabal view
@@ -0,0 +1,37 @@+-- Initial rewrite.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/++name: rewrite+version: 0.2+synopsis: open file and rewrite it with new contents+description:+ In the Unix shell there is no easy way to use a filter program+ to change the contents of a file in-place. For example, if you+ want to sort a file in place, this will not work:+ .+ sort < myfile > myfile+ .+ All that will get you is an empty myfile. This package+ gives you the rewrite program, so this will work:+ .+ rewrite myfile sort++homepage: http://www.github.com/massysett/rewrite+license: BSD3+license-file: LICENSE+author: Omari Norman+maintainer: omari@smileystation.com+copyright: 2013 Omari Norman+category: System+build-type: Simple+cabal-version: >=1.8++executable rewrite+ main-is: rewrite.hs+ build-depends:+ base ==4.6.*+ , multiarg ==0.16.*+ , temporary ==1.1.*+ , process ==1.1.*+ , directory ==1.2.*+ ghc-options: -Wall
+ rewrite.hs view
@@ -0,0 +1,112 @@+module Main (main) where++import Data.Either (partitionEithers)+import qualified System.Console.MultiArg as MA+import qualified System.IO as IO+import System.IO.Temp (withSystemTempDirectory)+import qualified System.Exit as Exit+import qualified System.Directory as D+import qualified System.Process as P++help :: String -> String+help pn = unlines+ [ "usage: " ++ pn ++ "[options] FILE PROGRAM [program options]"+ , "opens given FILE and feeds it to standard input of PROGRAM"+ , "and writes PROGRAM output back to FILE."+ , ""+ , "Aborts if PROGRAM exits with non-zero exit status."+ , ""+ , "Options:"+ , " -h, --help Show help and exit"+ , " -b, --backup SUFFIX Back up FILE to file with given SUFFIX"+ , " before writing new file"+ ]++type Backup = String+type ProgramOpt = String+type ProgName = String+type InputFile = String++errExit :: String -> IO a+errExit msg = do+ pn <- MA.getProgName+ IO.hPutStrLn IO.stderr $ pn ++ ": error: " ++ msg+ Exit.exitFailure++-- | Parses command line arguments; returns whether to do backup and+-- positional arguments+parseArgs :: IO (Maybe Backup, InputFile, ProgName, [ProgramOpt])+parseArgs = do+ let opts = [ MA.OptSpec ["backup"] "b" (MA.OneArg Left) ]+ as <- MA.simpleWithHelp help MA.StopOptions opts (return . Right)+ let (baks, os) = partitionEithers as+ bak <- case baks of+ [] -> return Nothing+ x:[] -> if null x+ then errExit "empty backup suffix given"+ else return $ Just x+ _ -> errExit "multiple backup suffixes given"+ (input, name, progOpts) <- case os of+ [] -> errExit "no input file or program name given"+ _:[] -> errExit "no program name given"+ x:y:xs -> return (x, y, xs)+ return (bak, input, name, progOpts)+++doBackup :: InputFile -> Backup -> IO ()+doBackup inf bak = D.copyFile inf (inf ++ "." ++ bak)+++runProgram+ :: Maybe Backup++ -> InputFile+ -- ^ Name of input file++ -> ProgName++ -> [ProgramOpt]++ -> FilePath+ -- ^ Temporary directory++ -> IO ()+runProgram mayBak inFile pn opts tempPath =+ let outPath = tempPath ++ "/output"+ in IO.withFile outPath IO.WriteMode $ \outHandle ->+ IO.withFile inFile IO.ReadMode $ \inHandle -> do+ writeReadme tempPath+ let cp = P.CreateProcess+ { P.cmdspec = P.RawCommand pn opts+ , P.cwd = Nothing+ , P.env = Nothing+ , P.std_in = P.UseHandle inHandle+ , P.std_out = P.UseHandle outHandle+ , P.std_err = P.Inherit+ , P.close_fds = False+ , P.create_group = False }+ (_, _, _, procHndle) <- P.createProcess cp+ code <- P.waitForProcess procHndle+ _ <- case code of+ Exit.ExitSuccess -> return ()+ Exit.ExitFailure bad ->+ errExit $ "program " ++ pn ++ " exited with code "+ ++ show bad+ _ <- case mayBak of+ Nothing -> return ()+ Just bak -> doBackup inFile bak+ D.copyFile outPath inFile+++writeReadme+ :: FilePath+ -- ^ Temporary directory+ -> IO ()++writeReadme fp = writeFile (fp ++ "/README")+ "This directory created by the rewrite program."++main :: IO ()+main = do+ (mayBak, inf, pn, opts) <- parseArgs+ withSystemTempDirectory "rewrite" $ runProgram mayBak inf pn opts