<commit_before>(ns twarc.core
  (:require [com.stuartsierra.component :as component]
            [plumbing.core :refer :all]
            [clojure.tools.logging :as log]
            [clojure.core.async :as a]
            [twarc.impl.core :as impl])
  (:import [org.quartz.impl StdSchedulerFactory]
           [org.quartz.impl.matchers OrMatcher NotMatcher NameMatcher KeyMatcher
            AndMatcher StringMatcher GroupMatcher
            EverythingMatcher]
           [org.quartz.utils Key]
           [org.quartz JobBuilder JobDataMap TriggerBuilder
            SimpleScheduleBuilder CronScheduleBuilder JobListener JobKey TriggerKey]
           [twarc TwarcJob TwarcStatefullJob]))


(defn make-job
  "If state is passed, job will be stateful, i.e. state will be passed to the job
  on each invocation. Job execution will result in new state."
  [{:keys [ns name arguments identity group desc recovery durably state]
    :or {identity (impl/uuid)}
    :as opts}]
  (-> (JobBuilder/newJob (if (contains? opts :state) TwarcStatefullJob TwarcJob))
      (.usingJobData (JobDataMap. {"ns" ns
                                   "name" name
                                   "arguments" arguments
                                   "state" state}))
      (cond->
       group (.withIdentity identity group)
       (not group) (.withIdentity identity)
       desc (.withDescription desc)
       durably (.withDurably)
       recovery (.withRecovery))
      (.build)))

(defn prepare-simple
  [{:keys [repeat interval misfire-handling]}]
  (-> (SimpleScheduleBuilder/simpleSchedule)
      (cond->
       (= :inf repeat) (.repeatForever)
       (number? repeat) (.withRepeatCount repeat)
       interval (.withIntervalInMilliseconds interval)
       misfire-handling
       (as-> schedule
             (case misfire-handling
               :fire-now
               (.withMisfireHandlingInstructionFireNow schedule)
               :ignore-misfires
               (.withMisfireHandlingInstructionIgnoreMisfires schedule)
               :next-with-existing-count
               (.withMisfireHandlingInstructionNextWithExistingCount schedule)
               :next-with-remaining-count
               (.withMisfireHandlingInstructionNextWithRemainingCount schedule)
               :now-with-existing-count
               (.withMisfireHandlingInstructionNowWithExistingCount schedule)
               :now-with-remaining-count
               (.withMisfireHandlingInstructionNowWithRemainingCount schedule))))))

(defn prepare-cron
  [options]
  (-> (if (map? options)
        (-> (if (:nonvalidated? options)
              (CronScheduleBuilder/cronScheduleNonvalidatedExpression (:expression options))
              (CronScheduleBuilder/cronSchedule (:expression options)))
            (as-> schedule
                  (case (:misfire-handling options)
                    :do-nothing
                    (.withMisfireHandlingInstructionDoNothing schedule)
                    :fire-and-process
                    (.withMisfireHandlingInstructionFireAndProceed schedule)
                    :ignore-misfires
                    (.withMisfireHandlingInstructionIgnoreMisfires schedule)))
            (?> (:time-zone options)
                (.inTimeZone (:time-zone options))))
        (CronScheduleBuilder/cronSchedule options))))

