Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/System/Cron/Describe.hs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ description t c = Desc (describeTime t (minute c) (hour c))
(return ddow)
where ddom = describeCronField domDescriptor $ dayOfMonthSpec (dayOfMonth c)
dm = describeCronField monthDescriptor $ monthSpec (month c)
ddow = describeCronField dowDescriptor $ dayOfWeekSpec (dayOfWeek c)
ddow = describeCronField dowDescriptor $ cronDayOfWeekSpec (cronDayOfWeek c)


matchVerbosity :: Verbosity -> Description -> Description
Expand Down
16 changes: 9 additions & 7 deletions src/System/Cron/Internal/Check.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ module System.Cron.Internal.Check where

-------------------------------------------------------------------------------
import Control.Applicative as A

import qualified Data.Foldable as FT
import Data.List
import Data.List.NonEmpty (NonEmpty (..))
import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.List.NonEmpty as NE
import Data.Maybe
import Data.Semigroup (sconcat)
import Data.Time
import Data.Time
import Data.Time.Calendar.WeekDate
import qualified Data.Traversable as FT

-------------------------------------------------------------------------------
import System.Cron.Types
-------------------------------------------------------------------------------
Expand Down Expand Up @@ -41,7 +43,7 @@ nextMatch cs@CronSchedule {..} now
domStarSpec <- mkDayOfMonthSpec (Field Star)
dowStarSpec <- mkDayOfWeekSpec (Field Star)
let domStarResult = nextMatch cs { dayOfMonth = domStarSpec } now
let dowStarResult = nextMatch cs { dayOfWeek = dowStarSpec} now
let dowStarResult = nextMatch cs { cronDayOfWeek = dowStarSpec} now
listToMaybe (sort (catMaybes [domStarResult, dowStarResult]))
| otherwise = do
expanded@Expanded {..} <- expand cs
Expand All @@ -50,7 +52,7 @@ nextMatch cs@CronSchedule {..} now
where
UTCTime startDay _ = addUTCTime 60 now
domRestricted = restricted (dayOfMonthSpec dayOfMonth)
dowRestricted = restricted (dayOfWeekSpec dayOfWeek)
dowRestricted = restricted (cronDayOfWeekSpec cronDayOfWeek)


-------------------------------------------------------------------------------
Expand Down Expand Up @@ -113,12 +115,12 @@ expand CronSchedule {..} = do
hourF' = expandF (0, 23) (hourSpec hour)
domF' = expandF (1, 31) (dayOfMonthSpec dayOfMonth)
monthF' = expandF (1, 12) (monthSpec month)
dowF' = remapSunday <$> expandF (0, 7) (dayOfWeekSpec dayOfWeek)
dowF' = remapSunday <$> expandF (0, 7) (cronDayOfWeekSpec cronDayOfWeek)
remapSunday lst = case NE.partition (\n -> n == 0 || n == 7) lst of
([], _) -> lst
(_, noSunday) -> 0 :| noSunday
domRestricted = restricted (dayOfMonthSpec dayOfMonth)
dowRestricted = restricted (dayOfWeekSpec dayOfWeek)
dowRestricted = restricted (cronDayOfWeekSpec cronDayOfWeek)
-- If DOM and DOW are restricted, they are ORed, so even if
-- there's an invalid day for the month, it is still satisfiable
-- because it will just choose the DOW path
Expand Down Expand Up @@ -257,7 +259,7 @@ scheduleMatches cs@CronSchedule {..} (UTCTime d t) =
-- however, achieve the desired result by adding a test to the
-- command (see the last example in EXAMPLE CRON FILE below).
checkDOMAndDOW
| restricted (dayOfMonthSpec dayOfMonth) && restricted (dayOfWeekSpec dayOfWeek) =
| restricted (dayOfMonthSpec dayOfMonth) && restricted (cronDayOfWeekSpec cronDayOfWeek) =
domMatches || dowMatches
| otherwise = domMatches && dowMatches
domMatches = FT.elem dom domF
Expand Down
1 change: 0 additions & 1 deletion src/System/Cron/Internal/Describe/Options.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ module System.Cron.Internal.Describe.Options where

-------------------------------------------------------------------------------
import Data.Default.Class
import Data.Semigroup
-------------------------------------------------------------------------------
import System.Cron.Internal.Describe.Types
-------------------------------------------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions src/System/Cron/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ classicP = CronSchedule <$> (minutesP <* space)
<*> (hoursP <* space)
<*> (dayOfMonthP <* space)
<*> (monthP <* space)
<*> dayOfWeekP
<*> cronDayOfWeekP
where space = A.char ' '


Expand Down Expand Up @@ -236,8 +236,8 @@ monthP = mParse mkMonthSpec "month out of range" =<< cronFieldP MonthString


