forked from I2P_Developers/i2p.i2p
Mac OS X Launcher:
* Bugfixes as always * Added Sparkle (native updater, https://sparkle-project.org/ ) * The launcher will now extract and overwrite older versions if found * Rewrite of the java extraction part (to enable overwrite) * Move more functionality to use EventManager as it works quite well * Added check for updates menu item
This commit is contained in:
@ -1,7 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14113" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14113"/>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14313.18"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
@ -36,5 +37,6 @@
|
||||
</items>
|
||||
<point key="canvasLocation" x="17" y="167"/>
|
||||
</menu>
|
||||
<customObject id="xTS-ll-kWI" customClass="SUUpdater"/>
|
||||
</objects>
|
||||
</document>
|
||||
|
@ -5,4 +5,5 @@
|
||||
#import "AppleStuffExceptionHandler.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "RouterTask.h"
|
||||
#import "Sparkle/SUUpdater.h"
|
||||
|
||||
|
@ -17,24 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLIconFile</key>
|
||||
<string>ItoopieTransparent</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>http+i2p</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>http+i2p</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<string>0.1.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4</string>
|
||||
<string>5</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
@ -54,6 +39,8 @@
|
||||
<dict/>
|
||||
</array>
|
||||
<key>SUFeedURL</key>
|
||||
<string>http://i2browser.i2p/updates/v1/appcast.xml</string>
|
||||
<string>https://download.i2p2.de/macosx/sparkle/updates/v1/appcast.xml</string>
|
||||
<key>SUPublicEDKey</key>
|
||||
<string>weKSpHXfJzk+5qy3UVfqsUwTeLnT9WCFVMwd9yW0+DA=</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -154,6 +154,7 @@
|
||||
</tabView>
|
||||
</viewController>
|
||||
<customObject id="d8g-wS-Zts" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
<customObject id="4gn-BI-uSC" userLabel="Updater" customClass="SUUpdater"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-823" y="166"/>
|
||||
</scene>
|
||||
|
@ -69,11 +69,17 @@ import Cocoa
|
||||
}
|
||||
|
||||
@objc func applicationDidFinishLaunching() {
|
||||
print("Hello from swift!")
|
||||
var i2pPath = NSHomeDirectory()
|
||||
i2pPath += "/Library/I2P"
|
||||
|
||||
findInstalledI2PVersion()
|
||||
}
|
||||
|
||||
@objc func listenForEvent(eventName: String, callbackActionFn: @escaping ((Any?)->()) ) {
|
||||
RouterManager.shared().eventManager.listenTo(eventName: eventName, action: callbackActionFn )
|
||||
}
|
||||
|
||||
@objc func triggerEvent(en: String, details: String? = nil) {
|
||||
RouterManager.shared().eventManager.trigger(eventName: en, information: details)
|
||||
}
|
||||
|
||||
@objc static func openLink(url: String) {
|
||||
|
@ -38,6 +38,7 @@ class RouterManager : NSObject {
|
||||
let currentVersion : String = information as! String
|
||||
if (packedVersion.compare(currentVersion, options: .numeric) == .orderedDescending) {
|
||||
Swift.print("event! - router version: Packed version is newer, gonna re-deploy")
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_must_upgrade", information: "got new version")
|
||||
} else {
|
||||
Swift.print("event! - router version: No update needed")
|
||||
RouterManager.shared().eventManager.trigger(eventName: "router_can_start", information: "all ok")
|
||||
|
@ -36,23 +36,16 @@ import AppKit
|
||||
@objc func triggerEvent(en: String, details: String? = nil) {
|
||||
RouterManager.shared().eventManager.trigger(eventName: en, information: details)
|
||||
}
|
||||
|
||||
@objc func listenForEvent(eventName: String, callbackActionFn: @escaping ((Any?)->()) ) {
|
||||
RouterManager.shared().eventManager.listenTo(eventName: eventName, action: callbackActionFn )
|
||||
}
|
||||
}
|
||||
|
||||
extension RouterProcessStatus {
|
||||
static var isRouterRunning : Bool = false
|
||||
static var isRouterChildProcess : Bool = false
|
||||
static var isRouterRunning : Bool = (RouterManager.shared().getRouterTask() != nil)
|
||||
static var isRouterChildProcess : Bool = (RouterManager.shared().getRouterTask() != nil)
|
||||
static var routerVersion : String? = Optional.none
|
||||
static var routerUptime : String? = Optional.none{
|
||||
//Called before the change
|
||||
willSet(newValue){
|
||||
print("RouterProcessStatus.routerUptime will change from ", (self.routerUptime ?? "nil"), " to "+(newValue ?? "nil"))
|
||||
}
|
||||
|
||||
//Called after the change
|
||||
didSet{
|
||||
print("RouterProcessStatus.routerUptime did change to "+self.routerUptime!)
|
||||
}
|
||||
}
|
||||
static var routerStartedAt : Date? = Optional.none
|
||||
static var knownJavaBinPath : String? = Optional.none
|
||||
static var i2pDirectoryPath : String = NSHomeDirectory() + "/Library/I2P"
|
||||
|
@ -28,7 +28,7 @@ import Cocoa
|
||||
|
||||
@objc func actionBtnStartRouter(_ sender: Any?) {
|
||||
NSLog("START ROUTER")
|
||||
if (!(RouterManager.shared().getRouterTask()?.isRunning())!) {
|
||||
if (RouterManager.shared().getRouterTask() == nil) {
|
||||
SBridge.sharedInstance().startupI2PRouter(RouterProcessStatus.i2pDirectoryPath, javaBinPath: RouterProcessStatus.knownJavaBinPath!)
|
||||
}
|
||||
RouterManager.shared().updateState()
|
||||
@ -36,7 +36,7 @@ import Cocoa
|
||||
|
||||
@objc func actionBtnStopRouter(_ sender: Any?) {
|
||||
NSLog("STOP ROUTER")
|
||||
if ((RouterManager.shared().getRouterTask()?.isRunning())!) {
|
||||
if (RouterManager.shared().getRouterTask() != nil) {
|
||||
NSLog("Found running router")
|
||||
RouterManager.shared().getRouterTask()?.requestShutdown()
|
||||
RouterManager.shared().updateState()
|
||||
@ -44,7 +44,7 @@ import Cocoa
|
||||
}
|
||||
|
||||
@objc func actionBtnRestartRouter(sender: Any?) {
|
||||
if ((RouterManager.shared().getRouterTask()?.isRunning())!) {
|
||||
if (RouterManager.shared().getRouterTask() != nil) {
|
||||
RouterManager.shared().getRouterTask()?.requestRestart()
|
||||
} else {
|
||||
NSLog("Can't restart a non running router, start it however...")
|
||||
|
@ -9,12 +9,13 @@
|
||||
import Foundation
|
||||
import Cocoa
|
||||
|
||||
|
||||
@objc class StatusBarController: NSObject, NSMenuDelegate {
|
||||
|
||||
let popover = NSPopover()
|
||||
let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength)
|
||||
//let storyboard = NSStoryboard(name: "Storyboard", bundle: nil)
|
||||
let storyboard = NSStoryboard(name: "Storyboard", bundle: Bundle.main)
|
||||
|
||||
var updateObjectRef : SUUpdater?
|
||||
|
||||
@objc func handleOpenConsole(_ sender: Any?) {
|
||||
SwiftMainDelegate.openLink(url: "http://localhost:7657")
|
||||
@ -23,8 +24,13 @@ import Cocoa
|
||||
@objc func constructMenu() -> NSMenu {
|
||||
let menu = NSMenu()
|
||||
|
||||
let updateMenuItem = NSMenuItem(title: "Check for updates", action: #selector(self.updateObjectRef?.checkForUpdates(_:)), keyEquivalent: "U")
|
||||
updateMenuItem.isEnabled = true
|
||||
|
||||
menu.addItem(NSMenuItem(title: "Open I2P Console", action: #selector(self.handleOpenConsole(_:)), keyEquivalent: "O"))
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
menu.addItem(updateMenuItem)
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
menu.addItem(NSMenuItem(title: "Quit I2P Launcher", action: #selector(SwiftMainDelegate.terminate(_:)), keyEquivalent: "q"))
|
||||
|
||||
return menu
|
||||
@ -34,6 +40,9 @@ import Cocoa
|
||||
override init() {
|
||||
super.init()
|
||||
popover.contentViewController = PopoverViewController.freshController()
|
||||
updateObjectRef = SUUpdater.shared()
|
||||
updateObjectRef?.checkForUpdatesInBackground()
|
||||
|
||||
|
||||
if let button = statusItem.button {
|
||||
button.image = NSImage(named:"StatusBarButtonImage")
|
||||
|
@ -39,15 +39,6 @@ const std::vector<std::string> defaultFlagsForExtractorJob {
|
||||
@class I2PRouterTask;
|
||||
@interface I2PRouterTask : NSObject
|
||||
@property (strong) NSTask* routerTask;
|
||||
|
||||
// TODO: Not in use, remove?
|
||||
/*
|
||||
@property (strong) NSUserDefaults *userPreferences;
|
||||
@property (strong) NSFileHandle *readLogHandle;
|
||||
@property (strong) NSMutableData *totalLogData;
|
||||
@property (strong) NSFileHandle *input;
|
||||
*/
|
||||
|
||||
@property (strong) NSPipe *processPipe;
|
||||
@property (atomic) BOOL isRouterRunning;
|
||||
@property (atomic) BOOL userRequestedRestart;
|
||||
|
@ -44,42 +44,6 @@
|
||||
[self.routerTask setStandardOutput:self.processPipe];
|
||||
[self.routerTask setStandardError:self.processPipe];
|
||||
|
||||
/*
|
||||
NSFileHandle *stdoutFileHandle = [self.processPipe fileHandleForReading];
|
||||
dup2([[self.processPipe fileHandleForWriting] fileDescriptor], fileno(stdout));
|
||||
auto source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, [stdoutFileHandle fileDescriptor], 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
|
||||
dispatch_source_set_event_handler(source, ^{
|
||||
void* data = malloc(4096);
|
||||
ssize_t readResult = 0;
|
||||
do
|
||||
{
|
||||
errno = 0;
|
||||
readResult = read([stdoutFileHandle fileDescriptor], data, 4096);
|
||||
} while (readResult == -1 && errno == EINTR);
|
||||
if (readResult > 0)
|
||||
{
|
||||
//AppKit UI should only be updated from the main thread
|
||||
dispatch_async(dispatch_get_main_queue(),^{
|
||||
NSString* stdOutString = [[NSString alloc] initWithBytesNoCopy:data length:readResult encoding:NSUTF8StringEncoding freeWhenDone:YES];
|
||||
NSAttributedString* stdOutAttributedString = [[NSAttributedString alloc] initWithString:stdOutString];
|
||||
NSLog(@"Router stdout: %@", stdOutString);
|
||||
//auto logForwarder = new LogForwarder();
|
||||
//[logForwarder appendLogViewWithLogLine:stdOutAttributedString];
|
||||
});
|
||||
}
|
||||
else{free(data);}
|
||||
});
|
||||
dispatch_resume(source);
|
||||
*/
|
||||
/*
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(routerStdoutData:)
|
||||
name:NSFileHandleDataAvailableNotification
|
||||
object:stdoutFileHandle];
|
||||
|
||||
[stdoutFileHandle waitForDataInBackgroundAndNotify];
|
||||
*/
|
||||
|
||||
[self.routerTask setTerminationHandler:^(NSTask* task) {
|
||||
// Cleanup
|
||||
NSLog(@"termHandler triggered!");
|
||||
@ -112,8 +76,6 @@
|
||||
- (int) execute
|
||||
{
|
||||
@try {
|
||||
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
|
||||
[swiftRouterStatus triggerEventWithEn:@"router_start" details:@"normal start"];
|
||||
[self.routerTask launch];
|
||||
self.isRouterRunning = YES;
|
||||
return 1;
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "include/fn.h"
|
||||
std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir);
|
||||
//std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir, RouterProcessStatus* routerStatus = nil);
|
||||
|
||||
|
||||
namespace osx {
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
|
||||
|
||||
std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir) {
|
||||
std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir, RouterProcessStatus* routerStatus) {
|
||||
@try {
|
||||
RTaskOptions* options = [RTaskOptions alloc];
|
||||
options.binPath = javaBin;
|
||||
@ -36,12 +36,16 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
|
||||
|
||||
[[SBridge sharedInstance] setCurrentRouterInstance:instance];
|
||||
[instance execute];
|
||||
if (routerStatus != nil) {
|
||||
[routerStatus setRouterStatus: true];
|
||||
[routerStatus setRouterRanByUs: true];
|
||||
[routerStatus triggerEventWithEn:@"router_start" details:@"normal start"];
|
||||
}
|
||||
sendUserNotification(APP_IDSTR, @"The I2P router is starting up.");
|
||||
auto pid = [instance getPID];
|
||||
NSLog(@"Got pid: %d", pid);
|
||||
|
||||
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
|
||||
[swiftRouterStatus triggerEventWithEn:@"router_pid" details:[NSString stringWithFormat:@"%d", pid]];
|
||||
if (routerStatus != nil) [routerStatus triggerEventWithEn:@"router_pid" details:[NSString stringWithFormat:@"%d", pid]];
|
||||
|
||||
return std::async(std::launch::async, [&pid]{
|
||||
return pid;
|
||||
@ -54,10 +58,11 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
|
||||
sendUserNotification(APP_IDSTR, errStr);
|
||||
[[SBridge sharedInstance] setCurrentRouterInstance:nil];
|
||||
|
||||
auto swiftRouterStatus = [[RouterProcessStatus alloc] init];
|
||||
[swiftRouterStatus setRouterStatus: false];
|
||||
[swiftRouterStatus setRouterRanByUs: false];
|
||||
[swiftRouterStatus triggerEventWithEn:@"router_exception" details:errStr];
|
||||
if (routerStatus != nil) {
|
||||
[routerStatus setRouterStatus: false];
|
||||
[routerStatus setRouterRanByUs: false];
|
||||
[routerStatus triggerEventWithEn:@"router_exception" details:errStr];
|
||||
}
|
||||
|
||||
return std::async(std::launch::async, [&]{
|
||||
return 0;
|
||||
@ -100,8 +105,6 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
|
||||
{
|
||||
std::string basePath([i2pRootPath UTF8String]);
|
||||
|
||||
// Get paths
|
||||
//NSBundle *launcherBundle = [NSBundle mainBundle];
|
||||
auto classPathStr = buildClassPathForObjC(basePath);
|
||||
|
||||
RouterProcessStatus* routerStatus = [[RouterProcessStatus alloc] init];
|
||||
@ -137,12 +140,11 @@ std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments,
|
||||
auto nsJavaBin = javaBinPath;
|
||||
auto nsBasePath = i2pRootPath;
|
||||
NSArray* arrArguments = [NSArray arrayWithObjects:&argList[0] count:argList.size()];
|
||||
// We don't really know yet, but per now a workaround
|
||||
[routerStatus setRouterStatus: true];
|
||||
|
||||
NSLog(@"Trying to run command: %@", javaBinPath);
|
||||
NSLog(@"With I2P Base dir: %@", i2pRootPath);
|
||||
NSLog(@"And Arguments: %@", arrArguments);
|
||||
startupRouter(nsJavaBin, arrArguments, nsBasePath);
|
||||
startupRouter(nsJavaBin, arrArguments, nsBasePath, routerStatus);
|
||||
} catch (std::exception &err) {
|
||||
auto errMsg = [NSString stringWithUTF8String:err.what()];
|
||||
NSLog(@"Exception: %@", errMsg);
|
||||
|
@ -200,9 +200,6 @@ using namespace subprocess;
|
||||
shouldAutoStartRouter = true;
|
||||
}
|
||||
|
||||
if (self.enableVerboseLogging) NSLog(@"processinfo %@", [[NSProcessInfo processInfo] arguments]);
|
||||
|
||||
|
||||
NSBundle *launcherBundle = [NSBundle mainBundle];
|
||||
|
||||
// Helper object to hold statefull path information
|
||||
@ -218,6 +215,23 @@ using namespace subprocess;
|
||||
std::string jarfile("-cp ");
|
||||
jarfile += [self.metaInfo.zipFile UTF8String];
|
||||
|
||||
// Might be hard to read if you're not used to Objective-C
|
||||
// But this is a "function call" that contains a "callback function"
|
||||
[routerStatus listenForEventWithEventName:@"router_can_start" callbackActionFn:^(NSString* information) {
|
||||
NSLog(@"Got signal, router can be started");
|
||||
[[SBridge sharedInstance] startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
|
||||
}];
|
||||
|
||||
// This will trigger the router start after an upgrade.
|
||||
[routerStatus listenForEventWithEventName:@"router_must_upgrade" callbackActionFn:^(NSString* information) {
|
||||
NSLog(@"Got signal, router must be upgraded");
|
||||
[self extractI2PBaseDir:^(BOOL success, NSError *error) {
|
||||
sendUserNotification(@"I2P is done extracting", @"I2P is now installed and ready to run!");
|
||||
NSLog(@"Done extracting I2P");
|
||||
[routerStatus triggerEventWithEn:@"router_can_start" details:@"upgrade complete"];
|
||||
}];
|
||||
}];
|
||||
|
||||
// Initialize the Swift environment (the UI components)
|
||||
[self.swiftRuntime applicationDidFinishLaunching];
|
||||
|
||||
@ -226,37 +240,16 @@ using namespace subprocess;
|
||||
{
|
||||
// I2P is not extracted.
|
||||
if (self.enableVerboseLogging) NSLog(@"I2P Directory don't exists!");
|
||||
|
||||
// Might be hard to read if you're not used to Objective-C
|
||||
// But this is a "function call" that contains a "callback function"
|
||||
[self extractI2PBaseDir:^(BOOL success, NSError *error) {
|
||||
sendUserNotification(@"I2P is done extracting", @"I2P is now installed and ready to run!");
|
||||
NSLog(@"Done extracting I2P");
|
||||
|
||||
NSLog(@"Time to detect I2P version in install directory");
|
||||
[self.swiftRuntime findInstalledI2PVersion];
|
||||
if (shouldAutoStartRouter) {
|
||||
[[SBridge sharedInstance] startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
|
||||
[routerStatus setRouterRanByUs: true];
|
||||
}
|
||||
}];
|
||||
|
||||
[routerStatus triggerEventWithEn:@"router_must_upgrade" details:@"deploy needed"];
|
||||
} else {
|
||||
// I2P was already found extracted
|
||||
NSLog(@"Time to detect I2P version in install directory");
|
||||
[self.swiftRuntime findInstalledI2PVersion];
|
||||
|
||||
if (shouldAutoStartRouter) {
|
||||
[[SBridge sharedInstance] startupI2PRouter:self.metaInfo.i2pBase javaBinPath:self.metaInfo.javaBinary];
|
||||
[routerStatus setRouterRanByUs: true];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Exit sequence
|
||||
|
@ -13,6 +13,10 @@ import java.nio.file.Path;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
import static java.nio.file.Files.*;
|
||||
|
||||
/**
|
||||
* As the name suggest, it extracts the base path.
|
||||
@ -24,35 +28,39 @@ public class BaseExtractor extends EnvCheck {
|
||||
|
||||
public boolean printDebug = false;
|
||||
|
||||
public void runExtract(String zipFilename) {
|
||||
String destinationPath = this.baseDirPath;
|
||||
try(ZipFile file = new ZipFile(zipFilename)) {
|
||||
FileSystem fileSystem = FileSystems.getDefault();
|
||||
Enumeration<? extends ZipEntry> entries = file.entries();
|
||||
|
||||
try {
|
||||
Files.createDirectory(fileSystem.getPath(destinationPath));
|
||||
} catch (IOException e) {
|
||||
// It's OK to fail here.
|
||||
public void unzip(final Path zipFile) {
|
||||
try {
|
||||
String destinationPath = this.baseDirPath;
|
||||
final Path destDir = Files.createDirectories(FileSystems.getDefault().getPath(destinationPath));
|
||||
if (notExists(destDir)) {
|
||||
createDirectories(destDir);
|
||||
}
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = entries.nextElement();
|
||||
if (printDebug) System.out.println("Found entry: "+entry.toString());
|
||||
if (entry.isDirectory()) {
|
||||
if (printDebug) System.out.println("Creating Directory:" + destinationPath + "/" + entry.getName());
|
||||
Files.createDirectories(fileSystem.getPath(destinationPath + "/" + entry.getName()));
|
||||
} else {
|
||||
InputStream is = file.getInputStream(entry);
|
||||
BufferedInputStream bis = new BufferedInputStream(is);
|
||||
String uncompressedFileName = destinationPath + "/" + entry.getName();
|
||||
Path uncompressedFilePath = fileSystem.getPath(uncompressedFileName);
|
||||
Files.createFile(uncompressedFilePath);
|
||||
BufferedOutputStream fileOutput = new BufferedOutputStream(new FileOutputStream(uncompressedFileName));
|
||||
while (bis.available() > 0) fileOutput.write(bis.read());
|
||||
fileOutput.close();
|
||||
if (printDebug) System.out.println("Written :" + entry.getName());
|
||||
}
|
||||
try (FileSystem zipFileSystem = FileSystems.newFileSystem(zipFile, null)) {
|
||||
final Path root = zipFileSystem.getRootDirectories().iterator().next();
|
||||
|
||||
walkFileTree(root, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
final Path destFile = Paths.get(destDir.toString(), file.toString());
|
||||
try {
|
||||
copy(file, destFile, StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (DirectoryNotEmptyException ignore) {
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
final Path dirToCreate = Paths.get(destDir.toString(), dir.toString());
|
||||
if (notExists(dirToCreate)) {
|
||||
createDirectory(dirToCreate);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (IOException e) {
|
||||
//
|
||||
@ -72,6 +80,6 @@ public class BaseExtractor extends EnvCheck {
|
||||
if (debug != null) {
|
||||
be.printDebug = true;
|
||||
}
|
||||
be.runExtract(System.getProperty("i2p.base.zip"));
|
||||
be.unzip( FileSystems.getDefault().getPath(System.getProperty("i2p.base.zip")) );
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user