summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Thompson <will@willthompson.co.uk>2018-07-04 10:42:21 +0000
committerWill Thompson <will@willthompson.co.uk>2018-07-04 10:42:21 +0000
commit457834d718c89f05659f2d2fe92a85596270fe5c (patch)
treed74453ee71078bc9f3d7070d0f8758938977a5d7
parent89bafbc61e726b0befcc3ef03e0ce432a53497a0 (diff)
parent0193b332d6d42d1820c16a616239aa66b06984a8 (diff)
Merge branch 'master' into 'master'
Add stack build, gitlab CI with stack and hlint See merge request bustle/bustle!1
-rw-r--r--.gitlab-ci.yml29
-rw-r--r--.hlint.yaml2
-rw-r--r--Bustle/Application/Monad.hs2
-rw-r--r--Bustle/Diagram.hs15
-rw-r--r--Bustle/Loader.hs4
-rw-r--r--Bustle/Loader/Pcap.hs27
-rw-r--r--Bustle/Marquee.hs4
-rw-r--r--Bustle/Monitor.hs2
-rw-r--r--Bustle/Noninteractive.hs4
-rw-r--r--Bustle/Regions.hs8
-rw-r--r--Bustle/Renderer.hs60
-rw-r--r--Bustle/StatisticsPane.hs5
-rw-r--r--Bustle/Stats.hs18
-rw-r--r--Bustle/UI.hs57
-rw-r--r--Bustle/UI/Canvas.hs9
-rw-r--r--Bustle/UI/DetailsView.hs2
-rw-r--r--Bustle/UI/FilterDialog.hs12
-rw-r--r--Bustle/UI/OpenTwoDialog.hs5
-rw-r--r--Bustle/Util.hs11
-rw-r--r--GetText.hs41
-rw-r--r--Setup.hs2
-rw-r--r--Test/PcapCrash.hs3
-rw-r--r--Test/Regions.hs16
-rw-r--r--bustle.cabal8
-rw-r--r--stack.yaml10
25 files changed, 189 insertions, 167 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..4723a15
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,29 @@
+image: zenhaskell/gtk:nightly-2018-06-29
+
+before_script:
+- apt install -y libpcap-dev
+
+cache:
+ key: "stack-work"
+ paths:
+ - .stack-work
+
+stages:
+ - build
+ - lint
+ - test
+
+lint:
+ stage: lint
+ script:
+ - hlint .
+
+build:
+ stage: build
+ script:
+ - stack build
+
+test:
+ stage: test
+ script:
+ - stack test
diff --git a/.hlint.yaml b/.hlint.yaml
new file mode 100644
index 0000000..132528b
--- /dev/null
+++ b/.hlint.yaml
@@ -0,0 +1,2 @@
+- ignore: {name: Use camelCase}
+- ignore: {name: Reduce duplication}
diff --git a/Bustle/Application/Monad.hs b/Bustle/Application/Monad.hs
index 7a5f749..e326f7d 100644
--- a/Bustle/Application/Monad.hs
+++ b/Bustle/Application/Monad.hs
@@ -94,7 +94,7 @@ embedIO act = B $ do
liftIO $ act r
makeCallback :: Bustle config state a -> BustleEnv config state -> IO a
-makeCallback (B act) x = runReaderT act x
+makeCallback (B act) = runReaderT act
runB :: config -> state -> Bustle config state a -> IO a
runB config s (B act) = do
diff --git a/Bustle/Diagram.hs b/Bustle/Diagram.hs
index c4bdd4b..0f35658 100644
--- a/Bustle/Diagram.hs
+++ b/Bustle/Diagram.hs
@@ -49,7 +49,6 @@ where
import Data.List (unzip4)
import Control.Arrow ((&&&))
-import Control.Applicative ((<$>), (<*>))
import Control.Monad.Reader
@@ -131,15 +130,15 @@ memberLabel :: ObjectPath
-> Bool -- ^ True if this is a return; False if it's a call
-> Double -- ^ y-coordinate
-> Shape
-memberLabel p i m isReturn y = MemberLabel p i m isReturn memberx y
+memberLabel p i m isReturn = MemberLabel p i m isReturn memberx
timestampLabel :: String -> Double -> Shape
-timestampLabel s y = TimestampLabel s timestampx y
+timestampLabel s = TimestampLabel s timestampx
type Diagram = [Shape]
arcControlPoints :: Shape -> (Point, Point)
-arcControlPoints (Arc { topx=x1, topy=y1, bottomx=x2, bottomy=y2, arcside=s }) =
+arcControlPoints Arc { topx=x1, topy=y1, bottomx=x2, bottomy=y2, arcside=s } =
let (+-) = offset s
cp1 = (x1 +- 60, y1 + 10)
cp2 = (x2 +- 60, y2 - 10)
@@ -230,11 +229,11 @@ bounds s = case s of
in (x1, y1, x2, y2)
SignalArrow {} ->
let (x1, x2) = xMinMax s
- (y1, y2) = (subtract 5) &&& (+5) $ shapey s
+ (y1, y2) = subtract 5 &&& (+5) $ shapey s
in (x1, y1, x2, y2)
DirectedSignalArrow {} ->
let (x1, x2) = minMax (epicentre s, shapex s)
- (y1, y2) = (subtract 5) &&& (+5) $ shapey s
+ (y1, y2) = subtract 5 &&& (+5) $ shapey s
in (x1, y1, x2, y2)
Arc { topx=x1, bottomx=x2, topy=y1, bottomy=y2 } ->
let ((cx, _), (dx, _)) = arcControlPoints s
@@ -406,13 +405,13 @@ drawSignalArrow e mleft mright y = do
arc e y 5 0 (2 * pi)
stroke
- maybeM mleft $ \left -> do
+ forM_ mleft $ \left -> do
moveTo left y
arrowHead False
lineTo (e - 5) y
stroke
- maybeM mright $ \right -> do
+ forM_ mright $ \right -> do
moveTo (e + 5) y
lineTo right y
arrowHead True
diff --git a/Bustle/Loader.hs b/Bustle/Loader.hs
index 821bf44..8fd40c8 100644
--- a/Bustle/Loader.hs
+++ b/Bustle/Loader.hs
@@ -26,7 +26,7 @@ module Bustle.Loader
where
import Control.Monad.Except
-import Control.Arrow ((***))
+import Control.Arrow (second)
import qualified Bustle.Loader.Pcap as Pcap
import Bustle.Types
@@ -43,7 +43,7 @@ readLog :: MonadIO io
readLog f = do
pcapResult <- io $ Pcap.readPcap f
case pcapResult of
- Right ms -> return $ (id *** filter (isRelevant . deEvent)) ms
+ Right ms -> return $ second (filter (isRelevant . deEvent)) ms
Left ioe -> throwError $ LoadError f (show ioe)
isRelevant :: Event
diff --git a/Bustle/Loader/Pcap.hs b/Bustle/Loader/Pcap.hs
index a707b39..bed6f31 100644
--- a/Bustle/Loader/Pcap.hs
+++ b/Bustle/Loader/Pcap.hs
@@ -118,10 +118,10 @@ isNOC (Just sender) s | looksLikeNOC =
names = map fromVariant $ signalBody s
looksLikeNOC =
- and [ sender == B.dbusName
- , signalInterface s == B.dbusInterface
- , formatMemberName (signalMember s) == "NameOwnerChanged"
- ]
+ (sender == B.dbusName) &&
+ (signalInterface s == B.dbusInterface) &&
+ (formatMemberName (signalMember s) == "NameOwnerChanged")
+
isNOC _ _ = Nothing
@@ -152,10 +152,10 @@ tryBustlifyGetNameOwnerReply maybeCall mr = do
-- • don't crash if the body of the call or reply doesn't contain one bus name.
(rawCall, _) <- maybeCall
guard (formatMemberName (methodCallMember rawCall) == "GetNameOwner")
- ownedName <- fromVariant $ (methodCallBody rawCall !! 0)
+ ownedName <- fromVariant (head (methodCallBody rawCall))
return $ bustlifyNOC ( ownedName
, Nothing
- , fromVariant $ (methodReturnBody mr !! 0)
+ , fromVariant (head (methodReturnBody mr))
)
bustlify :: Monad m
@@ -209,8 +209,7 @@ bustlify µs bytes m = do
| otherwise -> return $ B.MessageEvent $
B.Signal { B.sender = wrappedSender
, B.member = convertMember signalPath (Just . signalInterface) signalMember sig
- , B.signalDestination = fmap stupifyBusName
- $ signalDestination sig
+ , B.signalDestination = stupifyBusName <$> signalDestination sig
}
_ -> error "woah there! someone added a new message type."
@@ -222,7 +221,7 @@ convert :: Monad m
convert µs body =
case unmarshal body of
Left e -> return $ Left $ unmarshalErrorMessage e
- Right m -> liftM Right $ bustlify µs (BS.length body) m
+ Right m -> Right <$> bustlify µs (BS.length body) m
data Result e a =
EOF
@@ -242,7 +241,7 @@ readOne p f = do
-- or something?
if hdrCaptureLength hdr == 0
then return EOF
- else liftM Packet $ f (fromIntegral (hdrTime hdr)) body
+ else Packet <$> f (fromIntegral (hdrTime hdr)) body
-- This shows up as the biggest thing on the heap profile. Which is kind of a
-- surprise. It's supposedly the list.
@@ -253,7 +252,7 @@ mapBodies :: (Monad m, MonadIO m)
mapBodies p f = do
ret <- readOne p f
case ret of
- EOF -> return $ []
+ EOF -> return []
Packet x -> do
xs <- mapBodies p f
return $ x:xs
@@ -266,11 +265,11 @@ readPcap path = try $ do
dlt <- datalink p
-- DLT_NULL for extremely old logs.
-- DLT_DBUS is missing: https://github.com/bos/pcap/pull/8
- when (not $ elem dlt [DLT_NULL, DLT_UNKNOWN 231]) $ do
+ unless (dlt `elem` [DLT_NULL, DLT_UNKNOWN 231]) $ do
let message = "Incorrect link type " ++ show dlt
ioError $ mkIOError userErrorType message Nothing (Just path)
- liftM partitionEithers $ evalStateT (mapBodies p convert) Map.empty
+ partitionEithers <$> evalStateT (mapBodies p convert) Map.empty
where
snaplenErrorString = "invalid file capture length 134217728, bigger than maximum of 262144"
snaplenBugReference = __ "libpcap 1.8.0 and 1.8.1 are incompatible with Bustle. See \
@@ -280,6 +279,6 @@ readPcap path = try $ do
\Bustle from Flathub, which already includes the necessary \
\patches: https://flathub.org/apps/details/org.freedesktop.Bustle"
matchSnaplenBug e =
- if isUserError e && (snaplenErrorString `isSuffixOf` (ioeGetErrorString e))
+ if isUserError e && (snaplenErrorString `isSuffixOf` ioeGetErrorString e)
then Just $ ioeSetErrorString e snaplenBugReference
else Nothing
diff --git a/Bustle/Marquee.hs b/Bustle/Marquee.hs
index 365a72d..77a9db5 100644
--- a/Bustle/Marquee.hs
+++ b/Bustle/Marquee.hs
@@ -50,9 +50,11 @@ newtype Marquee = Marquee { unMarquee :: String }
toPangoMarkup :: Marquee -> String
toPangoMarkup = unMarquee
+instance Semigroup Marquee where
+ Marquee x <> Marquee y = Marquee (x <> y)
+
instance Monoid Marquee where
mempty = Marquee ""
- mappend x y = Marquee (unMarquee x `mappend` unMarquee y)
mconcat = Marquee . mconcat . map unMarquee
tag :: String -> Marquee -> Marquee
diff --git a/Bustle/Monitor.hs b/Bustle/Monitor.hs
index 53369a9..cb9d4ef 100644
--- a/Bustle/Monitor.hs
+++ b/Bustle/Monitor.hs
@@ -95,7 +95,7 @@ monitorNew target filename =
monitorStop :: Monitor
-> IO ()
-monitorStop monitor = do
+monitorStop monitor =
withForeignPtr (unMonitor monitor) bustle_pcap_monitor_stop
messageLoggedHandler :: (Microseconds -> BS.ByteString -> IO ())
diff --git a/Bustle/Noninteractive.hs b/Bustle/Noninteractive.hs
index b96b87f..215fc28 100644
--- a/Bustle/Noninteractive.hs
+++ b/Bustle/Noninteractive.hs
@@ -48,7 +48,7 @@ process filepath analyze format = do
warn $ printf (__ "Couldn't parse '%s': %s") filepath err
exitFailure
Right (warnings, log) -> do
- mapM warn warnings
+ mapM_ warn warnings
mapM_ (putStrLn . format) $ analyze log
formatInterface :: Maybe InterfaceName -> String
@@ -82,5 +82,5 @@ runDot filepath = process filepath makeDigraph id
| (s, d) <- nub . mapMaybe (methodCall . deEvent) $ log
]
- methodCall (MessageEvent (MethodCall {sender = s, destination = d})) = Just (s, d)
+ methodCall (MessageEvent MethodCall {sender = s, destination = d}) = Just (s, d)
methodCall _ = Nothing
diff --git a/Bustle/Regions.hs b/Bustle/Regions.hs
index 43b4e06..09b6f16 100644
--- a/Bustle/Regions.hs
+++ b/Bustle/Regions.hs
@@ -86,15 +86,15 @@ hits y stripe = y `relativeTo` stripe == EQ
nonOverlapping :: [Stripe]
-> Bool
nonOverlapping [] = True
-nonOverlapping (_:[]) = True
+nonOverlapping [_] = True
nonOverlapping (s1:s2:ss) =
stripeBottom s1 <= stripeTop s2 && nonOverlapping (s2:ss)
regionSelectionNew :: Regions a
-> RegionSelection a
regionSelectionNew rs
- | sorted /= map fst rs = error $ "regionSelectionNew: unsorted regions"
- | not (nonOverlapping sorted) = error $ "regionSelectionNew: overlapping regions"
+ | sorted /= map fst rs = error "regionSelectionNew: unsorted regions"
+ | not (nonOverlapping sorted) = error "regionSelectionNew: overlapping regions"
| otherwise = RegionSelection [] 0 Nothing rs
where
sorted = sort (map fst rs)
@@ -169,7 +169,7 @@ regionSelectionDown = invert . regionSelectionUp . invert
regionSelectionFirst :: RegionSelection a
-> RegionSelection a
regionSelectionFirst rs =
- case (reverse (rsBefore rs) ++ maybeToList (rsCurrent rs) ++ rsAfter rs) of
+ case reverse (rsBefore rs) ++ maybeToList (rsCurrent rs) ++ rsAfter rs of
[] -> rs
(first:others) -> RegionSelection []
(midpoint (fst first))
diff --git a/Bustle/Renderer.hs b/Bustle/Renderer.hs
index 42a282f..2771c17 100644
--- a/Bustle/Renderer.hs
+++ b/Bustle/Renderer.hs
@@ -35,21 +35,18 @@ module Bustle.Renderer
)
where
-import Prelude hiding (log)
-
import Bustle.Types
import Bustle.Diagram
import Bustle.Regions
-import Bustle.Util (maybeM, NonEmpty(..))
+import Bustle.Util (NonEmpty(..))
import qualified Data.Set as Set
import Data.Set (Set)
import qualified Data.Map as Map
import Data.Map (Map)
-import Control.Applicative (Applicative(..), (<$>), (<*>))
-import Control.Arrow ((***))
-import Control.Monad.Except
+import Control.Arrow (first)
+import Control.Monad
import Control.Monad.Identity
import Control.Monad.State
import Control.Monad.Writer
@@ -76,17 +73,19 @@ data Participants =
deriving
(Show, Eq)
-instance Monoid Participants where
- mempty = Participants Map.empty Map.empty
- mappend (Participants sess1 sys1) (Participants sess2 sys2) =
- Participants (f sess1 sess2)
- (f sys1 sys2)
+instance Semigroup Participants where
+ (<>) (Participants sess1 sys1) (Participants sess2 sys2) =
+ Participants (f sess1 sess2)
+ (f sys1 sys2)
where
f = Map.unionWith Set.union
+instance Monoid Participants where
+ mempty = Participants Map.empty Map.empty
+
sessionParticipants :: Participants
-> [(UniqueName, Set OtherName)] -- ^ sorted by column
-sessionParticipants = map (snd *** id) . Map.toAscList . pSession
+sessionParticipants = map (first snd) . Map.toAscList . pSession
data RendererResult apps =
RendererResult { rrCentreOffset :: Double
@@ -109,9 +108,9 @@ data RendererResult apps =
--
-- This is extremely unpleasant but it's a Monday. There's a test case in
-- Test/Renderer.hs because I don't trust myself.
-instance Monoid apps => Monoid (RendererResult apps) where
- mempty = RendererResult 0 0 [] [] mempty []
- mappend rr1 rr2 = RendererResult centreOffset topOffset shapes regions applications warnings
+
+instance Semigroup apps => Semigroup (RendererResult apps) where
+ rr1 <> rr2 = RendererResult centreOffset topOffset shapes regions applications warnings
where
centreOffset = rrCentreOffset rr1 `max` rrCentreOffset rr2
topOffset = rrTopOffset rr1 `max` rrTopOffset rr2
@@ -136,15 +135,19 @@ instance Monoid apps => Monoid (RendererResult apps) where
regions = translatedRegions rr1 ++ translatedRegions rr2
- applications = rrApplications rr1 `mappend` rrApplications rr2
- warnings = rrWarnings rr1 `mappend` rrWarnings rr2
+ applications = rrApplications rr1 <> rrApplications rr2
+ warnings = rrWarnings rr1 <> rrWarnings rr2
+
+
+instance Monoid apps => Monoid (RendererResult apps) where
+ mempty = RendererResult 0 0 [] [] mempty []
processWithFilters :: (Log, Set UniqueName)
-> (Log, Set UniqueName)
-> RendererResult ()
processWithFilters (sessionBusLog, sessionFilter)
(systemBusLog, systemFilter ) =
- fmap (const ()) $ fst $ processSome sessionBusLog systemBusLog rs
+ void $ fst $ processSome sessionBusLog systemBusLog rs
where
rs = initialState sessionFilter systemFilter
@@ -229,12 +232,13 @@ data RendererOutput =
deriving
(Show)
-instance Monoid RendererOutput where
- mempty = RendererOutput [] [] []
- mappend (RendererOutput s1 r1 w1)
- (RendererOutput s2 r2 w2) = RendererOutput (s1 ++ s2)
+instance Semigroup RendererOutput where
+ (<>) (RendererOutput s1 r1 w1)
+ (RendererOutput s2 r2 w2) = RendererOutput (s1 ++ s2)
(r1 ++ r2)
(w1 ++ w2)
+instance Monoid RendererOutput where
+ mempty = RendererOutput [] [] []
data BusState =
BusState { apps :: Applications
@@ -466,7 +470,7 @@ remUnique bus n = do
ai <- lookupUniqueName bus n
let mcolumn = aiCurrentColumn ai
modifyApps bus $ Map.insert n (ai { aiColumn = FormerColumn mcolumn })
- maybeM mcolumn $ \x ->
+ forM_ mcolumn $ \x ->
modifyBusState bus $ \bs ->
bs { columnsInUse = Set.delete x (columnsInUse bs) }
@@ -541,7 +545,7 @@ advanceBy d = do
]
let (height, ss) = headers xs' (current' + 20)
tellShapes ss
- modify $ \bs -> bs { mostRecentLabels = (current' + height + 10)
+ modify $ \bs -> bs { mostRecentLabels = current' + height + 10
, row = row bs + height + 10
}
current <- gets row
@@ -563,7 +567,7 @@ advanceBy d = do
bestNames :: UniqueName -> Set OtherName -> [String]
bestNames u os
| Set.null os = [unUniqueName u]
- | otherwise = reverse . sortBy (comparing length) . map readable $ Set.toList os
+ | otherwise = (sortBy (flip (comparing length)) . map readable) $ Set.toList os
where readable = reverse . takeWhile (/= '.') . reverse . unOtherName
edgemostApp :: Bus -> Renderer (Maybe Double)
@@ -633,7 +637,7 @@ returnArc bus mr callx cally duration = do
shape $ Arc { topx = callx, topy = cally
, bottomx = currentx, bottomy = currenty
- , arcside = if (destinationx > currentx) then L else R
+ , arcside = if destinationx > currentx then L else R
, caption = show (µsToMs duration) ++ "ms"
}
@@ -703,7 +707,7 @@ processNOC :: Bus
-> Renderer ()
processNOC bus noc =
case noc of
- Connected { actor = u } -> addUnique bus u >> return ()
+ Connected { actor = u } -> void (addUnique bus u)
Disconnected { actor = u } -> remUnique bus u
NameChanged { changedName = n
, change = c
@@ -734,7 +738,7 @@ signal bus dm = do
mtarget <- signalDestinationCoordinate bus dm
case mtarget of
- Just target -> do
+ Just target ->
shape $ DirectedSignalArrow emitter target t
Nothing -> do
-- fromJust is safe here because we must have an app to have a
diff --git a/Bustle/StatisticsPane.hs b/Bustle/StatisticsPane.hs
index 2838b16..3e4d3b5 100644
--- a/Bustle/StatisticsPane.hs
+++ b/Bustle/StatisticsPane.hs
@@ -23,7 +23,6 @@ module Bustle.StatisticsPane
)
where
-import Control.Applicative ((<$>))
import Control.Monad (forM_)
import Text.Printf
import Graphics.UI.Gtk
@@ -157,9 +156,9 @@ newCountView = do
countBar <- cellRendererProgressNew
cellLayoutPackStart countColumn countBar True
cellLayoutSetAttributes countColumn countBar countStore $
- \(FrequencyInfo {fiFrequency = count}) ->
+ \FrequencyInfo {fiFrequency = count} ->
[ cellProgressValue :=> do
- upperBound <- (maximum . map fiFrequency) <$>
+ upperBound <- maximum . map fiFrequency <$>
listStoreToList countStore
-- ensure that we always show *something*
return $ 2 + (count * 98 `div` upperBound)
diff --git a/Bustle/Stats.hs b/Bustle/Stats.hs
index 0ef7b19..30fb221 100644
--- a/Bustle/Stats.hs
+++ b/Bustle/Stats.hs
@@ -31,7 +31,7 @@ module Bustle.Stats
where
import Control.Monad (guard)
-import Data.List (sort, sortBy)
+import Data.List (sortBy)
import Data.Maybe (mapMaybe)
import Data.Ord (comparing)
@@ -62,9 +62,7 @@ data FrequencyInfo =
deriving (Show, Eq, Ord)
frequencies :: Log -> [FrequencyInfo]
-frequencies = reverse
- . sort
- . map (\((t, i, m), c) -> FrequencyInfo c t i m)
+frequencies = sortBy (flip compare) . map (\((t, i, m), c) -> FrequencyInfo c t i m)
. Map.toList
. foldr (Map.alter alt) Map.empty
. mapMaybe repr
@@ -86,9 +84,7 @@ data TimeInfo =
methodTimes :: Log
-> [TimeInfo]
-methodTimes = reverse
- . sortBy (comparing tiTotalTime)
- . map summarize
+methodTimes = sortBy (flip (comparing tiTotalTime)) . map summarize
. Map.toList
. foldr (\(i, method, time) ->
Map.alter (alt time) (i, method)) Map.empty
@@ -101,7 +97,7 @@ methodTimes = reverse
Just (newtime + total, newtime : times)
isReturn :: Message -> Bool
- isReturn (MethodReturn {}) = True
+ isReturn MethodReturn {} = True
isReturn _ = False
methodReturn :: Detailed Message
@@ -109,7 +105,7 @@ methodTimes = reverse
methodReturn dm = do
let m = deEvent dm
guard (isReturn m)
- Detailed start (call@(MethodCall {})) _ _ <- inReplyTo m
+ Detailed start call@MethodCall {} _ _ <- inReplyTo m
return ( iface (member call)
, membername (member call)
, deTimestamp dm - start
@@ -120,7 +116,7 @@ methodTimes = reverse
, tiMethodName = method
, tiTotalTime = fromIntegral total / 1000
, tiCallFrequency = length times
- , tiMeanCallTime = (mean $ map fromIntegral times) / 1000
+ , tiMeanCallTime = mean (map fromIntegral times) / 1000
}
-- FIXME: really? again?
@@ -145,7 +141,7 @@ data SizeInfo =
messageSizes :: Log
-> [SizeInfo]
messageSizes messages =
- reverse . sort . map summarize $ Map.assocs sizeTable
+ sortBy (flip compare) . map summarize $ Map.assocs sizeTable
where
summarize :: ((SizeType, Maybe InterfaceName, MemberName), [Int]) -> SizeInfo
summarize ((t, i, m), sizes) =
diff --git a/Bustle/UI.hs b/Bustle/UI.hs
index d2d95f4..44abafb 100644
--- a/Bustle/UI.hs
+++ b/Bustle/UI.hs
@@ -111,7 +111,7 @@ data WindowInfo =
, wiLogDetails :: IORef (Maybe LogDetails)
}
-data BConfig =
+newtype BConfig =
BConfig { debugEnabled :: Bool
}
@@ -175,7 +175,7 @@ consumeInitialWindow = do
putInitialWindow :: WindowInfo
-> B ()
-putInitialWindow wi = do
+putInitialWindow wi =
modify $ \s -> s { initialWindow = Just wi }
loadInInitialWindow :: LogDetails -> B ()
@@ -225,7 +225,7 @@ loadLogWith getWindow logDetails = do
let title = printf (__ "Could not read '%s'") f
io $ displayError windowInfo title (Just e)
putInitialWindow windowInfo
- Right () -> do
+ Right () ->
io $ hideError windowInfo
io $ windowPresent (wiWindow windowInfo)
@@ -235,7 +235,7 @@ updateRecordingSubtitle :: WindowInfo
-> Int
-> IO ()
updateRecordingSubtitle wi j = do
- let message = (printf (__ "Logged <b>%u</b> messages") j :: String)
+ let message = printf (__ "Logged <b>%u</b> messages") j :: String
labelSetMarkup (wiSubtitle wi) message
@@ -253,7 +253,7 @@ processBatch pendingRef n wi = do
pending <- readIORef pendingRef
writeIORef pendingRef []
- when (not (null pending)) $ do
+ unless (null pending) $ do
rr <- atomicModifyIORef' rendererStateRef $ \s ->
swap $ processSome (reverse pending) [] s
@@ -261,7 +261,7 @@ processBatch pendingRef n wi = do
let rr' = oldRR `mappend` rr
writeIORef rendererResultRef rr'
- when (not (null (rrShapes rr))) $ do
+ unless (null (rrShapes rr)) $ do
-- If the renderer produced some visible output, count it as a
-- message from the user's perspective.
modifyIORef' n (+ length pending)
@@ -292,7 +292,7 @@ recorderRun wi target filename r = C.handle newFailed $ do
case m of
Left e -> warn e
Right message
- | isRelevant (deEvent message) -> do
+ | isRelevant (deEvent message) ->
modifyIORef' pendingRef (message:)
| otherwise -> return ()
@@ -300,7 +300,7 @@ recorderRun wi target filename r = C.handle newFailed $ do
processor <- processBatch pendingRef n wi
processorId <- timeoutAdd processor 200
- stopActivatedId <- (wiStop wi) `on` buttonActivated $ monitorStop monitor
+ stopActivatedId <- wiStop wi `on` buttonActivated $ monitorStop monitor
handlerId <- monitor `on` monitorMessageLogged $ updateLabel
_stoppedId <- monitor `on` monitorStopped $ \domain code message -> do
handleError domain code message
@@ -312,7 +312,7 @@ recorderRun wi target filename r = C.handle newFailed $ do
timeoutRemove processorId
processor
- hadOutput <- liftM (/= 0) (readIORef n)
+ hadOutput <- fmap (/= 0) (readIORef n)
finished hadOutput
return ()
@@ -330,7 +330,7 @@ recorderRun wi target filename r = C.handle newFailed $ do
handleError domain code message = do
gIoErrorQuark <- quarkFromString "g-io-error-quark"
let cancelled = fromEnum IoErrorCancelled
- when (not (domain == gIoErrorQuark && code == cancelled)) $ do
+ unless (domain == gIoErrorQuark && code == cancelled) $
displayError wi (Marquee.toString message) Nothing
@@ -339,11 +339,11 @@ startRecording :: Either BusType String
startRecording target = do
wi <- consumeInitialWindow
- zt <- io $ getZonedTime
+ zt <- io getZonedTime
-- I hate time manipulation
let yyyy_mm_dd_hh_mm_ss = takeWhile (/= '.') (show zt)
- cacheDir <- io $ getCacheDir
+ cacheDir <- io getCacheDir
let filename = cacheDir </> yyyy_mm_dd_hh_mm_ss <.> "bustle"
let title = printf (__ "Recording %s&#8230;") $ case target of
@@ -377,8 +377,7 @@ onMenuItemActivate :: MenuItemClass menuItem
=> menuItem
-> IO ()
-> IO (ConnectId menuItem)
-onMenuItemActivate mi act =
- on mi menuItemActivate act
+onMenuItemActivate mi = on mi menuItemActivate
finishedRecording :: WindowInfo
-> FilePath
@@ -408,8 +407,8 @@ finishedRecording wi tempFilePath producedOutput = do
putInitialWindow wi
updateDisplayedLog wi (mempty :: RendererResult ())
io $ do
- (wiTitle wi) `set` [ labelText := "" ]
- (wiSubtitle wi) `set` [ labelText := "" ]
+ wiTitle wi `set` [ labelText := "" ]
+ wiSubtitle wi `set` [ labelText := "" ]
showSaveDialog :: WindowInfo
-> IO ()
@@ -431,10 +430,10 @@ showSaveDialog wi savedCb = do
hideError wi
savedCb
Left (GError _ _ msg) -> do
- let title = (__ "Couldn't save log: ") ++ (Marquee.toString msg)
+ let title = __ "Couldn't save log: " ++ Marquee.toString msg
secondary = printf
(__ "You might want to manually recover the log from the temporary file at \
- \\"%s\".") (tempFilePath)
+ \\"%s\".") tempFilePath
displayError wi title (Just secondary)
-- | Show a confirmation dialog if the log is unsaved. Suitable for use as a
@@ -509,7 +508,7 @@ emptyWindow = do
errorBarTitle <- getW castToLabel "errorBarTitle"
errorBarDetails <- getW castToLabel "errorBarDetails"
- io $ errorBar `on` infoBarResponse $ \_ -> do
+ io $ errorBar `on` infoBarResponse $ \_ ->
widgetHide errorBar
stack <- getW castToStack "diagramOrNot"
@@ -587,9 +586,9 @@ emptyWindow = do
updateDetailsView :: DetailsView
-> Maybe (Detailed Message)
-> IO ()
-updateDetailsView detailsView newMessage = do
+updateDetailsView detailsView newMessage =
case newMessage of
- Nothing -> do
+ Nothing ->
widgetHide $ detailsViewGetTop detailsView
Just m -> do
detailsViewUpdate detailsView m
@@ -644,9 +643,9 @@ wiSetLogDetails :: WindowInfo
wiSetLogDetails wi logDetails = do
writeIORef (wiLogDetails wi) (Just logDetails)
let (title, subtitle) = logWindowTitle logDetails
- (wiWindow wi) `set` [ windowTitle := title ]
- (wiTitle wi) `set` [ labelText := title ]
- (wiSubtitle wi) `set` [ labelText := subtitle ]
+ wiWindow wi `set` [ windowTitle := title ]
+ wiTitle wi `set` [ labelText := title ]
+ wiSubtitle wi `set` [ labelText := subtitle ]
setPage :: MonadIO io
=> WindowInfo
@@ -660,7 +659,7 @@ displayLog :: WindowInfo
-> Log
-> RendererResult Participants
-> B ()
-displayLog wi@(WindowInfo { wiWindow = window
+displayLog wi@WindowInfo { wiWindow = window
, wiExport = exportItem
, wiViewStatistics = viewStatistics
, wiFilterNames = filterNames
@@ -668,7 +667,7 @@ displayLog wi@(WindowInfo { wiWindow = window
, wiSidebarHeader = sidebarHeader
, wiSidebarStack = sidebarStack
, wiStatsPane = statsPane
- })
+ }
logDetails
sessionMessages
systemMessages
@@ -755,7 +754,7 @@ saveToPDFDialogue wi shapes = do
RecordedLog _ -> Nothing
SingleLog p -> Just $ takeDirectory p
TwoLogs p _ -> Just $ takeDirectory p
- maybeM mdirectory $ fileChooserSetCurrentFolder chooser
+ forM_ mdirectory $ fileChooserSetCurrentFolder chooser
chooser `after` response $ \resp -> do
when (resp == ResponseAccept) $ do
@@ -766,9 +765,9 @@ saveToPDFDialogue wi shapes = do
renderWith surface $ drawDiagram False shapes
case r of
Left (e :: C.IOException) -> do
- let title = (__ "Couldn't export log as PDF: ") ++ show e
+ let title = __ "Couldn't export log as PDF: " ++ show e
displayError wi title Nothing
- Right () -> do
+ Right () ->
hideError wi
widgetDestroy chooser
diff --git a/Bustle/UI/Canvas.hs b/Bustle/UI/Canvas.hs
index 2bfd87b..51d69f4 100644
--- a/Bustle/UI/Canvas.hs
+++ b/Bustle/UI/Canvas.hs
@@ -32,7 +32,7 @@ where
import Data.Maybe (isNothing)
import Data.IORef
-import Control.Monad (when)
+import Control.Monad (forM_, when)
import Graphics.UI.Gtk
import Graphics.Rendering.Cairo (Render, translate)
@@ -206,10 +206,10 @@ canvasUpdateSelection canvas f = do
writeIORef regionSelectionRef rs'
when (newMessage /= currentMessage) $ do
- maybeM currentMessage $ \(r, _) ->
+ forM_ currentMessage $ \(r, _) ->
canvasInvalidateStripe canvas r
- maybeM newMessage $ \(r, _) -> do
+ forM_ newMessage $ \(r, _) -> do
canvasInvalidateStripe canvas r
canvasClampAroundSelection canvas
@@ -281,8 +281,7 @@ canvasDraw canvas = do
canvasFocus :: Canvas a
-> IO ()
-canvasFocus canvas = do
- (canvasLayout canvas) `set` [ widgetIsFocus := True ]
+canvasFocus canvas = canvasLayout canvas `set` [ widgetIsFocus := True ]
canvasScrollToBottom :: Canvas a
-> IO ()
diff --git a/Bustle/UI/DetailsView.hs b/Bustle/UI/DetailsView.hs
index e60d311..8a28367 100644
--- a/Bustle/UI/DetailsView.hs
+++ b/Bustle/UI/DetailsView.hs
@@ -77,7 +77,7 @@ getMember (Detailed _ m _ _) = case m of
MethodReturn {} -> callMember
Error {} -> callMember
where
- callMember = fmap (member . deEvent) $ inReplyTo m
+ callMember = member . deEvent <$> inReplyTo m
getDestination :: Detailed Message -> Maybe TaggedBusName
getDestination (Detailed _ m _ _) = case m of
diff --git a/Bustle/UI/FilterDialog.hs b/Bustle/UI/FilterDialog.hs
index 6658d22..32d95d4 100644
--- a/Bustle/UI/FilterDialog.hs
+++ b/Bustle/UI/FilterDialog.hs
@@ -23,7 +23,7 @@ module Bustle.UI.FilterDialog
)
where
-import Data.List (intercalate, groupBy, findIndices)
+import Data.List (intercalate, groupBy, elemIndices)
import qualified Data.Set as Set
import Data.Set (Set)
import qualified Data.Function as F
@@ -35,7 +35,7 @@ import Bustle.Types
namespace :: String
-> (String, String)
-namespace name = case reverse (findIndices (== '.') name) of
+namespace name = case reverse (elemIndices '.' name) of
[] -> ("", name)
(i:_) -> splitAt (i + 1) name
@@ -51,17 +51,17 @@ formatNames (u, os)
groupGroup xs@((ns, _):_) = (ns, map snd xs)
formatGroup (ns, [y]) = ns ++ y
- formatGroup (ns, ys) = ns ++ "{" ++ (intercalate "," ys) ++ "}"
+ formatGroup (ns, ys) = ns ++ "{" ++ intercalate "," ys ++ "}"
type NameStore = ListStore (Bool, (UniqueName, Set OtherName))
makeStore :: [(UniqueName, Set OtherName)]
-> Set UniqueName
-> IO NameStore
-makeStore names currentlyHidden = do
+makeStore names currentlyHidden =
listStoreNew $ map toPair names
where
- toPair (name@(u, _)) = (not (Set.member u currentlyHidden), name)
+ toPair name@(u, _) = (not (Set.member u currentlyHidden), name)
makeView :: NameStore
-> IO ScrolledWindow
@@ -111,7 +111,7 @@ runFilterDialog parent names currentlyHidden = do
windowSetDefaultSize d (windowWidth * 7 `div` 8) (windowHeight `div` 2)
d `set` [ windowTransientFor := parent ]
dialogAddButton d stockClose ResponseClose
- vbox <- fmap castToBox $ dialogGetContentArea d
+ vbox <- castToBox <$> dialogGetContentArea d
boxSetSpacing vbox 6
nameStore <- makeStore names currentlyHidden
diff --git a/Bustle/UI/OpenTwoDialog.hs b/Bustle/UI/OpenTwoDialog.hs
index 440abc6..afb2217 100644
--- a/Bustle/UI/OpenTwoDialog.hs
+++ b/Bustle/UI/OpenTwoDialog.hs
@@ -42,10 +42,7 @@ propagateCurrentFolder d1 d2 = d1 `on` currentFolderChanged $ do
f1 <- fileChooserGetCurrentFolder d1
f2 <- fileChooserGetCurrentFolder d2
otherFile <- fileChooserGetFilename d2
- when (and [ isNothing otherFile
- , f1 /= f2
- , isJust f1
- ]) $ do
+ when (isNothing otherFile && f1 /= f2 && isJust f1) $ do
fileChooserSetCurrentFolder d2 (fromJust f1)
return ()
diff --git a/Bustle/Util.hs b/Bustle/Util.hs
index 5ac76a2..f0d1990 100644
--- a/Bustle/Util.hs
+++ b/Bustle/Util.hs
@@ -22,8 +22,6 @@ module Bustle.Util
io
, warn
- , maybeM
-
, getCacheDir
-- You probably don't actually want to use this function.
@@ -50,19 +48,12 @@ traceM x = trace (show x) $ return ()
-- Log a warning which isn't worth showing to the user, but which might
-- interest someone debugging the application.
warn :: String -> IO ()
-warn = hPutStrLn stderr . ((__ "Warning: ") ++)
+warn = hPutStrLn stderr . (__ "Warning: " ++)
-- Shorthand for liftIO.
io :: MonadIO m => IO a -> m a
io = liftIO
-maybeM :: Monad m
- => Maybe a
- -> (a -> m b)
- -> m ()
-maybeM Nothing _ = return ()
-maybeM (Just x) act = act x >> return ()
-
foreign import ccall "g_get_user_cache_dir"
g_get_user_cache_dir :: IO CString
diff --git a/GetText.hs b/GetText.hs
index 840af9f..b8b2601 100644
--- a/GetText.hs
+++ b/GetText.hs
@@ -73,7 +73,7 @@
-- see https://github.com/fpco/stackage/issues/746
--
-module GetText
+module GetText
(
-- | /TODO:/ upstream exporting the individual hooks?
installPOFiles,
@@ -118,18 +118,17 @@ gettextDefaultMain = defaultMainWithHooks $ installGetTextHooks simpleUserHooks
installGetTextHooks :: UserHooks -- ^ initial user hooks
-> UserHooks -- ^ patched user hooks
installGetTextHooks uh = uh{
- confHook = \a b ->
- (confHook uh) a b >>=
- return . updateLocalBuildInfo,
+ confHook = \a b ->
+ updateLocalBuildInfo <$> confHook uh a b,
- postInst = \a b c d ->
- (postInst uh) a b c d >>
+ postInst = \a b c d ->
+ postInst uh a b c d >>
installPOFiles a b c d
}
updateLocalBuildInfo :: LocalBuildInfo -> LocalBuildInfo
-updateLocalBuildInfo l =
+updateLocalBuildInfo l =
let sMap = getCustomFields l
[domDef, catDef] = map ($ sMap) [getDomainDefine, getMsgCatalogDefine]
dom = getDomainNameDefault sMap (getPackageName l)
@@ -138,7 +137,7 @@ updateLocalBuildInfo l =
in (appendCPPOptions [domMS,catMS] . appendExtension [EnableExtension CPP]) l
installPOFiles :: Args -> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO ()
-installPOFiles _ _ _ l =
+installPOFiles _ _ _ l =
let sMap = getCustomFields l
destDir = targetDataDir l
dom = getDomainNameDefault sMap (getPackageName l)
@@ -148,43 +147,43 @@ installPOFiles _ _ _ l =
let targetDir = destDir </> bname </> "LC_MESSAGES"
-- ensure we have directory destDir/{loc}/LC_MESSAGES
createDirectoryIfMissing True targetDir
- system $ "msgfmt --output-file=" ++
- (targetDir </> dom <.> "mo") ++
+ system $ "msgfmt --output-file=" ++
+ (targetDir </> dom <.> "mo") ++
" " ++ file
in do
filelist <- getPoFilesDefault sMap
-- copy all whose name is in the form of dir/{loc}.po to the
-- destDir/{loc}/LC_MESSAGES/dom.mo
-- with the 'msgfmt' tool
- mapM_ installFile filelist
+ mapM_ installFile filelist
forBuildInfo :: LocalBuildInfo -> (BuildInfo -> BuildInfo) -> LocalBuildInfo
-forBuildInfo l f =
+forBuildInfo l f =
let a = l{localPkgDescr = updPkgDescr (localPkgDescr l)}
- updPkgDescr x = x{library = updLibrary (library x),
+ updPkgDescr x = x{library = updLibrary (library x),
executables = updExecs (executables x)}
updLibrary Nothing = Nothing
updLibrary (Just x) = Just $ x{libBuildInfo = f (libBuildInfo x)}
- updExecs x = map updExec x
+ updExecs = map updExec
updExec x = x{buildInfo = f (buildInfo x)}
in a
appendExtension :: [Extension] -> LocalBuildInfo -> LocalBuildInfo
-appendExtension exts l =
+appendExtension exts l =
forBuildInfo l updBuildInfo
where updBuildInfo x = x{defaultExtensions = updExts (defaultExtensions x)}
updExts s = nub (s ++ exts)
appendCPPOptions :: [String] -> LocalBuildInfo -> LocalBuildInfo
-appendCPPOptions opts l =
+appendCPPOptions opts l =
forBuildInfo l updBuildInfo
where updBuildInfo x = x{cppOptions = updOpts (cppOptions x)}
updOpts s = nub (s ++ opts)
-formatMacro name value = "-D" ++ name ++ "=" ++ (show value)
+formatMacro name value = "-D" ++ name ++ "=" ++ show value
targetDataDir :: LocalBuildInfo -> FilePath
-targetDataDir l =
+targetDataDir l =
let dirTmpls = installDirTemplates l
prefix' = prefix dirTmpls
data' = datadir dirTmpls
@@ -201,7 +200,7 @@ findInParametersDefault :: [(String, String)] -> String -> String -> String
findInParametersDefault al name def = (fromMaybe def . lookup name) al
getDomainNameDefault :: [(String, String)] -> String -> String
-getDomainNameDefault al d = findInParametersDefault al "x-gettext-domain-name" d
+getDomainNameDefault al = findInParametersDefault al "x-gettext-domain-name"
getDomainDefine :: [(String, String)] -> String
getDomainDefine al = findInParametersDefault al "x-gettext-domain-def" "__MESSAGE_CATALOG_DOMAIN__"
@@ -212,8 +211,8 @@ getMsgCatalogDefine al = findInParametersDefault al "x-gettext-msg-cat-def" "__M
getPoFilesDefault :: [(String, String)] -> IO [String]
getPoFilesDefault al = toFileList $ findInParametersDefault al "x-gettext-po-files" ""
where toFileList "" = return []
- toFileList x = liftM concat $ mapM matchFileGlob $ split' x
+ toFileList x = fmap concat $ mapM matchFileGlob $ split' x
-- from Blow your mind (HaskellWiki)
-- splits string by newline, space and comma
- split' x = concatMap lines $ concatMap words $ unfoldr (\b -> fmap (const . (second $ drop 1) . break (==',') $ b) . listToMaybe $ b) x
+ split' x = concatMap lines $ concatMap words $ unfoldr (\b -> fmap (const . second (drop 1) . break (==',') $ b) . listToMaybe $ b) x
diff --git a/Setup.hs b/Setup.hs
index 9d3526f..9154f56 100644
--- a/Setup.hs
+++ b/Setup.hs
@@ -12,7 +12,7 @@ import Distribution.Text ( display )
import Distribution.ModuleName (ModuleName)
import qualified Distribution.ModuleName as ModuleName
-import qualified GetText as GetText
+import qualified GetText
main :: IO ()
main = defaultMainWithHooks $ installBustleHooks simpleUserHooks
diff --git a/Test/PcapCrash.hs b/Test/PcapCrash.hs
index e28a69c..4d03ae1 100644
--- a/Test/PcapCrash.hs
+++ b/Test/PcapCrash.hs
@@ -17,5 +17,4 @@ main = do
exitFailure
-- TODO: check there are no warnings (but there are because we don't
-- understand 'h', so we just skip it)
- Right _ -> do
- return ()
+ Right _ -> return ()
diff --git a/Test/Regions.hs b/Test/Regions.hs
index d4b46b0..720b2d3 100644
--- a/Test/Regions.hs
+++ b/Test/Regions.hs
@@ -4,7 +4,6 @@ import Test.QuickCheck.All
import Data.List (sort, group)
import Data.Maybe (isNothing, isJust)
-import Control.Applicative ((<$>), (<*>))
import Bustle.Regions
@@ -15,7 +14,7 @@ newtype NonOverlappingStripes = NonOverlappingStripes [Stripe]
instance Arbitrary NonOverlappingStripes where
arbitrary = do
-- listOf2
- tops <- sort <$> ((:) <$> arbitrary <*> (listOf1 arbitrary))
+ tops <- sort <$> ((:) <$> arbitrary <*> listOf1 arbitrary)
-- Generate dense stripes sometimes
let g :: Gen Double
@@ -37,7 +36,7 @@ instance (Eq a, Arbitrary a) => Arbitrary (ValidRegions a) where
values <- vector (length stripes) `suchThat` unique
return $ ValidRegions (zip stripes values)
where
- unique xs = all (== 1) . map length . group $ xs
+ unique = all (== 1) . map length . group
instance (Eq a, Arbitrary a) => Arbitrary (RegionSelection a) where
arbitrary = do
@@ -46,8 +45,8 @@ instance (Eq a, Arbitrary a) => Arbitrary (RegionSelection a) where
prop_NonOverlapping_generator_works (NonOverlappingStripes ss) = nonOverlapping ss
-prop_InitiallyUnselected = \rs -> isNothing $ rsCurrent rs
-prop_UpDoesNothing = \rs -> isNothing $ rsCurrent $ regionSelectionUp rs
+prop_InitiallyUnselected rs = isNothing $ rsCurrent rs
+prop_UpDoesNothing rs = isNothing $ rsCurrent $ regionSelectionUp rs
prop_DownDoesNothing vr@(ValidRegions regions) =
withRegions vr $ \rs ->
@@ -130,11 +129,10 @@ randomMutation = do
]
randomMutations :: Gen (RegionSelection a -> RegionSelection a)
-randomMutations = do
- fs <- listOf randomMutation
- return $ foldr (.) id fs
+randomMutations =
+ foldr (.) id <$> listOf randomMutation
-prop_ClickAlwaysInSelection = \rs ->
+prop_ClickAlwaysInSelection rs =
forAll (fmap Blind randomMutations) $ \(Blind f) ->
let
rs' = f rs
diff --git a/bustle.cabal b/bustle.cabal
index 125d8b1..26c22ca 100644
--- a/bustle.cabal
+++ b/bustle.cabal
@@ -1,7 +1,7 @@
Name: bustle
Category: Network, Desktop
Version: 0.7.1.1
-Cabal-Version: >= 1.24
+Cabal-Version: >= 2.0
Tested-With: GHC == 8.2.2, GHC == 8.4.3
Synopsis: Draw sequence diagrams of D-Bus traffic
Description: Draw sequence diagrams of D-Bus traffic
@@ -56,8 +56,8 @@ x-gettext-domain-name: bustle
custom-setup
setup-depends:
- base >= 4 && < 5,
- Cabal >= 1.24,
+ base >= 4.11 && < 5,
+ Cabal >= 2.0,
filepath,
directory,
process
@@ -114,7 +114,7 @@ Executable bustle
cc-options: -fPIC -g
pkgconfig-depends: glib-2.0 >= 2.54,
gio-unix-2.0
- Build-Depends: base >= 4 && < 5
+ Build-Depends: base >= 4.11 && < 5
, bytestring
, cairo
, containers
diff --git a/stack.yaml b/stack.yaml
new file mode 100644
index 0000000..6d13ece
--- /dev/null
+++ b/stack.yaml
@@ -0,0 +1,10 @@
+resolver: nightly-2018-06-29
+packages:
+- .
+allow-newer: true
+extra-deps:
+- gio-0.13.5.0
+- gtk3-0.14.9
+- hgettext-0.1.31.0
+- pcap-0.4.5.2
+