* Bug #13471 fixed - Infinite loop in ilib_build_jar used on an empty dir
[scilab.git] / scilab / modules / dynamic_link / macros / ilib_build_jar.sci
1 // ====================================================================
2 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 // Copyright (C) 2013 - Scilab Enterprises
4 //
5 // This file must be used under the terms of the CeCILL.
6 // This source file is licensed as described in the file COPYING, which
7 // you should have received as part of this distribution.  The terms
8 // are also available at
9 // http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10 // =====================================================================
11
12 // Builds a Java package (JAR) from a set of Java sources (see SEP #116)
13 // - jarFilePath: is the JAR target file path
14 // - packageNames: names of packages to archive in the JAR
15 // - sourcePaths: paths to directories containing Java sources
16 // - classPaths (optional): paths to dependencies (JARs or directories)
17 // - manifestFilePath (optional) : file path to manifest
18 function ilib_build_jar(jarFilePath, packageNames, sourcePaths, classPaths, manifestFilePath)
19
20     // Returns all the java source files contained in a path tree
21     function javaFilePaths = findJavaFiles(path, javaFilePaths)
22         fileNames = listfiles(path)';
23         if (isempty(fileNames)) then
24             return;
25         end
26         filePaths = fullfile(path, fileNames);
27
28         // First, explore sub directories
29         dirPaths = filePaths(find(isdir(filePaths)));
30         for i = 1:size(dirPaths, "*")
31             javaFilePaths = [javaFilePaths; findJavaFiles(dirPaths(i), [])];
32         end
33
34         // Then add Java files of that directory
35         dirJavaFilePaths = filePaths(find(fileext(filePaths) == ".java"));
36         javaFilePaths = [javaFilePaths; dirJavaFilePaths'];
37     endfunction
38
39     // Returns the JIMS build root path
40     // It is the JIMS/bin folder in TMPDIR
41     function jimsBuildPath = getJimsBuildPath()
42         jimsBuildPath = fullfile(TMPDIR, "JIMS/bin");
43     endfunction
44
45     // Returns the package compilation path
46     // It is the 'deepest' directory containing the built classes
47     // if package is 'com.foo.package' the returned path will be:
48     //   TMPDIR/JIMS/bin/com/foo/package
49     function packageCompilePath = getPackageCompilePath(packageName)
50         packageSubPath = strsubst(packageName, ".", filesep());
51         packageCompilePath = fullfile(getJimsBuildPath(), packageSubPath);
52     endfunction
53
54     // Returns the jar root input path
55     // It is the directory that will be jar-ed
56     // if jar is 'com.foo.package' the returned path will be:
57     //   TMPDIR/JIMS/bin/com.foo.package
58     function jarInputRootPath = getJarInputRootPath(jarName)
59         jarInputRootPath = fullfile(getJimsBuildPath(), "_jar_" + jarName);
60         if isdir(jarInputRootPath) then
61             removedir(jarInputRootPath);
62         end
63         mkdir(jarInputRootPath);
64     endfunction
65
66     // Returns the package path in the jar input path
67     // It is the directory where the classes will be copied
68     // if package is 'com.foo.package' the returned path will be:
69     //   TMPDIR/JIMS/com.foo.package/bin/com/foo/package
70     function jarInputPackagePath = getJarPackagePath(jarInputRootPath, packageName)
71         if ~isempty(packageName) then
72             packagePath = strsubst(packageName, ".", filesep());
73             jarInputPackagePath = fullfile(jarInputRootPath, packagePath);
74             mkdir(jarInputPackagePath);
75         else
76             jarInputPackagePath = jarInputRootPath;
77         end
78     endfunction
79
80     // Add header instructions for loader and cleaner script (license info, change dir, etc..)
81     function addHeaderToScript(scriptName, fd)
82         mputl("// This file is released under the 3-clause BSD license. See COPYING-BSD.", fd);
83         mputl("// Generated by builder.sce: Please, do not edit this file.", fd);
84         mputl("// ------------------------------------------------------", fd);
85         mputl("curdir = pwd();", fd);
86         mputl(msprintf("scriptdir = get_file_path(''%s'');", scriptName), fd);
87         mputl(msprintf("chdir(scriptdir);"), fd);
88         mputl("// ------------------------------------------------------", fd);
89     endfunction
90
91     // Add footer instructions for loader and cleaner script (restore dir, etc..)
92     function addFooterToScript(fd)
93         mputl("// ------------------------------------------------------", fd);
94         mputl("chdir(curdir);", fd);
95         mputl("clear curdir;", fd);
96     endfunction
97
98     // Creates a loader script (loader.sce)
99     // Does the javaclasspath on the created jar file
100     function createLoaderScript(loaderScriptName, jarFilePath)
101         fd = mopen(loaderScriptName, "wt");
102         addHeaderToScript(loaderScriptName, fd);
103         mputl(msprintf("jarFilePath = fullfile(scriptdir, ''%s'');", jarFilePath), fd);
104         mputl("javaclasspath(fullpath(jarFilePath));", fd);
105         addFooterToScript(fd);
106         mclose(fd);
107     endfunction
108
109     // Creates a cleaner script (cleaner.sce)
110     // Deletes the loader script and jar file
111     function createCleanerScript(cleanerScriptName, loaderScriptName, jarFilePath)
112         fd = mopen(cleanerScriptName, "wt");
113         addHeaderToScript(cleanerScriptName, fd);
114         mputl(msprintf("if fileinfo(''%s'') <> [] then", loaderScriptName), fd');
115         mputl(msprintf("    mdelete(''%s'');", loaderScriptName), fd);
116         mputl("end", fd);
117         mputl("// ------------------------------------------------------", fd);
118         mputl(msprintf("jarFilePath = fullfile(scriptdir, ''%s'');", jarFilePath), fd);
119         mputl("if fileinfo(jarFilePath) <> [] then", fd);
120         mputl("    mdelete(jarFilePath);", fd);
121         mputl("end", fd);
122         addFooterToScript(fd);
123         mclose(fd);
124     endfunction
125
126
127     // ilib_build_jar body
128
129     // ilib_build_jar needs Java, it is not usable in NWNI mode
130     if (getscilabmode() == "NWNI")
131         error(msprintf(_("%s: function not available in NWNI mode.\n"), "ilib_build_jar"));
132         return;
133     end
134
135     // Check input arguments
136     [lhs, rhs] = argn(0);
137     if rhs < 3 then
138         error(msprintf(_("%s: Wrong number of input argument(s): 3 to 5 expected.\n"), "ilib_build_jar"));
139         return;
140     end
141
142     // Input argument 1: jar file path
143     if type(jarFilePath) <> 10 then
144         error(999, msprintf(_("%s: Wrong type for input argument #%d: A string expected.\n"), "ilib_build_jar", 1));
145     end
146     if size(jarFilePath, "*") <> 1 then
147         error(999, msprintf(_("%s: Wrong size for input argument #%d: A string expected.\n"), "ilib_build_jar", 1));
148         return;
149     end
150
151     // Input argument 2: package names
152     if rhs > 2 then
153         if type(packageNames) <> 10 then
154             error(999, msprintf(_("%s: Wrong type for input argument #%d: A matrix of strings expected.\n"), "ilib_build_jar", 2));
155             return;
156         end
157     end
158
159     // Input argument 3: source paths
160     if type(sourcePaths) <> 10 then
161         error(999, msprintf(_("%s: Wrong type for input argument #%d: A matrix of strings expected.\n"), "ilib_build_jar", 3));
162         return;
163     end
164
165     // Input argument 4 (optional): class paths
166     if rhs > 3 then
167         if type(classPaths) <> 10 then
168             error(999, msprintf(_("%s: Wrong type for input argument #%d: A matrix of strings expected.\n"), "ilib_build_jar", 4));
169             return;
170         end
171     else
172         classPaths = "";
173     end
174
175     // Input argument 5 (optional): manifest file path
176     if rhs > 4 then
177         if type(manifestFilePath) <> 10 then
178             error(999, msprintf(_("%s: Wrong type for input argument #%d: A matrix of strings expected.\n"), "ilib_build_jar", 5));
179             return;
180         end
181     else
182         manifestFilePath = "";
183     end
184
185     [jarDir, jarName] = fileparts(jarFilePath);
186
187     if (ilib_verbose() <> 0) then
188         mprintf(_("   Building JAR library %s\n"), jarName + ".jar");
189     end
190
191     // Create a directory for jar creation
192     jarInputRootPath = getJarInputRootPath(jarName);
193     if ~isdir(jarInputRootPath) then
194         error(msprintf(_("Cannot create jar build dir %s"), jarInputRootPath));
195         return;
196     end
197
198     // Dependencies
199     if ~isempty(classPaths) then
200         if (ilib_verbose() == 2) then
201             mprintf(_("   Add dependency class paths:\n%s\n"), classPaths);
202         end
203         javaclasspath(classPaths);
204     end
205
206     nbPackages = size(packageNames, "*");
207     for i = 1:nbPackages
208         packageName = packageNames(i);
209         if (ilib_verbose() == 2) then
210             mprintf(_("   Build package %s\n"), packageName);
211         end
212
213         // Delete each package compilation directory if exists
214         packageCompilePath = getPackageCompilePath(packageName);
215         if isdir(packageCompilePath) then
216             removedir(packageCompilePath);
217         end
218
219         // Find all Java sources for that package and compile
220         sourcePath = sourcePaths(i);
221         javaFilePaths = findJavaFiles(sourcePath, []);
222         if javaFilePaths <> [] then
223             if (ilib_verbose() == 2) then
224                 mprintf(_("   Compiling source files:\n"));
225                 disp(javaFilePaths);
226             elseif (ilib_verbose() == 1) then
227                 mprintf(_("   Compiling Java sources in %s\n"), sourcePath);
228             end
229             jcompile(javaFilePaths);
230         else
231             if (ilib_verbose() <> 0) then
232                 warning(msprintf(_("No Java sources in %s to compile for package %s"), sourcePath, packageName));
233             end
234         end
235
236         // Copy package compiled classes ...
237         packageCompilePath = getPackageCompilePath(packageName);
238         if isdir(packageCompilePath) then
239             // ... to its location in JAR
240             jarInputPackagePath = getJarPackagePath(jarInputRootPath, packageName);
241             if ~isdir(jarInputPackagePath) then
242                 error(msprintf(_("Cannot create jar package directory %s"), jarInputRootPath));
243             end
244
245             if (ilib_verbose() == 2) then
246                 mprintf(_("   Copying compiled package from %s to %s\n"), packageCompilePath, jarInputPackagePath);
247             end
248             copyfile(packageCompilePath, jarInputPackagePath);
249         else
250             if (ilib_verbose() <> 0) then
251                 warning(msprintf(_("Cannot find compilation directory %s for package %s"), packageCompilePath, packageName));
252             end
253         end
254     end
255
256     // Delete target jar if already exists
257     if isfile(jarFilePath) then
258         deletefile(jarFilePath);
259     end
260
261     // Create jar
262     if (ilib_verbose() <> 0) then
263         mprintf(_("   Creating JAR archive %s\n"), jarFilePath);
264     end
265     jcreatejar(jarFilePath, jarInputRootPath, "", manifestFilePath);
266     if ~isfile(jarFilePath) then
267         error(msprintf(_("Cannot create JAR file %s"), jarFilePath));
268     end
269
270     // Creates script
271     jarFileRelativePath = getrelativefilename(pwd(), jarFilePath);
272     if (ilib_verbose() == 2) then
273         mprintf(_("   Creating scripts for JAR relative path %s\n"), jarFileRelativePath);
274     end
275
276     // Creates loader script
277     loaderScriptName = "loader.sce";
278     if (ilib_verbose() <> 0) then
279         mprintf(_("   Create loader script for Java %s\n"), loaderScriptName);
280     end
281     createLoaderScript(loaderScriptName, jarFileRelativePath);
282
283     // Creates cleaner script
284     cleanerScriptName = "cleaner.sce";
285     if (ilib_verbose() <> 0) then
286         mprintf(_("   Create cleaner script for Java %s\n"), cleanerScriptName);
287     end
288     createCleanerScript(cleanerScriptName, loaderScriptName, jarFileRelativePath);
289 endfunction