diff --git a/apisupport.harness/manifest.mf b/apisupport.harness/manifest.mf --- a/apisupport.harness/manifest.mf +++ b/apisupport.harness/manifest.mf @@ -1,5 +1,5 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.apisupport.harness -OpenIDE-Module-Specification-Version: 1.15 +OpenIDE-Module-Specification-Version: 1.16 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/apisupport/harness/Bundle.properties diff --git a/apisupport.harness/nbproject/project.properties b/apisupport.harness/nbproject/project.properties --- a/apisupport.harness/nbproject/project.properties +++ b/apisupport.harness/nbproject/project.properties @@ -110,3 +110,5 @@ test.unit.cp.extra=${cluster}/jnlp/jnlp-launcher.jar javadoc.arch=${basedir}/arch.xml + +nbm.executable.files=launchers/app.sh \ No newline at end of file diff --git a/apisupport.harness/release/README b/apisupport.harness/release/README --- a/apisupport.harness/release/README +++ b/apisupport.harness/release/README @@ -725,6 +725,10 @@ nbm.distribution - optional URL to location where your NBM can be downloaded from. +nbm.executable.files [since 6.8] - space separated patterns of files relative to +cluster directory for which executable permissions should be set on Unix system +when building the module and on NBM installation/update in runtime. + nbm.homepage - optional URL to HTML homepage for background about the module. nbm.is.global - set to "true" if NBM cannot be installed in user directory. diff --git a/apisupport.harness/taskdefs.properties b/apisupport.harness/taskdefs.properties --- a/apisupport.harness/taskdefs.properties +++ b/apisupport.harness/taskdefs.properties @@ -45,6 +45,7 @@ makemasterjnlp=org.netbeans.nbbuild.MakeMasterJNLP parseprojectxml=org.netbeans.nbbuild.ParseProjectXml genlist=org.netbeans.nbbuild.MakeListOfNBM +genexecutables=org.netbeans.nbbuild.MakeExecutableFilesList arch=org.netbeans.nbbuild.Arch fixdependencies=org.netbeans.nbbuild.FixDependencies sortsuitemodules=org.netbeans.nbbuild.SortSuiteModules diff --git a/autoupdate.services/libsrc/org/netbeans/updater/ModuleUpdater.java b/autoupdate.services/libsrc/org/netbeans/updater/ModuleUpdater.java --- a/autoupdate.services/libsrc/org/netbeans/updater/ModuleUpdater.java +++ b/autoupdate.services/libsrc/org/netbeans/updater/ModuleUpdater.java @@ -42,6 +42,7 @@ package org.netbeans.updater; import java.io.*; +import java.lang.reflect.Method; import java.util.*; import java.util.jar.*; @@ -97,6 +98,8 @@ public static final String UPDATER_JAR = "updater.jar"; // NOI18N public static final String AUTOUPDATE_UPDATER_JAR_PATH = "netbeans/modules/ext/" + UPDATER_JAR; // NOI18N + + public static final String EXECUTABLE_FILES_ENTRY = "Info/executable.list"; /** files that are supposed to be installed (when running inside the ide) */ private Collection forInstall; @@ -354,6 +357,8 @@ try { jarFile = new JarFile (nbm); Enumeration entries = jarFile.entries(); + List executableFiles = readExecutableFilesList(jarFile); + List filesToChmod = new ArrayList (); while( entries.hasMoreElements() ) { JarEntry entry = (JarEntry) entries.nextElement(); checkStop(); @@ -383,19 +388,26 @@ destFile.getParentFile ().mkdirs (); } bytesRead = copyStreams( jarFile.getInputStream( entry ), new FileOutputStream( destFile ), bytesRead ); + if(executableFiles.contains(pathTo)) { + filesToChmod.add(destFile); + } UpdaterFrame.setProgressValue( bytesRead ); } } else if ( entry.getName().startsWith( UPDATE_MAIN_DIR )&& !entry.isDirectory() ) { - // run main - File destFile = new File (getMainDirectory (cluster), - entry.getName().substring(UPDATE_MAIN_DIR.length() + 1) ); + // run main + String pathTo = entry.getName().substring(UPDATE_MAIN_DIR.length() + 1); + File destFile = new File (getMainDirectory (cluster), pathTo); + if(executableFiles.contains(pathTo)) { + filesToChmod.add(destFile); + } destFile.getParentFile ().mkdirs (); hasMainClass = true; bytesRead = copyStreams( jarFile.getInputStream( entry ), new FileOutputStream( destFile ), bytesRead ); UpdaterFrame.setProgressValue( bytesRead ); } } + chmod(filesToChmod); if ( hasMainClass ) { MainConfig mconfig = new MainConfig (getMainDirString (cluster) + UpdateTracking.FILE_SEPARATOR + JVM_PARAMS_FILE, cluster); if (mconfig.isValid()) { @@ -455,7 +467,82 @@ t.deleteUnusedFiles (); } } - + + private List readExecutableFilesList(JarFile jarFile) { + List list = new ArrayList(); + JarEntry executableFilesEntry = jarFile.getJarEntry(EXECUTABLE_FILES_ENTRY); + if (executableFilesEntry != null) { + BufferedInputStream bis = null; + try { + bis = new BufferedInputStream(jarFile.getInputStream(executableFilesEntry)); + byte[] buffer = new byte[8192]; + int c = 0; + StringBuilder sb = new StringBuilder(); + while ((c = bis.read(buffer)) != -1) { + sb.append(new String(buffer, 0, c)); + } + String[] lines = sb.toString().trim().split("(?:\r\n|\n|\r)"); + for (String s : lines) { + if (s.trim().length() > 0) { + list.add(s); + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (bis != null) { + try { + bis.close(); + } catch (IOException e) { + } + } + } + } + return list; + } + + private void chmod(List executableFiles) { + if(isWindows() || executableFiles.isEmpty()) { + return; + } + if (System.getProperty("java.version").startsWith("1.5")) { + // Find chmod + File chmod = new File("/bin/chmod"); // NOI18N + if (!chmod.isFile()) { + chmod = new File("/usr/bin/chmod"); // NOI18N + } + if (chmod.isFile()) { + Process process = null; + try { + List command = new ArrayList(); + command.add(chmod.getAbsolutePath()); + command.add("a+x"); + for(File executableFile : executableFiles) { + command.add(executableFile.getAbsolutePath()); + } + process = new ProcessBuilder(command).start(); + process.waitFor(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (process != null) { + process.destroy(); + } + } + } + } else { + // Determine if java.io.File.setExecutable method is supported + try { + Method setExecutableMethod = File.class.getMethod("setExecutable", Boolean.TYPE, Boolean.TYPE); + for(File executableFile : executableFiles) { + setExecutableMethod.invoke(executableFile, true, false); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + public static boolean trickyDeleteOnWindows(File destFile) { assert isWindows() : "Call it only on Windows but system is " + System.getProperty("os.name"); File f = new File(destFile.getParentFile(), destFile.getName()); diff --git a/autoupdate.services/manifest.mf b/autoupdate.services/manifest.mf --- a/autoupdate.services/manifest.mf +++ b/autoupdate.services/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.autoupdate.services OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/autoupdate/services/resources/Bundle.properties -OpenIDE-Module-Specification-Version: 1.9 +OpenIDE-Module-Specification-Version: 1.10 AutoUpdate-Show-In-Client: false AutoUpdate-Essential-Module: true diff --git a/autoupdate.services/test/unit/src/org/netbeans/api/autoupdate/data/org-yourorghere-executable-permissions.nbm b/autoupdate.services/test/unit/src/org/netbeans/api/autoupdate/data/org-yourorghere-executable-permissions.nbm new file mode 100644 index 0000000000000000000000000000000000000000..f8d72159342de92e377ece0dd36bf37b542e3a4f GIT binary patch literal 3206 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 diff --git a/autoupdate.services/test/unit/src/org/netbeans/modules/autoupdate/services/ExecutablePermissionsTest.java b/autoupdate.services/test/unit/src/org/netbeans/modules/autoupdate/services/ExecutablePermissionsTest.java new file mode 100644 --- /dev/null +++ b/autoupdate.services/test/unit/src/org/netbeans/modules/autoupdate/services/ExecutablePermissionsTest.java @@ -0,0 +1,174 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2008 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ +package org.netbeans.modules.autoupdate.services; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import org.netbeans.api.autoupdate.UpdateUnit; +import org.netbeans.spi.autoupdate.UpdateItem; +import org.netbeans.spi.autoupdate.UpdateProvider; + +/** + * + * @author Dmitry Lipin + */ +public class ExecutablePermissionsTest extends NbmAdvancedTestCase { + + private UpdateProvider p = null; + private String testModuleVersion = "1.0"; + private String testModuleName = "org.yourorghere.executable.permissions"; + + public ExecutablePermissionsTest(String name) { + super(name); + } + + @Override + protected void setUp() throws IOException, Exception { + super.setUp(); + } + + @Override + public boolean canRun() { + return super.canRun() && !System.getProperty("os.name").startsWith("Windows"); + } + + private String generateExecutablePermissionsModuleElement() { + String res = "\n\n"; + res += "\n"; + res += ""; + return res; + } + + public void testExecutablePermissionsModule() throws IOException { + String os = !org.openide.util.Utilities.isUnix() ? "Windows" : "Unix"; + String catalog = generateCatalog(generateExecutablePermissionsModuleElement()); + + p = createUpdateProvider(catalog); + p.refresh(true); + + Map unitImpls = new HashMap(); + Map updates = p.getUpdateItems(); + assertNotNull("Some modules are installed.", updates); + assertFalse("Some modules are installed.", updates.isEmpty()); + assertTrue(testModuleName + " found in parsed items.", updates.keySet().contains(testModuleName + "_" + testModuleVersion)); + + Map newImpls = UpdateUnitFactory.getDefault().appendUpdateItems(unitImpls, p); + assertNotNull("Some units found.", newImpls); + assertFalse("Some units found.", newImpls.isEmpty()); + + UpdateUnit u1 = newImpls.get(testModuleName); + installUpdateUnit(u1); + File f = new File(userDir, "bin/start.sh"); + assertTrue("File " + f + " should exist after module installation", f.exists()); + if (System.getProperty("java.version").startsWith("1.5")) { + File ls = new File("/bin/ls"); + if (!ls.isFile()) { + ls = new File("/usr/bin/ls"); + } + if (ls.isFile()) { + String output = readCommandOutput(ls.getAbsolutePath(), "-la", f.getAbsolutePath()).trim(); + int index = output.indexOf(" "); + assertFalse("Can`t read permissions from output:\n" + output, index == -1); + String permissions = output.substring(0, index); + assertTrue("File " + f + " does not have executable permissions after installation, actual perms : " + permissions, + permissions.matches(".*x.*x.*x.*")); + } + } else { + Method canExecuteMethod = null; + try { + canExecuteMethod = File.class.getMethod("canExecute", new Class[]{}); + } catch (Exception e) { + assertTrue("java.io.File.canExecute method is not accessible", false); + } + boolean canExecute = false; + try { + canExecute = (Boolean) canExecuteMethod.invoke(f); + } catch (Exception e) { + assertTrue("File " + f + " is not executable after module installation", canExecute); + e.printStackTrace(); + } + } + } + + private String readCommandOutput(String... command) { + ProcessBuilder builder = new ProcessBuilder(command); + boolean doRun = true; + StringBuilder sb = new StringBuilder(); + byte[] bytes = new byte[8192]; + int c = 0; + + try { + Process process = builder.start(); + while (doRun) { + try { + Thread.sleep(20); + } catch (InterruptedException e) { + } + try { + process.exitValue(); + doRun = false; + } catch (IllegalThreadStateException e) { + ; // do nothing - the process is still running + } + InputStream is = process.getInputStream(); + while ((c = is.read(bytes)) != -1) { + sb.append(new String(bytes, 0, c)); + } + } + return sb.toString(); + } catch (IOException e) { + e.printStackTrace(); + return new String(); + } + } +} diff --git a/nbbuild/antsrc/org/netbeans/nbbuild/MakeExecutableFilesList.java b/nbbuild/antsrc/org/netbeans/nbbuild/MakeExecutableFilesList.java new file mode 100644 --- /dev/null +++ b/nbbuild/antsrc/org/netbeans/nbbuild/MakeExecutableFilesList.java @@ -0,0 +1,150 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2009 Sun Microsystems, Inc. + */ +package org.netbeans.nbbuild; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.FileSet; + +/** + * Create the list of files which require executable permissions to be set. + * @author Dmitry Lipin + */ +public class MakeExecutableFilesList extends Task { + + File targetDir = null; + ModuleFileSet mfs = null; + String executableIncludes = null; + //String propertyName = null; + String refid; + private static final String ALL_FILES_PATTERN = "**"; + + + //String sep = null; + + public MakeExecutableFilesList() { + } + + @Override + public void execute() throws BuildException { + if (targetDir == null) { + throw new BuildException("You have to specify target directoty"); + } + //if (propertyName == null) { + // throw new BuildException("You have to specify property name for storing executable files list"); + //} + if (refid == null) { + throw new BuildException("You have to specify reference id for storing executable files list"); + } + + DirectoryScanner moduleFilesDs = mfs.getDirectoryScanner(this.getProject()); + moduleFilesDs.scan(); + FileSet efs = new FileSet(); + efs.setDir(targetDir); + efs.setProject(getProject()); + if(executableIncludes==null || executableIncludes.length() == 0) { + efs.setExcludes(ALL_FILES_PATTERN); + } else { + efs.setIncludes(executableIncludes); + } + DirectoryScanner executableDs = efs.getDirectoryScanner(this.getProject()); + executableDs.scan(); + String[] moduleIncludes = moduleFilesDs.getIncludedFiles(); + + List moduleExecutables = new ArrayList(); + for (String executable : executableDs.getIncludedFiles()) { + for (String include : moduleIncludes) { + if (executable.equals(include)) { + moduleExecutables.add(executable); + break; + } + } + } + + if (!moduleExecutables.isEmpty()) { + log("Executable files in module: " + moduleExecutables, Project.MSG_VERBOSE); + } else { + log("No executable files in module: " + moduleExecutables, Project.MSG_VERBOSE); + } + FileSet fs = new FileSet(); + fs.setDir(targetDir); + fs.setProject(getProject()); + StringBuilder sb = new StringBuilder(""); + for (int i = 0; i < moduleExecutables.size(); i++) { + if (i != 0) { + sb.append(" "); + } + sb.append(moduleExecutables.get(i).replace("\\", "/")); + } + if(sb.length()>0) { + fs.setIncludes(sb.toString()); + } else { + fs.setExcludes(ALL_FILES_PATTERN); + } + DirectoryScanner ds = fs.getDirectoryScanner(); + ds.scan(); + log("Executable files length: " + ds.getIncludedFilesCount()); + getProject().addReference(refid, fs); + } + + public void setRefid(String refid) { + this.refid = refid; + } + + public void setTargetDir(File s) { + this.targetDir = s; + } + + public void setIncludes(String executableIncludes) { + this.executableIncludes = executableIncludes; + } + public ModuleFileSet createModuleFileSet() { + return (mfs = new ModuleFileSet()); + } + + + + public static class ModuleFileSet extends FileSet { + } +} diff --git a/nbbuild/antsrc/org/netbeans/nbbuild/MakeNBM.java b/nbbuild/antsrc/org/netbeans/nbbuild/MakeNBM.java --- a/nbbuild/antsrc/org/netbeans/nbbuild/MakeNBM.java +++ b/nbbuild/antsrc/org/netbeans/nbbuild/MakeNBM.java @@ -73,10 +73,12 @@ import javax.xml.parsers.ParserConfigurationException; import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.Jar; import org.apache.tools.ant.taskdefs.SignJar; +import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.ZipFileSet; import org.w3c.dom.DOMImplementation; @@ -320,7 +322,8 @@ private ArrayList moduleAttributes = null; private Attributes englishAttr = null; private Path updaterJar; - + private FileSet executablesSet; + /** Try to find and create localized info.xml files */ public void setLocales(String s) { locales = new ArrayList(); @@ -342,6 +345,11 @@ public void setFile(File file) { this.file = file; } + + /** List of executable files in NBM concatinated by ${line.separator}. */ + public FileSet createExecutables() { + return (executablesSet = new FileSet()); + } /** Module manifest needed for versioning. * @deprecated Use {@link #setModule} instead. @@ -653,12 +661,43 @@ for (ZipFileSet zfs : infoXMLFileSets) { jar.addFileset(zfs); } + DirectoryScanner ds = executablesSet.getDirectoryScanner(); + ds.scan(); + String [] executables = ds.getIncludedFiles(); + + if(executables!=null && executables.length > 0) { + ZipFileSet executablesList = new ZipFileSet(); + File executablesFile; + StringBuilder sb = new StringBuilder(""); + String ls = System.getProperty("line.separator"); + for(int i=0;i < executables.length;i++) { + if(i!=0) { + sb.append(ls); + } + sb.append(executables[i].replace("\\","/")); + } + try { + executablesFile = File.createTempFile("executables",".list"); + OutputStream infoStream = new FileOutputStream (executablesFile); + try { + infoStream.write(sb.toString().getBytes()); + } finally { + infoStream.close (); + } + } catch (IOException e) { + throw new BuildException("exception when creating Info/executables.list", e, getLocation()); + } + executablesFile.deleteOnExit(); + executablesList.setFile(executablesFile); + executablesList.setFullpath("Info/executables.list"); + jar.addZipfileset(executablesList); + } if (main != null) { // Add the main dir main.setPrefix("main"); // use main prefix jar.addZipfileset(main); } - + jar.setCompress(true); jar.setLocation(getLocation()); jar.init (); diff --git a/nbbuild/default.xml b/nbbuild/default.xml --- a/nbbuild/default.xml +++ b/nbbuild/default.xml @@ -60,6 +60,9 @@ + diff --git a/nbbuild/templates/common.xml b/nbbuild/templates/common.xml --- a/nbbuild/templates/common.xml +++ b/nbbuild/templates/common.xml @@ -252,6 +252,14 @@ + + + + + + + + @@ -332,7 +340,17 @@ - + + + + + + + + + + + @@ -354,6 +372,7 @@ +