Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile service: Support passing RHS kconfig and building RHS #17

Merged
merged 1 commit into from
Sep 7, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-container.yml
Original file line number Diff line number Diff line change
@@ -60,11 +60,11 @@ jobs:
name: moergo-glove80-zmk-dev
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Build lambda image
run: nix-build release.nix --arg revision "\"${REVISION_TAG}\"" -A directLambdaImage -o directLambdaImage
run: nix-build release.nix --arg revision "\"${REVISION_TAG}\"" -A lambdaImage -o lambdaImage
- name: Import OCI image into docker-daemon
env:
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
run: skopeo --insecure-policy copy oci:directLambdaImage docker-daemon:$REGISTRY/$ECR_REPOSITORY:$REVISION_TAG
run: skopeo --insecure-policy copy oci:lambdaImage docker-daemon:$REGISTRY/$ECR_REPOSITORY:$REVISION_TAG
- name: Push container image to Amazon ECR
env:
REGISTRY: ${{ steps.login-ecr.outputs.registry }}
4 changes: 0 additions & 4 deletions lambda/Gemfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
source 'https://rubygems.org'
gem 'aws_lambda_ric'
gem 'rack'
gem 'sinatra', '~> 2'

# The version on rubygems (1.0.7) is very out of date
gem 'serverless-rack', git: 'https://github.com/logandk/serverless-rack', branch: '7364305bc'
23 changes: 0 additions & 23 deletions lambda/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,36 +1,13 @@
GIT
remote: https://github.com/logandk/serverless-rack
revision: 7364305bcbbf7f6cc6851497069a5a4cb91936b1
branch: 7364305bc
specs:
serverless-rack (1.0.7)
rack (~> 2.0)

GEM
remote: https://rubygems.org/
specs:
aws_lambda_ric (2.0.0)
mustermann (2.0.2)
ruby2_keywords (~> 0.0.1)
rack (2.2.4)
rack-protection (2.2.2)
rack
ruby2_keywords (0.0.5)
sinatra (2.2.2)
mustermann (~> 2.0)
rack (~> 2.2)
rack-protection (= 2.2.2)
tilt (~> 2.0)
tilt (2.0.11)

PLATFORMS
ruby

DEPENDENCIES
aws_lambda_ric
rack
serverless-rack!
sinatra (~> 2)

BUNDLED WITH
2.1.4
77 changes: 39 additions & 38 deletions lambda/app.rb
Original file line number Diff line number Diff line change
@@ -1,54 +1,42 @@
# frozen_string_literal: true

require 'rack'
require 'serverless_rack'

require './web_app'
require 'stringio'
require 'digest'
require 'json'
require './compiler'

$app = Rack::Builder.new do
run WebApp
end.to_app

module LambdaFunction
# Handle a API Gateway/ALB-structured HTTP request using the Sinatra app
class HttpHandler
def self.process(event:, context:)
handle_request(app: $app, event: event, context: context)
end
end

# Handle a non-HTTP proxied request, returning either the compiled result or
# an error as JSON.
class DirectHandler
# Handle a non-HTTP compile request, returning a JSON body of either the
# compiled result or an error.
class Handler
REVISION = ENV.fetch('REVISION', 'unknown')

def self.process(event:, context:)
return { type: 'keep_alive' } if event.has_key?('keep_alive')

keymap_data = event.fetch('keymap') do
return error(status: 400, message: 'Missing required argument: keymap')
parse_base64_param = ->(param, required: true) do
if event.include?(param)
Base64.strict_decode64(event.fetch(param))
elsif required
return error(status: 400, message: "Missing required argument: #{param}")
end
rescue ArgumentError
return error(status: 400, message: "Invalid Base64 in #{param} input")
end

keymap_data =
begin
Base64.strict_decode64(keymap_data)
rescue ArgumentError
return error(status: 400, message: 'Invalid Base64 in keymap input')
end
keymap_data = parse_base64_param.('keymap')
kconfig_data = parse_base64_param.('kconfig', required: false)

if event.has_key?('kconfig')
kconfig_data =
begin
Base64.strict_decode64(event['kconfig'])
rescue ArgumentError
return error(status: 400, message: 'Invalid Base64 in kconfig input')
end
end
# Including kconfig settings that affect the RHS require building both
# firmware images, doubling compile time. Clients should omit rhs_kconfig
# where possible.
rhs_kconfig_data = parse_base64_param.('rhs_kconfig', required: false)

result, log =
begin
Compiler.new.compile(keymap_data, kconfig_data)
log_compile(keymap_data, kconfig_data, rhs_kconfig_data)

Compiler.new.compile(keymap_data, kconfig_data, rhs_kconfig_data)
rescue Compiler::CompileError => e
return error(status: e.status, message: e.message, detail: e.log)
end
@@ -57,11 +45,24 @@ def self.process(event:, context:)

{ type: 'result', result: result, log: log, revision: REVISION }
rescue StandardError => e
error(status: 500, message: "Unexpected error: #{e.class}", detail: [e.message])
error(status: 500, message: "Unexpected error: #{e.class}", detail: [e.message], exception: e)
end