-------------------------------------------------------------------------------
dayOfWeekP :: Parser DayOfWeekSpec
dayOfWeekP = mParse mkDayOfWeekSpec "day of week out of range" =<< cronFieldP DayString
cronDayOfWeekP :: Parser DayOfWeekSpec
cronDayOfWeekP = mParse mkDayOfWeekSpec "day of week out of range" =<< cronFieldP DayString


-------------------------------------------------------------------------------
Expand Down
42 changes: 20 additions & 22 deletions src/System/Cron/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module System.Cron.Types
, dayOfMonthSpec
, mkDayOfMonthSpec
, DayOfWeekSpec
, dayOfWeekSpec
, cronDayOfWeekSpec
, mkDayOfWeekSpec
, BaseField(..)
, SpecificField
Expand Down Expand Up @@ -55,12 +55,10 @@ module System.Cron.Types

-------------------------------------------------------------------------------
import Control.Applicative as A
import Data.Data (Data)
import qualified Data.Foldable as FT
import Data.Ix
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NE
import Data.Monoid
import Data.Text (Text)
import qualified Data.Text as T
import Data.Typeable (Typeable)
Expand All @@ -85,7 +83,7 @@ monthly = daily { dayOfMonth = DaysOfMonth (Field (SpecificField' (SpecificField

-- | Shorthand for every sunday at midnight. Parsed with \@weekly, 0 0 * * 0
weekly :: CronSchedule
weekly = daily { dayOfWeek = DaysOfWeek (Field (SpecificField' (SpecificField 0))) }
weekly = daily { cronDayOfWeek = DaysOfWeek (Field (SpecificField' (SpecificField 0))) }


-- | Shorthand for every day at midnight. Parsed with \@daily, 0 0 * * *
Expand All @@ -105,7 +103,7 @@ everyMinute = CronSchedule {
, hour = Hours (Field Star)
, dayOfMonth = DaysOfMonth (Field Star)
, month = Months (Field Star)
, dayOfWeek = DaysOfWeek (Field Star)
, cronDayOfWeek = DaysOfWeek (Field Star)
}


Expand All @@ -132,8 +130,8 @@ data CronSchedule = CronSchedule {
, hour :: HourSpec -- ^ Which hours to run. Second field in a cron specification.
, dayOfMonth :: DayOfMonthSpec -- ^ Which days of the month to run. Third field in a cron specification.
, month :: MonthSpec -- ^ Which months to run. Fourth field in a cron specification.
, dayOfWeek :: DayOfWeekSpec -- ^ Which days of the week to run. Fifth field in a cron specification.
} deriving (Eq, Generic, Data, Typeable)
, cronDayOfWeek :: DayOfWeekSpec -- ^ Which days of the week to run. Fifth field in a cron specification.
} deriving (Eq, Generic, Typeable)


instance Show CronSchedule where
Expand All @@ -145,7 +143,7 @@ instance ShowT CronSchedule where
, showT hour
, showT dayOfMonth
, showT month
, showT dayOfWeek
, showT cronDayOfWeek
]

serializeCronSchedule :: CronSchedule -> Text
Expand All @@ -156,7 +154,7 @@ serializeCronSchedule = showT
-- | Crontab file, omitting comments.
newtype Crontab = Crontab {
crontabEntries :: [CrontabEntry]
} deriving (Eq, Generic, Data, Typeable)
} deriving (Eq, Generic, Typeable)


instance ShowT Crontab where
Expand All @@ -174,15 +172,15 @@ serializeCrontab = showT
-------------------------------------------------------------------------------
newtype CronCommand = CronCommand {
cronCommand :: Text
} deriving (Show, Eq, Ord, ShowT, Generic, Data, Typeable)
} deriving (Show, Eq, Ord, ShowT, Generic, Typeable)


-------------------------------------------------------------------------------
-- | Essentially a line in a crontab file. It is either a schedule with a
-- command after it or setting an environment variable (e.g. FOO=BAR)
data CrontabEntry = CommandEntry CronSchedule CronCommand
| EnvVariable Text Text
deriving (Eq, Generic, Data, Typeable)
deriving (Eq, Generic, Typeable)


instance ShowT CrontabEntry where
Expand All @@ -197,7 +195,7 @@ instance Show CrontabEntry where
-- | Minutes field of a cron expression
newtype MinuteSpec = Minutes {
minuteSpec :: CronField
} deriving (Eq, ShowT, Generic, Data, Typeable)
} deriving (Eq, ShowT, Generic, Typeable)


instance Show MinuteSpec where
Expand All @@ -215,7 +213,7 @@ mkMinuteSpec cf
-- | Hours field of a cron expression
newtype HourSpec = Hours {
hourSpec :: CronField
} deriving (Eq, ShowT, Generic, Data, Typeable)
} deriving (Eq, ShowT, Generic, Typeable)


instance Show HourSpec where
Expand All @@ -232,7 +230,7 @@ mkHourSpec cf
-- | Day of month field of a cron expression
newtype DayOfMonthSpec = DaysOfMonth {
dayOfMonthSpec :: CronField
} deriving (Eq, ShowT, Generic, Data, Typeable)
} deriving (Eq, ShowT, Generic, Typeable)


instance Show DayOfMonthSpec where
Expand All @@ -249,7 +247,7 @@ mkDayOfMonthSpec cf
-- | Month field of a cron expression
newtype MonthSpec = Months {
monthSpec :: CronField
} deriving (Eq, ShowT, Generic, Data, Typeable)
} deriving (Eq, ShowT, Generic, Typeable)


instance Show MonthSpec where
Expand All @@ -265,8 +263,8 @@ mkMonthSpec cf
-------------------------------------------------------------------------------
-- | Day of week field of a cron expression
newtype DayOfWeekSpec = DaysOfWeek {
dayOfWeekSpec :: CronField
} deriving (Eq, ShowT, Generic, Data, Typeable)
cronDayOfWeekSpec :: CronField
} deriving (Eq, ShowT, Generic, Typeable)


