aboutsummaryrefslogtreecommitdiff
path: root/lux-lein/src/leiningen/lux/utils.clj
blob: 6ed549ae21d5a8f0efaccd57984dd45644e88cd7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
(ns leiningen.lux.utils
  (:require (clojure
             [template :refer [do-template]]
             [string :as string])
            [leiningen.core.classpath :as classpath])
  (:import (java.io File
                    InputStreamReader
                    BufferedReader)))

(def ^:const ^String default-target-dir "target")
(def ^:const ^String output-package "program.jar")

(def ^:private unit-separator (str (char 31)))

(def ^:private vm-options
  ""
  ;; "-server -Xms2048m -Xmx2048m -XX:+OptimizeStringConcat"
  )

(defn sanitize-path [^String path]
  (.replace path "/" java.io.File/separator))

(defn prepare-path [path]
  (let [is-windows? (and (.startsWith path "/")
                         (= "\\" java.io.File/separator))]
    (sanitize-path (if is-windows?
                     (.substring path 1)
                     path))))

(defn ^:private project-id [project]
  [(get project :group) (get project :name)])

(def ^:private lux-group "com.github.luxlang")
(def ^:private compiler-id [lux-group "lux-bootstrapper"])
(def ^:private jvm-compiler-id [lux-group "lux-jvm"])
(def ^:private stdlib-id [lux-group "stdlib"])

(defn ^:private id-path
  "(-> Project-ID Text)"
  [[group name]]
  (str (.replace group "." "/") "/" name))

(def ^:private compiler-path (id-path compiler-id))
(def ^:private jvm-compiler-path (id-path jvm-compiler-id))
(def ^:private stdlib-path (id-path stdlib-id))

(defn ^:private project-jars [project]
  (->> project
       classpath/get-classpath
       (filter #(.endsWith % ".jar"))))

(do-template [<name> <path>]
  (defn <name> [jar-paths]
    (some (fn [^:private path]
            (if (.contains path <path>)
              path
              nil))
          jar-paths))

  ^:private find-compiler-path (sanitize-path compiler-path)
  ^:private find-jvm-compiler-path (sanitize-path jvm-compiler-path)
  ^:private find-stdlib-path   (sanitize-path stdlib-path)
  )

(defn ^:private compiler-dependency? [path]
  (or (.contains path (sanitize-path "org/ow2/asm/asm-all"))
      (.contains path (sanitize-path "org/clojure/core.match"))
      (.contains path (sanitize-path "org/clojure/clojure"))
      (.contains path (sanitize-path compiler-path))
      (.contains path (sanitize-path jvm-compiler-path))))

(defn ^:private java-command [project]
  (str (get project :java-cmd "java")
       ;; " " (->> (get project :jvm-opts) (interpose " ") (reduce str ""))
       " " vm-options))

(defn ^:private join-paths [paths]
  (->> paths
       (interpose unit-separator)
       (apply str)
       (str unit-separator)))

(defn ^:private lux-command [project mode program-dependencies source-paths]
  (str "lux " mode
       " " (join-paths program-dependencies)
       " " (join-paths source-paths)
       " " (get project :target-path default-target-dir)))

(do-template [<name> <mode>]
  (defn <name> [project module source-paths]
    (let [is-stdlib? (= stdlib-id
                        (project-id project))
          raw-paths (project-jars project)
          stdlib-path (when (not is-stdlib?)
                        (when-let [stdlib-path (find-stdlib-path raw-paths)]
                          (prepare-path stdlib-path)))
          sdk-path (get-in project [:lux :android :sdk])
          android-path (str sdk-path
                            java.io.File/separator "platforms"
                            java.io.File/separator "android-"
                            (get-in project [:lux :android :version])
                            java.io.File/separator "android.jar")
          compiler-dependencies (let [compiler-dependencies (->> raw-paths
                                                                 (filter compiler-dependency?)
                                                                 (map prepare-path))
                                      with-android (if (.exists (new File android-path))
                                                     (cons android-path compiler-dependencies)
                                                     compiler-dependencies)]
                                  with-android)
          program-dependencies (let [deps (->> raw-paths
                                               (filter (complement compiler-dependency?))
                                               (map prepare-path))]
                                 (if (or is-stdlib?
                                         (nil? stdlib-path))
                                   deps
                                   (list* stdlib-path deps)))
          compiler-path (prepare-path (find-compiler-path raw-paths))
          compiler-class-path (->> compiler-dependencies
                                   (list* compiler-path)
                                   (interpose java.io.File/pathSeparator)
                                   (reduce str "")
                                   sanitize-path)
          program-class-path (->> program-dependencies
                                  (interpose java.io.File/pathSeparator)
                                  (reduce str "")
                                  sanitize-path)]
      (str (java-command project)
           " -cp " (str compiler-class-path java.io.File/pathSeparator program-class-path)
           " " (lux-command project <mode> program-dependencies source-paths))))

  compile-path (str "release " module)
  repl-path    "repl"
  )

(defn build-jvm [project module]
  (let [raw-paths (project-jars project)]
    (when-let [compiler-path (find-jvm-compiler-path raw-paths)]
      (let [compiler (prepare-path compiler-path)
            sources (->> (get project :source-paths (list))
                         (map #(str " --source " %))
                         (string/join ""))
            target (get project :target-path default-target-dir)]
        (str (java-command project)
             " -jar " compiler " build"
             ;; " --library " "~/lux/stdlib/target/library.tar"
             sources
             " --target " target
             " --module " module)))))

(def ^:private normal-exit 0)

(defn run-process [command working-directory pre post]
  (let [process (.exec (Runtime/getRuntime) command nil working-directory)]
    (with-open [std-out (->> process .getInputStream (new InputStreamReader) (new BufferedReader))
                std-err (->> process .getErrorStream (new InputStreamReader) (new BufferedReader))]
      (println pre)
      (loop []
        (when-let [line (.readLine std-out)]
          (println line)
          (recur)))
      (loop []
        (when-let [line (.readLine std-err)]
          (println line)
          (recur)))
      (println post)
      (= normal-exit (.waitFor process)))))