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 +30/−0
- Main.hs +75/−0
- Setup.hs +2/−0
- Stat.hs +41/−0
- randfile.cabal +47/−0
+ 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