(defn make-trigger
  "Most of the options are obvious and are simply passed to TriggerBuilder. See
  http://www.quartz-scheduler.org/api/2.2.1/org/quartz/TriggerBuilder.html for details.

  The most interesting part of a trigger is defining a scheduler. It may be either
  simple or cron. For example:

  (make-trigger {:simple {:repeat :inf :interval 10000}})

  (make-trigger {:cron \"0 0 3 * 2 ?\"})

  Cron can be a string or a map:

  (make-trigger {:cron {:expression \"0 0 3 * 2 ?\" :misfire-handling :ignore-misfires
                        :time-zone (TimeZone/getTimeZone \"America/Los_Angeles\")}})"
  [{:keys [start-at start-now end-at for-job modified-by-calendars identity group description
           job-data priority simple cron]
    :or {identity (impl/uuid)}}]
  (-> (TriggerBuilder/newTrigger)
      (cond->
       group (.withIdentity identity group)
       (not group) (.withIdentity identity)
       for-job (.forJob for-job)
       start-at (.startAt start-at)
       end-at (.endAt end-at)
       start-now (.startNow)
       modified-by-calendars (as-> trigger
                                   (doseq [c modified-by-calendars]
                                     (.modifiedByCalendar trigger c)))
       priority (.withPriority priority)
       job-data (.usingJobData (JobDataMap. job-data))
       simple (.withSchedule (prepare-simple simple))
       cron (.withSchedule (prepare-cron cron)))
      (.build)))

(defn job-key
  ([group name] (JobKey. name group))
  ([name] (JobKey. name)))

(defn trigger-key
  ([group name] (TriggerKey. name group))
  ([name] (TriggerKey. name)))

(defn job-from-var
  [var options]
  (make-job (assoc options
              :ns (-> var meta :ns ns-name str)
              :name (-> var meta :name str))))

(defn schedule-job
  "Adds job and trigger to scheduler. Job will be executed as: (apply @var scheduler
  arguments), and for stateful jobs as: (apply @var scheduler state arguments).
  For job and trigger parameters see make-job and make-trigger.

  Set replace to true to update existing job and trigger."
  [scheduler var arguments & {:keys [job trigger replace] :or {replace false}}]
  (let [job (job-from-var var (assoc job :arguments arguments))
        trigger (make-trigger trigger)]
    (.scheduleJob (:twarc/quartz scheduler) job #{trigger} replace)))

(defn delete-job
  [scheduler & key]
  (.deleteJob (:twarc/quartz scheduler) (apply job-key key)))

(defn check-job-exists
  [scheduler & key]
  (.checkExists (:twarc/quartz scheduler) (apply job-key key)))

(defn check-trigger-exists
  [scheduler & key]
  (.checkExists (:twarc/quartz scheduler) (apply trigger-key key)))

(defmacro defjob
  [n binding & body]
  (let [generated-f (symbol (str n "*"))]<commit_msg>Returning job (JobDetail instance) from schedule-job.<commit_after>(ns twarc.core
  (:require [com.stuartsierra.component :as component]
            [plumbing.core :refer :all]
            [clojure.tools.logging :as log]
            [clojure.core.async :as a]
            [twarc.impl.core :as impl])
  (:import [org.quartz.impl StdSchedulerFactory]
           [org.quartz.impl.matchers OrMatcher NotMatcher NameMatcher KeyMatcher
            AndMatcher StringMatcher GroupMatcher
            EverythingMatcher]
           [org.quartz.utils Key]
           [org.quartz JobBuilder JobDataMap TriggerBuilder
            SimpleScheduleBuilder CronScheduleBuilder JobListener JobKey TriggerKey]
           [twarc TwarcJob TwarcStatefullJob]))


(defn make-job
  "If state is passed, job will be stateful, i.e. state will be passed to the job
  on each invocation. Job execution will result in new state."
  [{:keys [ns name arguments identity group desc recovery durably state]
    :or {identity (impl/uuid)}
    :as opts}]
  (-> (JobBuilder/newJob (if (contains? opts :state) TwarcStatefullJob TwarcJob))
      (.usingJobData (JobDataMap. {"ns" ns
                                   "name" name
                                   "arguments" arguments
                                   "state" state}))
      (cond->
       group (.withIdentity identity group)
       (not group) (.withIdentity identity)
       desc (.withDescription desc)
       durably (.withDurably)
       recovery (.withRecovery))
      (.build)))

(defn prepare-simple
  [{:keys [repeat interval misfire-handling]}]
  (-> (SimpleScheduleBuilder/simpleSchedule)
      (cond->
       (= :inf repeat) (.repeatForever)
       (number? repeat) (.withRepeatCount repeat)
       interval (.withIntervalInMilliseconds interval)
       misfire-handling
       (as-> schedule
             (case misfire-handling
               :fire-now
               (.withMisfireHandlingInstructionFireNow schedule)
               :ignore-misfires
               (.withMisfireHandlingInstructionIgnoreMisfires schedule)
               :next-with-existing-count
               (.withMisfireHandlingInstructionNextWithExistingCount schedule)
               :next-with-remaining-count
               (.withMisfireHandlingInstructionNextWithRemainingCount schedule)
               :now-with-existing-count
               (.withMisfireHandlingInstructionNowWithExistingCount schedule)
               :now-with-remaining-count
               (.withMisfireHandlingInstructionNowWithRemainingCount schedule))))))

(defn prepare-cron
  [options]
  (-> (if (map? options)
        (-> (if (:nonvalidated? options)
              (CronScheduleBuilder/cronScheduleNonvalidatedExpression (:expression options))
              (CronScheduleBuilder/cronSchedule (:expression options)))
            (as-> schedule
                  (case (:misfire-handling options)
                    :do-nothing
                    (.withMisfireHandlingInstructionDoNothing schedule)
                    :fire-and-process
                    (.withMisfireHandlingInstructionFireAndProceed schedule)
                    :ignore-misfires
                    (.withMisfireHandlingInstructionIgnoreMisfires schedule)))
            (?> (:time-zone options)
                (.inTimeZone (:time-zone options))))
        (CronScheduleBuilder/cronSchedule options))))

(defn make-trigger
  "Most of the options are obvious and are simply passed to TriggerBuilder. See
  http://www.quartz-scheduler.org/api/2.2.1/org/quartz/TriggerBuilder.html for details.

  The most interesting part of a trigger is defining a scheduler. It may be either
  simple or cron. For example:

  (make-trigger {:simple {:repeat :inf :interval 10000}})

  (make-trigger {:cron \"0 0 3 * 2 ?\"})

  Cron can be a string or a map:

  (make-trigger {:cron {:expression \"0 0 3 * 2 ?\" :misfire-handling :ignore-misfires
                        :time-zone (TimeZone/getTimeZone \"America/Los_Angeles\")}})"
  [{:keys [start-at start-now end-at for-job modified-by-calendars identity group description
           job-data priority simple cron]
    :or {identity (impl/uuid)}}]
  (-> (TriggerBuilder/newTrigger)
      (cond->
       group (.withIdentity identity group)
       (not group) (.withIdentity identity)
       for-job (.forJob for-job)
       start-at (.startAt start-at)
       end-at (.endAt end-at)
       start-now (.startNow)
       modified-by-calendars (as-> trigger
                                   (doseq [c modified-by-calendars]
                                     (.modifiedByCalendar trigger c)))
       priority (.withPriority priority)
       job-data (.usingJobData (JobDataMap. job-data))
       simple (.withSchedule (prepare-simple simple))
       cron (.withSchedule (prepare-cron cron)))
      (.build)))

(defn job-key
  ([group name] (JobKey. name group))
  ([name] (JobKey. name)))

(defn trigger-key
  ([group name] (TriggerKey. name group))
  ([name] (TriggerKey. name)))

(defn job-from-var
  [var options]
  (make-job (assoc options
              :ns (-> var meta :ns ns-name str)
              :name (-> var meta :name str))))

(defn schedule-job
  "Adds job and trigger to scheduler. Job will be executed as: (apply @var scheduler
  arguments), and for stateful jobs as: (apply @var scheduler state arguments).
  For job and trigger parameters see make-job and make-trigger.

  Set replace to true to update existing job and trigger."
  [scheduler var arguments & {:keys [job trigger replace] :or {replace false}}]
  (let [job (job-from-var var (assoc job :arguments arguments))
        trigger (make-trigger trigger)]
    (.scheduleJob (:twarc/quartz scheduler) job #{trigger} replace)
    job))

(defn delete-job
  [scheduler & key]
  (.deleteJob (:twarc/quartz scheduler) (apply job-key key)))

(defn check-job-exists
  [scheduler & key]
  (.checkExists (:twarc/quartz scheduler) (apply job-key key)))

(defn check-trigger-exists
  [scheduler & key]
  (.checkExists (:twarc/quartz scheduler) (apply trigger-key key)))

(defmacro defjob
  [n binding & body]
  (let [generated-f (symbol (str n "*"))]
{'fraction_non_alphanumeric': 0.10710185337051009, 'fraction_numerical': 0.0026242414302115793, 'mean_word_length': 2.407376362112322, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1633874', 'n_tokens_mistral': 3589, 'n_tokens_neox': 3374, 'n_words': 968}