1 /** 2 Copyright: Copyright (c) 2015-2016 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module packager; 7 8 import std.file; 9 import std.string; 10 import std.digest.crc; 11 import std.stdio; 12 import std.zip; 13 import std.path; 14 import std.process; 15 import std.datetime; 16 17 enum ROOT_PATH = "../.."; 18 string testDir; 19 20 void main(string[] args) 21 { 22 string semver = "0.7.0"; 23 testDir = buildNormalizedPath(ROOT_PATH, "test"); 24 if (exists(testDir)) 25 rmdirRecurse(testDir); 26 27 StopWatch sw; 28 sw.start(); 29 completeBuild(Arch.x32, semver); 30 writeln; 31 completeBuild(Arch.x64, semver); 32 sw.stop(); 33 writefln("Finished in %.1fs", sw.peek().to!("seconds", real)); 34 } 35 36 void completeBuild(Arch arch, string semver) 37 { 38 string dub_arch = arch == Arch.x32 ? "x86" : "x86_64"; 39 string launcher_arch = arch == Arch.x32 ? "32" : "64"; 40 41 string dubCom(Arch arch) { 42 return format(`dub run --root="tools/launcher" -q --nodeps --build=release --arch=%s -- --release=%s`, 43 dub_arch, launcher_arch); 44 } 45 46 string com = dubCom(arch); 47 writefln("Executing '%s'", com); stdout.flush(); 48 49 auto dub = executeShell(com, null, Config.none, size_t.max, ROOT_PATH); 50 51 if (dub.status != 0) 52 writeln("Failed to run launcher"); 53 dub.output.write; 54 55 writefln("Packing %sbit", launcher_arch); stdout.flush(); 56 pack(semver, arch, Platform.windows); 57 } 58 59 struct ReleasePackage 60 { 61 string semver; 62 Arch arch; 63 Platform platform; 64 ZipArchive zip; 65 string fileRoot; 66 string archRoot; 67 } 68 69 void pack(string semver, Arch arch, Platform pl) 70 { 71 ReleasePackage pack = ReleasePackage( 72 semver, 73 arch, 74 pl, 75 new ZipArchive, 76 ROOT_PATH); 77 string archName = archName(&pack, "voxelman"); 78 pack.archRoot = archName; 79 80 makePackage(&pack); 81 string archiveName = buildNormalizedPath(ROOT_PATH, archName) ~ ".zip"; 82 writePackage(&pack, archiveName); 83 84 extractArchive(archiveName, testDir); 85 } 86 87 enum Arch { x64, x32 } 88 enum Platform { windows, linux, macos } 89 string[Platform] platformToString; 90 string[Arch] archToString; 91 static this() 92 { 93 platformToString = [Platform.windows : "win", Platform.linux : "linux", Platform.macos : "mac"]; 94 archToString = [Arch.x64 : "64", Arch.x32 : "32"]; 95 } 96 97 void makePackage(ReleasePackage* pack) 98 { 99 pack.addFiles("builds/default", "*.exe"); 100 pack.addFiles("res", "*"); 101 pack.addFiles("config", "*.sdl"); 102 pack.addFiles("lib/"~archToString[pack.arch], "*.dll"); 103 pack.addFile("README.md"); 104 pack.addFile("CHANGELOG.md"); 105 pack.addFile("LICENSE.md"); 106 pack.addFile("pluginpacks/default.txt"); 107 pack.addFile("launcher.exe"); 108 } 109 110 void writePackage(ReleasePackage* pack, string path) 111 { 112 std.file.write(path, pack.zip.build()); 113 } 114 115 string archName(R)(ReleasePackage* pack, R baseName) 116 { 117 string arch = archToString[pack.arch]; 118 string platform = platformToString[pack.platform]; 119 return format("%s-v%s-%s%s", baseName, pack.semver, platform, arch); 120 } 121 122 alias normPath = buildNormalizedPath; 123 alias absPath = absolutePath; 124 void addFiles(ReleasePackage* pack, string path, string pattern) 125 { 126 import std.file : dirEntries, SpanMode; 127 128 string absRoot = pack.fileRoot.absPath.normPath; 129 foreach (entry; dirEntries(buildPath(pack.fileRoot, path), pattern, SpanMode.depth)) 130 if (entry.isFile) { 131 string absPath = entry.name.absPath.normPath; 132 addFile(pack, absPath, relativePath(absPath, absRoot)); 133 } 134 } 135 136 void addFile(ReleasePackage* pack, string arch_name) 137 { 138 addFile(pack.zip, buildPath(pack.fileRoot, arch_name).absPath.normPath, buildPath(pack.archRoot, arch_name)); 139 } 140 141 void addFile(ReleasePackage* pack, string fs_name, string arch_name) 142 { 143 addFile(pack.zip, fs_name.absPath.normPath, buildPath(pack.archRoot, arch_name)); 144 } 145 146 void addFile(ZipArchive arch, string fs_name, string arch_name) 147 { 148 string norm = arch_name.normPath; 149 writefln("Add %s as %s", fs_name, norm); 150 void[] data = std.file.read(fs_name); 151 ArchiveMember am = new ArchiveMember(); 152 am.name = norm; 153 am.compressionMethod = CompressionMethod.deflate; 154 am.expandedData(cast(ubyte[])data); 155 arch.addMember(am); 156 } 157 158 void extractArchive(string archive, string pathTo) 159 { 160 extractArchive(new ZipArchive(std.file.read(archive)), pathTo); 161 } 162 163 void extractArchive(ZipArchive archive, string pathTo) 164 { 165 foreach (ArchiveMember am; archive.directory) 166 { 167 string targetPath = buildPath(pathTo, am.name); 168 mkdirRecurse(dirName(targetPath)); 169 archive.expand(am); 170 std.file.write(targetPath, am.expandedData); 171 } 172 }