def self.error(status:, message:, detail: nil)
{ type: 'error', status: status, message: message, detail: detail, revision: REVISION }
def self.log_compile(keymap_data, kconfig_data, rhs_kconfig_data)
keymap = Digest::SHA1.base64digest(keymap_data)
kconfig = kconfig_data ? Digest::SHA1.base64digest(kconfig_data) : 'nil'
rhs_kconfig = rhs_kconfig_data ? Digest::SHA1.base64digest(rhs_kconfig_data) : 'nil'
puts("Compiling with keymap: #{keymap}; kconfig: #{kconfig}; rhs_kconfig: #{rhs_kconfig}")
end

def self.error(status:, message:, detail: nil, exception: nil)
reported_error = { type: 'error', status:, message:, detail:, revision: REVISION }

exception_detail = { class: exception.class, backtrace: exception.backtrace } if exception
logged_error = reported_error.merge(exception: exception_detail)
puts(JSON.dump(logged_error))

reported_error
end
end
end
35 changes: 28 additions & 7 deletions lambda/compiler.rb
Original file line number Diff line number Diff line change
@@ -15,20 +15,41 @@ def initialize(message, status: 400, log:)
end
end

def compile(keymap_data, kconfig_data)
def compile(keymap_data, lhs_kconfig_data, rhs_kconfig_data)
if rhs_kconfig_data && !rhs_kconfig_data.empty?
lhs_result, lhs_output = compile_board('glove80_lh', keymap_data:, kconfig_data: lhs_kconfig_data, include_static_rhs: false)
rhs_result, rhs_output = compile_board('glove80_rh', keymap_data: nil, kconfig_data: rhs_kconfig_data, include_static_rhs: false)
[
lhs_result.concat(rhs_result),
["LHS Output:", *lhs_output, "RHS Output:", *rhs_output],
]
else
compile_board('glove80_lh', keymap_data:, kconfig_data: lhs_kconfig_data, include_static_rhs: true)
end
end

def compile_board(board, keymap_data:, kconfig_data:, include_static_rhs: false)
in_build_dir do
compile_command = ['compileZmk', './build.keymap']
compile_command = ['compileZmk', '-b', board]

File.open('build.keymap', 'w') { |io| io.write(keymap_data) }
if keymap_data
File.open('build.keymap', 'w') { |io| io.write(keymap_data) }
compile_command << '-k' << './build.keymap'
end

if kconfig_data
File.open('build.conf', 'w') { |io| io.write(kconfig_data) }
compile_command << './build.conf'
compile_command << '-c' << './build.conf'
end

if include_static_rhs
# Concatenate the pre-compiled glove80_rh image to the resulting uf2
compile_command << '-m'
end

compile_output = nil

IO.popen(compile_command, err: [:child, :out]) do |io|
IO.popen(compile_command, 'rb', err: [:child, :out]) do |io|
compile_output = io.read
end

@@ -39,11 +60,11 @@ def compile(keymap_data, kconfig_data)
raise CompileError.new("Compile failed with exit status #{status}", log: compile_output)
end

unless File.exist?('zephyr/combined.uf2')
unless File.exist?('zmk.uf2')
raise CompileError.new('Compile failed to produce result binary', status: 500, log: compile_output)
end

result = File.read('zephyr/combined.uf2')
result = File.read('zmk.uf2')

[result, compile_output]
end
76 changes: 0 additions & 76 deletions lambda/gemset.nix
Original file line number Diff line number Diff line change
@@ -9,80 +9,4 @@
};
version = "2.0.0";
};
mustermann = {
dependencies = ["ruby2_keywords"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0m70qz27mlv2rhk4j1li6pw797gmiwwqg02vcgxcxr1rq2v53rnb";
type = "gem";
};
version = "2.0.2";
};
rack = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0axc6w0rs4yj0pksfll1hjgw1k6a5q0xi2lckh91knfb72v348pa";
type = "gem";
};
version = "2.2.4";
};
rack-protection = {
dependencies = ["rack"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "169jzzgvbjrqmz4q55wp9pg4ji2h90mggcdxy152gv5vp96l2hgx";
type = "gem";
};
version = "2.2.2";
};
ruby2_keywords = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "1vz322p8n39hz3b4a9gkmz9y7a5jaz41zrm2ywf31dvkqm03glgz";
type = "gem";
};
version = "0.0.5";
};
serverless-rack = {
dependencies = ["rack"];
groups = ["default"];
platforms = [];
source = {
fetchSubmodules = false;
rev = "7364305bcbbf7f6cc6851497069a5a4cb91936b1";
sha256 = "0c7ch0s0nl70p6ijg7q0jnq8ca2rhp5wqfp91kai81dy7d71mq65";
type = "git";
url = "https://github.com/logandk/serverless-rack";
};
version = "1.0.7";
};
sinatra = {
dependencies = ["mustermann" "rack" "rack-protection" "tilt"];
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "0mbjp75dy35q796iard8izsy7gk55g2c3q864r2p13my3yjmlcvz";
type = "gem";
};
version = "2.2.2";
};
tilt = {
groups = ["default"];
platforms = [];
source = {
remotes = ["https://rubygems.org"];
sha256 = "186nfbcsk0l4l86gvng1fw6jq6p6s7rc0caxr23b3pnbfb20y63v";
type = "gem";
};
version = "2.0.11";
};
}
43 changes: 0 additions & 43 deletions lambda/web_app.rb

This file was deleted.

Loading