instance Show DayOfWeekSpec where
Expand Down Expand Up @@ -313,7 +311,7 @@ validBF (RangeField' (RangeField n1 n2)) mn mx =
data BaseField = Star -- ^ Matches anything
| SpecificField' SpecificField -- ^ Matches a specific value (e.g. 1)
| RangeField' RangeField -- ^ Matches a range of values (e.g. 1-3)
deriving (Eq, Generic, Data, Typeable)
deriving (Eq, Generic, Typeable)


instance ShowT BaseField where
Expand All @@ -329,7 +327,7 @@ instance Show BaseField where
-------------------------------------------------------------------------------
newtype SpecificField = SpecificField {
specificField :: Int
} deriving (Eq, ShowT, Generic, Data, Typeable)
} deriving (Eq, ShowT, Generic, Typeable)


instance Show SpecificField where
Expand All @@ -346,7 +344,7 @@ mkSpecificField n
data RangeField = RangeField {
rfBegin :: Int
, rfEnd :: Int
} deriving (Eq, Generic, Data, Typeable)
} deriving (Eq, Generic, Typeable)


instance ShowT RangeField where
Expand All @@ -368,7 +366,7 @@ mkRangeField x y
data CronField = Field BaseField
| ListField (NonEmpty BaseField) -- ^ Matches a list of expressions.
| StepField' StepField -- ^ Matches a stepped expression, e.g. (*/2).
deriving (Generic, Data, Typeable)
deriving (Generic)


instance Eq CronField where
Expand All @@ -393,7 +391,7 @@ instance Show CronField where
-------------------------------------------------------------------------------
data StepField = StepField { sfField :: BaseField
, sfStepping :: Int
} deriving (Eq, Generic, Data, Typeable)
} deriving (Eq, Generic)


instance ShowT StepField where
Expand Down
2 changes: 1 addition & 1 deletion stack.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
resolver: lts-7.9
resolver: lts-13.21
packages:
- '.'
extra-deps: []
Expand Down
5 changes: 2 additions & 3 deletions test/SpecHelper.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import Data.Time.Clock as X
import Data.Time.LocalTime as X
import Debug.Trace as X
import qualified Generics.SOP as SOP
import qualified Generics.SOP.Constraint as SOP
import qualified Generics.SOP.GGP as SOP
import GHC.Generics (Generic)
import Test.QuickCheck.Instances ()
Expand All @@ -38,11 +37,11 @@ import System.Cron as X
-- this workaround is in place until we successfully beat down the
-- doors of castle QuickCheck and get generic deriving through. See
-- <https://github.com/nick8325/quickcheck/pull/40>
sopArbitrary :: (SOP.GTo b, SOP.SListI (SOP.GCode b), Generic b, SOP.AllF (SOP.All Arbitrary) (SOP.GCode b), SOP.AllF SOP.SListI (SOP.GCode b)) => Gen b
sopArbitrary :: (SOP.GTo b, SOP.SListI (SOP.GCode b), Generic b, SOP.All (SOP.All Arbitrary) (SOP.GCode b), SOP.All SOP.SListI (SOP.GCode b)) => Gen b
sopArbitrary = fmap SOP.gto sopArbitrary'


