From 9bbd39b67c0086d537bbdeeaa347c0a701152c30 Mon Sep 17 00:00:00 2001 From: orbiter Date: Thu, 28 Jun 2007 14:52:26 +0000 Subject: [PATCH] - removed unfinished auto-updater from roland and martin - added new download-option for releases on the status page still mising: - thomas-style restart for linux/mac - untar/gunzip on shell basis (comes next) git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@3931 6c8d7289-2bf4-0310-a012-ef5d649a1542 --- htroot/Status.html | 32 +++++ htroot/Status.java | 95 ++++++++++--- htroot/Steering.java | 9 +- htroot/yacy/transfer.java | 4 +- lib/YaCyUpdater_r4.jar | Bin 37139 -> 0 bytes source/de/anomic/http/httpdFileHandler.java | 1 - source/de/anomic/net/URL.java | 6 +- .../plasma/plasmaRankingDistribution.java | 8 -- .../de/anomic/plasma/plasmaSwitchboard.java | 44 +++--- .../anomic/server/serverUpdaterCallback.java | 12 -- source/de/anomic/yacy/yacyVersion.java | 125 +++++++++++++----- source/yacy.java | 47 +------ yacy.init | 3 + yacy.network.unit | 5 + 14 files changed, 240 insertions(+), 151 deletions(-) delete mode 100644 lib/YaCyUpdater_r4.jar delete mode 100644 source/de/anomic/server/serverUpdaterCallback.java diff --git a/htroot/Status.html b/htroot/Status.html index a4ac1d985..74afeceff 100644 --- a/htroot/Status.html +++ b/htroot/Status.html @@ -68,6 +68,7 @@ #(/hintVersionAvailable)# + + #(hintStatusSenior)#::
good
You are running a server in senior mode and you support the global internet index, @@ -146,6 +148,36 @@ +
+
+ System Update +
+
Available Releases
+
  +   
+
+
Downloaded Releases
+
  +
