engine/release: make packer
parent
e5616eed4f
commit
d60f48d49c
30
WORKSPACE
30
WORKSPACE
|
@ -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()
|
20
engine/BUILD
20
engine/BUILD
|
@ -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",
|
||||
},
|
||||
)
|
||||
)
|
|
@ -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"],
|
||||
)
|
|
@ -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"),
|
||||
),
|
||||
}
|
||||
)
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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__"],
|
||||
)
|
|
@ -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;
|
||||
}
|
|
@ -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?
|
||||
|
|
Loading…
Reference in New Issue