blob: 83796c0002cd6ec923dcf6120ff12157b6fbed0f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.updater;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.logging.Level;
import javax.swing.SwingUtilities;
/** Class used by autoupdate module for the work with module files and
* for installing / uninstalling modules
*
* @author Petr Hrebejk, Ales Kemr, Jiri Rechtacek
* @version
*/
public final class ModuleUpdater extends Thread {
/** Relative name of update directory */
private static final String DOWNLOAD_DIR_NAME = "download"; // NOI18N
/** Relative name of directory where the .NBM files are downloaded */
static final String DOWNLOAD_DIR = UpdaterDispatcher.UPDATE_DIR + UpdateTracking.FILE_SEPARATOR + DOWNLOAD_DIR_NAME; // NOI18N
/** Relative name of backup directory */
private static final String BACKUP_DIR = UpdaterDispatcher.UPDATE_DIR + UpdateTracking.FILE_SEPARATOR + "backup"; // NOI18N
/** The name of zip entry containing netbeans files */
public static final String UPDATE_NETBEANS_DIR = "netbeans"; // NOI18N
/** The name of zip entry containing java_extension files */
public static final String UPDATE_JAVA_EXT_DIR = "java_ext"; // NOI18N
/** The name of zip entry containing files for external installer */
public static final String UPDATE_MAIN_DIR = "main"; // NOI18N
/** Name of external installer parameters file*/
private static final String JVM_PARAMS_FILE = "main.properties"; // NOI18N
/** Extension of the distribution files */
public static final String NBM_EXTENSION = "nbm"; // NOI18N
/** Extension of the OSGi distribution files */
public static final String JAR_EXTENSION = "jar"; // NOI18N
/** The name of the log file */
public static final String LOG_FILE_NAME = "update.log"; // NOI18N
/** The name of the install_later file */
public static final String LATER_FILE_NAME = "install_later.xml"; // NOI18N
public static final char SPACE = ' ';
public static final char QUOTE = '\"';
private static final String TEMP_FILE_NAME = "temporary";
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 AUTOUPDATE_UPDATER_JAR_LOCALE_PATTERN = "netbeans/modules/ext/locale/updater(_[a-zA-Z0-9]+)+"; // NOI18N
public static final String EXECUTABLE_FILES_ENTRY = "Info/executables.list";
/** files that are supposed to be installed (when running inside the ide) */
private Map<File, Collection<File>> files2clustersForInstall;
/** Should the thread stop */
private volatile boolean stop = false;
/** Total length of unpacked files */
private long totalLength;
private final UpdatingContext context;
ModuleUpdater(UpdatingContext context) {
super("Module Updater");
this.context = context;
}
/** Creates new ModuleUpdater */
@Override
public void run() {
assert ! SwingUtilities.isEventDispatchThread () : "Cannot run in EQ";
try {
checkStop();
if (getClustersForInstall ().isEmpty ()) {
endRun();
}
checkStop();
totalLength();
checkStop();
unpack();
for (File cluster: UpdateTracking.clusters (true)) {
deleteAdditionalInfo (cluster);
}
} catch (Exception x) {
XMLUtil.LOG.log(Level.SEVERE, "Error while upgrading", x);
} finally {
context.runningFinished();
}
}
private void deleteInstallLater (File cluster) {
File later = new File (cluster, UpdateTracking.FILE_SEPARATOR + DOWNLOAD_DIR + UpdateTracking.FILE_SEPARATOR + LATER_FILE_NAME);
if ( later.exists() ) {
later.delete();
XMLUtil.LOG.info("File " + later + " deleted.");
}
File f = later.getParentFile ();
while (f != null && f.delete ()) { // remove empty dirs too
f = f.getParentFile ();
}
}
private void deleteAdditionalInfo (File cluster) {
File additional = new File (cluster, UpdateTracking.FILE_SEPARATOR + DOWNLOAD_DIR + UpdateTracking.FILE_SEPARATOR + UpdateTracking.ADDITIONAL_INFO_FILE_NAME);
if (additional != null && additional.exists ()) {
additional.delete ();
XMLUtil.LOG.info("File " + additional + " deleted.");
}
File f = additional == null ? null : additional.getParentFile ();
while (f != null && f.delete ()) { // remove empty dirs too
f = f.getParentFile ();
}
}
/** ends the run of update */
void endRun() {
stop = true;
}
/** checks wheter ends the run of update */
private void checkStop() {
if ( stop ) {
if (context.isFromIDE ()) {
context.unpackingFinished();
} else {
System.exit( 0 );
}
}
}
private void processFilesForInstall () {
// if installOnly are null then generate all NBMs around all clusters
if (context.forInstall() == null) {
files2clustersForInstall = new HashMap<File, Collection<File>> ();
for (File cluster : UpdateTracking.clusters (true)) {
Collection<File> tmp = getModulesToInstall (cluster);
files2clustersForInstall.put (cluster, tmp);
// if ModuleUpdater runs 'offline' then delete install_later files
if (!context.isFromIDE()) {
deleteInstallLater (cluster);
}
}
} else {
files2clustersForInstall = new HashMap<File, Collection<File>> ();
for (File nbm : context.forInstall()) {
if (nbm.exists()) {
File cluster = getCluster (nbm);
if (files2clustersForInstall.get (cluster) == null) {
files2clustersForInstall.put (cluster, new HashSet<File> ());
}
files2clustersForInstall.get (cluster).add (nbm);
}
}
}
}
private static File getCluster (File nbm) {
File cluster = null;
try {
// nbms are in <cluster>/update/download dir
// but try to check it
assert nbm.exists () : nbm + " for install exists.";
assert nbm.getParentFile () != null : nbm + " has parent.";
assert DOWNLOAD_DIR_NAME.equalsIgnoreCase (nbm.getParentFile ().getName ()) : nbm + " is in directory " + DOWNLOAD_DIR_NAME;
assert nbm.getParentFile ().getParentFile () != null : nbm.getParentFile () + " has parent.";
assert UpdaterDispatcher.UPDATE_DIR.equalsIgnoreCase (nbm.getParentFile ().getParentFile ().getName ()) :
nbm + " is in directory " + UpdaterDispatcher.UPDATE_DIR;
assert nbm.getParentFile ().getParentFile ().getParentFile () != null : nbm.getParentFile ().getParentFile () + " has parent.";
cluster = nbm.getParentFile ().getParentFile ().getParentFile ();
} catch (NullPointerException npe) {
XMLUtil.LOG.log(Level.SEVERE, "getCluster (" + nbm + ") throws an exception", npe);
}
return cluster;
}
private Collection<File> getFilesForInstallInCluster (File cluster) {
if (files2clustersForInstall == null) {
processFilesForInstall ();
}
return files2clustersForInstall == null ? null : files2clustersForInstall.get(cluster);
}
private Collection<File> getClustersForInstall () {
if (files2clustersForInstall == null) {
processFilesForInstall ();
}
return files2clustersForInstall == null ? null : files2clustersForInstall.keySet();
}
/** Determines size of unpacked modules */
private void totalLength () {
totalLength = 0L;
context.setLabel (Localization.getBrandedString ("CTL_PreparingUnpack"));
Collection<File> allFiles = new HashSet<File> ();
for (File c : getClustersForInstall ()) {
allFiles.addAll (getFilesForInstallInCluster (c));
}
context.setProgressRange (0, allFiles.size ());
int i = 0;
for (File f : allFiles) {
JarFile jarFile = null;
try {
if(f.getName().endsWith(".jar")) {
//OSGi bundle
totalLength += f.length();
} else {
jarFile = new JarFile (f);
Enumeration<JarEntry> entries = jarFile.entries ();
while (entries.hasMoreElements ()) {
JarEntry entry = entries.nextElement ();
checkStop ();
if ((entry.getName ().startsWith (UPDATE_NETBEANS_DIR) || entry.getName ().startsWith (ModuleUpdater.UPDATE_JAVA_EXT_DIR) || entry.getName ().startsWith (UPDATE_MAIN_DIR)) && ! entry.isDirectory ()) {
totalLength += entry.getSize ();
}
}
}
context.setProgressValue (i ++);
} catch (java.io.IOException e) {
XMLUtil.LOG.log(Level.WARNING, "Cannot count size of entries in " + f, e);
} finally {
try {
if (jarFile != null) {
jarFile.close ();
}
} catch (java.io.IOException e) {
// We can't close the file do nothing
XMLUtil.LOG.log(Level.WARNING, "While closing " + jarFile + " input stream", e); // NOI18N
}
}
}
}
/** Unpack the distribution files into update directory */
private void unpack () {
long bytesRead = 0L;
boolean hasMainClass;
context.setLabel( "" ); // NOI18N
context.setProgressRange( 0, totalLength );
ArrayList<UpdateTracking> allTrackings = new ArrayList<UpdateTracking> ();
Map<ModuleUpdate, UpdateTracking.Version> l10ns =
new HashMap<ModuleUpdate, UpdateTracking.Version>();
for (File cluster : getClustersForInstall ()) {
UpdateTracking tracking = UpdateTracking.getTracking (cluster, true, context);
if (tracking == null) {
throw new RuntimeException ("No update_tracking file in cluster " + cluster);
}
allTrackings.add (tracking);
int installedNBMs = 0;
for (File nbm : getFilesForInstallInCluster (cluster)) {
installedNBMs++;
UpdateTracking.Version version;
UpdateTracking.Module modtrack;
context.setLabel( Localization.getBrandedString("CTL_UnpackingFile") + " " + nbm.getName() ); //NOI18N
XMLUtil.LOG.info("780: " + Localization.getBrandedString("CTL_UnpackingFile") + " " + nbm.getName()); //NOI18N
context.unpackingIsRunning ();
ModuleUpdate mu;
try {
mu = new ModuleUpdate (nbm);
} catch (RuntimeException re) {
if (nbm.exists ()) {
XMLUtil.LOG.info("Deleteing file: " + nbm);
if (! nbm.delete ()) {
XMLUtil.LOG.log(Level.WARNING, "File " + nbm + " cannot be deleted. Propably file lock on the file."); // NOI18N
assert false : "Error: File " + nbm + " cannot be deleted. Propably file lock on the file.";
nbm.deleteOnExit ();
} else {
XMLUtil.LOG.info("File " + nbm + " deleted.");
}
}
continue;
}
assert mu != null : "Module update is not null for file: " + nbm; // NOI18N
if ( mu.isL10n() ) {
modtrack = null;
version = tracking.createVersion( "0" ); // NOI18N
l10ns.put( mu, version );
} else {
modtrack = tracking.readModuleTracking (mu.getCodenamebase (), true);
// find origin for file
UpdateTracking.AdditionalInfo info = UpdateTracking.getAdditionalInformation (cluster, context);
String origin = info != null && info.getSource (nbm.getName ()) != null ?
info.getSource (nbm.getName ()) : UpdateTracking.UPDATER_ORIGIN;
version = modtrack.addNewVersion (mu.getSpecification_version (), origin);
}
// input streams should be released, but following is needed
//System.gc();
hasMainClass = false;
context.setProgressValue( bytesRead );
JarFile jarFile = null;
try {
jarFile = new JarFile (nbm);
Enumeration<JarEntry> entries = jarFile.entries();
final Manifest manifest = jarFile.getManifest();
String symbolicName = manifest != null ? ModuleUpdate.extractCodeName(manifest.getMainAttributes()) : null;
if (symbolicName != null) {
//OSGi bundle
File osgiJar = nbm;
File destFile = new File(cluster, "modules/" + osgiJar.getName());
if (destFile.exists()) {
File bckFile = new File(getBackupDirectory(cluster), osgiJar.getName());
bckFile.getParentFile().mkdirs();
copyStreams(new FileInputStream(destFile), context.createOS(bckFile), -1);
XMLUtil.LOG.info("Backup file " + destFile + " to " + bckFile);
if (!destFile.delete() && isWindows()) {
trickyDeleteOnWindows(destFile);
} else {
XMLUtil.LOG.info("File " + destFile + " deleted.");
}
} else {
destFile.getParentFile().mkdirs();
}
bytesRead = copyStreams(new FileInputStream(osgiJar), context.createOS(destFile), bytesRead);
XMLUtil.LOG.info("Copied file " + osgiJar + " to " + destFile);
long crc = UpdateTracking.getFileCRC(destFile);
version.addFileWithCrc("modules/" + osgiJar.getName(), Long.toString(crc));
//create config/Modules/cnb.xml
File configDir = new File (new File (cluster, ModuleDeactivator.CONFIG), ModuleDeactivator.MODULES); // NOI18N
String configFileName = symbolicName.replace ('.', '-') + ".xml";
File configFile = new File(configDir, configFileName);
if (configFile.exists()) {
long configFileCRC = UpdateTracking.getFileCRC(configFile);
version.addFileWithCrc("config/Modules/" + configFileName, Long.toString(configFileCRC));
}
context.setProgressValue(bytesRead);
modtrack.setOSGi(true);
} else {
//NBM
List <String> executableFiles = readExecutableFilesList(jarFile);
List <File> filesToChmod = new ArrayList <File> ();
while( entries.hasMoreElements() ) {
JarEntry entry = entries.nextElement();
checkStop();
if ( entry.getName().startsWith( UPDATE_NETBEANS_DIR ) ) {
if (! entry.isDirectory ()) {
String pathTo = entry.getName().substring(UPDATE_NETBEANS_DIR.length() + 1);
File destFile = new File (cluster, pathTo);
if (AUTOUPDATE_UPDATER_JAR_PATH.equals (entry.getName ()) ||
entry.toString().matches(AUTOUPDATE_UPDATER_JAR_LOCALE_PATTERN)) {
// #220807 - NoClassDefFoundError: updater/XMLUtil
version.addFileWithCrc(pathTo, Long.toString(destFile.exists() ? UpdateTracking.getFileCRC(destFile) : 0));
if (destFile.exists()) {
// skip updater.jar
continue;
}
}
// path without netbeans prefix
if ( destFile.exists() ) {
File bckFile = new File( getBackupDirectory (cluster), entry.getName() );
bckFile.getParentFile ().mkdirs ();
copyStreams( new FileInputStream( destFile ), context.createOS( bckFile ), -1 );
XMLUtil.LOG.info("Backup file " + destFile + " to " + bckFile);
if (!destFile.delete() && isWindows()) {
trickyDeleteOnWindows(destFile);
} else {
XMLUtil.LOG.info("File " + destFile + " deleted.");
}
} else {
destFile.getParentFile ().mkdirs ();
}
long crc;
if (pathTo.endsWith(".external")) {
File downloaded = new File(destFile.getParentFile(), destFile.getName().substring(0, destFile.getName().lastIndexOf(".external")));
final InputStream spec = jarFile.getInputStream(entry);
pathTo = pathTo.substring(0, pathTo.length() - ".external".length());
long expectedCRC = externalDownload(spec, nbm);
File external = new File(nbm + "." + Long.toHexString(expectedCRC));
InputStream is = new FileInputStream(external);
try {
spec.close();
OutputStream os = context.createOS(downloaded);
try {
XMLUtil.LOG.info("810: " + Localization.getBrandedString("CTL_DownloadingFile") + " " + downloaded); //NOI18N
bytesRead = copyStreams(is, os, -1);
XMLUtil.LOG.info("Copied external file " + external + " to " + downloaded);
} finally {
os.close();
}
} finally {
external.delete();
XMLUtil.LOG.info("File " + external + " deleted.");
is.close();
}
crc = UpdateTracking.getFileCRC(downloaded);
if (crc != expectedCRC) {
downloaded.delete();
XMLUtil.LOG.info("File " + downloaded + " deleted.");
throw new IOException("Wrong CRC for " + downloaded);
}
} else {
bytesRead = copyStreams( jarFile.getInputStream( entry ), context.createOS( destFile ), bytesRead );
XMLUtil.LOG.info("Copied file " + jarFile.getName() + ":" + entry + " to " + destFile);
crc = entry.getCrc();
}
if(executableFiles.contains(pathTo)) {
filesToChmod.add(destFile);
}
if(pathTo.endsWith(".jar.pack.gz") &&
jarFile.getEntry(entry.getName().substring(0, entry.getName().lastIndexOf(".pack.gz")))==null) {
//check if file.jar.pack.gz does not exit for file.jar - then unpack current .pack.gz file
File unpacked = new File(destFile.getParentFile(), destFile.getName().substring(0, destFile.getName().lastIndexOf(".pack.gz")));
unpack200(destFile, unpacked);
destFile.delete();
XMLUtil.LOG.info("File " + destFile + " deleted.");
pathTo = pathTo.substring(0, pathTo.length() - ".pack.gz".length());
crc = UpdateTracking.getFileCRC(unpacked);
}
if ( mu.isL10n() ) {
version.addL10NFileWithCrc( pathTo, Long.toString(crc), mu.getSpecification_version());
} else {
version.addFileWithCrc( pathTo, Long.toString(crc));
}
context.setProgressValue( bytesRead );
}
} else if ( entry.getName().startsWith( UPDATE_MAIN_DIR )&&
!entry.isDirectory() ) {
// 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 ), context.createOS( destFile ), bytesRead );
XMLUtil.LOG.info("Copied file " + jarFile.getName() + ":" + entry + " to " + destFile);
context.setProgressValue( bytesRead );
}
}
chmod(filesToChmod);
if ( hasMainClass ) {
MainConfig mconfig = new MainConfig (getMainDirString (cluster) + UpdateTracking.FILE_SEPARATOR + JVM_PARAMS_FILE, cluster);
if (mconfig.isValid()) {
String java_path = System.getProperty ("java.home") + UpdateTracking.FILE_SEPARATOR
+ "bin" + UpdateTracking.FILE_SEPARATOR + "java"; // NOI18N
java_path = quoteString( java_path );
String torun = java_path + " -cp " + quoteString (getMainDirString (cluster) + mconfig.getClasspath() ) + mconfig.getCommand(); // NOI18N
startCommand(torun);
deleteDir( getMainDirectory (cluster) );
}
}
}
}
catch ( java.io.IOException e ) {
// Ignore non readable files
XMLUtil.LOG.log(Level.INFO, "Ignore non-readable files ", e);
}
finally {
try {
if ( jarFile != null ) {
jarFile.close();
}
}
catch ( java.io.IOException e ) {
// We can't close the file do nothing
// XMLUtil.LOG.info("Can't close : " + e ); // NOI18N
}
//XMLUtil.LOG.info("Dleting :" + nbmFiles[i].getName() + ":" + nbmFiles[i].delete() ); // NOI18N
if (! nbm.delete ()) {
XMLUtil.LOG.log(Level.WARNING, "Error: Cannot delete {0}", nbm); // NOI18N
nbm.deleteOnExit ();
} else {
XMLUtil.LOG.info("File " + nbm + " deleted.");
}
}
if (! mu.isL10n ()) {
modtrack.write ();
modtrack.writeConfigModuleXMLIfMissing ();
}
}
if (installedNBMs > 0) {
UpdaterDispatcher.touchLastModified (cluster);
}
}
for (UpdateTracking t: allTrackings) {
// update_tracking of l10n's
for (Map.Entry<ModuleUpdate, UpdateTracking.Version> entry: l10ns.entrySet()) {
ModuleUpdate mod = entry.getKey();
UpdateTracking.Version version = entry.getValue();
UpdateTracking.Module modtrack = t.readModuleTracking(
mod.getCodenamebase(),
true
);
modtrack.addL10NVersion( version );
modtrack.write();
}
t.deleteUnusedFiles ();
}
}
private boolean unpack200(File src, File dest) {
String unpack200 = "unpack200" + (isWindows() ? ".exe" : "");
File unpack200Executable = findUnpack200Executable(unpack200);
ProcessBuilder pb = new ProcessBuilder(unpack200Executable.getAbsolutePath(), src.getAbsolutePath(), dest.getAbsolutePath());
pb.directory(src.getParentFile());
int result = 1;
try {
//maybe reuse start() method here?
Process process = pb.start();
//TODO: Need to think of unpack200/lvprcsrv.exe issues
//https://netbeans.org/bugzilla/show_bug.cgi?id=117334
//https://netbeans.org/bugzilla/show_bug.cgi?id=119861
result = process.waitFor();
process.destroy();
XMLUtil.LOG.info("Unpack " + src + " to " + dest);
} catch (IOException e) {
XMLUtil.LOG.log(Level.WARNING, null, e);
} catch (InterruptedException e) {
XMLUtil.LOG.log(Level.WARNING, null, e);
}
return result == 0;
}
private File findUnpack200Executable(String unpack200) {
File unpack200Executable = new File(new File(System.getProperty("java.home"), "bin"), unpack200);
if (!unpack200Executable.canExecute()) {
for (File clusterRoot : UpdateTracking.clusters(true)) {
File uiConfig = new File(new File(new File(new File(new File(new File(new File(
clusterRoot, "config"), "Preferences"), "org"), "netbeans"), "modules"), // NOI18N
"autoupdate"), "services.properties"); // NOI18N
if (uiConfig.canRead()) {
Properties p = new Properties();
try (FileInputStream is = new FileInputStream(uiConfig)) {
p.load(is);
} catch (IOException ex) {
// go on
}
String unpackKey = p.getProperty("unpack200"); // NOI18N
if (unpackKey != null) {
File unpackKeyFile = new File(unpackKey);
if (unpackKeyFile.canExecute()) {
unpack200Executable = unpackKeyFile;
break;
}
}
}
}
}
return unpack200Executable;
}
private List<String> readExecutableFilesList(JarFile jarFile) {
List<String> list = new ArrayList<String>();
JarEntry executableFilesEntry = jarFile.getJarEntry(EXECUTABLE_FILES_ENTRY);
if (executableFilesEntry != null) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(jarFile.getInputStream(executableFilesEntry), StandardCharsets.UTF_8));
String s;
while ((s = reader.readLine()) != null) {
list.add(s);
}
reader.close();
} catch (Exception e) {
XMLUtil.LOG.log(Level.WARNING, null, e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
}
}
}
}
return list;
}
private void chmod(List<File> executableFiles) {
if (isWindows() || executableFiles.isEmpty()) {
return;
}
for (File executableFile : executableFiles) {
executableFile.setExecutable(true, false);
}
}
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());
assert f.exists() : "The file " + f + " must exists.";
try {
File tmpFile = File.createTempFile(TEMP_FILE_NAME, null, f.getParentFile());
if (tmpFile.delete()) {
f.renameTo(tmpFile);
XMLUtil.LOG.info("File " + f + " renamed to " + tmpFile);
tmpFile.deleteOnExit ();
XMLUtil.LOG.info("Locked file " + tmpFile + " will be deleted on exit.");
} else {
XMLUtil.LOG.info("File " + tmpFile + " was deleted.");
}
} catch (IOException ex) {
//no special handling needed
}
return !f.exists();
}
public static boolean isWindows() {
String os = System.getProperty("os.name"); // NOI18N
return (os != null && os.toLowerCase().startsWith("windows"));//NOI18N
}
private void startCommand(String torun) {
Runtime runtime=Runtime.getRuntime();
Process proces;
try {
proces=runtime.exec(parseParameters( torun ));
final Process proc2 = proces;
new Thread() {
@Override
public void run() {
try {
InputStreamReader stream= new InputStreamReader (proc2.getErrorStream());
BufferedReader reader= new BufferedReader(stream);
String vystup;
do {
vystup = reader.readLine();
if (vystup!=null) {
XMLUtil.LOG.info(vystup);
}
} while (vystup != null);
} catch (Exception e) {
XMLUtil.LOG.log(Level.INFO, null, e);
}
}
}.start();
int x=proces.waitFor();
}
catch (Exception e){
XMLUtil.LOG.log(Level.INFO, null, e);
}
}
/** The directory where to backup old versions of modules */
public File getBackupDirectory (File activeCluster) {
// #72960: Backup file created in wrong cluster
File backupDirectory = new File (activeCluster, BACKUP_DIR);
if (! backupDirectory.isDirectory ()) {
backupDirectory.mkdirs();
}
return backupDirectory;
}
/** Gets the netbeans directory */
private static File getMainDirectory (File activeCluster) {
// #72918: Post-install cannot write into platform cluster
File mainDirectory = new File (activeCluster, UpdateTracking.FILE_SEPARATOR + UpdaterDispatcher.UPDATE_DIR + UpdateTracking.FILE_SEPARATOR + UPDATE_MAIN_DIR);
if (! mainDirectory.isDirectory ()) {
mainDirectory.mkdirs();
}
return mainDirectory;
}
private static String getMainDirString (File activeCluster) {
return getMainDirectory (activeCluster).getPath ();
}
/** Quotes string correctly, eg. removes all quotes from the string and adds
* just one at the start and
* second one at the end.
* @param s string to be quoted
* @return correctly quoted string
*/
public static String quoteString(String s) {
if ( s.indexOf( SPACE ) > -1 ) {
StringBuilder sb = new StringBuilder(s);
int i = 0;
while ( i < sb.length() ) {
if ( sb.charAt(i) == QUOTE ) {
sb.deleteCharAt( i );
} else {
i++;
}
}
sb.insert( 0, QUOTE );
sb.append( QUOTE );
return sb.toString();
}
return s;
}
/**
* It takes the current progress value so it can update progress
* properly, and also return the new progress value after the
* copy is done.
*
* @param progressVal The current progress bar value. If this is
* negative, we don't want to update the progress bar.
*/
private long copyStreams( InputStream src, OutputStream dest,
long progressVal ) throws java.io.IOException {
BufferedInputStream bsrc = new BufferedInputStream( src );
BufferedOutputStream bdest = new BufferedOutputStream( dest );
int count = 0;
int c;
byte [] bytes = new byte [8192];
try {
while( ( c = bsrc.read(bytes) ) != -1 ) {
bdest.write(bytes, 0, c);
count+=c;
if ( count > 8500 ) {
if (progressVal >= 0) {
progressVal += count;
context.setProgressValue( progressVal );
}
count = 0;
checkStop();
}
}
// Just update the value, no need to update the
// GUI yet. Caller can do that.
if (progressVal >= 0) {
progressVal += count;
}
}
finally {
bsrc.close();
bdest.close();
src.close();
dest.close();
}
return progressVal;
}
private void deleteDir(File dir) {
File[] files=dir.listFiles();
for( int j = 0; j < files.length; j++ ) {
if ( files[j].isDirectory() ) {
deleteDir( files[j] );
}
if (! files[j].delete()) {
XMLUtil.LOG.log(Level.WARNING, "Cannot delete {0}", files [j]); //NOI18N
assert false : "Cannot delete " + files [j];
} else {
XMLUtil.LOG.info("File " + files[j] + " deleted.");
}
}
}
// [Copied from org.openide.util.Utilities]
/**
* Parses parameters from a given string in shell-like manner.
* Users of the Bourne shell (e.g. on Unix) will already be familiar
* with the behavior.
* For example, when using {@link org.openide.execution.NbProcessDescriptor}
* you should be able to:
* <ul>
* <li>Include command names with embedded spaces, such as
* <code>c:\Program Files\jdk\bin\javac</code>.
* <li>Include extra command arguments, such as <code>-Dname=value</code>.
* <li>Do anything else which might require unusual characters or
* processing. For example:
* <p><code><pre>
* "c:\program files\jdk\bin\java" -Dmessage="Hello /\\/\\ there!" -Xmx128m
* </pre></code>
* <p>This example would create the following executable name and arguments:
* <ol>
* <li> <code>c:\program files\jdk\bin\java</code>
* <li> <code>-Dmessage=Hello /\/\ there!</code>
* <li> <code>-Xmx128m</code>
* </ol>
* Note that the command string does not escape its backslashes--under the assumption
* that Windows users will not think to do this, meaningless escapes are just left
* as backslashes plus following character.
* </ul>
* <em>Caveat</em>: even after parsing, Windows programs (such as
* the Java launcher)
* may not fully honor certain
* characters, such as quotes, in command names or arguments. This is because programs
* under Windows frequently perform their own parsing and unescaping (since the shell
* cannot be relied on to do this). On Unix, this problem should not occur.
* @param s a string to parse
* @return an array of parameters
*/
private static String[] parseParameters(String s) {
int NULL = 0x0; // STICK + whitespace or NULL + non_"
int INPARAM = 0x1; // NULL + " or STICK + " or INPARAMPENDING + "\ // NOI18N
int INPARAMPENDING = 0x2; // INPARAM + \
int STICK = 0x4; // INPARAM + " or STICK + non_" // NOI18N
int STICKPENDING = 0x8; // STICK + \
@SuppressWarnings("UseOfObsoleteCollectionType")
Vector<String> params = new Vector<String>(5,5);
char c;
int state = NULL;
StringBuilder buff = new StringBuilder(20);
int slength = s.length();
for (int i = 0; i < slength; i++) {
c = s.charAt(i);
if (Character.isWhitespace(c)) {
if (state == NULL) {
if (buff.length () > 0) {
params.addElement(buff.toString());
buff.setLength(0);
}
} else if (state == STICK) {
params.addElement(buff.toString());
buff.setLength(0);
state = NULL;
} else if (state == STICKPENDING) {
buff.append('\\');
params.addElement(buff.toString());
buff.setLength(0);
state = NULL;
} else if (state == INPARAMPENDING) {
state = INPARAM;
buff.append('\\');
buff.append(c);
} else { // INPARAM
buff.append(c);
}
continue;
}
if (c == '\\') {
if (state == NULL) {
++i;
if (i < slength) {
char cc = s.charAt(i);
if (cc == '"' || cc == '\\') {
buff.append(cc);
} else if (Character.isWhitespace(cc)) {
buff.append(c);
--i;
} else {
buff.append(c);
buff.append(cc);
}
} else {
buff.append('\\');
break;
}
continue;
} else if (state == INPARAM) {
state = INPARAMPENDING;
} else if (state == INPARAMPENDING) {
buff.append('\\');
state = INPARAM;
} else if (state == STICK) {
state = STICKPENDING;
} else if (state == STICKPENDING) {
buff.append('\\');
state = STICK;
}
continue;
}
if (c == '"') {
if (state == NULL) {
state = INPARAM;
} else if (state == INPARAM) {
state = STICK;
} else if (state == STICK) {
state = INPARAM;
} else if (state == STICKPENDING) {
buff.append('"');
state = STICK;
} else { // INPARAMPENDING
buff.append('"');
state = INPARAM;
}
continue;
}
if (state == INPARAMPENDING) {
buff.append('\\');
state = INPARAM;
} else if (state == STICKPENDING) {
buff.append('\\');
state = STICK;
}
buff.append(c);
}
// collect
if (state == INPARAM) {
params.addElement(buff.toString());
} else if ((state & (INPARAMPENDING | STICKPENDING)) != 0) {
buff.append('\\');
params.addElement(buff.toString());
} else { // NULL or STICK
if (buff.length() != 0) {
params.addElement(buff.toString());
}
}
String[] ret = new String[params.size()];
params.copyInto(ret);
return ret;
}
private long externalDownload(InputStream spec, File nbm) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(spec));
for (;;) {
String line = br.readLine();
if (line == null) {
throw new IOException("No CRC in the .external file!");
}
if (line.startsWith("CRC:")) {
return Long.parseLong(line.substring(4).trim());
}
}
}
/** read jvm parameters from jvm parameters file */
static class MainConfig extends Object {
/** The names of properties from jvm parameters file */
private final String PAR_MAIN = "mainClass"; // NOI18N
private final String PAR_RELCP = "relativeClassPath"; // NOI18N
private final String PAR_JVMPAR = "jvm.parameters"; // NOI18N
private final String PAR_MAINARGS = "mainClass.arguments"; // NOI18N
/** The names of variables allow to use in jvm parameters file */
private final String VAR_IDE_HOME = "%IDE_HOME%"; // NOI18N
private final String VAR_IDE_USER = "%IDE_USER%"; // NOI18N
private final String VAR_FILE_SEPARATOR = "%FS%"; // NOI18N
private final String VAR_PATH_SEPARATOR = "%PS%"; // NOI18N
private final String VAR_JAVA_HOME = "%JAVA_HOME%"; // NOI18N
/** joined all parameters of jvm java command */
private String parameters = ""; // NOI18N
private String classpath = ""; // NOI18N
/** is jvm parameters file in valid stucture */
private boolean valid = false;
private final File activeCluster;
public MainConfig (String spath, File activeCluster) {
valid = readParms(spath);
this.activeCluster = activeCluster;
}
/** returns all parameters needed by jvm java command */
public String getCommand() {
return parameters;
}
/** returns all parameters needed by jvm java command */
public String getClasspath() {
return classpath;
}
/** is jvm parameters file in valid stucture */
public boolean isValid() {
return valid;
}
/** read jvm parameters from jvm parameters file */
@SuppressWarnings("empty-statement")
private boolean readParms(String spath) {
Properties details = new Properties();
FileInputStream fis = null;
try {
details.load(fis = new FileInputStream(spath)); // NOI18N
} catch (IOException e) {
return false;
} finally {
if (fis != null) {
try { fis.close(); } catch (IOException e) { /* ignore */ }
};
}
String mainclass;
String relpath;
String jvmparms;
String mainargs;
relpath = details.getProperty(PAR_RELCP,null);
if (relpath != null) {
relpath = replaceVars( relpath );
StringTokenizer token = new StringTokenizer( relpath, UpdateTracking.PATH_SEPARATOR, false );
while ( token.hasMoreTokens() ) {
classpath = classpath + UpdateTracking.PATH_SEPARATOR + changeRelative( token.nextToken() );
}
}
parameters = "";
jvmparms = details.getProperty(PAR_JVMPAR,null);
if (jvmparms != null) {
parameters = parameters + " " + jvmparms; // NOI18N
}
mainclass = details.getProperty(PAR_MAIN,null);
if (mainclass == null) {
return false;
} else {
parameters = parameters + " " + mainclass;
} // NOI18N
mainargs = details.getProperty(PAR_MAINARGS,null);
if (mainargs != null) {
parameters = parameters + " " + mainargs; // NOI18N
}
parameters = replaceVars( parameters );
return true;
}
private String replaceVars(String original) {
original = replaceAll(original, VAR_IDE_HOME,
UpdateTracking.getPlatformDir () == null ? "" : UpdateTracking.getPlatformDir ().getPath());
original = replaceAll(original, VAR_IDE_USER,
UpdateTracking.getUserDir () == null ? "" : UpdateTracking.getUserDir ().getPath());
original = replaceAll(original, VAR_FILE_SEPARATOR,
UpdateTracking.FILE_SEPARATOR);
original = replaceAll(original, VAR_PATH_SEPARATOR,
UpdateTracking.PATH_SEPARATOR);
original = replaceAll(original, VAR_JAVA_HOME,
System.getProperty ("java.home")); // NOI18N
return original;
}
private String changeRelative(String path) {
if ( new File( path ).isAbsolute() ) {
return path;
} else {
return getMainDirString (this.activeCluster) + UpdateTracking.FILE_SEPARATOR + path;
}
}
/** replace all occurrences of String what by String repl in the String sin */
private String replaceAll(String sin, String what, String repl) {
StringBuilder sb = new StringBuilder(sin);
int i = sb.toString().indexOf(what);
int len = what.length();
while ( i > -1 ) {
sb.replace(i,i + len,repl);
i = sb.toString().indexOf(what,i+1);
}
return sb.toString();
}
}
/** Compute the list of modules that should be installed into this
* cluster.
* @param File root of cluster
* @return List<File> of nbm files
*/
public static Set<File> getModulesToInstall (File cluster) {
class NbmFilter implements java.io.FilenameFilter {
@Override
public boolean accept (File dir, String name) {
return name.endsWith (ModuleUpdater.NBM_EXTENSION) || name.endsWith (ModuleUpdater.JAR_EXTENSION);
}
}
File idir = new File (cluster, ModuleUpdater.DOWNLOAD_DIR);
File[] arr = idir.listFiles (new NbmFilter ());
if (arr == null) {
return Collections.emptySet ();
} else {
return new HashSet<File> (Arrays.asList (arr));
}
}
}