+
+
+
+
Public System Properties
diff --git a/htroot/Status.java b/htroot/Status.java index 030a69dc3..9a537a15b 100644 --- a/htroot/Status.java +++ b/htroot/Status.java @@ -46,13 +46,17 @@ // javac -classpath .:../Classes Status.java // if the shell's current path is HTROOT +import java.io.IOException; import java.text.DecimalFormat; import java.util.Date; +import java.util.Iterator; +import java.util.TreeSet; import de.anomic.http.httpHeader; import de.anomic.http.httpd; import de.anomic.http.httpdByteCountInputStream; import de.anomic.http.httpdByteCountOutputStream; +import de.anomic.net.URL; import de.anomic.plasma.plasmaSwitchboard; import de.anomic.server.serverCore; import de.anomic.server.serverDate; @@ -61,6 +65,7 @@ import de.anomic.server.serverObjects; import de.anomic.server.serverSwitch; import de.anomic.yacy.yacyCore; import de.anomic.yacy.yacySeed; +import de.anomic.yacy.yacyVersion; public class Status { @@ -72,16 +77,16 @@ public class Status { final serverObjects prop = new serverObjects(); final plasmaSwitchboard sb = (plasmaSwitchboard) env; - if ((post != null) && (post.containsKey("login"))) { + if (post != null) { if (sb.adminAuthenticated(header) < 2) { prop.put("AUTHENTICATE","admin log-in"); - } else { - prop.put("LOCATION",""); + return prop; } - return prop; - } else if (post != null) { - boolean redirect = false; - if (post.containsKey("pauseCrawlJob")) { + boolean redirect = false; + if (post.containsKey("login")) { + prop.put("LOCATION",""); + return prop; + } else if (post.containsKey("pauseCrawlJob")) { String jobType = (String) post.get("jobType"); if (jobType.equals("localCrawl")) sb.pauseCrawlJob(plasmaSwitchboard.CRAWLJOB_LOCAL_CRAWL); @@ -111,7 +116,18 @@ public class Status { sb.setConfig("browserPopUpTrigger", "true"); } redirect = true; - } + } else if (post.containsKey("downloadRelease")) { + // download a release + String release = post.get("releasedownload", ""); + if (release.length() > 0) { + try { + yacyVersion.downloadRelease(new yacyVersion(new URL(release))); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } if (redirect) { prop.put("LOCATION",""); @@ -140,24 +156,64 @@ public class Status { } // if running on Windows or with updater/wrapper enable restart button - if ((sb.updaterCallback != null) || (System.getProperty("os.name").toLowerCase().startsWith("win"))) { + if (System.getProperty("os.name").toLowerCase().startsWith("win")) { prop.put("restartEnabled", 1); } // version information prop.put("versionpp", yacy.combined2prettyVersion(sb.getConfig("version","0.1"))); - - + double thisVersion = Double.parseDouble(sb.getConfig("version","0.1")); // cut off the SVN Rev in the Version try {thisVersion = Math.round(thisVersion*1000.0)/1000.0;} catch (NumberFormatException e) {} + + // list downloaded releases + yacyVersion release, dflt; + String[] downloaded = sb.releasePath.list(); + TreeSet downloadedreleases = new TreeSet(); + for (int j = 0; j < downloaded.length; j++) { + release = (yacyVersion) new yacyVersion(downloaded[j]); + downloadedreleases.add(release); + } + dflt = (downloadedreleases.size() == 0) ? null : (yacyVersion) downloadedreleases.last(); + Iterator i = downloadedreleases.iterator(); + int relcount = 0; + while (i.hasNext()) { + release = (yacyVersion) i.next(); + prop.put("downloadedreleases_" + relcount + "_name", (release.proRelease ? "pro" : "standard") + "/" + ((release.mainRelease) ? "main" : "dev") + " " + release.releaseNr + "/" + release.svn); + prop.put("downloadedreleases_" + relcount + "_file", release.name); + prop.put("downloadedreleases_" + relcount + "_selected", (release == dflt) ? 1 : 0); + relcount++; + } + prop.put("downloadedreleases", relcount); - if ((adminaccess) && (sb.updaterCallback != null) && (sb.updaterCallback.updateYaCyIsPossible())){ - prop.put("hintVersionAvailable", 1); - prop.put("hintVersionAvailable_latestVersion", sb.updaterCallback.getYaCyUpdateReleaseVersion()); - if ((post != null) && (post.containsKey("aquirerelease"))) { - sb.updaterCallback.grantYaCyUpdate(); - } + // list remotely available releases + TreeSet[] releasess = yacyVersion.allReleases(); // {0=promain, 1=prodev, 2=stdmain, 3=stddev} + relcount = 0; + // main + TreeSet releases = releasess[(yacy.pro) ? 0 : 2]; + releases.removeAll(downloadedreleases); + i = releases.iterator(); + while (i.hasNext()) { + release = (yacyVersion) i.next(); + prop.put("availreleases_" + relcount + "_name", (release.proRelease ? "pro" : "standard") + "/" + ((release.mainRelease) ? "main" : "dev") + " " + release.releaseNr + "/" + release.svn); + prop.put("availreleases_" + relcount + "_url", release.url.toString()); + prop.put("availreleases_" + relcount + "_selected", 0); + relcount++; } + // dev + dflt = (releasess[(yacy.pro) ? 1 : 3].size() == 0) ? null : (yacyVersion) releasess[(yacy.pro) ? 1 : 3].last(); + releases = releasess[(yacy.pro) ? 1 : 3]; + releases.removeAll(downloadedreleases); + i = releases.iterator(); + while (i.hasNext()) { + release = (yacyVersion) i.next(); + prop.put("availreleases_" + relcount + "_name", (release.proRelease ? "pro" : "standard") + "/" + ((release.mainRelease) ? "main" : "dev") + " " + release.releaseNr + "/" + release.svn); + prop.put("availreleases_" + relcount + "_url", release.url.toString()); + prop.put("availreleases_" + relcount + "_selected", (release == dflt) ? 1 : 0); + relcount++; + } + prop.put("availreleases", relcount); + /* if ((adminaccess) && (yacyVersion.latestRelease >= (thisVersion+0.01))) { // only new Versions(not new SVN) @@ -171,11 +227,12 @@ public class Status { prop.put("hintVersionAvailable", 1); } } + prop.put("hintVersionAvailable", 1); // for testing + prop.putASIS("hintVersionDownload_versionResMain", (yacyVersion.latestMainRelease == null) ? "-" : yacyVersion.latestMainRelease.toAnchor()); prop.putASIS("hintVersionDownload_versionResDev", (yacyVersion.latestDevRelease == null) ? "-" : yacyVersion.latestDevRelease.toAnchor()); prop.put("hintVersionAvailable_latestVersion", Double.toString(yacyVersion.latestRelease)); - */ - + */ // place some more hints if ((adminaccess) && (sb.getThread(plasmaSwitchboard.CRAWLJOB_LOCAL_CRAWL).getJobCount() == 0) && (sb.getThread(plasmaSwitchboard.INDEXER).getJobCount() == 0)) { prop.put("hintCrawlStart", 1); diff --git a/htroot/Steering.java b/htroot/Steering.java index 4d6b724de..a577f19dd 100644 --- a/htroot/Steering.java +++ b/htroot/Steering.java @@ -73,14 +73,13 @@ public class Steering { } if (post.containsKey("shutdown")) { - if (sb.updaterCallback != null) { sb.setConfig("Updater.restartSignal", 0); } sb.terminate(3000); prop.put("info", 3); return prop; } if (post.containsKey("restart")) { - if ((sb.updaterCallback == null) && (System.getProperty("os.name").toLowerCase().startsWith("win"))) { + if (System.getProperty("os.name").toLowerCase().startsWith("win")) { // create yacy.restart file which is used in Windows startscript final File yacyRestart = new File(sb.getRootPath(), "DATA/yacy.restart"); if (!yacyRestart.exists()) { @@ -92,12 +91,6 @@ public class Steering { } } } - - if (sb.updaterCallback != null) { - sb.setConfig("Updater.shutdownSignal", 1); - } else { - serverLog.logWarning("SHUTDOWN", "No wrapper/updater running! Performing a normal shutdown..."); - } sb.terminate(5000); prop.put("info", 4); diff --git a/htroot/yacy/transfer.java b/htroot/yacy/transfer.java index a1558d3ea..3371ca407 100644 --- a/htroot/yacy/transfer.java +++ b/htroot/yacy/transfer.java @@ -79,12 +79,10 @@ public final class transfer { prop.putASIS("process_path", ""); prop.putASIS("process_maxsize", "0"); - if (sb.isRobinsonMode()) { + if (sb.isRobinsonMode() || !sb.rankingOn) { // in a robinson environment, do not answer. We do not do any transfer in a robinson cluster. return prop; } - - if (!sb.rankingOn) { return prop; } yacySeed otherseed = yacyCore.seedDB.get(otherpeer); if ((otherseed == null) || (filename.indexOf("..") >= 0)) { diff --git a/lib/YaCyUpdater_r4.jar b/lib/YaCyUpdater_r4.jar deleted file mode 100644 index 4fd1219fdc9396d388dd22fbdb0f98d905416245..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37139 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 c6G4%V+9eL~W(5{w3=EP$mpublic static final String HTDOCS_PATH = "htDocsPath"

