| @@ -0,0 +1,205 | |||||
|
|
1 | # SOLID и контейнеры | |||
|
|
2 | ||||
|
|
3 | Рассмотрим простой пример того, как может быть построено приложения и почему приходится прибегать к такому сложному и непонятному решению как контейнеры. | |||
|
|
4 | ||||
|
|
5 | Допустим у нас есть приложение, которое работает с комментариями к товару, и мы решили разделить логику и работу с источником данных, разнеся ее между контроллером и контекстом данных и тут возникает вопрос, как они должны взаимодействовать друг с другом. | |||
|
|
6 | ||||
|
|
7 | ```ts | |||
|
|
8 | // BAD | |||
|
|
9 | class CommentsController { | |||
|
|
10 | ||||
|
|
11 | _db : DataContext, | |||
|
|
12 | ||||
|
|
13 | constructor(connectionString: string) { | |||
|
|
14 | // explicit dependency | |||
|
|
15 | this._db = new PgSqlDataContext(connectionString); | |||
|
|
16 | } | |||
|
|
17 | ||||
|
|
18 | //... | |||
|
|
19 | } | |||
|
|
20 | ||||
|
|
21 | // GOOD | |||
|
|
22 | class CommmentsController { | |||
|
|
23 | ||||
|
|
24 | _db : DataContext, | |||
|
|
25 | ||||
|
|
26 | constructor(dataContext: DataContext) { | |||
|
|
27 | // a dependency is passed through the constructor | |||
|
|
28 | this._db = dataContext; | |||
|
|
29 | } | |||
|
|
30 | ||||
|
|
31 | //... | |||
|
|
32 | } | |||
|
|
33 | ||||
|
|
34 | // the container will do all the work | |||
|
|
35 | // the container knows which DataContext to create | |||
|
|
36 | let commentsController = container.getService<CommmentsController>("commmentsController"); | |||
|
|
37 | ||||
|
|
38 | //... | |||
|
|
39 | ||||
|
|
40 | commmentsController.createComment({ text: "Hello, unfair world!" }); | |||
|
|
41 | ||||
|
|
42 | ``` | |||
|
|
43 | ||||
|
|
44 | Для ответа на вопрос, что такое хорошо и что такое - плохо существует *SOLID* - набор принципов ООП при разработки программного обеспечения | |||
|
|
45 | ||||
|
|
46 | - **S**ingle responsibility | |||
|
|
47 | - **O**pen-closed | |||
|
|
48 | - **L**iskov substitution | |||
|
|
49 | - **I**nterface segregation | |||
|
|
50 | - **D**ependency inversion | |||
|
|
51 | ||||
|
|
52 | Использование данных принципов позволяет писать код, которыей будет обладать | |||
|
|
53 | ||||
|
|
54 | - повоторной используемостью | |||
|
|
55 | - тестируемостью | |||
|
|
56 | - читаемостью | |||
|
|
57 | - поддаваться доработкам | |||
|
|
58 | ||||
|
|
59 | *IoC* Контейнеры являются инструментом для построения ПО согласно принциам SOLID, как клей связывают друг с другом компоненты. | |||
|
|
60 | ||||
|
|
61 | Контейнеры предоставляют стандарный механизм для описания и конструирования объектов, т.е. это некоторый объект в котором сосредоточена информация о сруктуре приложения и именно он должен создавать объекты и устанавливать между ними связи. Контейнер похож на шаблоны *абстрактная фабрика (Abstract Factory)* и *строитель (Builder)*. | |||
|
|
62 | ||||
|
|
63 | Для построения графа объектов контейнеру требуется конфигурация, которая состоит из набора дескрипторов сервисов, а также зависимостями между ними. | |||
|
|
64 | ||||
|
|
65 | Сервисы регистрируются в контейнере, каждый сервис имеет свое имя, позволяющее получить его у контейнера. | |||
|
|
66 | ||||
|
|
67 | ```js | |||
|
|
68 | ||||
|
|
69 | await container.configure({ | |||
|
|
70 | db: { | |||
|
|
71 | $type : 'my/app/PgSqlDataContext', | |||
|
|
72 | params: { | |||
|
|
73 | host: 'localhost', | |||
|
|
74 | port: 5432 | |||
|
|
75 | } | |||
|
|
76 | }, | |||
|
|
77 | commmentsController: { | |||
|
|
78 | $type: 'my/app/CommmentsController', | |||
|
|
79 | params: {$dependency: 'db'} | |||
|
|
80 | } | |||
|
|
81 | }); | |||
|
|
82 | ||||
|
|
83 | ``` | |||
|
|
84 | ||||
|
|
85 | В приведенном примере в контейнере объявляются два сервиса, один для работы с базой, воторой - для работы с комментариями. Между сервисами устанавливается зависимость, при создании `commmentsController` ему в контроллер передается созданный экземпляр контекста данных. | |||
|
|
86 | ||||
|
|
87 | Приложению остается только получить нужный сервис у контейнера и воспользоваться последним. | |||
|
|
88 | ||||
|
|
89 | > **Правило:** объекты не должны знать про контейнер! | |||
|
|
90 | ||||
|
|
91 | Очень важно соблюдать данное правило, поскольку если внутри класса будет использоваться контейнер, то он может запрашивать любые сервисы в любое время, что сильно усложнит отслеживание зависимостей. Исключением могут быть только объекты отвечающие за жизненный цикл приложения, которые создают и конфигурируют контейнер и не участвуют в бизнес-логике. | |||
|
|
92 | ||||
|
|
93 | Конфигурация контейнера является асинхронной операцией, поскольку может привести к загрузке модулей, где находятся объявления типов. Полностью сконфигурированный контейнер позволяет получать сервисы уже синхронно, что упрощает работу с ним и не тратит дополнительные ресурсы на использование асинхронных операций. | |||
|
|
94 | ||||
|
|
95 | ## Конфигурация | |||
|
|
96 | ||||
|
|
97 | Контейнер представляет собой словарь дескрипторов содержащих информацию о сервисах, в роли сервисов можно зарегистрировать: | |||
|
|
98 | ||||
|
|
99 | - типы | |||
|
|
100 | - фабричные методы | |||
|
|
101 | - существующие объекты и простые занчения | |||
|
|
102 | ||||
|
|
103 | подробоное описание конфигурации контейнера [di-config.md](di-config.md) | |||
|
|
104 | ||||
|
|
105 | ## Вложенные контейнеры | |||
|
|
106 | ||||
|
|
107 | Контейнеры могут создаваться на основе уже существующих, так называемые дочерние контейнеры, они получают все сервисы описанные в родительском контейнере. | |||
|
|
108 | ||||
|
|
109 | При изменении конфигурации дочернего контейнера - родительский контейнер останется без изменений. Использование дочерних контейнеров позволяет оптимизировать конфигурирование и дальнейшую работу с сервисами. | |||
|
|
110 | ||||
|
|
111 | Примером такой оптимизации может служить веб-приложение, в котором загружается контейнер для всего приложения, а для каждого запроса создается свой дочерний контейнер, который донастраивается контроллером запроса. По окончанию выполнения запроса дочерний контейнр уничтожается, освобождая ресурсы. | |||
|
|
112 | ||||
|
|
113 | ## Активация сервисов | |||
|
|
114 | ||||
|
|
115 | Активация - процесс, когда контейнер в ответ на запрос выдает экземпляр сервиса. При обработке запроса на получение сервиса контейнер создает контекст активации, всю работу по получению экземпляра сервиса выполняет дескриптор, которому передается контекст активации. | |||
|
|
116 | ||||
|
|
117 | 1. создается контекст активации, | |||
|
|
118 | 2. ищется запись декриптора сервиса в контейнере, | |||
|
|
119 | 3. дескриптору передается контекст активации, | |||
|
|
120 | 4. дескриптор возвращает экземпляр сервиса. | |||
|
|
121 | ||||
|
|
122 | В процессе создания экземпляра сервиса, дескриптор может использовать контекст активации для обращения к контейнеру, текущим сервисам, а также может использовать его для активации других дескрипторов. | |||
|
|
123 | ||||
|
|
124 | ### Типы активации сервисов | |||
|
|
125 | ||||
|
|
126 | Тип активации относится к сервисам, в качестве которых были зарегистрированы либо типы, либо фабричные методы. | |||
|
|
127 | ||||
|
|
128 | ```ts | |||
|
|
129 | ||||
|
|
130 | container.configure({ | |||
|
|
131 | foo: { | |||
|
|
132 | $type: 'my/ServiceClass', | |||
|
|
133 | activation: 'container' | |||
|
|
134 | }, | |||
|
|
135 | bar: { | |||
|
|
136 | $factory: () => { | |||
|
|
137 | return new ServiceClass(); | |||
|
|
138 | }, | |||
|
|
139 | activation: 'context' | |||
|
|
140 | } | |||
|
|
141 | }); | |||
|
|
142 | ||||
|
|
143 | ``` | |||
|
|
144 | ||||
|
|
145 | #### call | |||
|
|
146 | ||||
|
|
147 | Тип активации по-умолчанию, создается каждый раз, когда сервис запрашивается. | |||
|
|
148 | ||||
|
|
149 | #### context | |||
|
|
150 | ||||
|
|
151 | Экземпляр будет создан только один раз в рамках текущего контекста активации, т.е. при разрешении зависимостей будет использоваться все время один и тотже экземплар. | |||
|
|
152 | ||||
|
|
153 | #### container | |||
|
|
154 | ||||
|
|
155 | Будет создан только один экземпляр для контейнера, где сервис зарегистрирован. Созданный экземпляр сервиса будет автоматически очищен при освобождении контейнера. | |||
|
|
156 | ||||
|
|
157 | ```ts | |||
|
|
158 | container.cofigure({ | |||
|
|
159 | db: { | |||
|
|
160 | $type : 'my/app/PgSqlDataContext', | |||
|
|
161 | activation: 'container', | |||
|
|
162 | params: { | |||
|
|
163 | host: 'localhost', | |||
|
|
164 | port: 5432 | |||
|
|
165 | } | |||
|
|
166 | } | |||
|
|
167 | }) | |||
|
|
168 | ||||
|
|
169 | let db = container.getService<DataContext>('db'); | |||
|
|
170 | ||||
|
|
171 | let db2 = childContainer.getService<DataContext>('db'); | |||
|
|
172 | ||||
|
|
173 | //db === db2 | |||
|
|
174 | ||||
|
|
175 | container.dispose(); // will dispose db | |||
|
|
176 | ||||
|
|
177 | ``` | |||
|
|
178 | ||||
|
|
179 | #### hierarchy | |||
|
|
180 | ||||
|
|
181 | Будет создан только один экземпляр для контейнера, который создал контекст активации. Созданный экземпляр червиса будет автоматически очищен при освобождении контейнера. | |||
|
|
182 | ||||
|
|
183 | Данный вариант похож на тип активации `container`, но позволяет описать сервисы в родительском контейнере, а управлять временем жизни экземпляров этих сервисов при помощи дочерних контейнеров. Такой подход позволяет оптимизировать конфигурацию контейнеров. | |||
|
|
184 | ||||
|
|
185 | ```ts | |||
|
|
186 | container.cofigure({ | |||
|
|
187 | db: { | |||
|
|
188 | $type : 'my/app/PgSqlDataContext', | |||
|
|
189 | activation: 'hierarchy', | |||
|
|
190 | params: { | |||
|
|
191 | host: 'localhost', | |||
|
|
192 | port: 5432 | |||
|
|
193 | } | |||
|
|
194 | } | |||
|
|
195 | }) | |||
|
|
196 | ||||
|
|
197 | let db = container.getService<DataContext>('db'); | |||
|
|
198 | ||||
|
|
199 | let db2 = childContainer.getService<DataContext>('db'); | |||
|
|
200 | ||||
|
|
201 | //db !== db2 | |||
|
|
202 | ||||
|
|
203 | childContainer.dispose(); // will dispose db2, db will be left intact | |||
|
|
204 | ||||
|
|
205 | ``` No newline at end of file | |||
| 1 | NO CONTENT: new file 100644, binary diff hidden |
|
NO CONTENT: new file 100644, binary diff hidden |
| @@ -0,0 +1,5 | |||||
|
|
1 | distributionBase=GRADLE_USER_HOME | |||
|
|
2 | distributionPath=wrapper/dists | |||
|
|
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.7-bin.zip | |||
|
|
4 | zipStoreBase=GRADLE_USER_HOME | |||
|
|
5 | zipStorePath=wrapper/dists | |||
| @@ -0,0 +1,172 | |||||
|
|
1 | #!/usr/bin/env sh | |||
|
|
2 | ||||
|
|
3 | ############################################################################## | |||
|
|
4 | ## | |||
|
|
5 | ## Gradle start up script for UN*X | |||
|
|
6 | ## | |||
|
|
7 | ############################################################################## | |||
|
|
8 | ||||
|
|
9 | # Attempt to set APP_HOME | |||
|
|
10 | # Resolve links: $0 may be a link | |||
|
|
11 | PRG="$0" | |||
|
|
12 | # Need this for relative symlinks. | |||
|
|
13 | while [ -h "$PRG" ] ; do | |||
|
|
14 | ls=`ls -ld "$PRG"` | |||
|
|
15 | link=`expr "$ls" : '.*-> \(.*\)$'` | |||
|
|
16 | if expr "$link" : '/.*' > /dev/null; then | |||
|
|
17 | PRG="$link" | |||
|
|
18 | else | |||
|
|
19 | PRG=`dirname "$PRG"`"/$link" | |||
|
|
20 | fi | |||
|
|
21 | done | |||
|
|
22 | SAVED="`pwd`" | |||
|
|
23 | cd "`dirname \"$PRG\"`/" >/dev/null | |||
|
|
24 | APP_HOME="`pwd -P`" | |||
|
|
25 | cd "$SAVED" >/dev/null | |||
|
|
26 | ||||
|
|
27 | APP_NAME="Gradle" | |||
|
|
28 | APP_BASE_NAME=`basename "$0"` | |||
|
|
29 | ||||
|
|
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |||
|
|
31 | DEFAULT_JVM_OPTS="" | |||
|
|
32 | ||||
|
|
33 | # Use the maximum available, or set MAX_FD != -1 to use that value. | |||
|
|
34 | MAX_FD="maximum" | |||
|
|
35 | ||||
|
|
36 | warn () { | |||
|
|
37 | echo "$*" | |||
|
|
38 | } | |||
|
|
39 | ||||
|
|
40 | die () { | |||
|
|
41 | echo | |||
|
|
42 | echo "$*" | |||
|
|
43 | echo | |||
|
|
44 | exit 1 | |||
|
|
45 | } | |||
|
|
46 | ||||
|
|
47 | # OS specific support (must be 'true' or 'false'). | |||
|
|
48 | cygwin=false | |||
|
|
49 | msys=false | |||
|
|
50 | darwin=false | |||
|
|
51 | nonstop=false | |||
|
|
52 | case "`uname`" in | |||
|
|
53 | CYGWIN* ) | |||
|
|
54 | cygwin=true | |||
|
|
55 | ;; | |||
|
|
56 | Darwin* ) | |||
|
|
57 | darwin=true | |||
|
|
58 | ;; | |||
|
|
59 | MINGW* ) | |||
|
|
60 | msys=true | |||
|
|
61 | ;; | |||
|
|
62 | NONSTOP* ) | |||
|
|
63 | nonstop=true | |||
|
|
64 | ;; | |||
|
|
65 | esac | |||
|
|
66 | ||||
|
|
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | |||
|
|
68 | ||||
|
|
69 | # Determine the Java command to use to start the JVM. | |||
|
|
70 | if [ -n "$JAVA_HOME" ] ; then | |||
|
|
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | |||
|
|
72 | # IBM's JDK on AIX uses strange locations for the executables | |||
|
|
73 | JAVACMD="$JAVA_HOME/jre/sh/java" | |||
|
|
74 | else | |||
|
|
75 | JAVACMD="$JAVA_HOME/bin/java" | |||
|
|
76 | fi | |||
|
|
77 | if [ ! -x "$JAVACMD" ] ; then | |||
|
|
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | |||
|
|
79 | ||||
|
|
80 | Please set the JAVA_HOME variable in your environment to match the | |||
|
|
81 | location of your Java installation." | |||
|
|
82 | fi | |||
|
|
83 | else | |||
|
|
84 | JAVACMD="java" | |||
|
|
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |||
|
|
86 | ||||
|
|
87 | Please set the JAVA_HOME variable in your environment to match the | |||
|
|
88 | location of your Java installation." | |||
|
|
89 | fi | |||
|
|
90 | ||||
|
|
91 | # Increase the maximum file descriptors if we can. | |||
|
|
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then | |||
|
|
93 | MAX_FD_LIMIT=`ulimit -H -n` | |||
|
|
94 | if [ $? -eq 0 ] ; then | |||
|
|
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | |||
|
|
96 | MAX_FD="$MAX_FD_LIMIT" | |||
|
|
97 | fi | |||
|
|
98 | ulimit -n $MAX_FD | |||
|
|
99 | if [ $? -ne 0 ] ; then | |||
|
|
100 | warn "Could not set maximum file descriptor limit: $MAX_FD" | |||
|
|
101 | fi | |||
|
|
102 | else | |||
|
|
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | |||
|
|
104 | fi | |||
|
|
105 | fi | |||
|
|
106 | ||||
|
|
107 | # For Darwin, add options to specify how the application appears in the dock | |||
|
|
108 | if $darwin; then | |||
|
|
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | |||
|
|
110 | fi | |||
|
|
111 | ||||
|
|
112 | # For Cygwin, switch paths to Windows format before running java | |||
|
|
113 | if $cygwin ; then | |||
|
|
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` | |||
|
|
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | |||
|
|
116 | JAVACMD=`cygpath --unix "$JAVACMD"` | |||
|
|
117 | ||||
|
|
118 | # We build the pattern for arguments to be converted via cygpath | |||
|
|
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | |||
|
|
120 | SEP="" | |||
|
|
121 | for dir in $ROOTDIRSRAW ; do | |||
|
|
122 | ROOTDIRS="$ROOTDIRS$SEP$dir" | |||
|
|
123 | SEP="|" | |||
|
|
124 | done | |||
|
|
125 | OURCYGPATTERN="(^($ROOTDIRS))" | |||
|
|
126 | # Add a user-defined pattern to the cygpath arguments | |||
|
|
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then | |||
|
|
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | |||
|
|
129 | fi | |||
|
|
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh | |||
|
|
131 | i=0 | |||
|
|
132 | for arg in "$@" ; do | |||
|
|
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | |||
|
|
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option | |||
|
|
135 | ||||
|
|
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition | |||
|
|
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | |||
|
|
138 | else | |||
|
|
139 | eval `echo args$i`="\"$arg\"" | |||
|
|
140 | fi | |||
|
|
141 | i=$((i+1)) | |||
|
|
142 | done | |||
|
|
143 | case $i in | |||
|
|
144 | (0) set -- ;; | |||
|
|
145 | (1) set -- "$args0" ;; | |||
|
|
146 | (2) set -- "$args0" "$args1" ;; | |||
|
|
147 | (3) set -- "$args0" "$args1" "$args2" ;; | |||
|
|
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; | |||
|
|
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | |||
|
|
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | |||
|
|
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | |||
|
|
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | |||
|
|
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | |||
|
|
154 | esac | |||
|
|
155 | fi | |||
|
|
156 | ||||
|
|
157 | # Escape application args | |||
|
|
158 | save () { | |||
|
|
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done | |||
|
|
160 | echo " " | |||
|
|
161 | } | |||
|
|
162 | APP_ARGS=$(save "$@") | |||
|
|
163 | ||||
|
|
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules | |||
|
|
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" | |||
|
|
166 | ||||
|
|
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong | |||
|
|
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then | |||
|
|
169 | cd "$(dirname "$0")" | |||
|
|
170 | fi | |||
|
|
171 | ||||
|
|
172 | exec "$JAVACMD" "$@" | |||
| @@ -0,0 +1,84 | |||||
|
|
1 | @if "%DEBUG%" == "" @echo off | |||
|
|
2 | @rem ########################################################################## | |||
|
|
3 | @rem | |||
|
|
4 | @rem Gradle startup script for Windows | |||
|
|
5 | @rem | |||
|
|
6 | @rem ########################################################################## | |||
|
|
7 | ||||
|
|
8 | @rem Set local scope for the variables with windows NT shell | |||
|
|
9 | if "%OS%"=="Windows_NT" setlocal | |||
|
|
10 | ||||
|
|
11 | set DIRNAME=%~dp0 | |||
|
|
12 | if "%DIRNAME%" == "" set DIRNAME=. | |||
|
|
13 | set APP_BASE_NAME=%~n0 | |||
|
|
14 | set APP_HOME=%DIRNAME% | |||
|
|
15 | ||||
|
|
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |||
|
|
17 | set DEFAULT_JVM_OPTS= | |||
|
|
18 | ||||
|
|
19 | @rem Find java.exe | |||
|
|
20 | if defined JAVA_HOME goto findJavaFromJavaHome | |||
|
|
21 | ||||
|
|
22 | set JAVA_EXE=java.exe | |||
|
|
23 | %JAVA_EXE% -version >NUL 2>&1 | |||
|
|
24 | if "%ERRORLEVEL%" == "0" goto init | |||
|
|
25 | ||||
|
|
26 | echo. | |||
|
|
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |||
|
|
28 | echo. | |||
|
|
29 | echo Please set the JAVA_HOME variable in your environment to match the | |||
|
|
30 | echo location of your Java installation. | |||
|
|
31 | ||||
|
|
32 | goto fail | |||
|
|
33 | ||||
|
|
34 | :findJavaFromJavaHome | |||
|
|
35 | set JAVA_HOME=%JAVA_HOME:"=% | |||
|
|
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe | |||
|
|
37 | ||||
|
|
38 | if exist "%JAVA_EXE%" goto init | |||
|
|
39 | ||||
|
|
40 | echo. | |||
|
|
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | |||
|
|
42 | echo. | |||
|
|
43 | echo Please set the JAVA_HOME variable in your environment to match the | |||
|
|
44 | echo location of your Java installation. | |||
|
|
45 | ||||
|
|
46 | goto fail | |||
|
|
47 | ||||
|
|
48 | :init | |||
|
|
49 | @rem Get command-line arguments, handling Windows variants | |||
|
|
50 | ||||
|
|
51 | if not "%OS%" == "Windows_NT" goto win9xME_args | |||
|
|
52 | ||||
|
|
53 | :win9xME_args | |||
|
|
54 | @rem Slurp the command line arguments. | |||
|
|
55 | set CMD_LINE_ARGS= | |||
|
|
56 | set _SKIP=2 | |||
|
|
57 | ||||
|
|
58 | :win9xME_args_slurp | |||
|
|
59 | if "x%~1" == "x" goto execute | |||
|
|
60 | ||||
|
|
61 | set CMD_LINE_ARGS=%* | |||
|
|
62 | ||||
|
|
63 | :execute | |||
|
|
64 | @rem Setup the command line | |||
|
|
65 | ||||
|
|
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | |||
|
|
67 | ||||
|
|
68 | @rem Execute Gradle | |||
|
|
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | |||
|
|
70 | ||||
|
|
71 | :end | |||
|
|
72 | @rem End local scope for the variables with windows NT shell | |||
|
|
73 | if "%ERRORLEVEL%"=="0" goto mainEnd | |||
|
|
74 | ||||
|
|
75 | :fail | |||
|
|
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | |||
|
|
77 | rem the _cmd.exe /c_ return code! | |||
|
|
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | |||
|
|
79 | exit /b 1 | |||
|
|
80 | ||||
|
|
81 | :mainEnd | |||
|
|
82 | if "%OS%"=="Windows_NT" endlocal | |||
|
|
83 | ||||
|
|
84 | :omega | |||
| @@ -0,0 +1,15 | |||||
|
|
1 | /* | |||
|
|
2 | * This settings file was generated by the Gradle 'init' task. | |||
|
|
3 | * | |||
|
|
4 | * The settings file is used to specify which projects to include in your build. | |||
|
|
5 | * In a single project build this file can be empty or even removed. | |||
|
|
6 | * | |||
|
|
7 | * Detailed information about configuring a multi-project build in Gradle can be found | |||
|
|
8 | * in the user guide at https://docs.gradle.org/3.5/userguide/multi_project_builds.html | |||
|
|
9 | */ | |||
|
|
10 | ||||
|
|
11 | // To declare projects as part of a multi-project build use the 'include' method | |||
|
|
12 | ||||
|
|
13 | //include 'sub-project-name' | |||
|
|
14 | ||||
|
|
15 | rootProject.name = 'implab-core' No newline at end of file | |||
| @@ -1,91 +1,94 | |||||
|
|
1 | if (release != 'rtm') { | |||
|
|
2 | version += "-$release" | |||
|
|
3 | } | |||
| 1 |
|
4 | |||
| 2 | println "version: $version" |
|
5 | println "version: $version" | |
| 3 |
|
6 | |||
| 4 | def distDir = "$buildDir/dist" |
|
7 | def distDir = "$buildDir/dist" | |
| 5 | def testDir = "$buildDir/test" |
|
8 | def testDir = "$buildDir/test" | |
| 6 |
|
9 | |||
| 7 | task clean { |
|
10 | task clean { | |
| 8 | doLast { |
|
11 | doLast { | |
| 9 | delete buildDir |
|
12 | delete buildDir | |
| 10 | delete 'node_modules/@implab' |
|
13 | delete 'node_modules/@implab' | |
| 11 | } |
|
14 | } | |
| 12 | } |
|
15 | } | |
| 13 |
|
16 | |||
| 14 | task cleanNpm { |
|
17 | task cleanNpm { | |
| 15 | doLast { |
|
18 | doLast { | |
| 16 | delete 'node_modules' |
|
19 | delete 'node_modules' | |
| 17 | } |
|
20 | } | |
| 18 | } |
|
21 | } | |
| 19 |
|
22 | |||
| 20 | task _npmInstall() { |
|
23 | task _npmInstall() { | |
| 21 | inputs.file("package.json") |
|
24 | inputs.file("package.json") | |
| 22 | outputs.dir("node_modules") |
|
25 | outputs.dir("node_modules") | |
| 23 | doLast { |
|
26 | doLast { | |
| 24 | exec { |
|
27 | exec { | |
| 25 | commandLine 'npm', 'install' |
|
28 | commandLine 'npm', 'install' | |
| 26 | } |
|
29 | } | |
| 27 | } |
|
30 | } | |
| 28 | } |
|
31 | } | |
| 29 |
|
32 | |||
| 30 | task _legacyJs(type:Copy) { |
|
33 | task _legacyJs(type:Copy) { | |
| 31 | from 'src/js/' |
|
34 | from 'src/js/' | |
| 32 | into distDir |
|
35 | into distDir | |
| 33 | } |
|
36 | } | |
| 34 |
|
37 | |||
| 35 | task _buildTs(dependsOn: _npmInstall, type:Exec) { |
|
38 | task _buildTs(dependsOn: _npmInstall, type:Exec) { | |
| 36 | inputs.dir('src/ts') |
|
39 | inputs.dir('src/ts') | |
| 37 | inputs.file('tsc.json') |
|
40 | inputs.file('tsc.json') | |
| 38 | outputs.dir(distDir) |
|
41 | outputs.dir(distDir) | |
| 39 |
|
42 | |||
| 40 | commandLine 'node_modules/.bin/tsc', '-p', 'tsc.json' |
|
43 | commandLine 'node_modules/.bin/tsc', '-p', 'tsc.json' | |
| 41 | } |
|
44 | } | |
| 42 |
|
45 | |||
| 43 | task _packageMeta(type: Copy) { |
|
46 | task _packageMeta(type: Copy) { | |
| 44 | inputs.property("version", version) |
|
47 | inputs.property("version", version) | |
| 45 | from('.') { |
|
48 | from('.') { | |
| 46 | include 'package.json', '.npmignore', 'readme.md', 'license', 'history.md' |
|
49 | include 'package.json', '.npmignore', 'readme.md', 'license', 'history.md' | |
| 47 | } |
|
50 | } | |
| 48 | into distDir |
|
51 | into distDir | |
| 49 | doLast { |
|
52 | doLast { | |
| 50 | exec { |
|
53 | exec { | |
| 51 | workingDir distDir |
|
54 | workingDir distDir | |
| 52 | commandLine 'npm', 'version', version |
|
55 | commandLine 'npm', 'version', version | |
| 53 | } |
|
56 | } | |
| 54 | } |
|
57 | } | |
| 55 | } |
|
58 | } | |
| 56 |
|
59 | |||
| 57 | task build(dependsOn: [_npmInstall, _buildTs, _legacyJs, _packageMeta]) { |
|
60 | task build(dependsOn: [_npmInstall, _buildTs, _legacyJs, _packageMeta]) { | |
| 58 |
|
61 | |||
| 59 | } |
|
62 | } | |
| 60 |
|
63 | |||
| 61 | task _localInstall(dependsOn: build, type: Exec) { |
|
64 | task _localInstall(dependsOn: build, type: Exec) { | |
| 62 | inputs.file("$distDir/package.json") |
|
65 | inputs.file("$distDir/package.json") | |
| 63 | outputs.upToDateWhen { |
|
66 | outputs.upToDateWhen { | |
| 64 | new File("$projectDir/node_modules/@implab/core").exists() |
|
67 | new File("$projectDir/node_modules/@implab/core").exists() | |
| 65 | } |
|
68 | } | |
| 66 |
|
69 | |||
| 67 | commandLine 'npm', 'install', '--no-save', '--force', distDir |
|
70 | commandLine 'npm', 'install', '--no-save', '--force', distDir | |
| 68 | } |
|
71 | } | |
| 69 |
|
72 | |||
| 70 | task copyJsTests(type: Copy) { |
|
73 | task copyJsTests(type: Copy) { | |
| 71 | from 'test/js' |
|
74 | from 'test/js' | |
| 72 | into testDir |
|
75 | into testDir | |
| 73 | } |
|
76 | } | |
| 74 |
|
77 | |||
| 75 | task buildTests(dependsOn: _localInstall, type: Exec) { |
|
78 | task buildTests(dependsOn: _localInstall, type: Exec) { | |
| 76 | inputs.dir('test/ts') |
|
79 | inputs.dir('test/ts') | |
| 77 | inputs.file('tsc.test.json') |
|
80 | inputs.file('tsc.test.json') | |
| 78 | outputs.dir(testDir) |
|
81 | outputs.dir(testDir) | |
| 79 |
|
82 | |||
| 80 | commandLine 'node_modules/.bin/tsc', '-p', 'tsc.test.json' |
|
83 | commandLine 'node_modules/.bin/tsc', '-p', 'tsc.test.json' | |
| 81 | } |
|
84 | } | |
| 82 |
|
85 | |||
| 83 | task test(dependsOn: [copyJsTests, buildTests], type: Exec) { |
|
86 | task test(dependsOn: [copyJsTests, buildTests], type: Exec) { | |
| 84 | commandLine 'node', 'run-amd-tests.js' |
|
87 | commandLine 'node', 'run-amd-tests.js' | |
| 85 | } |
|
88 | } | |
| 86 |
|
89 | |||
| 87 | task pack(dependsOn: build, type: Exec) { |
|
90 | task pack(dependsOn: build, type: Exec) { | |
| 88 | workingDir = distDir |
|
91 | workingDir = distDir | |
| 89 |
|
92 | |||
| 90 | commandLine 'npm', 'pack' |
|
93 | commandLine 'npm', 'pack' | |
| 91 | } No newline at end of file |
|
94 | } | |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
| 1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now
