func Tesses.CrossLang.BuildTool(pm) { func copyFile(src,dest) { var src = FS.Local.OpenFile(src,"rb"); var dest = FS.Local.OpenFile(dest, "wb"); src.CopyTo(dest); src.Close(); dest.Close(); } return { DirectoriesCompiled = [], GetPackageDependencies = (this,name,version,dir)=>{ var dep = pm.GetPackage(name,version); if(TypeOf(dep) == "Null") throw $"Package {name} with version {version} does not exist"; var pkgPath = dir / $"{name}-{version}.crvm"; var strm = FS.Local.OpenFile(pkgPath,"wb"); strm.WriteBlock(dep,0,dep.Count); strm.Close(); var strm = FS.Local.OpenFile(pkgPath,"rb"); var package = VM.LoadExecutable(strm); strm.Close(); var deps = []; each(var dep : package.Dependencies) { deps.Add(this.GetPackageDependencies(dep.Name, dep.Version, dir)); } each(var pkg : package.Tools) { dep.Add(this.GetPackageDependencies(dep.Name, dep.Version, dir)); } return { Name = name, Version = version, Info = Json.Decode(package.Info), Dependencies = deps, Output = pkgPath }; }, BuildProject = (this,projectDirectory)=>{ var dir = FS.MakeFull(projectDirectory); var dirStr = dir.ToString(); each(var item : this.DirectoriesCompiled) { if(item.Path == dirStr) return item.Data; } var crossConf = dir / "cross.json"; if(FS.Local.FileExists(crossConf)) { var configData = Json.Decode(FS.ReadAllText(FS.Local,crossConf)); var info = {type = "console"}; var name = "out"; var version = "1.0.0.0-prod"; var outputDir = "bin"; var objDir = "obj"; var srcDir = "src"; var resDir = "res"; var compTime = "none"; var icon = ""; if(TypeOf(configData.compTime) != "Undefined") compTime = configData.compTime; if(compTime == "full" && !this.AllowFullCompTime) throw { Type="CompTimeException", Message="Failed to build due to having insecure comptime, use --allow-insecure-comptime if using the shell when building if you trust the program.", ToString=(this)=>$"{this.Type} on line: {this.Line} {this.Message}" }; if(TypeOf(configData.name) != "Undefined") name = configData.name; if(TypeOf(configData.version) != "Undefined") version = configData.version; if(TypeOf(configData.bin_directory) != "Undefined") outputDir = configData.bin_directory; if(TypeOf(configData.obj_directory) != "Undefined") outputDir = configData.obj_directory; if(TypeOf(configData.source_directory) != "Undefined") srcDir = configData.source_directory; if(TypeOf(configData.resource_directory) != "Undefined") resDir = configData.resource_directory; if(TypeOf(configData.info) != "Undefined") info = configData.info; if(TypeOf(configData.icon) != "Undefined") icon = configData.icon; FS.Local.CreateDirectory(dir / outputDir); if(TypeOf(info.type) == "String" && info.type == "template") { //vfs, strm, name, version, info var subdir = new SubdirFilesystem(FS.Local,dir); var output = $"{name}-{version}.crvm"; var outFile = FS.Local.OpenFile(dir / outputDir / output,"wb"); if(TypeOf(info.template_ignored_files) != "Undefined") { var ignored = ""; each(var item : info.template_ignored_files) { ignored += $"{item}\n"; } FS.WriteAllText(FS.Local, dir / ".crossarchiveignore", ignored); } FS.CreateArchive(subdir, outFile, name, version, Json.Encode(info),icon); outFile.Close(); subdir.Close(); return null; } FS.Local.CreateDirectory(dir / objDir / "packages"); FS.Local.CreateDirectory(dir/resDir); var dependencies = []; if(TypeOf(configData.project_dependencies) == "List") { each(var dep : configData.project_dependencies) { if(Path.FromString(dep).IsRelative()) { dependencies.Add(this.BuildProject((dir / dep))); } else dependencies.Add(this.BuildProject(dep)); } } var sources = []; if(TypeOf(configData.dependencies) == "List") { each(var dep : configData.dependencies) { dependencies.Add(this.GetPackageDependencies(dep.name,dep.version,dir / objDir / "packages")); } } each(var item : this.DirectoriesCompiled) { if(item.Path == dirStr) return item.Data; } func walk_for_compiling(item,dir2) { if(item.Info.type == "compile_tool") { var newDir = dir / objDir / $"{item.Name}-{item.Version}"; FS.Local.CreateDirectory(newDir); var newFile = newDir / $"{item.Name}-{item.Version}.crvm"; copyFile(item.Output, newFile); each(var item2 : item.Dependencies) { walk_for_compiling(item2, newDir); } //we need to load this var env = VM.CreateEnvironment({}); env.RegisterEverything(); env.LockRegister(); env.LoadFileWithDependencies(FS.Local,newFile); env.GetDictionary().RunTool({ Project = new SubdirFilesystem(FS.Local, dir), ProjectInfo = info, GeneratedSource = sources, Config = this.Config }); } else { copyFile(item.Output, dir2 / $"{item.Name}-{item.Version}.crvm"); each(var item2 : item.Dependencies) { walk_for_compiling(item2, dir2); } } } var file_deps = []; var file_tools = []; each(var dep : dependencies) { if(dep.Info.type == "lib") { file_deps.Add({ Name = dep.Name, Version = dep.Version }); } else if(dep.Info.type == "compile_tool") { file_tools.Add({ Name = dep.Name, Version = dep.Version }); } walk_for_compiling(dep,dir / outputDir); } func walk_for_source(sourceDir) { each(var file : FS.Local.EnumeratePaths(sourceDir)) { if(FS.Local.RegularFileExists(file) && file.GetExtension()==".tcross") { var src = { FileName = file.ToString(), Source = FS.ReadAllText(FS.Local, file) }; sources.Add(src); } else if(FS.Local.DirectoryExists(file)) { walk_for_source(file); } } } walk_for_source(dir / srcDir); var output = $"{name}-{version}.crvm"; var outFile = FS.Local.OpenFile(dir / outputDir / output,"wb"); var compTimeEnv = null; if(compTime != "none") { //dir / outputDir; var exec = Env.GetRealExecutablePath("git"); var git_hash = ""; var git_tag = ""; if(FS.Local.FileExists(exec)) { var process = new Process(); process.FileName = exec.ToString(); process.Arguments = ["rev-parse","HEAD"]; process.RedirectStandardInput = true; process.RedirectStandardOutput = true; process.WorkingDirectory = dirStr; if(process.Start()) { var memStrm = new MemoryStream(true); process.StandardOutput.CopyTo(memStrm); git_hash = memStrm.GetBytes().ToString().Split("\n")[0]; } } var dict = { BuildTime = { Git = { Hash = git_hash, Tag = git_tag } } }; compTimeEnv = VM.CreateEnvironment(dict); switch(compTime) { case "secure_file": compTimeEnv.RegisterConsole(); compTimeEnv.RegisterClass(); compTimeEnv.RegisterCrypto(); compTimeEnv.RegisterDictionary(); compTimeEnv.RegisterJson(); compTimeEnv.RegisterRoot(); compTimeEnv.RegisterIO(false); dict.FS.Local = new SubdirFilesystem(FS.Local,dir); break; case "full": compTimeEnv.RegisterEverything(); break; default: //secure compTimeEnv.RegisterConsole(); compTimeEnv.RegisterClass(); compTimeEnv.RegisterCrypto(); compTimeEnv.RegisterDictionary(); compTimeEnv.RegisterJson(); compTimeEnv.RegisterRoot(); compTimeEnv.RegisterIO(false); break; } compTimeEnv.LockRegister(); each(var dep : file_deps) { compTimeEnv.LoadFileWithDependencies(FS.Local,dir/outputDir/$"{dep.Name}-{dep.Version}.crvm"); } } var result = VM.Compile({ Name = name, Version = version, Sources = sources, Info = Json.Encode(info), Icon = icon, Tools = file_tools, ResourceFileSystem = new SubdirFilesystem(FS.Local, dir / resDir), Dependencies = file_deps, Output = outFile, CompTime = compTimeEnv }); outFile.Close(); if(!result.Success) { throw result.Reason; } var myData = { Name = name, Version = version, Info = info, Output = dir / outputDir / output, Dependencies = dependencies }; this.DirectoriesCompiled.Add({ Path = dirStr, Data = myData }); return myData; } return null; } }; }