 
 (boot/deftask monitor
   "watch etc. for gae project"
-  [s service bool "service"
+  [d dir DIR str "target dir"
+   s servlet bool "servlet"
    v verbose bool "verbose"]
-  ;;(let [mod (str (-> (boot/get-env) :gae :module :name))]
-  (comp (builtin/watch)
-        (builtin/notify :audible true)
-        (builtin/sift :move {#"(.*\.clj$)" (str classes-dir "/$1")})
-        (if service
-          (target :no-clean true :service service :monitor true)
-          (target :no-clean true :service service :monitor false))))
-
-;; FIXME: not sure what this was for.  Just moving clj sources to the right output dir?
-;; replaced by sifting?
-#_(boot/deftask make
-  "dev build, source only"
-  [v verbose bool "verbose"]
-  (let [mod (str (-> (boot/get-env) :gae :module))
-        prev (atom nil)
-        cache-dir (boot/cache-dir! :boot-gae/build)
-        tmpdir (boot/tmp-dir!)]
-    ;; (println "MODULE: " mod)
-    (boot/empty-dir! tmpdir)
-    (comp
-     (boot/with-pre-wrap [fileset]
-       (let [changes (->> (boot/fileset-diff @prev fileset)
-                          boot/output-files
-                          (map :path))]
-             ;; fs (boot/new-fileset)]
-         (doseq [path changes]
-           (if verbose (util/info (str "changed: " path "\n")))
-           (let [in-file (boot/tmp-file (boot/tmp-get fileset path))
-                 out-file (if (str/ends-with? path "clj")
-                            (doto (io/file cache-dir classes-dir path) io/make-parents)
-                            (doto (io/file cache-dir path) io/make-parents))
-                 tmp-file (if (str/ends-with? path "clj")
-                            (doto (io/file tmpdir classes-dir path) io/make-parents)
-                            (doto (io/file tmpdir path) io/make-parents))]
-             (io/copy in-file out-file)
-             (io/copy in-file tmp-file)))
-         (reset! prev fileset)))
-     (builtin/sift :include #{#"^.*$"} :invert true)
-     (boot/with-pre-wrap [fileset]
-       (-> fileset
-           (boot/add-asset tmpdir)
-           boot/commit!))
-     )))
+  (fn middleware [next-handler]
+    (fn handler [fileset]
+      (let [dir (or dir (get-target-dir fileset servlet))
+            _ (println "TARGET DIR: " dir)
+            target-middleware (comp (builtin/watch)
+                                    (builtin/notify :audible true)
+                                    (builtin/sift :move {#"(.*\.clj$)" (str classes-dir "/$1")})
+                                    (if servlet
+                                      (target :no-clean true :servlet servlet)
+                                      (target :no-clean true :servlet servlet :dir dir)))
+            target-handler (target-middleware next-handler)]
+        (target-handler fileset)))))
 
 (boot/deftask rollback
   "appcfg rollback"

  (if verbose (println "TASK: boot-gae/deploy"))
  (validate-tools-api-jar)
  ;; (println "PARAMS: " *opts*)
  (let [mod      (-> (boot/get-env) :gae :module :name)
        app-dir  (-> (boot/get-env) :gae :app :dir)
        ;; dir      (if service (str "target/" mod) "target")
        opts (merge {:sdk-root (:sdk-root config-map)
                     ;; :use-java7 true
                     :build-dir (str "target/" (if service mod))}
                                  ;; build-dir build-dir (gae-app-dir))} ;; (:build-dir config-map)}
                    *opts*)
        _ (println "OPTS: " opts)
        params (into [] (for [[k v] (remove (comp nil? second)
                                            (dissoc opts :build-dir :verbose :sdk-help))]
                          (str "--" (str/replace (name k) #"-" "_")
                               (if (not (instance? Boolean v)) (str "=" v)))))
        params (if (:sdk-help *opts*)
                 ["help" "update"]
                 (conj params "update" (:build-dir opts)))
        params (into-array String params)
        ;; ClassLoader classLoader = Thread.currentThread().contextClassLoader
        class-loader (-> (Thread/currentThread) (.getContextClassLoader))
        cl (.getParent class-loader)
        app-cfg (Class/forName appcfg-class true class-loader)]

  ;; def appCfg = classLoader.loadClass(APPENGINE_TOOLS_MAIN)
  ;; appCfg.main(params as String[])
    (def method (first (filter #(= (. % getName) "main") (. app-cfg getMethods))))
    (def invoke-args (into-array Object [params]))
    (if verbose ;; (or (:verbose *opts*) (:verbose config-map))
      (do (println "CMD: AppCfg")
          (doseq [arg params]
            (println "\t" arg))))
    (. method invoke nil invoke-args)))

(boot/deftask filters
  "generate filters class files"

   m module MODULE str "module pfx"
   n gen-reloader-ns NS sym "ns for gen-reloader"
   r reloader-impl-ns NS sym "ns for reloader"
   s servlet bool "build as servlet"
   w web-inf WEB-INF str "WEB-INF dir, default: WEB-INF"
   v verbose bool "Print trace messages."]
  (let [workspace (boot/tmp-dir!)
        prev-pre (atom nil)
        web-inf (if web-inf web-inf web-inf-dir)

        gen-reloader-ns (if gen-reloader-ns (symbol gen-reloader-ns) (gensym "reloadergen"))
        gen-reloader-path (str gen-reloader-ns ".clj")
        reloader-impl-ns (if reloader-impl-ns (symbol reloader-impl-ns) "reloader")
        reloader-impl-path (str reloader-impl-ns ".clj")]
    (comp
     (boot/with-pre-wrap [fileset]
       (let [boot-config-edn-files (->> (boot/fileset-diff @prev-pre fileset)
                                        boot/input-files
                                        (boot/by-re [(re-pattern (str boot-config-edn "$"))]))
             ;; (boot/by-name [boot-config-edn]))
             boot-config-edn-f (condp = (count boot-config-edn-files)
                                 0 (do (util/info (str "Creating " boot-config-edn "\n"))
                                       (io/file boot-config-edn)) ;; this creates a java.io.File
                                 1 (first boot-config-edn-files)  ;; this is a boot.tmpdir.TmpFile
                                 (throw (Exception.
                                         (str "only one _boot_config.edn file allowed, found "
                                              (count boot-config-edn-files)))))
             boot-config-edn-map (if (instance? boot.tmpdir.TmpFile boot-config-edn-f)
                                   (-> (boot/tmp-file boot-config-edn-f) slurp read-string)
                                   {})

             module (if-let [module (-> boot-config-edn-map :module :name)]
                      module
                      (let [appengine-config-edn-files
                            (->> (boot/fileset-diff @prev-pre fileset)
                                 boot/input-files
                                 (boot/by-re [(re-pattern (str appengine-edn "$"))]))

                            appengine-config-edn-f
                            (condp = (count appengine-config-edn-files)
                              0 (throw (Exception. appengine-edn " file not found"))
                              1 (first appengine-config-edn-files)
                              (throw (Exception.
                                      (str "Only one " appengine-edn " file allowed, found "
                                           (count appengine-config-edn-files)))))

                            appengine-config-edn-map
                            (-> (boot/tmp-file boot-config-edn-f) slurp read-string)]
                        (-> appengine-config-edn-map :module :name)))
             ]
         (println "MODULE: " module)

         (if (:reloader boot-config-edn-map)
           fileset
