package helpers; import haxe.io.Path; import helpers.LogHelper; import helpers.ProcessHelper; import project.Architecture; import project.Haxelib; import project.NDLL; import project.Platform; import sys.io.Process; import sys.FileSystem; class PathHelper { public static var haxelibOverrides = new Map (); private static var haxelibPaths = new Map (); public static function combine (firstPath:String, secondPath:String):String { if (firstPath == null || firstPath == "") { return secondPath; } else if (secondPath != null && secondPath != "") { if (PlatformHelper.hostPlatform == Platform.WINDOWS) { if (secondPath.indexOf (":") == 1) { return secondPath; } } else { if (secondPath.substr (0, 1) == "/") { return secondPath; } } var firstSlash = (firstPath.substr (-1) == "/" || firstPath.substr (-1) == "\\"); var secondSlash = (secondPath.substr (0, 1) == "/" || secondPath.substr (0, 1) == "\\"); if (firstSlash && secondSlash) { return firstPath + secondPath.substr (1); } else if (!firstSlash && !secondSlash) { return firstPath + "/" + secondPath; } else { return firstPath + secondPath; } } else { return firstPath; } } public static function escape (path:String):String { if (PlatformHelper.hostPlatform != Platform.WINDOWS) { path = StringTools.replace (path, "\\ ", " "); path = StringTools.replace (path, " ", "\\ "); path = StringTools.replace (path, "\\'", "'"); path = StringTools.replace (path, "'", "\\'"); } else { path = StringTools.replace (path, "^,", ","); path = StringTools.replace (path, ",", "^,"); } return expand (path); } public static function expand (path:String):String { if (path == null) { path = ""; } if (PlatformHelper.hostPlatform != Platform.WINDOWS) { if (StringTools.startsWith (path, "~/")) { path = Sys.getEnv ("HOME") + "/" + path.substr (2); } } return path; } public static function findTemplate (templatePaths:Array , path:String, warnIfNotFound:Bool = true):String { var matches = findTemplates (templatePaths, path, warnIfNotFound); if (matches.length > 0) { return matches[matches.length - 1]; } return null; } public static function findTemplates (templatePaths:Array , path:String, warnIfNotFound:Bool = true):Array { var matches = []; for (templatePath in templatePaths) { var targetPath = combine (templatePath, path); if (FileSystem.exists (targetPath)) { matches.push (targetPath); } } if (matches.length == 0 && warnIfNotFound) { LogHelper.warn ("Could not find template file: " + path); } return matches; } public static function getHaxelib (haxelib:Haxelib, validate:Bool = false, clearCache:Bool = false):String { var name = haxelib.name; if (haxelibOverrides.exists (name)) { return haxelibOverrides.get (name); } if (haxelib.version != "") { name += ":" + haxelib.version; } if (clearCache) { haxelibPaths.remove (name); } if (!haxelibPaths.exists (name)) { var cache = LogHelper.verbose; LogHelper.verbose = false; var output = ""; try { var cacheDryRun = ProcessHelper.dryRun; ProcessHelper.dryRun = false; output = ProcessHelper.runProcess (Sys.getEnv ("HAXEPATH"), "haxelib", [ "path", name ], true, true, true); ProcessHelper.dryRun = cacheDryRun; } catch (e:Dynamic) { } LogHelper.verbose = cache; var lines = output.split ("\n"); var result = ""; for (i in 1...lines.length) { if (StringTools.trim (lines[i]) == "-D " + haxelib.name) { result = StringTools.trim (lines[i - 1]); } } if (result == "") { try { for (line in lines) { if (line != "" && line.substr (0, 1) != "-") { if (FileSystem.exists (line)) { result = line; break; } } } } catch (e:Dynamic) {} } if (validate) { if (result == "") { if (output.indexOf ("does not have") > -1) { var directoryName = ""; if (PlatformHelper.hostPlatform == Platform.WINDOWS) { directoryName = "Windows"; } else if (PlatformHelper.hostPlatform == Platform.MAC) { directoryName = PlatformHelper.hostArchitecture == Architecture.X64 ? "Mac64" : "Mac"; } else { directoryName = PlatformHelper.hostArchitecture == Architecture.X64 ? "Linux64" : "Linux"; } LogHelper.error ("haxelib \"" + haxelib.name + "\" does not have an \"ndll/" + directoryName + "\" directory"); } else { if (haxelib.version != "") { LogHelper.error ("Could not find haxelib \"" + haxelib.name + "\" version \"" + haxelib.version + "\", does it need to be installed?"); } else { LogHelper.error ("Could not find haxelib \"" + haxelib.name + "\", does it need to be installed?"); } } } } haxelibPaths.set (name, result); } return haxelibPaths.get (name); } public static function getLibraryPath (ndll:NDLL, directoryName:String, namePrefix:String = "", nameSuffix:String = ".ndll", allowDebug:Bool = false):String { var usingDebug = false; var path = ""; if (allowDebug) { path = searchForLibrary (ndll, directoryName, namePrefix + ndll.name + "-debug" + nameSuffix); usingDebug = FileSystem.exists (path); } if (!usingDebug) { path = searchForLibrary (ndll, directoryName, namePrefix + ndll.name + nameSuffix); } return path; } public static function getTemporaryFile (extension:String = ""):String { var path = ""; if (PlatformHelper.hostPlatform == Platform.WINDOWS) { path = Sys.getEnv ("TEMP"); } else { path = Sys.getEnv ("TMPDIR"); if (path == null) { path = "/tmp"; } } path += "/temp_" + Math.round (0xFFFFFF * Math.random ()) + extension; if (FileSystem.exists (path)) { return getTemporaryFile (extension); } return path; } public static function getTemporaryDirectory ():String { var path = getTemporaryFile (); mkdir (path); return path; } public static function isAbsolute (path:String):Bool { if (StringTools.startsWith (path, "/") || StringTools.startsWith (path, "\\")) { return true; } return false; } public static function isRelative (path:String):Bool { return !isAbsolute (path); } public static function mkdir (directory:String):Void { directory = StringTools.replace (directory, "\\", "/"); var total = ""; if (directory.substr (0, 1) == "/") { total = "/"; } var parts = directory.split("/"); var oldPath = ""; if (parts.length > 0 && parts[0].indexOf (":") > -1) { oldPath = Sys.getCwd (); Sys.setCwd (parts[0] + "\\"); parts.shift (); } for (part in parts) { if (part != "." && part != "") { if (total != "" && total != "/") { total += "/"; } total += part; if (!FileSystem.exists (total)) { LogHelper.info ("", " - \x1b[1mCreating directory:\x1b[0m " + total); FileSystem.createDirectory (total); } } } if (oldPath != "") { Sys.setCwd (oldPath); } } public static function readDirectory (directory:String, ignore:Array = null, paths:Array = null):Array { if (FileSystem.exists (directory)) { if (paths == null) { paths = []; } var files; try { files = FileSystem.readDirectory (directory); } catch (e:Dynamic) { return paths; } for (file in FileSystem.readDirectory (directory)) { if (ignore != null) { var filtered = false; for (filter in ignore) { if (filter == file) { filtered = true; } } if (filtered) continue; } var path = directory + "/" + file; try { if (FileSystem.isDirectory (path)) { readDirectory (path, ignore, paths); } else { paths.push (path); } } catch (e:Dynamic) { return paths; } } return paths; } return null; } public static function relocatePath (path:String, targetDirectory:String):String { // this should be improved for target directories that are outside the current working path if (isAbsolute (path) || targetDirectory == "") { return path; } else if (isAbsolute (targetDirectory)) { return FileSystem.fullPath (path); } else { targetDirectory = StringTools.replace (targetDirectory, "\\", "/"); var splitTarget = targetDirectory.split ("/"); var directories = 0; while (splitTarget.length > 0) { switch (splitTarget.shift ()) { case ".": // ignore case "..": directories--; default: directories++; } } var adjust = ""; for (i in 0...directories) { adjust += "../"; } return adjust + path; } } public static function relocatePaths (paths:Array , targetDirectory:String):Array { var relocatedPaths = paths.copy (); for (i in 0...paths.length) { relocatedPaths[i] = relocatePath (paths[i], targetDirectory); } return relocatedPaths; } public static function removeDirectory (directory:String):Void { if (FileSystem.exists (directory)) { var files; try { files = FileSystem.readDirectory (directory); } catch (e:Dynamic) { return; } for (file in FileSystem.readDirectory (directory)) { var path = directory + "/" + file; try { if (FileSystem.isDirectory (path)) { removeDirectory (path); } else { FileSystem.deleteFile (path); } } catch (e:Dynamic) {} } LogHelper.info ("", " - \x1b[1mRemoving directory:\x1b[0m " + directory); try { FileSystem.deleteDirectory (directory); } catch (e:Dynamic) {} } } public static function safeFileName (name:String):String { var safeName = StringTools.replace (name, " ", ""); return safeName; } private static function searchForLibrary (ndll:NDLL, directoryName:String, filename:String):String { if (ndll.path != null && ndll.path != "") { return ndll.path; } else if (ndll.haxelib == null) { if (ndll.extensionPath != null && ndll.extensionPath != "") { var subdirectory = "ndll/"; if (ndll.subdirectory != null) { if (ndll.subdirectory != "") { subdirectory = ndll.subdirectory + "/"; } else { subdirectory = ""; } } return combine (ndll.extensionPath, subdirectory + directoryName + "/" + filename); } else { return filename; } } else if (ndll.haxelib.name == "hxcpp") { var extension = Path.extension (filename); if (extension == "a" || extension == "lib") { return combine (getHaxelib (ndll.haxelib, true), "lib/" + directoryName + "/" + filename); } else { return combine (getHaxelib (ndll.haxelib, true), "bin/" + directoryName + "/" + filename); } } else { var subdirectory = "ndll/"; if (ndll.subdirectory != null) { if (ndll.subdirectory != "") { subdirectory = ndll.subdirectory + "/"; } else { subdirectory = ""; } } return combine (getHaxelib (ndll.haxelib, true), subdirectory + directoryName + "/" + filename); } } public static function standardize (path:String, trailingSlash:Bool = false):String { path = StringTools.replace (path, "\\", "/"); path = StringTools.replace (path, "//", "/"); path = StringTools.replace (path, "//", "/"); if (!trailingSlash && StringTools.endsWith (path, "/")) { path = path.substr (0, path.length - 1); } else if (trailingSlash && !StringTools.endsWith (path, "/")) { path += "/"; } return path; } public static function tryFullPath (path:String):String { try { return FileSystem.fullPath (path); } catch (e:Dynamic) { return expand (path); } } }