summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog1
-rw-r--r--debian/control6
-rw-r--r--joeyconfig.hs28
-rw-r--r--propellor.cabal15
-rw-r--r--src/Propellor/Bootstrap.hs9
-rw-r--r--src/Propellor/Gpg.hs2
-rw-r--r--src/Propellor/Property.hs14
-rw-r--r--src/Propellor/Property/Apt/PPA.hs3
-rw-r--r--src/Propellor/Property/Chroot.hs2
-rw-r--r--src/Propellor/Property/Docker.hs2
-rw-r--r--src/Propellor/Property/Hostname.hs2
-rw-r--r--src/Propellor/Property/Sbuild.hs4
-rw-r--r--src/Propellor/Property/SiteSpecific/JoeySites.hs2
-rw-r--r--src/Propellor/Property/Systemd.hs2
-rw-r--r--src/Propellor/Property/ZFS/Process.hs3
-rw-r--r--src/Propellor/Ssh.hs18
-rw-r--r--src/Propellor/Types/Dns.hs8
-rw-r--r--src/Propellor/Types/ZFS.hs4
-rw-r--r--src/Utility/FileMode.hs22
-rw-r--r--src/Utility/FileSystemEncoding.hs39
-rw-r--r--src/Utility/LinuxMkLibs.hs2
-rw-r--r--src/Utility/PartialPrelude.hs2
-rw-r--r--src/Utility/Path.hs28
-rw-r--r--src/Utility/Process.hs28
-rw-r--r--src/Utility/SafeCommand.hs4
-rw-r--r--src/Utility/Scheduled.hs2
-rw-r--r--src/Utility/Split.hs28
-rw-r--r--src/Utility/Tuple.hs17
28 files changed, 171 insertions, 126 deletions
diff --git a/debian/changelog b/debian/changelog
index 43e3cd6f..80ff4b38 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -11,6 +11,7 @@ propellor (4.0.3) unstable; urgency=medium
Thanks, Daniel Brooks.
* Added Propellor.Property.Bootstrap, which can be used to make
disk images contain their own installation of propellor.
+ * Removed dependency on MissingH, instead depends on split and hashable.
-- Joey Hess <id@joeyh.name> Thu, 20 Apr 2017 00:54:32 -0400
diff --git a/debian/control b/debian/control
index 289e663b..e6819060 100644
--- a/debian/control
+++ b/debian/control
@@ -7,7 +7,7 @@ Build-Depends:
ghc (>= 7.6),
cabal-install,
libghc-async-dev,
- libghc-missingh-dev,
+ libghc-split-dev,
libghc-hslogger-dev,
libghc-unix-compat-dev,
libghc-ansi-terminal-dev,
@@ -18,6 +18,7 @@ Build-Depends:
libghc-exceptions-dev (>= 0.6),
libghc-stm-dev,
libghc-text-dev,
+ libghc-hashable-dev,
libghc-concurrent-output-dev,
Maintainer: Joey Hess <id@joeyh.name>
Standards-Version: 3.9.8
@@ -31,7 +32,7 @@ Depends: ${misc:Depends}, ${shlibs:Depends},
ghc (>= 7.4),
cabal-install,
libghc-async-dev,
- libghc-missingh-dev,
+ libghc-split-dev,
libghc-hslogger-dev,
libghc-unix-compat-dev,
libghc-ansi-terminal-dev,
@@ -42,6 +43,7 @@ Depends: ${misc:Depends}, ${shlibs:Depends},
libghc-exceptions-dev (>= 0.6),
libghc-stm-dev,
libghc-text-dev,
+ libghc-hashable-dev,
libghc-concurrent-output-dev,
git,
Description: property-based host configuration management in haskell
diff --git a/joeyconfig.hs b/joeyconfig.hs
index 58b9263b..dbba0ea4 100644
--- a/joeyconfig.hs
+++ b/joeyconfig.hs
@@ -50,7 +50,6 @@ hosts = -- (o) `
, gnu
, clam
, mayfly
- , oyster
, orca
, baleen
, honeybee
@@ -118,7 +117,7 @@ clam :: Host
clam = host "clam.kitenet.net" $ props
& standardSystem Unstable X86_64
["Unreliable server. Anything here may be lost at any time!" ]
- & ipv4 "167.88.41.194"
+ & ipv4 "64.137.231.62"
& CloudAtCost.decruft
& Ssh.hostKeys hostContext
@@ -157,31 +156,6 @@ mayfly = host "mayfly.kitenet.net" $ props
& Tor.named "kite3"
& Tor.bandwidthRate (Tor.PerMonth "400 GB")
-oyster :: Host
-oyster = host "oyster.kitenet.net" $ props
- & standardSystem Unstable X86_64
- [ "Unreliable server. Anything here may be lost at any time!" ]
- & ipv4 "64.137.179.21"
-
- & CloudAtCost.decruft
- & Ssh.hostKeys hostContext
- [ (SshEcdsa, "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBP0ws/IxQegVU0RhqnIm5A/vRSPTO70wD4o2Bd1jL970dTetNyXzvWGe1spEbLjIYSLIO7WvOBSE5RhplBKFMUU=")
- ]
- & Apt.unattendedUpgrades
- & Network.ipv6to4
- & Systemd.persistentJournal
- & Journald.systemMaxUse "500MiB"
- & Apt.serviceInstalledRunning "swapspace"
-
- & Tor.isRelay
- & Tor.named "kite4"
- & Tor.bandwidthRate (Tor.PerMonth "400 GB")
-
- -- Nothing is using http port 80, so listen on
- -- that port for ssh, for traveling on bad networks that
- -- block 22.
- & Ssh.listenPort (Port 80)
-
baleen :: Host
baleen = host "baleen.kitenet.net" $ props
& standardSystem Unstable X86_64 [ "New git-annex build box." ]
diff --git a/propellor.cabal b/propellor.cabal
index a5ed5ed9..9dda1ad8 100644
--- a/propellor.cabal
+++ b/propellor.cabal
@@ -46,9 +46,9 @@ Executable propellor
-- propellor needs to support the ghc shipped in Debian stable,
-- and also only depends on packages in Debian stable.
base >= 4.5, base < 5,
- MissingH, directory, filepath, IfElse, process, bytestring, hslogger,
+ directory, filepath, IfElse, process, bytestring, hslogger, split,
unix, unix-compat, ansi-terminal, containers (>= 0.5), network, async,
- time, mtl, transformers, exceptions (>= 0.6), stm, text
+ time, mtl, transformers, exceptions (>= 0.6), stm, text, hashable
Other-Modules:
Propellor.DotDir
@@ -61,9 +61,9 @@ Executable propellor-config
Hs-Source-Dirs: src
Build-Depends:
base >= 4.5, base < 5,
- MissingH, directory, filepath, IfElse, process, bytestring, hslogger,
+ directory, filepath, IfElse, process, bytestring, hslogger, split,
unix, unix-compat, ansi-terminal, containers (>= 0.5), network, async,
- time, mtl, transformers, exceptions (>= 0.6), stm, text
+ time, mtl, transformers, exceptions (>= 0.6), stm, text, hashable
Library
GHC-Options: -Wall -fno-warn-tabs -O0
@@ -73,9 +73,9 @@ Library
Hs-Source-Dirs: src
Build-Depends:
base >= 4.5, base < 5,
- MissingH, directory, filepath, IfElse, process, bytestring, hslogger,
+ directory, filepath, IfElse, process, bytestring, hslogger, split,
unix, unix-compat, ansi-terminal, containers (>= 0.5), network, async,
- time, mtl, transformers, exceptions (>= 0.6), stm, text
+ time, mtl, transformers, exceptions (>= 0.6), stm, text, hashable
Exposed-Modules:
Propellor
@@ -222,10 +222,13 @@ Library
Utility.Process.NonConcurrent
Utility.SafeCommand
Utility.Scheduled
+ Utility.Scheduled
+ Utility.Split
Utility.SystemDirectory
Utility.Table
Utility.ThreadScheduler
Utility.Tmp
+ Utility.Tuple
Utility.UserInfo
System.Console.Concurrent
System.Console.Concurrent.Internal
diff --git a/src/Propellor/Bootstrap.hs b/src/Propellor/Bootstrap.hs
index 29c55213..a3b7f315 100644
--- a/src/Propellor/Bootstrap.hs
+++ b/src/Propellor/Bootstrap.hs
@@ -83,7 +83,7 @@ depsCommand msys = "( " ++ intercalate " ; " (concat [osinstall, cabalinstall])
, "ghc"
, "cabal-install"
, "libghc-async-dev"
- , "libghc-missingh-dev"
+ , "libghc-split-dev"
, "libghc-hslogger-dev"
, "libghc-unix-compat-dev"
, "libghc-ansi-terminal-dev"
@@ -94,13 +94,14 @@ depsCommand msys = "( " ++ intercalate " ; " (concat [osinstall, cabalinstall])
, "libghc-exceptions-dev"
, "libghc-stm-dev"
, "libghc-text-dev"
+ , "libghc-hashable-dev"
]
fbsddeps =
[ "gnupg"
, "ghc"
, "hs-cabal-install"
, "hs-async"
- , "hs-MissingH"
+ , "hs-split"
, "hs-hslogger"
, "hs-unix-compat"
, "hs-ansi-terminal"
@@ -111,13 +112,14 @@ depsCommand msys = "( " ++ intercalate " ; " (concat [osinstall, cabalinstall])
, "hs-exceptions"
, "hs-stm"
, "hs-text"
+ , "hs-hashable"
]
archlinuxdeps =
[ "gnupg"
, "ghc"
, "cabal-install"
, "haskell-async"
- , "haskell-missingh"
+ , "haskell-split"
, "haskell-hslogger"
, "haskell-unix-compat"
, "haskell-ansi-terminal"
@@ -129,6 +131,7 @@ depsCommand msys = "( " ++ intercalate " ; " (concat [osinstall, cabalinstall])
, "haskell-exceptions"
, "haskell-stm"
, "haskell-text"
+ , "hashell-hashable"
]
installGitCommand :: Maybe System -> ShellCommand
diff --git a/src/Propellor/Gpg.hs b/src/Propellor/Gpg.hs
index 6ac153cc..43c4eddf 100644
--- a/src/Propellor/Gpg.hs
+++ b/src/Propellor/Gpg.hs
@@ -2,7 +2,6 @@ module Propellor.Gpg where
import System.IO
import Data.Maybe
-import Data.List.Utils
import Control.Monad
import Control.Applicative
import Prelude
@@ -18,6 +17,7 @@ import Utility.Misc
import Utility.Tmp
import Utility.Env
import Utility.Directory
+import Utility.Split
type KeyId = String
diff --git a/src/Propellor/Property.hs b/src/Propellor/Property.hs
index 94c82c9f..8b2a4e3d 100644
--- a/src/Propellor/Property.hs
+++ b/src/Propellor/Property.hs
@@ -50,8 +50,8 @@ import Data.Monoid
import Control.Monad.IfElse
import "mtl" Control.Monad.RWS.Strict
import System.Posix.Files
-import qualified Data.Hash.MD5 as MD5
import Data.List
+import Data.Hashable
import Control.Applicative
import Prelude
@@ -64,8 +64,8 @@ import Propellor.Info
import Propellor.EnsureProperty
import Utility.Exception
import Utility.Monad
-import Utility.Misc
import Utility.Directory
+import Utility.Misc
-- | Makes a perhaps non-idempotent Property be idempotent by using a flag
-- file to indicate whether it has run before.
@@ -228,12 +228,12 @@ changesFile p f = checkResult getstat comparestat p
-- Changes to mtime etc that do not change file content are treated as
-- NoChange.
changesFileContent :: Checkable p i => p i -> FilePath -> Property i
-changesFileContent p f = checkResult getmd5 comparemd5 p
+changesFileContent p f = checkResult gethash comparehash p
where
- getmd5 = catchMaybeIO $ MD5.md5 . MD5.Str <$> readFileStrict f
- comparemd5 oldmd5 = do
- newmd5 <- getmd5
- return $ if oldmd5 == newmd5 then NoChange else MadeChange
+ gethash = catchMaybeIO $ hash <$> readFileStrict f
+ comparehash oldhash = do
+ newhash <- gethash
+ return $ if oldhash == newhash then NoChange else MadeChange
-- | Determines if the first file is newer than the second file.
--
diff --git a/src/Propellor/Property/Apt/PPA.hs b/src/Propellor/Property/Apt/PPA.hs
index 346125ff..a8f7db15 100644
--- a/src/Propellor/Property/Apt/PPA.hs
+++ b/src/Propellor/Property/Apt/PPA.hs
@@ -6,10 +6,11 @@ module Propellor.Property.Apt.PPA where
import Data.List
import Control.Applicative
import Prelude
-import Data.String.Utils
import Data.String (IsString(..))
+
import Propellor.Base
import qualified Propellor.Property.Apt as Apt
+import Utility.Split
-- | Ensure software-properties-common is installed.
installed :: Property DebianLike
diff --git a/src/Propellor/Property/Chroot.hs b/src/Propellor/Property/Chroot.hs
index 5f764d47..ad2ae705 100644
--- a/src/Propellor/Property/Chroot.hs
+++ b/src/Propellor/Property/Chroot.hs
@@ -33,9 +33,9 @@ import qualified Propellor.Property.File as File
import qualified Propellor.Shim as Shim
import Propellor.Property.Mount
import Utility.FileMode
+import Utility.Split
import qualified Data.Map as M
-import Data.List.Utils
import System.Posix.Directory
import System.Console.Concurrent
diff --git a/src/Propellor/Property/Docker.hs b/src/Propellor/Property/Docker.hs
index 1080418b..d53bab71 100644
--- a/src/Propellor/Property/Docker.hs
+++ b/src/Propellor/Property/Docker.hs
@@ -59,13 +59,13 @@ import qualified Propellor.Property.Pacman as Pacman
import qualified Propellor.Shim as Shim
import Utility.Path
import Utility.ThreadScheduler
+import Utility.Split
import Control.Concurrent.Async hiding (link)
import System.Posix.Directory
import System.Posix.Process
import Prelude hiding (init)
import Data.List hiding (init)
-import Data.List.Utils
import qualified Data.Map as M
import System.Console.Concurrent
diff --git a/src/Propellor/Property/Hostname.hs b/src/Propellor/Property/Hostname.hs
index e1342d91..1eb9d690 100644
--- a/src/Propellor/Property/Hostname.hs
+++ b/src/Propellor/Property/Hostname.hs
@@ -3,9 +3,9 @@ module Propellor.Property.Hostname where
import Propellor.Base
import qualified Propellor.Property.File as File
import Propellor.Property.Chroot (inChroot)
+import Utility.Split
import Data.List
-import Data.List.Utils
-- | Ensures that the hostname is set using best practices, to whatever
-- name the `Host` has.
diff --git a/src/Propellor/Property/Sbuild.hs b/src/Propellor/Property/Sbuild.hs
index 00109381..460d0b16 100644
--- a/src/Propellor/Property/Sbuild.hs
+++ b/src/Propellor/Property/Sbuild.hs
@@ -98,10 +98,10 @@ import qualified Propellor.Property.File as File
import qualified Propellor.Property.Schroot as Schroot
import qualified Propellor.Property.Reboot as Reboot
import qualified Propellor.Property.User as User
-
import Utility.FileMode
+import Utility.Split
+
import Data.List
-import Data.List.Utils
type Suite = String
diff --git a/src/Propellor/Property/SiteSpecific/JoeySites.hs b/src/Propellor/Property/SiteSpecific/JoeySites.hs
index 063a2eda..9b4a3378 100644
--- a/src/Propellor/Property/SiteSpecific/JoeySites.hs
+++ b/src/Propellor/Property/SiteSpecific/JoeySites.hs
@@ -22,10 +22,10 @@ import qualified Propellor.Property.Systemd as Systemd
import qualified Propellor.Property.Fail2Ban as Fail2Ban
import qualified Propellor.Property.LetsEncrypt as LetsEncrypt
import Utility.FileMode
+import Utility.Split
import Data.List
import System.Posix.Files
-import Data.String.Utils
scrollBox :: Property (HasInfo + DebianLike)
scrollBox = propertyList "scroll server" $ props
diff --git a/src/Propellor/Property/Systemd.hs b/src/Propellor/Property/Systemd.hs
index 7c40bd16..d1a94aa8 100644
--- a/src/Propellor/Property/Systemd.hs
+++ b/src/Propellor/Property/Systemd.hs
@@ -55,9 +55,9 @@ import qualified Propellor.Property.Apt as Apt
import qualified Propellor.Property.File as File
import Propellor.Property.Systemd.Core
import Utility.FileMode
+import Utility.Split
import Data.List
-import Data.List.Utils
import qualified Data.Map as M
type ServiceName = String
diff --git a/src/Propellor/Property/ZFS/Process.hs b/src/Propellor/Property/ZFS/Process.hs
index 372bac6d..42b23df2 100644
--- a/src/Propellor/Property/ZFS/Process.hs
+++ b/src/Propellor/Property/ZFS/Process.hs
@@ -5,7 +5,8 @@
module Propellor.Property.ZFS.Process where
import Propellor.Base
-import Data.String.Utils (split)
+import Utility.Split
+
import Data.List
-- | Gets the properties of a ZFS volume.
diff --git a/src/Propellor/Ssh.hs b/src/Propellor/Ssh.hs
index a7a9452e..a8f50ed0 100644
--- a/src/Propellor/Ssh.hs
+++ b/src/Propellor/Ssh.hs
@@ -6,7 +6,7 @@ import Utility.FileSystemEncoding
import System.PosixCompat
import Data.Time.Clock.POSIX
-import qualified Data.Hash.MD5 as MD5
+import Data.Hashable
-- Parameters can be passed to both ssh and scp, to enable a ssh connection
-- caching socket.
@@ -50,24 +50,22 @@ sshCachingParams hn = do
-- 100 bytes. Try to never construct a filename longer than that.
--
-- When space allows, include the full hostname in the socket filename.
--- Otherwise, include at least a partial md5sum of it,
--- to avoid using the same socket file for multiple hosts.
+-- Otherwise, a checksum of the hostname is included in the name, to
+-- avoid using the same socket file for multiple hosts.
socketFile :: FilePath -> HostName -> FilePath
socketFile home hn = selectSocketFile
- [ sshdir </> hn ++ ".sock"
+ [ sshdir </> hn ++ ".sock"
, sshdir </> hn
- , sshdir </> take 10 hn ++ "-" ++ md5
- , sshdir </> md5
- , home </> ".propellor-" ++ md5
+ , sshdir </> take 10 hn ++ "-" ++ checksum
+ , sshdir </> checksum
]
- (".propellor-" ++ md5)
+ (home </> ".propellor-" ++ checksum)
where
sshdir = home </> ".ssh" </> "propellor"
- md5 = take 9 $ MD5.md5s $ MD5.Str hn
+ checksum = take 9 $ show $ abs $ hash hn
selectSocketFile :: [FilePath] -> FilePath -> FilePath
selectSocketFile [] d = d
-selectSocketFile [f] _ = f
selectSocketFile (f:fs) d
| valid_unix_socket_path f = f
| otherwise = selectSocketFile fs d
diff --git a/src/Propellor/Types/Dns.hs b/src/Propellor/Types/Dns.hs
index 8d62e63b..87756d81 100644
--- a/src/Propellor/Types/Dns.hs
+++ b/src/Propellor/Types/Dns.hs
@@ -6,12 +6,12 @@ import Propellor.Types.OS (HostName)
import Propellor.Types.Empty
import Propellor.Types.Info
import Propellor.Types.ConfigurableValue
+import Utility.Split
import Data.Word
import qualified Data.Map as M
import qualified Data.Set as S
import Data.List
-import Data.String.Utils (split, replace)
import Data.Monoid
import Prelude
@@ -102,14 +102,14 @@ data Record
type ReverseIP = String
reverseIP :: IPAddr -> ReverseIP
-reverseIP (IPv4 addr) = intercalate "." (reverse $ split "." addr) ++ ".in-addr.arpa"
+reverseIP (IPv4 addr) = intercalate "." (reverse $ splitc '.' addr) ++ ".in-addr.arpa"
reverseIP addr@(IPv6 _) = reverse (intersperse '.' $ replace ":" "" $ val $ canonicalIP addr) ++ ".ip6.arpa"
-- | Converts an IP address (particularly IPv6) to canonical, fully
-- expanded form.
canonicalIP :: IPAddr -> IPAddr
canonicalIP (IPv4 addr) = IPv4 addr
-canonicalIP (IPv6 addr) = IPv6 $ intercalate ":" $ map canonicalGroup $ split ":" $ replaceImplicitGroups addr
+canonicalIP (IPv6 addr) = IPv6 $ intercalate ":" $ map canonicalGroup $ splitc ':' $ replaceImplicitGroups addr
where
canonicalGroup g
| l <= 4 = replicate (4 - l) '0' ++ g
@@ -117,7 +117,7 @@ canonicalIP (IPv6 addr) = IPv6 $ intercalate ":" $ map canonicalGroup $ split ":
where
l = length g
emptyGroups n = iterate (++ ":") "" !! n
- numberOfImplicitGroups a = 8 - length (split ":" $ replace "::" "" a)
+ numberOfImplicitGroups a = 8 - length (splitc ':' $ replace "::" "" a)
replaceImplicitGroups a = concat $ aux $ split "::" a
where
aux [] = []
diff --git a/src/Propellor/Types/ZFS.hs b/src/Propellor/Types/ZFS.hs
index 22b848fa..c68f6ba5 100644
--- a/src/Propellor/Types/ZFS.hs
+++ b/src/Propellor/Types/ZFS.hs
@@ -7,10 +7,10 @@
module Propellor.Types.ZFS where
import Propellor.Types.ConfigurableValue
+import Utility.Split
import Data.String
import qualified Data.Set as Set
-import qualified Data.String.Utils as SU
import Data.List
-- | A single ZFS filesystem.
@@ -46,7 +46,7 @@ instance Show ZDataset where
show = val
instance IsString ZDataset where
- fromString s = ZDataset $ SU.split "/" s
+ fromString s = ZDataset $ splitc '/' s
instance IsString ZPool where
fromString p = ZPool p
diff --git a/src/Utility/FileMode.hs b/src/Utility/FileMode.hs
index bb3780c6..d9a26944 100644
--- a/src/Utility/FileMode.hs
+++ b/src/Utility/FileMode.hs
@@ -1,6 +1,6 @@
{- File mode utilities.
-
- - Copyright 2010-2012 Joey Hess <id@joeyh.name>
+ - Copyright 2010-2017 Joey Hess <id@joeyh.name>
-
- License: BSD-2-clause
-}
@@ -130,6 +130,21 @@ withUmask umask a = bracket setup cleanup go
withUmask _ a = a
#endif
+getUmask :: IO FileMode
+#ifndef mingw32_HOST_OS
+getUmask = bracket setup cleanup return
+ where
+ setup = setFileCreationMask nullFileMode
+ cleanup = setFileCreationMask
+#else
+getUmask = return nullFileMode
+#endif
+
+defaultFileMode :: IO FileMode
+defaultFileMode = do
+ umask <- getUmask
+ return $ intersectFileModes (complement umask) stdFileMode
+
combineModes :: [FileMode] -> FileMode
combineModes [] = 0
combineModes [m] = m
@@ -162,7 +177,10 @@ writeFileProtected file content = writeFileProtected' file
(\h -> hPutStr h content)
writeFileProtected' :: FilePath -> (Handle -> IO ()) -> IO ()
-writeFileProtected' file writer = withUmask 0o0077 $
+writeFileProtected' file writer = protectedOutput $
withFile file WriteMode $ \h -> do
void $ tryIO $ modifyFileMode file $ removeModes otherGroupModes
writer h
+
+protectedOutput :: IO a -> IO a
+protectedOutput = withUmask 0o0077
diff --git a/src/Utility/FileSystemEncoding.hs b/src/Utility/FileSystemEncoding.hs
index be43ace9..862f0721 100644
--- a/src/Utility/FileSystemEncoding.hs
+++ b/src/Utility/FileSystemEncoding.hs
@@ -10,8 +10,8 @@
module Utility.FileSystemEncoding (
useFileSystemEncoding,
+ fileEncoding,
withFilePath,
- md5FilePath,
decodeBS,
encodeBS,
decodeW8,
@@ -19,6 +19,8 @@ module Utility.FileSystemEncoding (
encodeW8NUL,
decodeW8NUL,
truncateFilePath,
+ s2w8,
+ w82s,
) where
import qualified GHC.Foreign as GHC
@@ -26,17 +28,15 @@ import qualified GHC.IO.Encoding as Encoding
import Foreign.C
import System.IO
import System.IO.Unsafe
-import qualified Data.Hash.MD5 as MD5
import Data.Word
-import Data.Bits.Utils
import Data.List
-import Data.List.Utils
import qualified Data.ByteString.Lazy as L
#ifdef mingw32_HOST_OS
import qualified Data.ByteString.Lazy.UTF8 as L8
#endif
import Utility.Exception
+import Utility.Split
{- Makes all subsequent Handles that are opened, as well as stdio Handles,
- use the filesystem encoding, instead of the encoding of the current
@@ -63,6 +63,13 @@ useFileSystemEncoding = do
hSetEncoding stderr e
Encoding.setLocaleEncoding e
+fileEncoding :: Handle -> IO ()
+#ifndef mingw32_HOST_OS
+fileEncoding h = hSetEncoding h =<< Encoding.getFileSystemEncoding
+#else
+fileEncoding h = hSetEncoding h Encoding.utf8
+#endif
+
{- Marshal a Haskell FilePath into a NUL terminated C string using temporary
- storage. The FilePath is encoded using the filesystem encoding,
- reversing the decoding that should have been done when the FilePath
@@ -93,10 +100,6 @@ _encodeFilePath fp = unsafePerformIO $ do
GHC.withCString enc fp (GHC.peekCString Encoding.char8)
`catchNonAsync` (\_ -> return fp)
-{- Encodes a FilePath into a Md5.Str, applying the filesystem encoding. -}
-md5FilePath :: FilePath -> MD5.Str
-md5FilePath = MD5.Str . _encodeFilePath
-
{- Decodes a ByteString into a FilePath, applying the filesystem encoding. -}
decodeBS :: L.ByteString -> FilePath
#ifndef mingw32_HOST_OS
@@ -137,14 +140,26 @@ decodeW8 = s2w8 . _encodeFilePath
{- Like encodeW8 and decodeW8, but NULs are passed through unchanged. -}
encodeW8NUL :: [Word8] -> FilePath
-encodeW8NUL = intercalate nul . map encodeW8 . split (s2w8 nul)
+encodeW8NUL = intercalate [nul] . map encodeW8 . splitc (c2w8 nul)
where
- nul = ['\NUL']
+ nul = '\NUL'
decodeW8NUL :: FilePath -> [Word8]
-decodeW8NUL = intercalate (s2w8 nul) . map decodeW8 . split nul
+decodeW8NUL = intercalate [c2w8 nul] . map decodeW8 . splitc nul
where
- nul = ['\NUL']
+ nul = '\NUL'
+
+c2w8 :: Char -> Word8
+c2w8 = fromIntegral . fromEnum
+
+w82c :: Word8 -> Char
+w82c = toEnum . fromIntegral
+
+s2w8 :: String -> [Word8]
+s2w8 = map c2w8
+
+w82s :: [Word8] -> String
+w82s = map w82c
{- Truncates a FilePath to the given number of bytes (or less),
- as represented on disk.
diff --git a/src/Utility/LinuxMkLibs.hs b/src/Utility/LinuxMkLibs.hs
index 122f3964..15f82fd1 100644
--- a/src/Utility/LinuxMkLibs.hs
+++ b/src/Utility/LinuxMkLibs.hs
@@ -12,10 +12,10 @@ import Utility.Directory
import Utility.Process
import Utility.Monad
import Utility.Path
+import Utility.Split
import Data.Maybe
import System.FilePath
-import Data.List.Utils
import System.Posix.Files
import Data.Char
import Control.Monad.IfElse
diff --git a/src/Utility/PartialPrelude.hs b/src/Utility/PartialPrelude.hs
index 55795563..47e98318 100644
--- a/src/Utility/PartialPrelude.hs
+++ b/src/Utility/PartialPrelude.hs
@@ -2,7 +2,7 @@
- bugs.
-
- This exports functions that conflict with the prelude, which avoids
- - them being accidentially used.
+ - them being accidentally used.
-}
{-# OPTIONS_GHC -fno-warn-tabs #-}
diff --git a/src/Utility/Path.hs b/src/Utility/Path.hs
index 3ee5ff39..2383ad06 100644
--- a/src/Utility/Path.hs
+++ b/src/Utility/Path.hs
@@ -10,7 +10,6 @@
module Utility.Path where
-import Data.String.Utils
import System.FilePath
import Data.List
import Data.Maybe
@@ -25,7 +24,6 @@ import System.Posix.Files
import Utility.Exception
#endif
-import qualified "MissingH" System.Path as MissingH
import Utility.Monad
import Utility.UserInfo
import Utility.Directory
@@ -68,18 +66,6 @@ simplifyPath path = dropTrailingPathSeparator $
absPathFrom :: FilePath -> FilePath -> FilePath
absPathFrom dir path = simplifyPath (combine dir path)
-{- On Windows, this converts the paths to unix-style, in order to run
- - MissingH's absNormPath on them. -}
-absNormPathUnix :: FilePath -> FilePath -> Maybe FilePath
-#ifndef mingw32_HOST_OS
-absNormPathUnix dir path = MissingH.absNormPath dir path
-#else
-absNormPathUnix dir path = todos <$> MissingH.absNormPath (fromdos dir) (fromdos path)
- where
- fromdos = replace "\\" "/"
- todos = replace "/" "\\"
-#endif
-
{- takeDirectory "foo/bar/" is "foo/bar". This instead yields "foo" -}
parentDir :: FilePath -> FilePath
parentDir = takeDirectory . dropTrailingPathSeparator
@@ -89,12 +75,11 @@ parentDir = takeDirectory . dropTrailingPathSeparator
upFrom :: FilePath -> Maybe FilePath
upFrom dir
| length dirs < 2 = Nothing
- | otherwise = Just $ joinDrive drive (intercalate s $ init dirs)
+ | otherwise = Just $ joinDrive drive $ joinPath $ init dirs
where
-- on Unix, the drive will be "/" when the dir is absolute, otherwise ""
(drive, path) = splitDrive dir
- dirs = filter (not . null) $ split s path
- s = [pathSeparator]
+ dirs = filter (not . null) $ splitPath path
prop_upFrom_basics :: FilePath -> Bool
prop_upFrom_basics dir
@@ -149,11 +134,10 @@ relPathDirToFile from to = relPathDirToFileAbs <$> absPath from <*> absPath to
relPathDirToFileAbs :: FilePath -> FilePath -> FilePath
relPathDirToFileAbs from to
| takeDrive from /= takeDrive to = to
- | otherwise = intercalate s $ dotdots ++ uncommon
+ | otherwise = joinPath $ dotdots ++ uncommon
where
- s = [pathSeparator]
- pfrom = split s from
- pto = split s to
+ pfrom = splitPath from
+ pto = splitPath to
common = map fst $ takeWhile same $ zip pfrom pto
same (c,d) = c == d
uncommon = drop numcommon pto
@@ -227,6 +211,8 @@ inPath command = isJust <$> searchPath command
-
- The command may be fully qualified already, in which case it will
- be returned if it exists.
+ -
+ - Note that this will find commands in PATH that are not executable.
-}
searchPath :: String -> IO (Maybe FilePath)
searchPath command
diff --git a/src/Utility/Process.hs b/src/Utility/Process.hs
index ed02f49e..6d981cb5 100644
--- a/src/Utility/Process.hs
+++ b/src/Utility/Process.hs
@@ -174,22 +174,21 @@ createBackgroundProcess p a = a =<< createProcess p
-- returns a transcript combining its stdout and stderr, and
-- whether it succeeded or failed.
processTranscript :: String -> [String] -> (Maybe String) -> IO (String, Bool)
-processTranscript = processTranscript' id
+processTranscript cmd opts = processTranscript' (proc cmd opts)
-processTranscript' :: (CreateProcess -> CreateProcess) -> String -> [String] -> Maybe String -> IO (String, Bool)
-processTranscript' modproc cmd opts input = do
+processTranscript' :: CreateProcess -> Maybe String -> IO (String, Bool)
+processTranscript' cp input = do
#ifndef mingw32_HOST_OS
{- This implementation interleves stdout and stderr in exactly the order
- the process writes them. -}
(readf, writef) <- System.Posix.IO.createPipe
readh <- System.Posix.IO.fdToHandle readf
writeh <- System.Posix.IO.fdToHandle writef
- p@(_, _, _, pid) <- createProcess $ modproc $
- (proc cmd opts)
- { std_in = if isJust input then CreatePipe else Inherit
- , std_out = UseHandle writeh
- , std_err = UseHandle writeh
- }
+ p@(_, _, _, pid) <- createProcess $ cp
+ { std_in = if isJust input then CreatePipe else Inherit
+ , std_out = UseHandle writeh
+ , std_err = UseHandle writeh
+ }
hClose writeh
get <- mkreader readh
@@ -200,12 +199,11 @@ processTranscript' modproc cmd opts input = do
return (transcript, ok)
#else
{- This implementation for Windows puts stderr after stdout. -}
- p@(_, _, _, pid) <- createProcess $ modproc $
- (proc cmd opts)
- { std_in = if isJust input then CreatePipe else Inherit
- , std_out = CreatePipe
- , std_err = CreatePipe
- }
+ p@(_, _, _, pid) <- createProcess $ cp
+ { std_in = if isJust input then CreatePipe else Inherit
+ , std_out = CreatePipe
+ , std_err = CreatePipe
+ }
getout <- mkreader (stdoutHandle p)
geterr <- mkreader (stderrHandle p)
diff --git a/src/Utility/SafeCommand.hs b/src/Utility/SafeCommand.hs
index 5ce17a84..eb34d3de 100644
--- a/src/Utility/SafeCommand.hs
+++ b/src/Utility/SafeCommand.hs
@@ -11,7 +11,7 @@ module Utility.SafeCommand where
import System.Exit
import Utility.Process
-import Data.String.Utils
+import Utility.Split
import System.FilePath
import Data.Char
import Data.List
@@ -86,7 +86,7 @@ shellEscape :: String -> String
shellEscape f = "'" ++ escaped ++ "'"
where
-- replace ' with '"'"'
- escaped = intercalate "'\"'\"'" $ split "'" f
+ escaped = intercalate "'\"'\"'" $ splitc '\'' f
-- | Unescapes a set of shellEscaped words or filenames.
shellUnEscape :: String -> [String]
diff --git a/src/Utility/Scheduled.hs b/src/Utility/Scheduled.hs
index d23aaf03..b68ff901 100644
--- a/src/Utility/Scheduled.hs
+++ b/src/Utility/Scheduled.hs
@@ -29,6 +29,7 @@ module Utility.Scheduled (
import Utility.Data
import Utility.PartialPrelude
import Utility.Misc
+import Utility.Tuple
import Data.List
import Data.Time.Clock
@@ -37,7 +38,6 @@ import Data.Time.Calendar
import Data.Time.Calendar.WeekDate
import Data.Time.Calendar.OrdinalDate
import Data.Time.Format ()
-import Data.Tuple.Utils
import Data.Char
import Control.Applicative
import Prelude
diff --git a/src/Utility/Split.hs b/src/Utility/Split.hs
new file mode 100644
index 00000000..b3e5e276
--- /dev/null
+++ b/src/Utility/Split.hs
@@ -0,0 +1,28 @@
+{- split utility functions
+ -
+ - Copyright 2017 Joey Hess <id@joeyh.name>
+ -
+ - License: BSD-2-clause
+ -}
+
+module Utility.Split where
+
+import Data.List (intercalate)
+import Data.List.Split (splitOn)
+
+-- | same as Data.List.Utils.split
+--
+-- intercalate x . splitOn x === id
+split :: Eq a => [a] -> [a] -> [[a]]
+split = splitOn
+
+-- | Split on a single character. This is over twice as fast as using
+-- split on a list of length 1, while producing identical results. -}
+splitc :: Eq c => c -> [c] -> [[c]]
+splitc c s = case break (== c) s of
+ (i, _c:rest) -> i : splitc c rest
+ (i, []) -> i : []
+
+-- | same as Data.List.Utils.replace
+replace :: Eq a => [a] -> [a] -> [a] -> [a]
+replace old new = intercalate new . split old
diff --git a/src/Utility/Tuple.hs b/src/Utility/Tuple.hs
new file mode 100644
index 00000000..25c6e8f3
--- /dev/null
+++ b/src/Utility/Tuple.hs
@@ -0,0 +1,17 @@
+{- tuple utility functions
+ -
+ - Copyright 2017 Joey Hess <id@joeyh.name>
+ -
+ - License: BSD-2-clause
+ -}
+
+module Utility.Tuple where
+
+fst3 :: (a,b,c) -> a
+fst3 (a,_,_) = a
+
+snd3 :: (a,b,c) -> b
+snd3 (_,b,_) = b
+
+thd3 :: (a,b,c) -> c
+thd3 (_,_,c) = c