4444(def terminus-prefix " puppet/" )
4545(def additional-uberjar-checkouts-dir " target/uberjars" )
4646(def cli-defaults-filename (str shared-cli-defaults-prefix " cli-defaults.sh.erb" ))
47+ (def classpath-jars-prefix " ext/classpath-jars/" )
48+ (def project-files-prefix " ext/project-files/" )
4749
4850; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4951; ;; Schemas
6870 (schema/optional-key :image-name ) schema/Str
6971 (schema/optional-key :ports ) [schema/Int]})
7072
73+ (def ClasspathJarInstallSpec
74+ {(schema/optional-key :path ) schema/Str
75+ (schema/optional-key :mode ) schema/Str
76+ (schema/optional-key :owner ) schema/Str
77+ (schema/optional-key :group ) schema/Str})
78+
79+ (def ClasspathJarSpec
80+ {:artifact schema/Symbol
81+ (schema/optional-key :install ) ClasspathJarInstallSpec})
82+
83+ (def ProjectFileSpec
84+ {:file schema/Str
85+ :install {:path schema/Str
86+ (schema/optional-key :mode ) schema/Str
87+ (schema/optional-key :owner ) schema/Str
88+ (schema/optional-key :group ) schema/Str}})
89+
7190(def LocalProjectVars
7291 {(schema/optional-key :user ) schema/Str
7392 (schema/optional-key :numeric-uid-gid ) schema/Int
@@ -385,6 +404,122 @@ Additional uberjar dependencies:
385404 (for [config-file config-files]
386405 (cp-to-staging-dir config-dir config-file system-config-dir))))
387406
407+ ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
408+ ; ;; Classpath Jar Extraction
409+
410+ (schema/defn find-jar-on-classpath :- (schema/maybe File)
411+ " Given a lein project and an artifact symbol (e.g., 'org.bouncycastle/bcpkix-jdk18on),
412+ find the corresponding jar file on the resolved classpath. For artifacts where
413+ the group-id equals the artifact-id (e.g., commons-io), an unqualified symbol
414+ like 'commons-io may be used.
415+ Returns the File for the jar, or nil if not found."
416+ [lein-project artifact-symbol :- schema/Symbol]
417+ (let [group-id (or (namespace artifact-symbol) (name artifact-symbol))
418+ artifact-id (name artifact-symbol)
419+ jar-pattern (re-pattern (format " %s-.+\\ .jar$"
420+ (java.util.regex.Pattern/quote artifact-id)))
421+ group-path (str/replace group-id " ." " /" )
422+ classifier-pattern #"-(sources|javadoc|tests)\. jar$"
423+ classpath-jars (lein-classpath/resolve-managed-dependencies
424+ :dependencies :managed-dependencies lein-project)]
425+ (->> classpath-jars
426+ (filter #(and (re-find jar-pattern (.getPath %))
427+ (str/includes? (.getPath %) group-path)
428+ (not (re-find classifier-pattern (.getPath %)))))
429+ first)))
430+
431+ (schema/defn cp-classpath-jar-to-staging
432+ " Copy a single jar from the classpath to the staging directory.
433+ Returns a map with :jar-name, :staged-path, and :install-spec (if provided).
434+ Aborts the build if the jar is not found on the classpath."
435+ [lein-project {:keys [artifact install] :as jar-spec} :- ClasspathJarSpec]
436+ (let [jar-file (find-jar-on-classpath lein-project artifact)
437+ dest-dir (fs/file staging-dir classpath-jars-prefix)]
438+ (if jar-file
439+ (do
440+ (fs/mkdirs dest-dir)
441+ (let [dest-file (fs/file dest-dir (fs/base-name jar-file))]
442+ (lein-main/info (format " Copying classpath jar %s (%s) to %s"
443+ artifact (.getName jar-file) classpath-jars-prefix))
444+ (fs/copy jar-file dest-file)
445+ {:artifact artifact
446+ :jar-name (fs/base-name jar-file)
447+ :staged-path (str classpath-jars-prefix (fs/base-name jar-file))
448+ :install-spec install}))
449+ (lein-main/abort (format " Could not find jar for artifact %s on classpath" artifact)))))
450+
451+ (schema/defn cp-classpath-jars
452+ " Copy all configured classpath jars to the staging directory.
453+ Returns a sequence of maps describing what was copied."
454+ [lein-project]
455+ (let [jar-specs (get-in lein-project [:lein-ezbake :classpath-jars ] [])]
456+ (mapv (partial cp-classpath-jar-to-staging lein-project) jar-specs)))
457+
458+ ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
459+ ; ;; Staged file installation for classpath jars and project files
460+
461+ (defn- get-unique-install-dirs
462+ " Extract unique installation directories from staged file results."
463+ [staged-results]
464+ (->> staged-results
465+ (map #(get-in % [:install-spec :path ]))
466+ (remove nil?)
467+ distinct))
468+
469+ (defn- generate-mkdir-cmd
470+ " Generate a mkdir install command for a directory."
471+ [dir]
472+ (format " install -d -m 0755 \" ${DESTDIR}%s\" " dir))
473+
474+ (defn- generate-file-install-cmd
475+ " Generate an install command for a single staged file."
476+ [{:keys [staged-path install-spec]}]
477+ (let [{:keys [path mode owner group]} install-spec
478+ mode (or mode " 0644" )
479+ ownership-args (str (when owner (str " -o " owner))
480+ (when group (str " -g " group)))]
481+ (format " install -m %s%s \" %s\" \" ${DESTDIR}%s/\" "
482+ mode ownership-args staged-path path)))
483+
484+ (schema/defn generate-staged-file-install-commands :- [schema/Str]
485+ " Generate install commands for staged files that have :install-spec with :path.
486+ Returns a vector of shell command strings: directory creation followed by file installs."
487+ [staged-results]
488+ (let [with-install (->> staged-results
489+ (filter :install-spec )
490+ (filter #(get-in % [:install-spec :path ])))
491+ install-dirs (get-unique-install-dirs with-install)
492+ mkdir-cmds (map generate-mkdir-cmd install-dirs)
493+ install-cmds (map generate-file-install-cmd with-install)]
494+ (vec (concat mkdir-cmds install-cmds))))
495+
496+ ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
497+ ; ;; Project File Installation
498+
499+ (schema/defn cp-project-file-to-staging
500+ " Copy a project file to the staging directory for installation.
501+ Returns a map with :file-name, :staged-path, and :install-spec."
502+ [{:keys [file install] :as file-spec} :- ProjectFileSpec]
503+ (let [source-file (io/file file)
504+ dest-dir (fs/file staging-dir project-files-prefix)]
505+ (if (.exists source-file)
506+ (do
507+ (fs/mkdirs dest-dir)
508+ (let [dest-file (fs/file dest-dir (fs/base-name source-file))]
509+ (lein-main/info (format " Copying project file %s to %s" file project-files-prefix))
510+ (fs/copy source-file dest-file)
511+ {:file-name (fs/base-name source-file)
512+ :staged-path (str project-files-prefix (fs/base-name source-file))
513+ :install-spec install}))
514+ (lein-main/abort (format " Could not find project file %s" file)))))
515+
516+ (schema/defn cp-project-files
517+ " Copy all configured project files to the staging directory.
518+ Returns a sequence of maps describing what was copied."
519+ [lein-project]
520+ (let [file-specs (get-in lein-project [:lein-ezbake :project-files ] [])]
521+ (mapv cp-project-file-to-staging file-specs)))
522+
388523(defn get-real-name
389524 [project-name]
390525 (str/replace-first project-name #"^pe-" " " ))
@@ -579,7 +714,7 @@ Additional uberjar dependencies:
579714 " Construct the map of variables to pass on to the ezbake.rb template"
580715 [lein-project build-target
581716 config-files system-config-files cli-app-files bin-files terminus-files
582- upstream-ezbake-configs additional-uberjars timestamp]
717+ upstream-ezbake-configs additional-uberjars classpath-jar-results project-file-results timestamp]
583718 (let [termini (for [[name version files] terminus-files]
584719 {:name (as-ruby-literal name)
585720 :version (as-ruby-literal version)
@@ -592,6 +727,12 @@ Additional uberjar dependencies:
592727 platform
593728 name))
594729 val->ruby #(as-ruby-literal (get-val %1 %2 ))
730+ all-staged-results (concat classpath-jar-results project-file-results)
731+ all-install-cmds (generate-staged-file-install-commands all-staged-results)
732+ ; ; For :install, we need to append classpath jar commands to the upstream commands
733+ val->ruby-install (fn [platform]
734+ (as-ruby-literal
735+ (concat (get-val platform :install ) all-install-cmds)))
595736 get-local #(get-local-ezbake-var lein-project %1 %2 )
596737 local->ruby #(as-ruby-literal (get-local %1 %2 ))]
597738 {:project (as-ruby-literal (:name lein-project))
@@ -622,7 +763,7 @@ Additional uberjar dependencies:
622763 :debian-prerm (val->ruby :debian :prerm )
623764 :debian-postinst (val->ruby :debian :postinst )
624765 :debian-postinst-install (val->ruby :debian :postinst-install )
625- :debian-install (val->ruby :debian :install )
766+ :debian-install (val->ruby-install :debian )
626767 :debian-pre-start-action (val->ruby :debian :pre-start-action )
627768 :debian-post-start-action (val->ruby :debian :post-start-action )
628769 :debian-activated-triggers (local->ruby :debian-activated-triggers [])
@@ -635,7 +776,7 @@ Additional uberjar dependencies:
635776 :redhat-preinst (val->ruby :redhat :preinst )
636777 :redhat-postinst (val->ruby :redhat :postinst )
637778 :redhat-postinst-install (val->ruby :redhat :postinst-install )
638- :redhat-install (val->ruby :redhat :install )
779+ :redhat-install (val->ruby-install :redhat )
639780 :redhat-pre-start-action (val->ruby :redhat :pre-start-action )
640781 :redhat-post-start-action (val->ruby :redhat :post-start-action )
641782 :terminus-map termini
@@ -687,6 +828,8 @@ Additional uberjar dependencies:
687828 terminus-files
688829 upstream-ezbake-configs
689830 additional-uberjars
831+ classpath-jar-results
832+ project-file-results
690833 timestamp]
691834 (lein-main/info " generating ezbake config file" )
692835 (spit
@@ -702,6 +845,8 @@ Additional uberjar dependencies:
702845 terminus-files
703846 upstream-ezbake-configs
704847 additional-uberjars
848+ classpath-jar-results
849+ project-file-results
705850 timestamp))))
706851
707852(defn generate-project-data-yaml
@@ -939,6 +1084,8 @@ Additional uberjar dependencies:
9391084 upstream-ezbake-configs (get-upstream-ezbake-configs lein-project)
9401085 additional-uberjar-info (build-additional-uberjars! lein-project)
9411086 additional-uberjar-filenames (map #(fs/base-name (:uberjar %)) additional-uberjar-info)
1087+ classpath-jar-results (cp-classpath-jars lein-project)
1088+ project-file-results (cp-project-files lein-project)
9421089 timestamp (get-timestamp-string )]
9431090 (cp-shared-files non-excluded-deps get-cli-defaults-files-in)
9441091 (cp-shared-files non-excluded-deps get-build-scripts-files-in)
@@ -965,6 +1112,8 @@ Additional uberjar dependencies:
9651112 terminus-files
9661113 upstream-ezbake-configs
9671114 additional-uberjar-filenames
1115+ classpath-jar-results
1116+ project-file-results
9681117 timestamp)
9691118 (let [project-w-deployed-version (assoc lein-project :version deployed-version)]
9701119 (generate-project-data-yaml project-w-deployed-version build-target additional-uberjar-filenames)
0 commit comments