squeeze 1.0.2.0 → 1.0.2.2
raw patch · 13 files changed
+134/−113 lines, 13 filesdep −haskell98dep ~toolshed
Dependencies removed: haskell98
Dependency ranges changed: toolshed
Files
- changelog +11/−1
- debian/DEBIAN/control +1/−1
- makefile +7/−7
- man/man1/squeeze.1 +6/−6
- squeeze.cabal +7/−4
- squeeze.spec +2/−2
- src/Main.hs +46/−37
- src/Squeeze/Data/CommandOptions.hs +12/−12
- src/Squeeze/Data/File.hs +8/−9
- src/Squeeze/Data/FileCombination.hs +7/−7
- src/Squeeze/Squeeze.hs +17/−17
- src/Squeeze/Test/Performance.hs +3/−3
- src/Squeeze/Test/QC.hs +7/−7
changelog view
@@ -46,4 +46,14 @@ * Made the data-type 'CommandOptions.CommandOptions' polymorphic in terms of the /ratio/-type fields. * Inserted new layers "Data" and "Test" into the module-hierarchy, and relocated existing modules accordingly. * Added module "Squeeze.Test.Performance" to test with randomly generated virtual files.-+1.0.2.1+ * Added check for zero file-names when reading from stdin.+ * Corrected the syntax required when specifying ratios, in the man-page.+1.0.2.2+ * Renamed 'Squeeze.Data.File.order' to 'Squeeze.Data.File.orderBySize'.+ * Used 'Paths_squeeze.version' in 'Main', rather than hard-coding it.+ * Added 'Squeeze.Data.CommandOptions.getErrors' to permit better error-diagnosis.+ * Reacted to new module-hierarchy and addition of method 'ToolShed.SelfValidate.getErrors', in toolshed-0.13.0.0.+ * Replaced use of 'Control.Exception.bracket' with 'System.IO.withFile', in 'Squeeze.Data.File.findSize'.+ * Replaced "System" with "System.Environment" and "System.Exit".+ * Removed dependency on "haskell98".
debian/DEBIAN/control view
@@ -1,5 +1,5 @@ Package: squeeze-Version: 1.0.2.0-1+Version: 1.0.2.2-1 Section: utils Priority: optional Architecture: i386
makefile view
@@ -1,19 +1,19 @@ # Copyright (C) 2010 Dr. Alistair Ward-# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version.-# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details.-# +# # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -.PHONY: all build check clean clobber configure copy deb haddock help hlint install lintian prof rpm rpmlint sdist +.PHONY: all build check clean clobber configure copy deb haddock help hlint install lintian prof rpm rpmlint sdist all: install @@ -22,7 +22,7 @@ runhaskell Setup.hs $@ $$CABAL_INSTALL_OPTIONS prof:- CABAL_CONFIGURE_OPTIONS="--enable-executable-profiling $$CABAL_CONFIGURE_OPTIONS" make install+ CABAL_CONFIGURE_OPTIONS="--enable-executable-profiling $$CABAL_CONFIGURE_OPTIONS" make build copy: build @[ -z "$$CABAL_COPY_OPTIONS" ] || echo "INFO: CABAL_COPY_OPTIONS='$$CABAL_COPY_OPTIONS'"@@ -40,7 +40,7 @@ PATH=~/.cabal/bin:$$PATH runhaskell Setup.hs $@ --hyperlink-source --executables #Amend path to find 'HsColour', as required for 'hyperlink-source'. hlint:- @$@ src/+ @$@ -i 'Reduce duplication' src/ sdist: configure runhaskell Setup.hs $@@@ -69,7 +69,7 @@ clean: runhaskell Setup.hs $@ rm -rf 'debian/usr/' 'debian/DEBIAN/md5sums'- find src -type f \( -name '*.o' -o -name '*.hi' \) -delete+ find src -type f \( -name '*.hc' -o -name '*.hcr' -o -name '*.hi' -o -name '*.o' \) -delete clobber: clean rm -f -- *.rpm *.deb
man/man1/squeeze.1 view
@@ -13,8 +13,8 @@ .SH OPTIONS .SS "Selection" .TP-\fB-b\fR, \fB--bisectionRatio=\fR\fILHS/Total\fR-Defines the ratio (in the unit interval [0 .. 1], defaulting to 1/2), at which the file-list will be bisected.+\fB-b\fR, \fB--bisectionRatio='\fR\fILHS%Total\fR'+Defines the ratio (in the unit interval [0 .. 1], defaulting to \fB1%2\fR, i.e. 50%), at which the file-list will be bisected. The first of the combinations generated from the LHS, is then concatenated with each of the combinations generated from the RHS. The same operation is then performed on subsequent combinations from the LHS. This alters the order in which file-combinations are assessed, & so the set of suitable combinations returned may differ, though the optimum value remains the same.@@ -24,7 +24,7 @@ .TP \fB-m\fR, \fB--minimumUsageRatio=\fR\fIRATIO\fR Define the minimum acceptable usage-ratio of \fBmaximumBytes\fR,-from 0 .. 1, defaulting to \fB99/100\fR, i.e. 99%.+from 0 .. 1, defaulting to \fB99%100\fR, i.e. 99%. .TP \fB-q\fR, \fB--runQuickChecks\fR Run Quick-checks using arbitrary data & then exit.@@ -65,7 +65,7 @@ ArabStrap/ BobDylan/ JeffBuckley/ JohnMartyn/ JoniMitchell/ ReservoirDogsOST/ RichardThompson/ SethLakeman/ SusheelaRaman/ TeddyThompson/ Vangelis/ .PP .TP-\fBsqueeze -M 700000000 -m 0.999 *\fR+\fBsqueeze -M 700000000 -m '999%1000' *\fR 699871313 ["BobDylan","RichardThompson","SethLakeman","TeddyThompson"] @@ -86,7 +86,7 @@ .SS Trial 2 We can improve on that result if we're prepared to split some of the artist-specific directories into individual albums. .TP-\fBsqueeze -M 700000000 -m 0.99999 ArabStrap BobDylan/* JeffBuckley JohnMartyn JoniMitchell ReservoirDogsOST RichardThompson SethLakeman SusheelaRaman TeddyThompson Vangelis\fR+\fBsqueeze -M 700000000 -m '99999%100000' ArabStrap BobDylan/* JeffBuckley JohnMartyn JoniMitchell ReservoirDogsOST RichardThompson SethLakeman SusheelaRaman TeddyThompson Vangelis\fR 699995815 ["ArabStrap","BobDylan/BlondeOnBlonde","BobDylan/Highway61Revisited","BobDylan/ModernTimes","BobDylan/StreetLegal","BobDylan/SubterraneanHomesickBlues","JoniMitchell","RichardThompson","SusheelaRaman","TeddyThompson","Vangelis"] .br@@ -97,7 +97,7 @@ .SS Trial 3 If we're prepared to add individual files from another artist: .TP-\fBsqueeze -M 700000000 -m 0.9999999 ArabStrap BobDylan/* JeffBuckley JohnMartyn JoniMitchell ReservoirDogsOST $(find RichardThompson -type f) SethLakeman SusheelaRaman TeddyThompson Vangelis\fR+\fBsqueeze -M 700000000 -m '9999999%10000000' ArabStrap BobDylan/* JeffBuckley JohnMartyn JoniMitchell ReservoirDogsOST $(find RichardThompson -type f) SethLakeman SusheelaRaman TeddyThompson Vangelis\fR 699999964 ["ArabStrap","BobDylan/Desire","BobDylan/Infidels","BobDylan/ModernTimes","BobDylan/OhMercy","BobDylan/SubterraneanHomesickBlues","BobDylan/TimeOutOfMind","JeffBuckley","JohnMartyn","JoniMitchell","ReservoirDogsOST","RichardThompson/FrontParlourBallads/RichardThompson-06-MySoulMySoul.ogg","RichardThompson/RumorAndSigh/RichardThompson-12-MotherKnowsBest.ogg","RichardThompson/TheOldKitBag/RichardThompson-01-Gethsemane.ogg","RichardThompson/TheOldKitBag/RichardThompson-11-OutsideOfTheInside.ogg","SethLakeman","SusheelaRaman","TeddyThompson","Vangelis"]
squeeze.cabal view
@@ -1,6 +1,6 @@ --Package-properties Name: squeeze-Version: 1.0.2.0+Version: 1.0.2.2 Cabal-Version: >= 1.6 Copyright: (C) 2010 Dr. Alistair Ward License: GPL@@ -40,14 +40,17 @@ directory, factory >= 0.1, filepath,- haskell98, QuickCheck >= 2.4, random,- toolshed >= 0.12,+ toolshed == 0.13.*, unix GHC-options: -Wall -O2- GHC-prof-options: -prof -auto-all -caf-all++ if impl(ghc >= 7.4.1)+ GHC-prof-options: -prof -fprof-auto -fprof-cafs+ else+ GHC-prof-options: -prof -auto-all -caf-all if impl(ghc >= 7.0) GHC-options: -rtsopts
squeeze.spec view
@@ -5,9 +5,9 @@ %define _docdir %prefix/share/doc/%package %define _mandir %prefix/share/man -Summary: Finds the optimal subset of the specified files, to fit into a limited space, with minimal wastage.+Summary: Finds the optimal subset of the specified files, to fit into a limited space, with minimal wastage. Name: squeeze-Version: 1.0.2.0+Version: 1.0.2.2 Release: 1 License: GPLv3 #From '/usr/share/doc/packages/rpm/GROUPS'.
src/Main.hs view
@@ -26,7 +26,8 @@ -} module Main(--- * Type-classes+-- * Types+-- ** Type-synonyms -- CommandOptions', -- CommandLineAction, -- * Functions@@ -36,23 +37,26 @@ import Control.Applicative((<*>), (<$>)) import qualified Data.List import qualified Data.Ratio+import qualified Data.Version import qualified Distribution.Package import qualified Distribution.Text import qualified Distribution.Version-import qualified Factory.Math.Probability as Math.Probability+import qualified Factory.Math.Probability+import qualified Paths_squeeze as Paths --Either local stub, or package-instance autogenerated by 'Setup.hs build'. import qualified Squeeze.Data.CommandOptions as Data.CommandOptions import qualified Squeeze.Data.File as Data.File import qualified Squeeze.Squeeze as Squeeze import qualified Squeeze.Test.Performance as Test.Performance import qualified Squeeze.Test.QC as Test.QC-import qualified System import qualified System.Console.GetOpt as G+import qualified System.Environment+import qualified System.Exit import qualified System.IO import qualified System.IO.Error import qualified Test.QuickCheck-import qualified ToolShed.Defaultable as Defaultable-import qualified ToolShed.TimeAction as TimeAction-import qualified ToolShed.SelfValidate as SelfValidate+import qualified ToolShed.Defaultable+import qualified ToolShed.SelfValidate+import qualified ToolShed.System.TimeAction -- | Coerce the polymorphic data-type to concrete instance, in order that it's fields may be read from the command-line. type CommandOptions' = Data.CommandOptions.CommandOptions Data.Ratio.Rational --'Double' would also be a suitable type-parameter.@@ -61,7 +65,7 @@ type CommandLineAction = (CommandOptions' -> IO CommandOptions') --Supplied as the type-argument to 'G.OptDescr'. {- |- * Parses the command-line arguments, to determine 'Data.CommandOptions.CommandOptions', some of which may over-ride the 'Defaultable.defaultValue'.+ * Parses the command-line arguments, to determine 'Data.CommandOptions.CommandOptions', some of which may over-ride the 'ToolShed.Defaultable.defaultValue'. * Any arguments which follow known 'Data.CommandOptions.CommandOptions', are interpreted as file-names to consider when attempting to find a suitable fit for the specified space-constraints.@@ -76,20 +80,23 @@ -} main :: IO () main = do- progName <- System.getProgName- args <- System.getArgs+ progName <- System.Environment.getProgName+ args <- System.Environment.getArgs let usage :: String usage = "Usage:\t" ++ G.usageInfo progName optDescrList ++ " [<file/directory-name>, ...]\n\nExamples:\n\t" ++ progName ++ " -M 700000000 *.ogg\t\t#Find the best-fit for the globbed file-names, into the space available on a CD." defaultValue :: CommandOptions'- defaultValue = Defaultable.defaultValue+ defaultValue = ToolShed.Defaultable.defaultValue optDescrList :: [G.OptDescr CommandLineAction] optDescrList = [ -- String [String] (G.ArgDescr CommandLineAction) String- G.Option "b" ["bisectionRatio"] (setBisectionRatio `G.ReqArg` "<Ratio>") ("The file-list is bisected at LHS/Total, & combinations from the LHS, concatenated with each of those from the RHS; default '" ++ show (Data.CommandOptions.bisectionRatio defaultValue) ++ "'."),+ G.Option "?" ["help"] (G.NoArg $ const printUsage) "Display this help, & then exit.",+ G.Option "v" ["verbose"] (G.NoArg $ return . Data.CommandOptions.setVerbose) "Produce additional explanatory output where appropriate. CAVEAT: to be effective, it should precede other options.",+ G.Option "" ["version"] (G.NoArg $ const printVersion) "Print version-information, & then exit.",+ G.Option "b" ["bisectionRatio"] (setBisectionRatio `G.ReqArg` "<Ratio>") ("The list of file-paths is bisected at LHS/Total, & combinations from the LHS, concatenated with each of those from the RHS; default '" ++ show (Data.CommandOptions.bisectionRatio defaultValue) ++ "'."), G.Option "M" ["maximumBytes"] (setMaximumBytes `G.ReqArg` "<Integer>") ("The maximum bytes of available space; default '" ++ show (Data.CommandOptions.maximumBytes defaultValue) ++ "'."), G.Option "m" ["minimumUsageRatio"] (setMinimumUsageRatio `G.ReqArg` "<Ratio>") ("The minimum acceptable space usage-ratio; default '" ++ show (Data.CommandOptions.minimumUsageRatio defaultValue) ++ "'."), G.Option "q" ["runQuickChecks"] (G.NoArg runQuickChecks) "Run Quick-checks using arbitrary data & then exit.",@@ -98,40 +105,37 @@ ) "Test the performance, using the specified number of randomly generated virtual files, the size of which conform to the specified probability-distribution; then exit.", G.Option "" ["graphPerformance"] ( graphPerformance `G.ReqArg` "<Factory.Math.Probability.DiscreteDistribution>"- ) "Graph the performance, against a linearly increasing number of randomly generated virtual files, the size of which conform to the specified probability-distribution. Doesn't normally terminate.",- G.Option "v" ["verbose"] (G.NoArg $ return . Data.CommandOptions.setVerbose) "Produce additional explanatory output where appropriate. CAVEAT: should precede other options.",- G.Option "" ["version"] (G.NoArg $ const printVersion) "Print version-information, & then exit.",- G.Option "?" ["help"] (G.NoArg $ const printUsage) "Display this help, & then exit."+ ) "Graph the performance, against a linearly increasing number of randomly generated virtual files, the size of which conform to the specified probability-distribution. Doesn't normally terminate." ] where setBisectionRatio, setMaximumBytes, setMinimumUsageRatio, testPerformance, graphPerformance :: String -> CommandLineAction setBisectionRatio arg commandOptions = return {-to IO-monad-} commandOptions {Data.CommandOptions.bisectionRatio = read arg} setMaximumBytes arg commandOptions = return {-to IO-monad-} commandOptions {Data.CommandOptions.maximumBytes = read arg} setMinimumUsageRatio arg commandOptions = return {-to IO-monad-} commandOptions {Data.CommandOptions.minimumUsageRatio = read arg} - testPerformance arg commandOptions = if not $ SelfValidate.isValid commandOptions- then error $ "Invalid " ++ show commandOptions+ testPerformance arg commandOptions = if not $ ToolShed.SelfValidate.isValid commandOptions+ then error $ ToolShed.SelfValidate.getFirstError commandOptions else do- TimeAction.printCPUSeconds $ Test.Performance.run commandOptions fileCount probabilityDistribution >>= mapM_ print+ ToolShed.System.TimeAction.printCPUSeconds $ Test.Performance.run commandOptions fileCount probabilityDistribution >>= mapM_ print - System.exitWith System.ExitSuccess+ System.Exit.exitWith System.Exit.ExitSuccess where fileCount :: Int- probabilityDistribution :: Math.Probability.DiscreteDistribution Double+ probabilityDistribution :: Factory.Math.Probability.DiscreteDistribution Double (fileCount, probabilityDistribution) = read arg - graphPerformance arg commandOptions = if not $ SelfValidate.isValid commandOptions- then error $ "Invalid " ++ show commandOptions+ graphPerformance arg commandOptions = if not $ ToolShed.SelfValidate.isValid commandOptions+ then error $ ToolShed.SelfValidate.getFirstError commandOptions else do- mapM_ (\fileCount -> TimeAction.printCPUSeconds $ Test.Performance.run commandOptions fileCount probabilityDistribution >>= mapM_ print) [1 ..]+ mapM_ (\fileCount -> ToolShed.System.TimeAction.printCPUSeconds $ Test.Performance.run commandOptions fileCount probabilityDistribution >>= mapM_ print) [1 ..] - System.exitWith $ System.ExitFailure 1+ System.Exit.exitWith $ System.Exit.ExitFailure 1 where- probabilityDistribution :: Math.Probability.DiscreteDistribution Double+ probabilityDistribution :: Factory.Math.Probability.DiscreteDistribution Double probabilityDistribution = read arg runQuickChecks :: (Num f, Ord f) => Data.CommandOptions.CommandOptions f -> IO (Data.CommandOptions.CommandOptions f)- runQuickChecks commandOptions = if not $ SelfValidate.isValid commandOptions- then error $ "Invalid " ++ show commandOptions+ runQuickChecks commandOptions = if not $ ToolShed.SelfValidate.isValid commandOptions+ then error $ ToolShed.SelfValidate.getFirstError commandOptions else do Test.QC.quickChecks $ if Data.CommandOptions.verbose commandOptions then@@ -142,33 +146,33 @@ #endif else Test.QuickCheck.quickCheck - System.exitWith System.ExitSuccess+ System.Exit.exitWith System.Exit.ExitSuccess printVersion, printUsage :: IO (Data.CommandOptions.CommandOptions f)- printVersion = System.IO.hPutStrLn System.IO.stderr (Distribution.Text.display packageIdentifier ++ "\n\nCopyright (C) 2010 Dr. Alistair Ward.\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it under certain conditions.\n\nWritten by Dr. Alistair Ward.") >> System.exitWith System.ExitSuccess where+ printVersion = System.IO.hPutStrLn System.IO.stderr (Distribution.Text.display packageIdentifier ++ "\n\nCopyright (C) 2010 Dr. Alistair Ward.\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it under certain conditions.\n\nWritten by Dr. Alistair Ward.") >> System.Exit.exitWith System.Exit.ExitSuccess where packageIdentifier :: Distribution.Package.PackageIdentifier packageIdentifier = Distribution.Package.PackageIdentifier { Distribution.Package.pkgName = Distribution.Package.PackageName "squeeze",- Distribution.Package.pkgVersion = Distribution.Version.Version [1, 0, 2, 0] []+ Distribution.Package.pkgVersion = Distribution.Version.Version (Data.Version.versionBranch Paths.version) [] } - printUsage = System.IO.hPutStrLn System.IO.stderr usage >> System.exitWith System.ExitSuccess+ printUsage = System.IO.hPutStrLn System.IO.stderr usage >> System.Exit.exitWith System.Exit.ExitSuccess -- G.getOpt :: G.ArgOrder CommandLineAction -> [G.OptDescr CommandLineAction] -> [String] -> ([CommandLineAction], [String], [String]) case G.getOpt G.RequireOrder optDescrList args of (commandLineActions, nonOptions, [{-errors-}]) -> do commandOptions <- Data.List.foldl' (>>=) (- return {-to IO-monad-} Defaultable.defaultValue+ return {-to IO-monad-} ToolShed.Defaultable.defaultValue ) {-transform using CommandLineAction-mutators-} commandLineActions --ie: do o1 <- CommandLineAction[0] commandOptions[0]; o2 <- CommandLineAction[1] o1; ... - if not $ SelfValidate.isValid commandOptions- then error $ "Invalid " ++ show commandOptions+ if not $ ToolShed.SelfValidate.isValid commandOptions+ then error $ ToolShed.SelfValidate.getFirstError commandOptions else ( if Data.CommandOptions.verbose commandOptions- then TimeAction.printCPUSeconds+ then ToolShed.System.TimeAction.printCPUSeconds else id ) $ mapM_ print {-print immediately rather than batching-} =<< Squeeze.squeeze commandOptions =<< if null nonOptions- then error "No files specified."+ then error "No file-paths specified." else if "-" `elem` nonOptions then let getFilePaths :: IO Data.File.FilePathList@@ -178,7 +182,12 @@ if eof then return {-to IO-monad-} [] else {-more to read-} (:) <$> getLine <*> getFilePaths {-recurse-}- in (filter (/= "-") nonOptions ++) <$> getFilePaths+ in do+ filePaths <- (filter (/= "-") nonOptions ++) <$> getFilePaths++ if null filePaths+ then error "No file-paths."+ else return filePaths else {-real fileNames-} return {-to IO-monad-} nonOptions (_, _, errors) -> System.IO.Error.ioError . System.IO.Error.userError $ concatMap init {-chop-} errors
src/Squeeze/Data/CommandOptions.hs view
@@ -42,10 +42,10 @@ setVerbose ) where -import qualified Factory.Data.Interval as Data.Interval+import qualified Factory.Data.Interval import qualified Squeeze.Data.File as Data.File-import qualified ToolShed.Defaultable as Defaultable-import qualified ToolShed.SelfValidate as SelfValidate+import qualified ToolShed.Defaultable+import qualified ToolShed.SelfValidate {- | * Declare a record to contain command-line options.@@ -59,7 +59,7 @@ verbose :: Bool -- ^ Output ancillary information. } deriving Show -instance Fractional f => Defaultable.Defaultable (CommandOptions f) where+instance Fractional f => ToolShed.Defaultable.Defaultable (CommandOptions f) where defaultValue = MkCommandOptions { bisectionRatio = recip 2, --Bisection the file-list into equal halves. maximumBytes = 4700000000, --DVD-size; just under 4.4GiB.@@ -67,13 +67,13 @@ verbose = False } -instance (Num f, Ord f) => SelfValidate.SelfValidator (CommandOptions f) where- isValid commandOptions = all ($ commandOptions) [- (>= 0) . bisectionRatio,- (<= 1) . bisectionRatio,- (>= 0) . maximumBytes,- (>= 0) . minimumUsageRatio,- (<= 1) . minimumUsageRatio+instance (Num ratio, Ord ratio, Show ratio) => ToolShed.SelfValidate.SelfValidator (CommandOptions ratio) where+ getErrors commandOptions = map snd $ filter (($ commandOptions) . fst) [+ ((< 0) . bisectionRatio, "Invalid bisectionRatio='" ++ show (bisectionRatio commandOptions) ++ "'."),+ ((> 1) . bisectionRatio, "Invalid bisectionRatio='" ++ show (bisectionRatio commandOptions) ++ "'."),+ ((< 0) . maximumBytes, "Invalid maximumBytes=" ++ show (maximumBytes commandOptions) ++ "."),+ ((< 0) . minimumUsageRatio, "Invalid minimumUsageRatio='" ++ show (minimumUsageRatio commandOptions) ++ "'."),+ ((> 1) . minimumUsageRatio, "Invalid minimumUsageRatio='" ++ show (minimumUsageRatio commandOptions) ++ "'.") ] -- | Derives the minimum number of bytes, from other options.@@ -81,7 +81,7 @@ minimumBytes commandOptions = floor $ minimumUsageRatio commandOptions * realToFrac (maximumBytes commandOptions) -- | The permissible bounds on the size of a file, or set of files.-fileSizeBounds :: RealFrac f => CommandOptions f -> Data.Interval.Interval Data.File.FileSize+fileSizeBounds :: RealFrac f => CommandOptions f -> Factory.Data.Interval.Interval Data.File.FileSize fileSizeBounds commandOptions = (minimumBytes commandOptions, maximumBytes commandOptions) -- | Mutator.
src/Squeeze/Data/File.hs view
@@ -20,7 +20,7 @@ [@DESCRIPTION@] Defines file-related type-synonyms, and associated operations. -} -module Squeeze.Data.File (+module Squeeze.Data.File( -- * Types -- ** Type-synonyms FilePathList,@@ -31,7 +31,7 @@ aggregateSize, -- findSize, findSizes,- order,+ orderBySize, -- ** Accessors getSize, getPath,@@ -54,7 +54,6 @@ type FilePathList = [System.IO.FilePath] -- | A type-synonym specifically to hold file-sizes (in bytes).---type FileSize = Data.Int.Int64 --About 1/6th faster. type FileSize = Integer --Matches the return-type of 'IO.hFileSize'. -- | A type suitable for containing a file-path, qualified by the corresponding 'FileSize'.@@ -86,7 +85,7 @@ stat <- System.Posix.Files.getFileStatus f --CAVEAT: throws if the user is unauthorised, or the file is non-existent. if System.Posix.Files.isRegularFile stat- then Control.Exception.bracket (System.IO.openFile f System.IO.ReadMode) System.IO.hClose $ \handle -> fromInteger <$> System.IO.hFileSize handle+ then System.IO.withFile f System.IO.ReadMode System.IO.hFileSize else {-not a regular file-} if System.Posix.Files.isDirectory stat then System.Directory.getDirectoryContents f >>= fmap {-into IO-monad-} aggregateSize . findSizes . map (f </>) . filter (`notElem` [".", ".."]) --Treat any directory as an atomic unit. else {-non-directory-} Control.Exception.throw $ System.IO.Error.mkIOError System.IO.Error.illegalOperationErrorType ("file='" ++ f ++ "' has unexpected type") Nothing (Just f)@@ -96,12 +95,12 @@ findSizes filePathList = (`zip` filePathList) <$> {-lift into IO-monad-} mapM findSize filePathList -- | Sorts a list of 'FileSizeAndPath' by reverse order of size; ie. largest first.-order :: [FileSizeAndPath] -> [FileSizeAndPath]-order = Data.List.sortBy (flip $ Data.Ord.comparing getSize)+orderBySize :: [FileSizeAndPath] -> [FileSizeAndPath]+orderBySize = Data.List.sortBy (flip $ Data.Ord.comparing getSize) --- | 'True' if the specified file has the required size according to the specified predicate.-hasSize ::- (FileSize -> Bool) -- ^ The predicate.+-- | True if the specified file has the required size according to the specified predicate.+hasSize+ :: (FileSize -> Bool) -- ^ The predicate. -> FileSizeAndPath -- ^ The file-parameters to be tested. -> Bool hasSize f = f . getSize
src/Squeeze/Data/FileCombination.hs view
@@ -20,7 +20,7 @@ [@DESCRIPTION@] A data-type which references a set of files by their paths, and qualifies them with their aggregate size. -} -module Squeeze.Data.FileCombination (+module Squeeze.Data.FileCombination( -- * Types -- ** Data-types FileCombination(@@ -65,8 +65,8 @@ -- | Prepend a 'Data.File.FileSizeAndPath' to an existing 'FileCombination'. {-# INLINE (+>) #-}-(+>) ::- Data.File.FileSizeAndPath -- ^ The new path to prepend to the incumbent file-combination.+(+>)+ :: Data.File.FileSizeAndPath -- ^ The new path to prepend to the incumbent file-combination. -> FileCombination -- ^ The incumbent combination of files. -> FileCombination (fileSize, filePath) +> MkFileCombination {@@ -75,8 +75,8 @@ } = MkFileCombination (fileSize + s) (filePath : l) -- | Add two 'FileCombination's.-(<+>) ::- FileCombination -- ^ The combination to be prepended.+(<+>)+ :: FileCombination -- ^ The combination to be prepended. -> FileCombination -- ^ The incumbent to which the new value is prepended. -> FileCombination MkFileCombination {@@ -89,8 +89,8 @@ -- | Predicate used to determine whether a specific file-combination matches a size-related requirement. {-# INLINE hasSize #-}-hasSize ::- (Data.File.FileSize -> Bool) -- ^ The predicate.+hasSize+ :: (Data.File.FileSize -> Bool) -- ^ The predicate. -> FileCombination -- ^ The input datum to be tested. -> Bool hasSize f MkFileCombination { getAggregateFileSize = s } = f s
src/Squeeze/Squeeze.hs view
@@ -46,8 +46,8 @@ import qualified Control.Arrow import qualified Control.Monad import qualified Data.List-import qualified Factory.Data.Interval as Data.Interval-import qualified Factory.Math.Statistics as Math.Statistics+import qualified Factory.Data.Interval+import qualified Factory.Math.Statistics import qualified Squeeze.Data.CommandOptions as Data.CommandOptions import qualified Squeeze.Data.File as Data.File import qualified Squeeze.Data.FileCombination as Data.FileCombination@@ -55,8 +55,8 @@ import qualified System.IO -- | Progressively raises the selection-criterion, as each match is found.-risingFilter ::- Data.File.FileSize -- ^ The initial minimum byte-size of file to accept.+risingFilter+ :: Data.File.FileSize -- ^ The initial minimum byte-size of file to accept. -> [Data.FileCombination.FileCombination] -- ^ The input list of files to filter. -> [Data.FileCombination.FileCombination] -- ^ The resulting list of files, which have met rising criterion. risingFilter _ [] = []@@ -77,8 +77,8 @@ * The algorithm is stable, in that it maintains the specified file-order within each combination; though the order in which the combinations are concatenated is rather arbitrary. -}-findCombinations ::- Data.Interval.Interval Data.File.FileSize -- ^ The acceptable size-span of file-combinations.+findCombinations+ :: Factory.Data.Interval.Interval Data.File.FileSize -- ^ The acceptable size-span of file-combinations. -> [Data.File.FileSizeAndPath] -- ^ The input list of file-names and sizes. -> [Data.FileCombination.FileCombination] -- ^ The resulting unordered list of suitable file-combinations. findCombinations (minimumCombinationSize, maximumCombinationSize) = filter (@@ -108,10 +108,10 @@ -- | Bisects the data and calls 'findCombinations' on the halves. distribute :: RealFrac ratio- => ratio -- ^ The ratio at which to bisect the list of files, in a /divide-and-conquer/ strategy.- -> Data.Interval.Interval Data.File.FileSize -- ^ The /interval/ within which to find file-combinations.- -> [Data.File.FileSizeAndPath] -- ^ The input list of file-names and sizes.- -> [Data.FileCombination.FileCombination] -- ^ The complete unordered list of suitable file-combinations.+ => ratio -- ^ The ratio at which to bisect the list of files, in a /divide-and-conquer/ strategy.+ -> Factory.Data.Interval.Interval Data.File.FileSize -- ^ The /interval/ within which to find file-combinations.+ -> [Data.File.FileSizeAndPath] -- ^ The input list of file-names and sizes.+ -> [Data.FileCombination.FileCombination] -- ^ The complete unordered list of suitable file-combinations. distribute bisectionRatio fileSizeBounds fileSizeAndPathList | any ($ bisectionIndex) [ (<= 0),@@ -126,7 +126,7 @@ distribute' :: [Data.File.FileSizeAndPath] -> [Data.File.FileSizeAndPath] -> [Data.FileCombination.FileCombination] distribute' fileSizeAndPathListL fileSizeAndPathListR = concatMap ( \combinationL -> (combinationL <+>) `map` findCombinations (- negate (Data.FileCombination.getAggregateFileSize combinationL) `Data.Interval.shift` fileSizeBounds+ negate (Data.FileCombination.getAggregateFileSize combinationL) `Factory.Data.Interval.shift` fileSizeBounds ) fileSizeAndPathListR ) $ Control.Arrow.first (+ negate (Data.File.aggregateSize fileSizeAndPathListR)) {-Adjust the lower bound-} fileSizeBounds `findCombinations` fileSizeAndPathListL @@ -138,15 +138,15 @@ * Calls the private function 'risingFilter' to progressively select better file-combinations from those returned by 'distribute'. -} findBestFit :: RealFrac ratio- => ratio -- ^ The ratio at which to bisect the list of files, in a /divide-and-conquer/ strategy.- -> Data.Interval.Interval Data.File.FileSize -- ^ The /interval/ within which to find file-combinations.- -> [Data.File.FileSizeAndPath] -- ^ The input list of file-names and sizes.- -> [Data.FileCombination.FileCombination] -- ^ A reduced list of suitable file-combinations, sorted best first.-findBestFit bisectionRatio fileSizeBounds = risingFilter (Data.Interval.getMinBound fileSizeBounds) . distribute bisectionRatio fileSizeBounds . Data.File.order+ => ratio -- ^ The ratio at which to bisect the list of files, in a /divide-and-conquer/ strategy.+ -> Factory.Data.Interval.Interval Data.File.FileSize -- ^ The /interval/ within which to find file-combinations.+ -> [Data.File.FileSizeAndPath] -- ^ The input list of file-names and sizes.+ -> [Data.FileCombination.FileCombination] -- ^ A reduced list of suitable file-combinations, sorted best first.+findBestFit bisectionRatio fileSizeBounds = risingFilter (Factory.Data.Interval.getMinBound fileSizeBounds) . distribute bisectionRatio fileSizeBounds . Data.File.orderBySize -- | Acquire statistics related to a list of files. getFileSizeStatistics :: (Fractional mean, Floating standardDeviation) => [Data.File.FileSizeAndPath] -> (Int, Data.File.FileSize, mean, standardDeviation)-getFileSizeStatistics l = (length l, sum sizes, Math.Statistics.getMean sizes, Math.Statistics.getStandardDeviation sizes) where+getFileSizeStatistics l = (length l, sum sizes, Factory.Math.Statistics.getMean sizes, Factory.Math.Statistics.getStandardDeviation sizes) where sizes = map Data.File.getSize l {- |
src/Squeeze/Test/Performance.hs view
@@ -26,7 +26,7 @@ ) where import Control.Arrow((&&&))-import qualified Factory.Math.Probability as Math.Probability+import qualified Factory.Math.Probability import qualified Squeeze.Data.CommandOptions as Data.CommandOptions import qualified Squeeze.Data.FileCombination as Data.FileCombination import qualified Squeeze.Squeeze as Squeeze@@ -43,7 +43,7 @@ run :: (RealFrac ratio, RealFloat f, System.Random.Random f) => Data.CommandOptions.CommandOptions ratio -> Int -- ^ The number of /virtual/ files to randomly generate.- -> Math.Probability.DiscreteDistribution f+ -> Factory.Math.Probability.DiscreteDistribution f -> IO [Data.FileCombination.FileCombination] -- ^ The results.-run commandOptions fileCount probabilityDistribution = System.Random.getStdGen >>= Squeeze.findBestFitM commandOptions . map (id &&& show) . Math.Probability.generateDiscretePopulation fileCount probabilityDistribution+run commandOptions fileCount probabilityDistribution = System.Random.getStdGen >>= Squeeze.findBestFitM commandOptions . map (id &&& show) . Factory.Math.Probability.generateDiscretePopulation fileCount probabilityDistribution
src/Squeeze/Test/QC.hs view
@@ -30,7 +30,7 @@ import qualified Control.Arrow import qualified Data.List-import qualified Factory.Data.Interval as Data.Interval+import qualified Factory.Data.Interval import qualified Squeeze.Data.File as Data.File import qualified Squeeze.Data.FileCombination as Data.FileCombination import qualified Squeeze.Squeeze as Squeeze@@ -47,32 +47,32 @@ prop_bisectionRatio, prop_totalCombinations, prop_bounds, prop_all :: Testable prop_bisectionRatio fileSizeAndPathList = not (null l) ==> Test.QuickCheck.label "prop_bisectionRatio" $ (== 1) . length . Data.List.nub . map (- \bisectionRatio -> Data.List.sort . Squeeze.distribute bisectionRatio fileSizeBounds $ Data.File.order l+ \bisectionRatio -> Data.List.sort . Squeeze.distribute bisectionRatio fileSizeBounds $ Data.File.orderBySize l ) . take (length l) $ map recip [1 :: Double ..] where l :: [Data.File.FileSizeAndPath] l = take 14 {-arbitrarily-} $ translate fileSizeAndPathList --CAVEAT: may be shorter than requested. - fileSizeBounds :: Data.Interval.Interval Data.File.FileSize+ fileSizeBounds :: Factory.Data.Interval.Interval Data.File.FileSize fileSizeBounds = (minimumBytes, maximumBytes) where maximumBytes, minimumBytes :: Data.File.FileSize maximumBytes = round $ fromIntegral (Data.File.aggregateSize l) / (4.0 :: Double) --Arbitrarily. minimumBytes = maximumBytes `div` 2 --Arbitrarily. - prop_totalCombinations fileSizeAndPathList = Test.QuickCheck.label "prop_totalCombinations" $ (length . Data.List.nub . Squeeze.findCombinations (0, fromIntegral (maxBound :: Int)) $ Data.File.order l) == 2 ^ length l where+ prop_totalCombinations fileSizeAndPathList = Test.QuickCheck.label "prop_totalCombinations" $ (length . Data.List.nub . Squeeze.findCombinations (0, fromIntegral (maxBound :: Int)) $ Data.File.orderBySize l) == 2 ^ length l where l :: [Data.File.FileSizeAndPath] l = take 10 {-arbitrarily-} $ translate fileSizeAndPathList --CAVEAT: may be shorter than requested. - prop_bounds fileSizeAndPathList = Test.QuickCheck.label "prop_bounds" . all ((`Data.Interval.elem'` fileSizeBounds) . Data.FileCombination.getAggregateFileSize) . Squeeze.findCombinations fileSizeBounds $ Data.File.order l where+ prop_bounds fileSizeAndPathList = Test.QuickCheck.label "prop_bounds" . all ((`Factory.Data.Interval.elem'` fileSizeBounds) . Data.FileCombination.getAggregateFileSize) . Squeeze.findCombinations fileSizeBounds $ Data.File.orderBySize l where l :: [Data.File.FileSizeAndPath] l = take 16 {-arbitrarily-} $ translate fileSizeAndPathList --CAVEAT: may be shorter than requested. - fileSizeBounds :: Data.Interval.Interval Data.File.FileSize+ fileSizeBounds :: Factory.Data.Interval.Interval Data.File.FileSize fileSizeBounds = (minimumBytes, maximumBytes) where maximumBytes, minimumBytes :: Data.File.FileSize maximumBytes = round $ fromIntegral (Data.File.aggregateSize l) / (4.0 :: Double) --Arbitrarily. minimumBytes = maximumBytes `div` 2 --Arbitrarily. - prop_all fileSizeAndPathList = Test.QuickCheck.label "prop_all" . (== bytes) . last . map Data.FileCombination.getAggregateFileSize $ Squeeze.findBestFit (recip 2 :: Double) (Data.Interval.precisely bytes) l where+ prop_all fileSizeAndPathList = Test.QuickCheck.label "prop_all" . (== bytes) . last . map Data.FileCombination.getAggregateFileSize $ Squeeze.findBestFit (recip 2 :: Double) (Factory.Data.Interval.precisely bytes) l where l :: [Data.File.FileSizeAndPath] l = take 16 {-arbitrarily-} $ translate fileSizeAndPathList --CAVEAT: may be shorter than requested.