*

Name of the setting specifying the folder beginning from the YaCy-installation's top-folder, where all @@ -934,6 +932,10 @@ public final class plasmaSwitchboard extends serverAbstractSwitch implements ser } } + // set auto-updater locations + yacyVersion.latestDevReleaseLocation = getConfig("network.unit.update.location.dev", ""); + yacyVersion.latestMainReleaseLocation = getConfig("network.unit.update.location.main", ""); + // load values from configs this.plasmaPath = new File(rootPath, getConfig(DBPATH, DBPATH_DEFAULT)); this.log.logConfig("Plasma DB Path: " + this.plasmaPath.toString()); @@ -1079,6 +1081,18 @@ public final class plasmaSwitchboard extends serverAbstractSwitch implements ser boolean cacheMigration = getConfigBool(PROXY_CACHE_MIGRATION, true); this.cacheManager = new plasmaHTCache(htCachePath, maxCacheSize, ramHTTP_time, cacheLayout, cacheMigration); + // create the release download directory + String release = getConfig(RELEASE_PATH, RELEASE_PATH_DEFAULT); + release = release.replace('\\', '/'); + if (release.endsWith("/")) { release = release.substring(0, release.length() - 1); } + if (new File(release).isAbsolute()) { + releasePath = new File(release); // don't use rootPath + } else { + releasePath = new File(rootPath, release); + } + releasePath.mkdirs(); + this.log.logInfo("RELEASE Path = " + releasePath.getAbsolutePath()); + // starting message board initMessages(ramMessage_time); @@ -1225,7 +1239,7 @@ public final class plasmaSwitchboard extends serverAbstractSwitch implements ser CRDist1Percent = 30 CRDist1Target = kaskelix.de:8080,yacy.dyndns.org:8000,suma-lab.de:8080 **/ - rankingOn = getConfig(RANKING_DIST_ON, "true").equals("true"); + rankingOn = getConfig(RANKING_DIST_ON, "true").equals("true") && getConfig("network.unit.name", "").equals("freeworld"); rankingOwnDistribution = new plasmaRankingDistribution(log, new File(rankingPath, getConfig(RANKING_DIST_0_PATH, plasmaRankingDistribution.CR_OWN)), (int) getConfigLong(RANKING_DIST_0_METHOD, plasmaRankingDistribution.METHOD_ANYSENIOR), (int) getConfigLong(RANKING_DIST_0_METHOD, 0), getConfig(RANKING_DIST_0_TARGET, "")); rankingOtherDistribution = new plasmaRankingDistribution(log, new File(rankingPath, getConfig(RANKING_DIST_1_PATH, plasmaRankingDistribution.CR_OTHER)), (int) getConfigLong(RANKING_DIST_1_METHOD, plasmaRankingDistribution.METHOD_MIXEDSENIOR), (int) getConfigLong(RANKING_DIST_1_METHOD, 30), getConfig(RANKING_DIST_1_TARGET, "kaskelix.de:8080,yacy.dyndns.org:8000,suma-lab.de:8080")); @@ -1757,14 +1771,6 @@ public final class plasmaSwitchboard extends serverAbstractSwitch implements ser errorURL.close(); wordIndex.close(); yc.close(); - // signal shutdown to the updater - if (updaterCallback != null) { - if (sb.getConfigLong("Updater.shutdownSignal", -1) == 0) - updaterCallback.signalYaCyShutdown(); - else if - (sb.getConfigLong("Updater.shutdownSignal", -1) == 1) - updaterCallback.signalYaCyRestart(); - } log.logConfig("SWITCHBOARD SHUTDOWN TERMINATED"); } @@ -1916,9 +1922,11 @@ public final class plasmaSwitchboard extends serverAbstractSwitch implements ser int count = rankingOwnDistribution.size() / 100; if (count == 0) count = 1; if (count > 5) count = 5; - rankingOwnDistribution.transferRanking(count); - rankingOtherDistribution.transferRanking(1); - + if (rankingOn) { + rankingOwnDistribution.transferRanking(count); + rankingOtherDistribution.transferRanking(1); + } + // clean up delegated stack checkInterruption(); if ((delegatedURL.stackSize() > 1000)) { diff --git a/source/de/anomic/server/serverUpdaterCallback.java b/source/de/anomic/server/serverUpdaterCallback.java deleted file mode 100644 index 3cbcd97e1..000000000 --- a/source/de/anomic/server/serverUpdaterCallback.java +++ /dev/null @@ -1,12 +0,0 @@ -package de.anomic.server; - -public interface serverUpdaterCallback { - public boolean updateYaCyIsPossible(); - public void grantYaCyUpdate(); - public String getYaCyUpdateReleaseVersion(); - //public File getYaCyUpdateReleaseFile(); - public String getYaCyUpdateSource(); - /** Signal a user initiated YaCy shutdown (not restart!) to the updater so it can terminate itself */ - public void signalYaCyShutdown(); - public void signalYaCyRestart(); -} \ No newline at end of file diff --git a/source/de/anomic/yacy/yacyVersion.java b/source/de/anomic/yacy/yacyVersion.java index 137a65bf3..64f0b1124 100644 --- a/source/de/anomic/yacy/yacyVersion.java +++ b/source/de/anomic/yacy/yacyVersion.java @@ -27,6 +27,7 @@ package de.anomic.yacy; +import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.util.Comparator; @@ -35,7 +36,10 @@ import java.util.Map; import java.util.TreeSet; import de.anomic.htmlFilter.htmlFilterContentScraper; +import de.anomic.http.httpc; import de.anomic.net.URL; +import de.anomic.plasma.plasmaSwitchboard; +import de.anomic.server.serverFileUtils; public final class yacyVersion implements Comparator, Comparable { @@ -50,16 +54,20 @@ public final class yacyVersion implements Comparator, Comparable { public static double latestRelease = 0.1; // this value is overwritten when a peer with later version appears // information about latest release, retrieved from download pages - public static yacyVersion latestDevRelease = null; - public static yacyVersion latestMainRelease = null; - + // this static information should be overwritten by network-specific locations + // for details see yacy.network.unit + private static TreeSet[] allDevReleases = null; + private static TreeSet[] allMainReleases = null; + public static String latestDevReleaseLocation = ""; // will be initialized with value in yacy.network.unit + public static String latestMainReleaseLocation = ""; // will be initialized with value in yacy.network.unit // class variables public float releaseNr; public String dateStamp; public int svn; - public boolean mainRelease; + public boolean proRelease, mainRelease; public URL url; + public String name; public yacyVersion(URL url) { this(url.getFileName()); @@ -73,16 +81,17 @@ public final class yacyVersion implements Comparator, Comparable { // yacy_v${releaseVersion}_${DSTAMP}_${releaseNr}.tar.gz // i.e. yacy_v0.51_20070321_3501.tar.gz this.url = null; + this.name = release; if ((release == null) || (!release.endsWith(".tar.gz"))) { throw new RuntimeException("release file name '" + release + "' is not valid, no tar.gz"); } // cut off tail release = release.substring(0, release.length() - 7); - if (release.startsWith("yacy_dev_v")) { - mainRelease = false; + if (release.startsWith("yacy_pro_v")) { + proRelease = true; release = release.substring(10); } else if (release.startsWith("yacy_v")) { - mainRelease = true; + proRelease = false; release = release.substring(6); } else { throw new RuntimeException("release file name '" + release + "' is not valid, wrong prefix"); @@ -98,6 +107,8 @@ public final class yacyVersion implements Comparator, Comparable { } catch (NumberFormatException e) { throw new RuntimeException("release file name '" + release + "' is not valid, '" + comp[0] + "' should be a float number"); } + this.mainRelease = ((int) (this.releaseNr * (float) 1000)) % 10 == 0; + //System.out.println("Release version " + this.releaseNr + " is " + ((this.mainRelease) ? "main" : "std")); this.dateStamp = comp[1]; if (this.dateStamp.length() != 8) { throw new RuntimeException("release file name '" + release + "' is not valid, '" + comp[1] + "' should be a 8-digit date string"); @@ -110,16 +121,6 @@ public final class yacyVersion implements Comparator, Comparable { // finished! we parsed a relase string } - /* - public yacyVersion(URL url, float releaseNr, String dateStamp, int svn, boolean mainRelease) { - this.url = url; - this.releaseNr = releaseNr; - this.dateStamp = dateStamp; - this.svn = svn; - this.mainRelease = mainRelease; - } - */ - public int compareTo(Object obj) { yacyVersion v = (yacyVersion) obj; return compare(this, v); @@ -144,35 +145,67 @@ public final class yacyVersion implements Comparator, Comparable { public String toAnchor() { // generates an anchor string that can be used to embed in an html for direct download - return "YaCy " + ((this.mainRelease) ? "main release" : "developer release") + " v" + this.releaseNr + ", SVN " + this.svn + ""; + return "YaCy " + ((this.proRelease) ? "pro release" : "standard release") + " v" + this.releaseNr + ", SVN " + this.svn + ""; + } + /* + public static yacyVersion latestStandardRelease() { + // get the latest release info from a internet resource + yacyVersion devrel = (yacyVersion) allDevReleases().last(); + yacyVersion mainrel = (yacyVersion) allDevReleases().last(); } - public static void aquireLatestReleaseInfo() { - if ((latestDevRelease == null) && (latestMainRelease == null)) { - if (latestDevRelease == null) latestDevRelease = aquireLatestDevRelease(); - if (latestMainRelease == null) latestMainRelease = aquireLatestMainRelease(); + public static yacyVersion latestProRelease() { + // get the latest release info from a internet resource + return (yacyVersion) allMainReleases().last(); + } + */ + public static TreeSet[] allReleases() { + // join the release infos + // {promainreleases, prodevreleases, stdmainreleases, stddevreleases} + TreeSet[] a = allMainReleases(); + TreeSet[] b = allDevReleases(); + TreeSet[] r = new TreeSet[4]; + TreeSet s; + for (int i = 0; i < 4; i++) { + s = new TreeSet(); + if (b[i] != null) s.addAll((TreeSet) b[i]); + if (a[i] != null) s.addAll((TreeSet) a[i]); + r[i] = s; } + return r; } - public static yacyVersion aquireLatestDevRelease() { - // get the latest release info from a internet resource - try { - return latestReleaseFrom(new URL("http://latest.yacy-forum.net")); + private static TreeSet[] allDevReleases() { + // get release info from a internet resource + // {promainreleases, prodevreleases, stdmainreleases, stddevreleases} + if ((allDevReleases == null) || + ((allDevReleases[0].size() == 0) && + (allDevReleases[1].size() == 0) && + (allDevReleases[2].size() == 0) && + (allDevReleases[3].size() == 0) )) try { + allDevReleases = allReleaseFrom(new URL(latestDevReleaseLocation)); } catch (MalformedURLException e) { return null; } + return allDevReleases; } - public static yacyVersion aquireLatestMainRelease() { - // get the latest release info from a internet resource - try { - return latestReleaseFrom(new URL("http://yacy.net/yacy/Download.html")); + private static TreeSet[] allMainReleases() { + // get release info from a internet resource + // {promainreleases, prodevreleases, stdmainreleases, stddevreleases} + if ((allMainReleases == null) || + ((allMainReleases[0].size() == 0) && + (allMainReleases[1].size() == 0) && + (allMainReleases[2].size() == 0) && + (allMainReleases[3].size() == 0) )) try { + allMainReleases = allReleaseFrom(new URL(latestMainReleaseLocation)); } catch (MalformedURLException e) { return null; } + return allMainReleases; } - public static yacyVersion latestReleaseFrom(URL url) { + private static TreeSet[] allReleaseFrom(URL url) { // retrieves the latest info about releases // this is done by contacting a release location, // parsing the content and filtering+parsing links @@ -187,7 +220,10 @@ public final class yacyVersion implements Comparator, Comparable { // analyse links in scraper resource, and find link to latest release in it Map anchors = scraper.getAnchors(); // a url (String) / name (String) relation Iterator i = anchors.keySet().iterator(); - TreeSet releases = new TreeSet(); // will contain a release (Float) / url (String) relation + TreeSet stddevreleases = new TreeSet(); + TreeSet prodevreleases = new TreeSet(); + TreeSet stdmainreleases = new TreeSet(); + TreeSet promainreleases = new TreeSet(); yacyVersion release; while (i.hasNext()) { try { @@ -198,7 +234,10 @@ public final class yacyVersion implements Comparator, Comparable { try { release = new yacyVersion(url); //System.out.println("r " + release.toAnchor()); - releases.add(release); + if ( release.proRelease && release.mainRelease) promainreleases.add(release); + if ( release.proRelease && !release.mainRelease) prodevreleases.add(release); + if (!release.proRelease && release.mainRelease) stdmainreleases.add(release); + if (!release.proRelease && !release.mainRelease) stddevreleases.add(release); } catch (RuntimeException e) { // the release string was not well-formed. // that might have been another link @@ -206,8 +245,22 @@ public final class yacyVersion implements Comparator, Comparable { continue; } } - if (releases.size() == 0) return null; - //i = releases.iterator(); while (i.hasNext()) {System.out.println("v " + ((yacyVersion) i.next()).toAnchor());} - return (yacyVersion) releases.last(); + return new TreeSet[] {promainreleases, prodevreleases, stdmainreleases, stddevreleases} ; + } + + public static void downloadRelease(yacyVersion release) throws IOException { + File storagePath = plasmaSwitchboard.getSwitchboard().releasePath; + // load file + byte[] file = httpc.wget( + release.url, + release.url.getHost(), + 10000, + null, + null, + plasmaSwitchboard.getSwitchboard().remoteProxyConfig + ); + if (file == null) throw new IOException("wget of url " + release.url + " failed"); + // save file + serverFileUtils.write(file, new File(storagePath, release.url.getFileName())); } } diff --git a/source/yacy.java b/source/yacy.java index 69bfd8b4e..b7bc7121b 100644 --- a/source/yacy.java +++ b/source/yacy.java @@ -90,7 +90,6 @@ import de.anomic.server.serverFileUtils; import de.anomic.server.serverMemory; import de.anomic.server.serverSemaphore; import de.anomic.server.serverSystem; -import de.anomic.server.serverUpdaterCallback; import de.anomic.server.logging.serverLog; import de.anomic.tools.enumerateFiles; import de.anomic.yacy.yacyClient; @@ -137,7 +136,8 @@ public final class yacy { // static objects private static String vString = "@REPL_VERSION@"; private static double version = 0.1; - + public static boolean pro; + private static final String vDATE = "@REPL_DATE@"; private static final String copyright = "[ YaCy v" + vString + ", build " + vDATE + " by Michael Christen / www.yacy.net ]"; private static final String hline = "-------------------------------------------------------------------------------"; @@ -258,27 +258,8 @@ public final class yacy { } f.createNewFile(); f.deleteOnExit(); - - /* - // Testing if the yacy archive file were unzipped correctly. - // This test is needed because of classfile-names longer than 100 chars - // which could cause problems with incompatible unzip software. - // See: - // - http://www.yacy-forum.de/viewtopic.php?t=1763 - // - http://www.yacy-forum.de/viewtopic.php?t=715 - // - http://www.yacy-forum.de/viewtopic.php?t=1674 - File unzipTest = new File(homePath,"doc/This_is_a_test_if_the_archive_file_containing_YaCy_was_unpacked_correctly_If_not_please_use_gnu_tar_instead.txt"); - if (!unzipTest.exists()) { - String errorMsg = "The archive file containing YaCy was not unpacked correctly. " + - "Please use 'GNU-Tar' or upgrade to a newer version of your unzip software.\n" + - "For detailed information on this bug see: " + - "http://www.yacy-forum.de/viewtopic.php?t=715"; - System.err.println(errorMsg); - serverLog.logSevere("STARTUP", errorMsg); - System.exit(1); - } - */ - boolean pro = new File(homePath, "libx").exists(); + + pro = new File(homePath, "libx").exists(); sb = new plasmaSwitchboard(homePath, "yacy.init", "DATA/SETTINGS/httpProxy.conf", pro); sbSync.V(); // signal that the sb reference was set @@ -548,26 +529,6 @@ public final class yacy { } } - /** - * Function to set the updater callback class - * @param updaterCallback - * @throws InterruptedException - */ - public static void setUpdaterCallback(serverUpdaterCallback updaterCallback) throws InterruptedException { - sbSync.P(); - sb.updaterCallback = updaterCallback; - sbSync.V(); - } - - /** - * Function allowing the updater to block until the startup has finished - * @throws InterruptedException - */ - public static void waitForFinishedStartup() throws InterruptedException { - startupFinishedSync.P(); - startupFinishedSync.V(); - } - /** * Call the shutdown-page of YaCy to tell it to shut down. This method is * called if you start yacy with the argument -shutdown. diff --git a/yacy.init b/yacy.init index 7bc7284fd..c9f7bd3d2 100644 --- a/yacy.init +++ b/yacy.init @@ -157,6 +157,9 @@ proxyCache = DATA/HTCACHE proxyCacheSize = 100 proxyCacheSize__pro = 600 +# storage place for new releases +releases = DATA/RELEASE + # use the mostly direct mapping of URLs to Filenames # makes it easy watching the content of the cache using file browsers # problems arise when a file already exists where a new entry expects a directory diff --git a/yacy.network.unit b/yacy.network.unit index 93ce5ae39..13720a503 100644 --- a/yacy.network.unit +++ b/yacy.network.unit @@ -62,6 +62,11 @@ network.unit.bootstrap.seedlist4 = http://www.yacy.net/yacy/seed.txt network.unit.bootstrap.seedlist5 = http://www.marcelhenseler.de/yacy/seed.txt network.unit.bootstrap.seedlist6 = http://www.dc-art.de/yacy/seed.txt +# each network may use different yacy distributions. +# the auto-updater can access network-specific update locations +network.unit.update.location.dev = http://latest.yacy-forum.net +network.unit.update.location.main = http://yacy.net/yacy/Download.html + # properties for in-protocol response authentification: #network.unit.protocol.control = uncontrolled #network.unit.protocol.request.authentification.method = salted-magic