class FilePublisher { public FilePublisher(program, publish) { this.Program = program; this.OutputDirectory = publish; } /^ The file to publish ^/ public Program; /^ The {name,version,info} from executable ^/ public ProjectInfo; /^ Where we output the published files ^/ public OutputDirectory; /^ The runtime identifier builtins: "crvm" (merge to one crvm) "header" (merge to one crvm and generate C header) "cmake" (merge to one crvm and generate C header and create a cmake project) actual runtimes can be found here: https://cpkg.tesseslanguage.com/packages?q=Tesses.CrossLang.Runtime. (you need to strip the Tesses.CrossLang.Runtime. from the names) ^/ public RuntimeIdentifier="crvm"; /^ The prefix of the package (to prepend onto runtime identifier, we put the trailing period for you) ^/ public PackagePrefix = "Tesses.CrossLang.Runtime"; /^ Merge for runtimes (one crvm file) ^/ public MergeForRuntimes = false; private Build() { var strm = FS.Local.OpenFile(this.Program, "rb"); var exec=VM.LoadExecutable(strm); strm.Close(); this.ProgramInfo = { name = exec.Name, version = exec.Version.ToString(), info = Json.Decode(exec.Info) }; return FS.MakeFull(this.Program); } private Merge() { var path = this.Build(); var packPath = path / "__merge"; if(packPath.Count > 0 && FS.Local.DirectoryExists(packPath)) { FS.Local.DeleteDirectoryRecurse(packPath); } FS.Local.CreateDirectory(packPath); var pack_dir = new SubdirFilesystem(FS.Local, packPath); return packPath / VM.Merge(FS.Local,path,pack_dir); } private CopyBuild(destPath) { func CopyCRVM(src,dest) { 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(); Console.WriteLine($"{src} -> {dest}"); } if(FS.Local.FileExists(dest)) return; copyFile(src,dest); var srcStrm = FS.Local.OpenFile(src,"rb"); var crvm = VM.LoadExecutable(srcStrm); srcStrm.Close(); each(var dep : crvm.Dependencies) { var name = $"{dep.Name}-{dep.Version.ToString()}.crvm"; CopyCRVM(src.GetParent()/name, dest.GetParent()/name); } } each(var item : FS.Local.EnumeratePaths(destPath.GetParent())) { if(item.GetExtension() == ".crvm" && FS.Local.FileExists(item)) { FS.Local.DeleteFile(item); } } CopyCRVM(this.Build(), destPath); } private CreateCMake(dir, short_name) { FS.Local.CreateDirectory(dir / "src"); var path = this.Merge(); var bytes = FS.ReadAllBytes(FS.Local, path); var caps_version = this.FixCHeaderName(short_name); FS.WriteAllText(FS.Local, dir / "src" / $"{short_name}.h", bytes.ToCHeaderFile(caps_version)); if(!FS.Local.RegularFileExists(dir / "CMakeLists.txt")) { var cmake_file = embed("cml.txt").ToString().Replace("@<>@",caps_version).Replace("@<>@",short_name); FS.WriteAllText(FS.Local,dir / "CMakeLists.txt", cmake_file); } if(!FS.Local.RegularFileExists(dir / "src"/"main.cpp")) { var cppFile = embed("cppfiletemplate.cpp").ToString().Replace("@<>@", caps_version).Replace("@<
>@",short_name); FS.WriteAllText(FS.Local,dir / "src"/"main.cpp", cppFile); } } private CopyFile(src,dest) { var srcStrm = FS.Local.OpenFile(src,"rb"); var destStrm = FS.Local.OpenFile(dest, "wb"); srcStrm.CopyTo(destStrm); srcStrm.Close(); destStrm.Close(); } private FixCHeaderName(name) { var myStr = name.ToUpper(); name = ""; each(var item : myStr) { if((item >= 'A' && item <= 'Z') || (item >= '0' && item <= '9') || item == '_') name += item; } if(name.Length == 0) return "NONAME"; else if(name[0] >= '0' && name[0] <= '9') return $"_{name}"; return name; } /^ Start the publishing process ^/ public Publish() { var outDir =this.OutputDirectory; var short_name = TypeOf(this.ProjectInfo.info.short_name) == "String" ? this.ProjectInfo.info.short_name : this.ProjectInfo.name; FS.Local.CreateDirectory(outDir); switch(this.RuntimeIdentifier) { case "copy": { if(this.MergeForRuntimes) { FS.Local.MoveFile(this.Merge(), outDir / short_name + ".crvm"); } else { this.CopyBuild(outDir / short_name + ".crvm"); } } break; case "crvm": { var path = this.Merge(); FS.Local.MoveFile(path, outDir / $"{short_name}.crvm"); } break; case "header": { var path = this.Merge(); var bytes = FS.ReadAllBytes(FS.Local, path); FS.WriteAllText(FS.Local, outDir / $"{short_name}.h", bytes.ToCHeaderFile(this.FixCHeaderName(short_name))); } break; case "cmake": { this.CreateCMake(outDir, short_name); } break; default: { var runtimePackageName = this.PackagePrefix; if(runtimePackageName.Count > 0 && !runtimePackageName.EndsWith('.')) runtimePackageName += "."; runtimePackageName += this.RuntimeIdentifier; var version = this.ProjectBuilder.PackageManager.GetLatest(runtimePackageName); if(TypeOf(version) != "String") { throw { Type="PackageNotFoundException", Message=$"Could not find package {runtimePackageName}.", ToString=(this)=>$"{this.Type} on line: {this.Line} {this.Message}" }; } var pkgObj = this.ProjectBuilder.PackageManager.GetPackage(runtimePackageName, version); var strm = new MemoryStream(true); strm.WriteBlock(pkgObj,0,pkgObj.Length); strm.Seek(0,0); var sdfs = new SubdirFilesystem(FS.Local, outDir); var archiveResponse = FS.ExtractArchive(strm,sdfs); sdfs.Close(); var archiveInfo = Json.Decode(archiveResponse.Info); if(archiveInfo.executable_can_be_renamed) { var executable_name_path = /archiveInfo.executable_name; var executable_extension = executable_name_path.GetExtension(); var newName = outDir/short_name; if(executable_extension.Length > 0) newName += executable_extension; FS.Local.MoveFile(outDir/archiveInfo.executable_name,newName); FS.Local.Chmod(newName, 0755); if(this.MergeForRuntimes) { FS.Local.MoveFile(this.Merge(), outDir / short_name + ".crvm"); } else { this.CopyBuild(outDir / short_name + ".crvm"); } } else { var executable_name_path = /archiveInfo.executable_name; FS.Local.Chmod(outDir/archiveInfo.executable_name, 0755); var executable_name_no_ext = executable_name_path.ChangeExtension(null).GetFileName(); if(this.MergeForRuntimes) { FS.Local.MoveFile(this.Merge(), outDir / executable_name_no_ext + ".crvm"); } else { this.CopyBuild(outDir / executable_name_no_ext + ".crvm"); } } } break; } } }