packages feed

randfile (empty) → 0.1.0.0

raw patch · 5 files changed

+195/−0 lines, 5 filesdep +Win32dep +basedep +crypto-apisetup-changed

Dependencies added: Win32, base, crypto-api, directory, filepath, monadcryptorandom, transformers, unix

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2011, Joseph Adams++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 Joseph Adams 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.
+ Main.hs view
@@ -0,0 +1,75 @@+import Prelude hiding (catch)++import Stat++import Control.Applicative+import Control.Exception+import Control.Monad.CryptoRandom+import Control.Monad.Trans.Class+import Control.Monad.Trans.Error+import Crypto.Random+import System.Directory+import System.Environment+import System.Exit+import System.FilePath+import System.IO++-- | Handle an IOException by returning the given value instead.+onIOException :: a -> IO a -> IO a+onIOException fallback_result action =+        action `catch` handler fallback_result+    where+        handler :: a -> IOException -> IO a+        handler x _ = return x++notSpecial :: FilePath -> Bool+notSpecial name = name /= "." && name /= ".."++listFiles :: FilePath -> IO [FilePath]+listFiles dir = onIOException []+              $ map (dir </>) . filter notSpecial <$> getDirectoryContents dir++randFile :: (CryptoRandomGen g, Error e, ContainsGenError e)+         => FilePath+         -> CRandT g e IO (Maybe FilePath)+randFile dir = lift (listFiles dir) >>= pickFromList where+    pickFromList list =+        if null list+            then return Nothing+            else do+                let len = length list+                idx  <- getCRandomR (0, len-1)+                let path = list !! idx++                st <- lift (stat path)+                case st of+                    File      -> return (Just path)+                    Directory -> do+                        r <- randFile path+                        case r of+                            Just _  -> return r+                            Nothing -> pickFromList (list `without` idx)+                    Other     -> pickFromList (list `without` idx)+    without list idx = as ++ bs where+        (as, _:bs) = splitAt idx list++-- | Like 'runCRandT', but discard the generator and throw the error+-- (if necessary).+runCRandT_ :: CRandT g GenError IO a -> g -> IO a+runCRandT_ action gen = do+    res <- runCRandT action gen+    case res of+        Left e       -> throwIO $ userError $ show e+        Right (a, _) -> return a++main :: IO ()+main = do+    g <- newGenIO :: IO SystemRandom+    file <- runCRandT_ (randFile ".") g+    case file of+        Just f  -> putStrLn $ makeRelative "." $ f+        Nothing -> do+            progName <- getProgName+            hPutStrLn stderr $+                progName ++ ": Current directory does not contain any files"+            exitFailure
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Stat.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE CPP #-}+-- | Portably test if a given path is a file, directory, or something else.+module Stat (+    Stat(..)+  , stat+) where++import Prelude hiding (catch)+import Control.Applicative+import Control.Exception++#ifdef mingw32_HOST_OS+import Data.Bits+import qualified System.Win32 as Win32+#else+import qualified System.Posix as Posix+#endif++data Stat = File | Directory | Other++stat :: FilePath -> IO Stat+stat path = stat_ path `catch` handler+    where+        handler :: IOException -> IO Stat+        handler _ = return Other++stat_ :: FilePath -> IO Stat++#ifdef mingw32_HOST_OS+stat_ path = decode <$> Win32.getFileAttributes path+    where+        decode flags | flags .&. Win32.fILE_ATTRIBUTE_DIRECTORY /= 0 = Directory+                        -- TODO: Handle non-file non-directory files properly+                     | otherwise = File+#else+stat_ path = decode <$> Posix.getFileStatus path+    where+        decode s | Posix.isRegularFile s  = File+                 | Posix.isDirectory s    = Directory+                 | otherwise              = Other+#endif
+ randfile.cabal view
@@ -0,0 +1,47 @@+name:                randfile+version:             0.1.0.0+synopsis:            Program for picking a random file+description:+    This program selects a random file from the current directory, including+    files in subdirectories.  If you like to manage your music collection using+    the command line, this program can be used to approximate \"shuffle\".+    .+    More precisely, it starts at the current directory, picks a random entry,+    and descends if it is a directory.  It does not give more weight to+    directories containing more files.  It should only fail if there are no+    regular files under the current directory that you can see.+    .+    If you are wondering why I bothered to use crypto-grade random number+    generation, it is because I found @System.Random@ to be unsatisfactory.+    With @System.Random@, this program tended to return the same file+    repeatedly.+    .+    Note: on Unix, this program follows symbolic links, while on Windows, it+    doesn't.  Symbolic links were introduced in Windows Vista and+    Windows Server 2008.+license:             BSD3+license-file:        LICENSE+author:              Joey Adams+maintainer:          joeyadams3.14159@gmail.com+copyright:           Copyright (c) Joseph Adams 2011+category:            System+build-type:          Simple+cabal-version:       >=1.8++executable randfile+    main-is:         Main.hs+    other-modules:+        Stat+    build-depends:   base == 4.*+                   , filepath+                   , directory+                   , crypto-api+                   , transformers+                   , monadcryptorandom+    if os(windows) {+        build-depends: Win32+    } else {+        build-depends: unix+    }+    other-extensions:   CPP+    ghc-options:     -Wall