fishfood 0.0.1.0 → 0.0.1.3
raw patch · 13 files changed
+93/−54 lines, 13 filessetup-changed
Files
- Setup.hs +2/−2
- changelog +10/−0
- debian/DEBIAN/control +13/−0
- fishfood.cabal +7/−6
- fishfood.spec +2/−2
- makefile +11/−4
- man/man1/fishfood.1 +8/−4
- src/FishFood/Data/CommandOptions.hs +2/−2
- src/FishFood/Data/File.hs +4/−4
- src/FishFood/Profiler.hs +15/−15
- src/FishFood/Test/Data/CommandOptions.hs +3/−2
- src/FishFood/Test/Profiler.hs +1/−1
- src/Main.hs +15/−12
Setup.hs view
@@ -1,5 +1,5 @@ #!/usr/bin/env runhaskell -import qualified Distribution.Simple+import qualified Distribution.Simple -main = Distribution.Simple.defaultMain+main = Distribution.Simple.defaultMain
changelog view
@@ -8,3 +8,13 @@ * Migrated all but the I/O, from "Main" to a new module "FishFood.Profiler". * Added module "FishFood.Test", containing "Test.QuickCheck"-implementation. * Added Command-line options; '--deriveProbabilityMassFunction', '--binSizeRatio', '--runQuickChecks'.+0.0.1.1+ * Added files to build .deb to 'fishfood.cabal'.+0.0.1.2+ * Added '--runQuickChecks' to 'man/man1/fishfood.1' & corrected typo.+ * Improved the syntax of 'verbosity' in the usage-message.+ * Tested with 'haskell-platform-2013.2.0.0'.+0.0.1.3+ * In module "FishFood.Data.File", replaced 'Control.Exception.throw' with 'Control.Exception.throwIO'.+ * Either replaced instances of '(<$>)' with 'fmap' to avoid ambiguity between "Control.Applicative" & "Prelude" which (from 'base-4.8') also exports this symbol, or hid the symbol when importing the "Prelude"..+ * In module "Main", redirected version-message to stderr.
+ debian/DEBIAN/control view
@@ -0,0 +1,13 @@+Package: fishfood+Version: 0.0.1.3-1+Section: utils+Priority: optional+#Architecture: i386+Architecture: amd64+Depends: libc6+Installed-size: 2252+Maintainer: Dr. Alistair Ward <fishfood at functionalley dot eu>+Provides:+Homepage: http://functionalley.eu+Description: Counts the number of files in a set of bins, each of which holds only those files which fall within a specific size-interval.+
fishfood.cabal view
@@ -1,8 +1,8 @@---Package-properties+-- Package-properties Name: fishfood-Version: 0.0.1.0+Version: 0.0.1.3 Cabal-Version: >= 1.6-Copyright: (C) 2013 Dr. Alistair Ward+Copyright: (C) 2013-2015 Dr. Alistair Ward License: GPL License-file: LICENSE Author: Dr. Alistair Ward@@ -11,13 +11,14 @@ Build-Type: Simple Description: Counts the number of files in a set of bins, each of which holds only those files which fall within a specific size-interval. Category: Utils-Tested-With: GHC == 7.4+Tested-With: GHC == 7.4, GHC == 7.6, GHC == 7.10 Homepage: http://functionalley.eu Maintainer: fishfood <at> functionalley <dot> eu Bug-reports: fishfood <at> functionalley <dot> eu Data-files:-Extra-Source-Files: changelog copyright makefile man/man1/fishfood.1 fishfood.spec+Extra-Source-Files: changelog copyright debian/DEBIAN/control makefile man/man1/fishfood.1 fishfood.spec +-- Turn on using: 'runhaskell ./Setup.hs configure -f llvm'. flag llvm Description: Whether the 'llvm' compiler-backend has been installed and is required for code-generation. manual: True@@ -46,7 +47,7 @@ toolshed >= 0.13, unix - GHC-options: -Wall+ GHC-options: -Wall -fno-warn-tabs if impl(ghc >= 7.4.1) GHC-prof-options: -prof -fprof-auto -fprof-cafs
fishfood.spec view
@@ -1,4 +1,4 @@-# Copyright (C) 2013 Dr. Alistair Ward+# Copyright (C) 2013-2014 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@@ -22,7 +22,7 @@ Summary: Calculates file-size frequency-distribution. Name: fishfood-Version: 0.0.1.0+Version: 0.0.1.3 Release: 1 License: GPLv3 #From '/usr/share/doc/packages/rpm/GROUPS'.
makefile view
@@ -1,4 +1,4 @@-# Copyright (C) 2010 Dr. Alistair Ward+# Copyright (C) 2013-2014 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@@ -13,7 +13,7 @@ # 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 haddock help hlint install prof rpm sdist+.PHONY: all build check clean clobber configure copy deb haddock help hlint install prof rpm sdist PACKAGE_NAME=fishfood @@ -42,10 +42,10 @@ PATH=~/.cabal/bin:$$PATH runhaskell Setup $@ --hyperlink-source --executables #Amend path to find 'HsColour', as required for 'hyperlink-source'. hlint:- @$@ src/+ @$@ src/ +RTS -N sdist:- runhaskell Setup $@+ TAR_OPTIONS='--format=ustar' runhaskell Setup $@ check: sdist cabal upload --check --verbose=3 dist/*.tar.gz;@@ -53,6 +53,13 @@ rpm: $(PACKAGE_NAME).spec rpmbuild -bb --nodeps -- $^ mv -- `find ~/rpmbuild -type f -name '$(PACKAGE_NAME)*.rpm' -mtime 0 -print` ./++deb: build+ mkdir -p debian/usr/bin/ && strip --strip-all 'dist/build/$(PACKAGE_NAME)/$(PACKAGE_NAME)' && mv 'dist/build/$(PACKAGE_NAME)/$(PACKAGE_NAME)' debian/usr/bin/+ mkdir -p 'debian/usr/share/doc/$(PACKAGE_NAME)/' && cp changelog changelog.Debian copyright LICENSE 'debian/usr/share/doc/$(PACKAGE_NAME)/' && cd 'debian/usr/share/doc/$(PACKAGE_NAME)/' && gzip --best -f changelog changelog.Debian LICENSE+ mkdir -p debian/usr/share/ && cp -R man/ debian/usr/share/ && gzip --best -f debian/usr/share/man/man1/*.1+ cd debian/ && md5sum `find usr -type f -print` >'DEBIAN/md5sums'+ fakeroot dpkg-deb --build debian . clean: runhaskell Setup $@
man/man1/fishfood.1 view
@@ -23,7 +23,7 @@ \fB-d\fR \fIInt\fR, \fB--nDecimalDigits=\fR\fIInt\fR The precision to which fractional auxiliary data is displayed. .TP-\fB--verbosity=\fR\fBSilent\fR|\fBNormal\fR|\fBVerbose\fR|\fBDeafening\fR+\fB--verbosity=\fR(\fBSilent\fR|\fBNormal\fR|\fBVerbose\fR|\fBDeafening\fR) Produces additional output where appropriate; i.e. file-names, file-size statistics, & column-headers. .SS "Generic Program-information" .TP@@ -32,8 +32,12 @@ .TP \fB-?\fR, \fB--help\fR Displays help & then exits.-.SS "File-paths"+.SS Test .TP+\fB-q\fR, \fB--runQuickChecks\fR+Tests the implementation, by validating some invariant properties using arbitrary data; & then exits.+.SS File-paths+.TP If \fIFile-path\fR is a single hyphen-minus (\fB-\fR), then the list of file-paths will be read from standard-input. Only plain files are acceptable; no directories, symlinks, sockets, ... .SH EXIT-STATUS \fB0\fR on success, & >\fB0\fR if an error occurs.@@ -103,7 +107,7 @@ 1000000 1 .fi .PP-From this data one can conclude that there are 4 files whose size lies in the semi-closed interval [0, 1) bytes, 3 files in [1, 10), 100 files in [10, 100), ...+From this data one can conclude that there are 4 files whose size is zero, 2 files in the semi-closed interval [1, 10), 100 files in [10, 100), ... .IP .B find $HOME -name '*.png' -o -name '*.gif' -o -name '*.jp*g' | fishfood --verbosity=Verbose -r 2 -p - .nf@@ -161,6 +165,6 @@ .IP \(bu .B http://en.wikipedia.org/wiki/Probability_mass_function .IP \(bu-Source-documentation is generated by \fBHaddock\fR, & is available in the distribution.+Source-documentation is generated by "\fBHaddock\fR", & is available in the distribution. .IP \(bu .B http://www.haskell.org/haddock/
src/FishFood/Data/CommandOptions.hs view
@@ -65,7 +65,7 @@ instance ToolShed.Defaultable.Defaultable (CommandOptions ratio) where defaultValue = MkCommandOptions {- getBinSizeDelta = Left Nothing, --Interpreted as one standard-deviation.+ getBinSizeDelta = Left Nothing, -- Interpreted as one standard-deviation. getDeriveProbabilityMassFunction = False, getNDecimalDigits = 3, getVerbosity = Distribution.Verbosity.normal@@ -87,7 +87,7 @@ let maxNDecimalDigits = floor $ fromIntegral ( floatDigits (- undefined :: Double --CAVEAT: the actual type could be merely 'Float', but that's currently unknown.+ undefined :: Double -- CAVEAT: the actual type could be merely 'Float', but that's currently unknown. ) ) * (logBase 10 2 :: Double) in (
src/FishFood/Data/File.hs view
@@ -1,5 +1,5 @@ {-- Copyright (C) 2013 Dr. Alistair Ward+ Copyright (C) 2013-2014 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@@ -36,16 +36,16 @@ import qualified System.Posix.Files -- | A type-synonym specifically to hold file-sizes (in bytes).-type FileSize = Integer --Matches the return-type of 'IO.hFileSize'.+type FileSize = Integer -- Matches the return-type of 'IO.hFileSize'. -- | Get the size of the specified file. findSize :: System.IO.FilePath -> IO FileSize findSize f = do- stat <- System.Posix.Files.getFileStatus f --CAVEAT: throws if the user is unauthorised, or the file is non-existent.+ 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 System.IO.withFile f System.IO.ReadMode System.IO.hFileSize- else {-non-directory-} Control.Exception.throw $ System.IO.Error.mkIOError System.IO.Error.illegalOperationErrorType ("file=" ++ show f ++ " has unexpected type") Nothing (Just f)+ else {-non-directory-} Control.Exception.throwIO $ System.IO.Error.mkIOError System.IO.Error.illegalOperationErrorType ("file=" ++ show f ++ " has unexpected type") Nothing (Just f) -- | Acquire statistics related to a list of file-sizes. getFileSizeStatistics
src/FishFood/Profiler.hs view
@@ -76,24 +76,24 @@ return {-to Writer-monad-} $ if standardDeviation == 0 then return {-to List-monad-} . (,) (head fileSizes) $ if deriveProbabilityMassFunction- then Right 1 --i.e. certainty.- else Left nFiles --i.e. all.+ then Right 1 -- i.e. certainty.+ else Left nFiles -- i.e. all. else let getDefaultedBinSizeIncrement :: Maybe Data.File.FileSize -> Data.File.FileSize- getDefaultedBinSizeIncrement = Data.Maybe.fromMaybe $ round standardDeviation `max` 1 {-minimum increment-} --CAVEAT: guard against subsequent division by zero or infinite iteration.+ getDefaultedBinSizeIncrement = Data.Maybe.fromMaybe $ round standardDeviation `max` 1 {-minimum increment-} -- CAVEAT: guard against subsequent division by zero or infinite iteration. calculatedBinSizes :: [Data.File.FileSize] calculatedBinSizes = map ( \fileSize -> either (- div {-round down-} fileSize . getDefaultedBinSizeIncrement {-non-zero-} + div {-round down-} fileSize . getDefaultedBinSizeIncrement {-non-zero-} ) (- floor {-round down-} . (`logBase` fromIntegral fileSize) --CAVEAT: converts file-size 0, to bin-size -infinity.+ floor {-round down-} . (`logBase` fromIntegral fileSize) -- CAVEAT: converts file-size 0, to bin-size -infinity. ) binSizeDelta- ) fileSizes --Each bin spans the semi-closed integral interval [size, succ size), so round down fractional values to match the lower bin.+ ) fileSizes -- Each bin spans the semi-closed integral interval [size, succ size), so round down fractional values to match the lower bin. initialFrequencyDistribution :: Data.Map.Map Data.File.FileSize Int initialFrequencyDistribution = Data.Map.fromAscList . (- `zip` repeat 0 --The initial file-count.+ `zip` repeat 0 -- The initial file-count. ) . takeWhile ( <= maximum calculatedBinSizes ) . dropWhile (@@ -101,21 +101,21 @@ ) $ either ( \maybeBinSizeIncrement -> iterate (+ getDefaultedBinSizeIncrement {-non-zero-} maybeBinSizeIncrement) 0 ) (- \binRatio -> map round {-file-sizes are integral-} $ iterate (* binRatio) 1 --The sequence could be started at fractional values in the open unit-interval, but the only value less than 1 which may be required is 0 (which isn't a sequence-member), which will be created later on demand.+ \binRatio -> map round {-file-sizes are integral-} $ iterate (* binRatio) 1 -- The sequence could be started at fractional values in the open unit-interval, but the only value less than 1 which may be required is 0 (which isn't a sequence-member), which will be created later on demand. ) binSizeDelta mapBinSizeToFileSize :: Data.Map.Map Data.File.FileSize value -> Data.Map.Map Data.File.FileSize value mapBinSizeToFileSize = Data.Map.mapKeys $ \binSize -> either ( (* binSize) . getDefaultedBinSizeIncrement ) (- ceiling {-round up-} . (^^ binSize) --Converts binSize -infinity, back to file-size 0.- ) binSizeDelta --Represent each bin by the minimum file-size it can accept.+ ceiling {-round up-} . (^^ binSize) -- Converts binSize -infinity, back to file-size 0.+ ) binSizeDelta -- Represent each bin by the minimum file-size it can accept. in Data.Map.toList . ( if deriveProbabilityMassFunction then Data.Map.map Right . mapBinSizeToFileSize . Data.Map.map ((/ fromIntegral nFiles {-non-zero-}) . fromIntegral) else Data.Map.map Left . mapBinSizeToFileSize ) $ foldr (- Data.Map.insertWith (+) `flip` 1 --Count the files allocated to each bin.+ Data.Map.insertWith (+) `flip` 1 -- Count the files allocated to each bin. ) initialFrequencyDistribution calculatedBinSizes -- | Formats a file-size distribution.@@ -128,10 +128,10 @@ [ ( ($ (fileSizeWidth, fileSizeHeader)) &&& ($ (valueWidth, valueHeader))- ) . uncurry $ Text.Printf.printf "%*s", --Column-headers.- (`replicate` '=') *** (`replicate` '=') $ columnWidths --Separator-bar.+ ) . uncurry $ Text.Printf.printf "%*s", -- Column-headers.+ (`replicate` '=') *** (`replicate` '=') $ columnWidths -- Separator-bar. ] ++- ) --Section.+ ) -- Section. else id ) . map ( Text.Printf.printf "%*d" fileSizeWidth *** either (@@ -144,5 +144,5 @@ headers@(fileSizeHeader, valueHeader) = (,) "Bin-size" $ if Data.CommandOptions.getDeriveProbabilityMassFunction commandOptions then "Probability" else "Frequency" fileSizeWidth, valueWidth :: Int- columnWidths@(fileSizeWidth, valueWidth) = (`max` 10) . length *** length $ headers --CAVEAT: the data-length may exceed the header-length, so define a minimum.+ columnWidths@(fileSizeWidth, valueWidth) = (`max` 10) . length *** length $ headers -- CAVEAT: the data-length may exceed the header-length, so define a minimum.
src/FishFood/Test/Data/CommandOptions.hs view
@@ -1,6 +1,6 @@ {-# OPTIONS_GHC -fno-warn-orphans #-} {-- Copyright (C) 2013 Dr. Alistair Ward+ Copyright (C) 2013-2015 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@@ -27,7 +27,8 @@ CommandOptions ) where -import Control.Applicative((<$>), (<*>)) +import Prelude hiding ((<$>), (<*>)) -- The "Prelude" from 'base-4.8' exports this symbol.+import Control.Applicative((<$>), (<*>)) import qualified Test.QuickCheck import qualified FishFood.Data.CommandOptions as Data.CommandOptions import FishFood.Test.Data.Verbosity()
src/FishFood/Test/Profiler.hs view
@@ -49,7 +49,7 @@ prop_attendance commandOptions fileSizes = not (null fileSizes') && ToolShed.SelfValidate.isValid commandOptions' ==> Test.QuickCheck.label "prop_attendance" . ( == Data.Set.fromList fileSizes' ) . Data.Set.fromList . map Profiler.getFileSize . filter (- (/= 0) . either fromIntegral id . Profiler.getValue --Remove file-sizes which match zero actual files.+ (/= 0) . either fromIntegral id . Profiler.getValue -- Remove file-sizes which match zero actual files. ) . fst {-distribution-} . Control.Monad.Writer.runWriter $ Profiler.calculateFileSizeDistribution commandOptions' fileSizes' where fileSizes' = map abs fileSizes
src/Main.hs view
@@ -1,5 +1,5 @@ {-- Copyright (C) 2013 Dr. Alistair Ward+ Copyright (C) 2013-2015 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@@ -28,6 +28,7 @@ module Main(main) where +import Prelude hiding ((<$>), (<*>)) -- The "Prelude" from 'base-4.8' exports this symbol. import Control.Applicative((<$>),(<*>)) import qualified Control.Monad import qualified Control.Monad.Writer@@ -42,13 +43,13 @@ import qualified FishFood.Data.Verbosity as Data.Verbosity import qualified FishFood.Profiler as Profiler import qualified FishFood.Test.QuickChecks as Test.QuickChecks-import qualified Paths_fishfood as Paths --Either local stub, or package-instance autogenerated by 'Setup.hs build'.+import qualified Paths_fishfood as Paths -- Either local stub, or package-instance autogenerated by 'Setup.hs build'. 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 Text.Printf+import qualified ToolShed.Data.List import qualified ToolShed.Defaultable import qualified ToolShed.SelfValidate @@ -56,7 +57,7 @@ type CommandOptions = Data.CommandOptions.CommandOptions Double -- | Used to thread user-defined command-line options, though the list of functions which implement them.-type CommandLineAction = CommandOptions -> IO CommandOptions --Supplied as the type-argument to 'G.OptDescr'.+type CommandLineAction = CommandOptions -> IO CommandOptions -- Supplied as the type-argument to 'G.OptDescr'. -- | On failure to parse the specified string, returns an explanatory error. read' :: Read a => String -> String -> a@@ -97,7 +98,8 @@ -- String [String] (G.ArgDescr CommandLineAction) String G.Option "?" ["help"] (G.NoArg $ const printUsage) "Display this help, & then exit.", G.Option "" ["verbosity"] (- setVerbosity `G.ReqArg` show Data.Verbosity.range+ setVerbosity `G.ReqArg` ToolShed.Data.List.showListWith listDelimiters Data.Verbosity.range ""+ ) ("Define the log-level; default '" ++ show (Data.CommandOptions.getVerbosity defaultCommandOptions) ++ "'." ), G.Option "v" ["version"] (G.NoArg $ const printVersion) "Print version-information, & then exit.",@@ -105,8 +107,10 @@ G.Option "r" ["binSizeRatio"] (setBinSizeRatio `G.ReqArg` "<Float>") "The constant size-ratio in the geometric sequence of bins into which the byte-sizes of files are categorised; an alternative to 'binSizeIncrement'.", G.Option "p" ["deriveProbabilityMassFunction"] (setDeriveProbabilityMassFunction `G.OptArg` "<Bool>") ("Whether to derive the \"Probability mass function\" rather than the \"Frequency-distribution\"; default '" ++ show (Data.CommandOptions.getDeriveProbabilityMassFunction defaultCommandOptions) ++ "'."), G.Option "d" ["nDecimalDigits"] (setNDecimalDigits `G.ReqArg` "<Int>") ("The precision to which fractional auxiliary data is displayed; default " ++ show (Data.CommandOptions.getNDecimalDigits defaultCommandOptions) ++ "."),- G.Option "q" ["runQuickChecks"] (G.NoArg runQuickChecks) "Run Quick-checks using arbitrary data, & then exit."+ G.Option "q" ["runQuickChecks"] (G.NoArg runQuickChecks) "Test the implementation, by validating some invariant properties using arbitrary data; & then exit." ] where+ listDelimiters = ('(', '|', ')')+ setBinSizeIncrement, setBinSizeRatio, setNDecimalDigits, setVerbosity :: String -> CommandLineAction setBinSizeIncrement arg = return {-to IO-monad-} . Data.CommandOptions.setBinSizeIncrement (readCommandArg arg) setBinSizeRatio arg = return {-to IO-monad-} . Data.CommandOptions.setBinSizeRatio (readCommandArg arg)@@ -117,16 +121,15 @@ setDeriveProbabilityMassFunction arg commandOptions = return {-to IO-monad-} commandOptions { Data.CommandOptions.getDeriveProbabilityMassFunction = Data.Maybe.maybe True readCommandArg arg } printVersion, printUsage :: IO CommandOptions- printVersion = Text.Printf.printf "%s\n\n%s %s.\n%s.\n%s.\n%s %s.\n" packageName "Copyright (C) 2013" author "This program comes with ABSOLUTELY NO WARRANTY" "This is free software, & you are welcome to redistribute it under certain conditions" "Written by" author >> System.Exit.exitWith System.Exit.ExitSuccess where+ printVersion = System.IO.hPutStrLn System.IO.stderr (Distribution.Text.display packageIdentifier ++ "\n\nCopyright (C) 2013-2015 " ++ author ++ ".\nThis program comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it under certain conditions.\n\nWritten by " ++ author ++ ".") >> System.Exit.exitWith System.Exit.ExitSuccess where packageIdentifier :: Distribution.Package.PackageIdentifier packageIdentifier = Distribution.Package.PackageIdentifier {- Distribution.Package.pkgName = Distribution.Package.PackageName progName, --CAVEAT: coincidentally.+ Distribution.Package.pkgName = Distribution.Package.PackageName progName, -- CAVEAT: coincidentally. Distribution.Package.pkgVersion = Distribution.Version.Version (Data.Version.versionBranch Paths.version) [] } - packageName, author :: String- packageName = Distribution.Text.display packageIdentifier- author = "Dr. Alistair Ward"+ author :: String+ author = "Dr. Alistair Ward" printUsage = System.IO.hPutStrLn System.IO.stderr ("Usage:\t" ++ G.usageInfo progName optDescrList ++ " [<File-path> ...]") >> System.Exit.exitWith System.Exit.ExitSuccess @@ -163,7 +166,7 @@ else return filePaths else {-real fileNames-} return {-to IO-monad-} nonOptions - Control.Monad.when (Data.CommandOptions.getVerbosity commandOptions == maxBound) $ System.IO.hPrint System.IO.stderr filePaths --CAVEAT: potentially very long.+ Control.Monad.when (Data.CommandOptions.getVerbosity commandOptions == maxBound) $ System.IO.hPrint System.IO.stderr filePaths -- CAVEAT: potentially very long. (fileSizeDistribution, statistics) <- Control.Monad.Writer.runWriter . Profiler.calculateFileSizeDistribution commandOptions <$> mapM Data.File.findSize (Data.List.nub filePaths)