sopArbitrary' :: (SOP.SListI xss, SOP.AllF SOP.SListI xss, SOP.AllF (SOP.All Arbitrary) xss) => Gen (SOP.SOP SOP.I xss)
sopArbitrary' :: (SOP.SListI xss, SOP.All SOP.SListI xss, SOP.All (SOP.All Arbitrary) xss) => Gen (SOP.SOP SOP.I xss)
sopArbitrary' = oneof (map SOP.hsequence $ SOP.apInjs_POP $ SOP.hcpure p arbitrary)
where
p :: Proxy Arbitrary
Expand Down
12 changes: 6 additions & 6 deletions test/System/Test/Cron.hs
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ describeScheduleMatches = testGroup "scheduleMatches"
(day 5 3 13 2) @?= True

, testCase "matches a monday as 1" $
scheduleMatches stars { dayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 1))) }
scheduleMatches stars { cronDayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 1))) }
(UTCTime (fromGregorian 2014 3 17) 0) @?= True

, testCase "matches a sunday as 0" $
scheduleMatches stars { dayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 0))) }
scheduleMatches stars { cronDayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 0))) }
(UTCTime (fromGregorian 2014 3 16) 0) @?= True

, testCase "matches a sunday as 7" $
scheduleMatches stars { dayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 7))) }
scheduleMatches stars { cronDayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 7))) }
(UTCTime (fromGregorian 2014 3 16) 0) @?= True

, testCase "matches weekly on a sunday at 0:00" $
Expand All @@ -93,7 +93,7 @@ describeScheduleMatches = testGroup "scheduleMatches"
-- example in EXAMPLE CRON FILE below).
--
-- so we deliberately set the correct day of month but wrong day of week
scheduleMatches stars { dayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 1))),
scheduleMatches stars { cronDayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 1))),
dayOfMonth = mkDayOfMonthSpec' (Field (SpecificField' (mkSpecificField' 1))) }
(UTCTime (fromGregorian 2014 11 1) 600) @?= True
-- https://github.com/MichaelXavier/cron/issues/18
Expand Down Expand Up @@ -201,7 +201,7 @@ describeCronScheduleShow = testGroup "CronSchedule show"
show stars @?= "CronSchedule * * * * *"

, testCase "formats specific numbers" $
show stars { dayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 3)))} @?=
show stars { cronDayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 3)))} @?=
"CronSchedule * * * * 3"

, testCase "formats lists" $
Expand Down Expand Up @@ -285,7 +285,7 @@ describeNextMatch = testGroup "nextMatch"
let t = posixSecondsToUTCTime 0
let cs = stars { month = mkMonthSpec' (Field (SpecificField' (mkSpecificField' 9)))
, dayOfMonth = mkDayOfMonthSpec' (ListField (SpecificField' (mkSpecificField' 31) :| []))
, dayOfWeek = mkDayOfWeekSpec' (ListField (Star :| []))
, cronDayOfWeek = mkDayOfWeekSpec' (ListField (Star :| []))
}
nextMatch cs t @?= Nothing
]
Expand Down
10 changes: 5 additions & 5 deletions test/System/Test/Cron/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,19 @@ describeCronSchedule = testGroup "cronSchedule"

, testCase "parses ranges at the last field" $
assertSuccessfulParse "* * * * 3-4"
stars { dayOfWeek = mkDayOfWeekSpec' (Field (RangeField' (mkRangeField' 3 4))) }
stars { cronDayOfWeek = mkDayOfWeekSpec' (Field (RangeField' (mkRangeField' 3 4))) }
, testCase "parses lists at the last field" $
assertSuccessfulParse "* * * * 3,4"
stars { dayOfWeek = mkDayOfWeekSpec' (ListField (SpecificField' (mkSpecificField' 3) :| [SpecificField' (mkSpecificField' 4)])) }
stars { cronDayOfWeek = mkDayOfWeekSpec' (ListField (SpecificField' (mkSpecificField' 3) :| [SpecificField' (mkSpecificField' 4)])) }
, testCase "parses steps at the last field" $
assertSuccessfulParse "* * * * */4"
stars { dayOfWeek = mkDayOfWeekSpec' (StepField' (mkStepField' Star 4)) }
stars { cronDayOfWeek = mkDayOfWeekSpec' (StepField' (mkStepField' Star 4)) }
, testCase "parses a sunday as 7" $
assertSuccessfulParse "* * * * 7"
stars { dayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 7))) }
stars { cronDayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 7))) }
, testCase "parses a sunday as 0" $
assertSuccessfulParse "* * * * 0"
stars { dayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 0))) }
stars { cronDayOfWeek = mkDayOfWeekSpec' (Field (SpecificField' (mkSpecificField' 0))) }
, testCase "parses another example" $
assertSuccessfulParse "1-59/2 * * * *"
stars { minute = mkMinuteSpec' (StepField' (mkStepField' (RangeField' (mkRangeField' 1 59)) 2)) }
Expand Down