engine/release: make packer

master
q3k 2021-05-08 23:48:58 +02:00
parent e5616eed4f
commit d60f48d49c
8 changed files with 293 additions and 14 deletions

View File

@ -54,3 +54,33 @@ http_archive(
],
build_file = "//third_party/q3d:BUILD",
)
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "io_bazel_rules_go",
sha256 = "69de5c704a05ff37862f7e0f5534d4f479418afc21806c887db544a316f3cb6b",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.27.0/rules_go-v0.27.0.tar.gz",
"https://github.com/bazelbuild/rules_go/releases/download/v0.27.0/rules_go-v0.27.0.tar.gz",
],
)
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
go_rules_dependencies()
go_register_toolchains(version = "1.16")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "com_google_protobuf",
sha256 = "9748c0d90e54ea09e5e75fb7fac16edce15d2028d4356f32211cfa3c0e956564",
strip_prefix = "protobuf-3.11.4",
urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.11.4.zip"],
)
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
protobuf_deps()

View File

@ -72,19 +72,11 @@ rust_binary(
],
)
pkg_tar(
load("//engine/release:defs.bzl", "abrasion_release")
abrasion_release(
name = "demo",
srcs = [
":engine",
"dist_start.sh",
"//engine/shaders:forward_vert",
"//engine/shaders:forward_frag",
"//assets:test-128px.png",
"//assets:test-128px-roughness.png",
deps = [
":engine"
],
strip_prefix = '/',
package_dir = 'demo',
remap_paths = {
"engine/dist_start.sh": "start.sh",
},
)
)

View File

@ -0,0 +1,12 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary")
go_binary(
name = "pack",
srcs = ["pack.go"],
deps = [
"//engine/release/proto:manifest_go_proto",
"@org_golang_google_protobuf//encoding/prototext",
"@org_golang_google_protobuf//proto",
],
visibility = ["//visibility:public"],
)

51
engine/release/defs.bzl Normal file
View File

@ -0,0 +1,51 @@
def _abrasion_release_impl(ctx):
main = ctx.files.deps[0]
runfiles = depset([], transitive = [
dep[DefaultInfo].default_runfiles.files for dep in ctx.attr.deps
]).to_list()
# HACK: flatbuffer/ruest rules use genrules, which propagate source rust
# files unnecessarily into their runfiles. Strip 'em out here.
runfiles = [rf for rf in runfiles if not rf.path.endswith(".rs")]
runfiles = [rf for rf in runfiles if not rf.path == main.path]
# Proprietary little manifest format, for //engine/release/pack.go to use.
runfile_manifest = ctx.actions.declare_file(ctx.attr.name + "-manifest.text.pb")
ctx.actions.write(runfile_manifest, proto.encode_text(struct(file = [
struct(short_path=rf.short_path, path=rf.path)
for rf in runfiles
])))
zipfile = ctx.actions.declare_file(ctx.attr.name + ".zip")
ctx.actions.run(
mnemonic = "AbrasionPack",
executable = ctx.executable._pack,
inputs = runfiles + [
runfile_manifest,
main
],
outputs = [zipfile],
arguments = [
"-pack_manifest", runfile_manifest.path,
"-pack_exe", main.path,
"-pack_zip", zipfile.path
]
)
return [
DefaultInfo(files=depset([zipfile]))
]
abrasion_release = rule(
implementation = _abrasion_release_impl,
attrs = {
"deps": attr.label_list(
),
"_pack": attr.label(
executable = True,
cfg = "exec",
default = Label("//engine/release:pack"),
),
}
)

102
engine/release/pack.go Normal file
View File

@ -0,0 +1,102 @@
package main
import (
"archive/zip"
"crypto/sha256"
"flag"
"fmt"
"log"
"os"
"io/ioutil"
"sort"
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/proto"
pb "abrasion/engine/release/proto"
)
var (
flagManifest string
flagExe string
flagZip string
)
func packFile(w *zip.Writer, file *pb.File) error {
fo, err := w.Create(file.ShortPath)
if err != nil {
return fmt.Errorf("Create: %w", err)
}
// TODO(q3k): maybe don't read this into memory...
data, err := ioutil.ReadFile(file.Path)
if err != nil {
return fmt.Errorf("Open: %w", err)
}
h := sha256.Sum256(data)
file.Sha256 = h[:]
_, err = fo.Write(data)
if err != nil {
return fmt.Errorf("Write: %w", err)
}
// We don't need this in the release manifest.
file.Path = ""
return nil
}
func main() {
flag.StringVar(&flagManifest, "pack_manifest", "", "Path to manifest.text.pb")
flag.StringVar(&flagExe, "pack_exe", "", "Path to main .exe")
flag.StringVar(&flagZip, "pack_zip", "", "Path to generated release .zip")
flag.Parse()
data, err := ioutil.ReadFile(flagManifest)
if err != nil {
log.Fatalf("ReadFile: %v", err)
}
var manifest pb.Manifest
if err := prototext.Unmarshal(data, &manifest); err != nil {
log.Fatalf("Unmashal: %v", err)
}
sort.Slice(manifest.File, func(i, j int) bool {
return manifest.File[i].ShortPath < manifest.File[j].ShortPath
})
f, err := os.Create(flagZip)
if err != nil {
log.Fatalf("Create: %v", err)
}
defer f.Close()
w := zip.NewWriter(f)
defer w.Close()
// Pack runfiles
for _, file := range manifest.File {
if err := packFile(w, file); err != nil {
log.Fatalf("Failed to pack file %q (%q): %v", file.ShortPath, file.Path, err)
}
}
// Pack engine
engine := pb.File{
ShortPath: "abrasion.exe",
Path: flagExe,
}
if err := packFile(w, &engine); err != nil {
log.Fatalf("Failed to pack engine: %v", err)
}
manifest.File = append(manifest.File, &engine)
// Pack binary manifest.
manifestBytes, err := proto.Marshal(&manifest)
if err != nil {
}
mo, err := w.Create("abrasion.manifest")
if err != nil {
log.Fatalf("Failed to create manifest: %v", err)
}
if _, err := mo.Write(manifestBytes); err != nil {
log.Fatalf("Failed to write manifest: %v", err)
}
}

View File

@ -0,0 +1,14 @@
load("@rules_proto//proto:defs.bzl", "proto_library")
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
proto_library(
name = "manifest_proto",
srcs = ["manifest.proto"],
)
go_proto_library(
name = "manifest_go_proto",
importpath = "abrasion/engine/release/proto",
protos = [":manifest_proto"],
visibility = ["//engine/release:__pkg__"],
)

View File

@ -0,0 +1,18 @@
syntax = "proto3";
package abrasion.engine.release.proto;
option go_package = "abrasion/engine/release/proto";
message File {
string short_path = 1;
string path = 2;
bytes sha256 = 3;
}
message Manifest {
repeated File file = 1;
ReleaseInfo release_info = 2;
}
message ReleaseInfo {
string target = 1;
}

View File

@ -69,6 +69,51 @@ impl std::io::Seek for Resource {
}
}
/// ReleaseFiles is a file/resource accessible for abrasion releases build via
/// //engine/release.
struct ReleaseFiles {
}
impl ReleaseFiles {
fn new() -> Option<Self> {
let exec_path = match std::env::args().nth(0) {
Some(p) => p,
None => {
log::warn!("Could not load release files: no argv 0.");
return None;
}
}.to_owned();
let mut exec_path = std::path::PathBuf::from(&exec_path);
exec_path.set_extension("manifest");
if !exec_path.is_file() {
return None;
}
Some(ReleaseFiles {
})
}
fn rlocation(&self, rel: &str) -> Option<String> {
Some(rel.to_string())
}
}
fn release_files() -> std::sync::Arc<Option<ReleaseFiles>> {
use std::sync::{Arc, Mutex, Once};
static mut SINGLETON: *const Arc<Option<ReleaseFiles>> = 0 as *const Arc<Option<ReleaseFiles>>;
static ONCE: Once = Once::new();
unsafe {
ONCE.call_once(|| {
let rf = ReleaseFiles::new();
SINGLETON = std::mem::transmute(Box::new(Arc::new(rf)));
});
(*SINGLETON).clone()
}
}
pub fn resource<T>(name: T) -> Result<Resource>
where
T: Into<String>
@ -84,6 +129,21 @@ where
if rel.contains("//") {
return Err(ResourceError::InvalidPath);
}
if let Some(r) = &*release_files() {
let loc = match r.rlocation(rel) {
Some(loc) => Ok(loc),
None => Err(ResourceError::NotFound),
}?;
return std::fs::File::open(loc).map_err(|e| {
match e.kind() {
std::io::ErrorKind::NotFound => ResourceError::NotFound,
_ => ResourceError::Other(e),
}
}).map(|f| {
Resource::File(std::io::BufReader::new(f))
});
}
if let Ok(r) = Runfiles::create() {
// TODO(q3k): unhardcode workspace name?