ruby_everywhere 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +339 -0
- data/bridge/README.md +70 -1
- data/bridge/everywhere/bridge.js +211 -3
- data/bridge/everywhere/native.css +61 -0
- data/lib/everywhere/android_resources.rb +217 -0
- data/lib/everywhere/android_sdk.rb +330 -0
- data/lib/everywhere/asset_catalog.rb +185 -0
- data/lib/everywhere/auth_handoff.rb +404 -0
- data/lib/everywhere/auth_token.rb +118 -0
- data/lib/everywhere/builders/android.rb +844 -0
- data/lib/everywhere/builders/desktop.rb +326 -0
- data/lib/everywhere/builders/ios.rb +40 -3
- data/lib/everywhere/child_processes.rb +74 -0
- data/lib/everywhere/commands/build.rb +95 -14
- data/lib/everywhere/commands/clean.rb +10 -5
- data/lib/everywhere/commands/dev.rb +462 -57
- data/lib/everywhere/commands/doctor.rb +89 -3
- data/lib/everywhere/commands/install.rb +21 -1
- data/lib/everywhere/commands/logs.rb +117 -8
- data/lib/everywhere/commands/release.rb +2 -2
- data/lib/everywhere/config.rb +703 -13
- data/lib/everywhere/console.rb +117 -0
- data/lib/everywhere/desktop_assets.rb +150 -0
- data/lib/everywhere/dock/footer.rb +150 -0
- data/lib/everywhere/dock/screen.rb +114 -0
- data/lib/everywhere/dock/state.rb +59 -0
- data/lib/everywhere/dock.rb +238 -0
- data/lib/everywhere/emulator.rb +405 -0
- data/lib/everywhere/engine.rb +12 -0
- data/lib/everywhere/fatal.rb +20 -0
- data/lib/everywhere/icon.rb +196 -0
- data/lib/everywhere/line_pump.rb +89 -0
- data/lib/everywhere/log_filter.rb +111 -0
- data/lib/everywhere/native_helper.rb +39 -9
- data/lib/everywhere/omniauth.rb +88 -0
- data/lib/everywhere/paths.rb +109 -11
- data/lib/everywhere/relay.rb +77 -0
- data/lib/everywhere/shellout.rb +90 -15
- data/lib/everywhere/task_pool.rb +123 -0
- data/lib/everywhere/ui.rb +54 -11
- data/lib/everywhere/version.rb +1 -1
- data/support/desktop/README.md +121 -0
- data/support/{shell → desktop}/src-tauri/Cargo.lock +23 -0
- data/support/{shell → desktop}/src-tauri/Cargo.toml +19 -1
- data/support/{shell → desktop}/src-tauri/capabilities/default.json +7 -0
- data/support/desktop/src-tauri/gen/schemas/capabilities.json +1 -0
- data/support/desktop/src-tauri/src/extension_host.rs +53 -0
- data/support/desktop/src-tauri/src/extensions/mod.rs +39 -0
- data/support/{shell → desktop}/src-tauri/src/main.rs +355 -10
- data/support/{shell → desktop}/src-tauri/tauri.conf.json +2 -2
- data/support/mobile/android/README.md +217 -0
- data/support/mobile/android/app/build.gradle.kts +156 -0
- data/support/mobile/android/app/everywhere.properties +8 -0
- data/support/mobile/android/app/native-packages.gradle.kts +16 -0
- data/support/mobile/android/app/proguard-rules.pro +21 -0
- data/support/mobile/android/app/src/debug/res/xml/network_security_config.xml +30 -0
- data/support/mobile/android/app/src/main/AndroidManifest.xml +42 -0
- data/support/mobile/android/app/src/main/assets/everywhere.json +9 -0
- data/support/mobile/android/app/src/main/assets/fonts/MaterialIcons-Regular.codepoints +2235 -0
- data/support/mobile/android/app/src/main/assets/fonts/MaterialIcons-Regular.ttf +0 -0
- data/support/mobile/android/app/src/main/assets/json/path-configuration.json +19 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/AuthFlow.kt +268 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/EverywhereApplication.kt +178 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/EverywhereConfig.kt +409 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/EverywhereEvents.kt +68 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/EverywhereHost.kt +101 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/IconFont.kt +211 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/MainActivity.kt +975 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/MainTabs.kt +201 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/WebBottomSheetFragment.kt +13 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/WebFragment.kt +36 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/BiometricsComponent.kt +535 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/HapticsComponent.kt +141 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/MenuComponent.kt +361 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/NotificationComponent.kt +151 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/PermissionsComponent.kt +271 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/StorageComponent.kt +101 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/bridge/WebControlChannel.kt +204 -0
- data/support/mobile/android/app/src/main/java/com/rubyeverywhere/shell/extensions/EverywhereExtensions.kt +51 -0
- data/support/mobile/android/app/src/main/res/color/bottom_navigation_active_indicator.xml +4 -0
- data/support/mobile/android/app/src/main/res/color/bottom_navigation_item.xml +11 -0
- data/support/mobile/android/app/src/main/res/drawable/ic_launcher_foreground.xml +26 -0
- data/support/mobile/android/app/src/main/res/drawable/ic_tab_placeholder.xml +28 -0
- data/support/mobile/android/app/src/main/res/layout/activity_main.xml +116 -0
- data/support/mobile/android/app/src/main/res/layout/bridge_menu_sheet.xml +83 -0
- data/support/mobile/android/app/src/main/res/layout/bridge_menu_sheet_item.xml +35 -0
- data/support/mobile/android/app/src/main/res/layout/tab_more_sheet.xml +48 -0
- data/support/mobile/android/app/src/main/res/layout/tab_more_sheet_item.xml +35 -0
- data/support/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +12 -0
- data/support/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
- data/support/mobile/android/app/src/main/res/values/colors.xml +21 -0
- data/support/mobile/android/app/src/main/res/values/ic_launcher_background.xml +5 -0
- data/support/mobile/android/app/src/main/res/values/strings.xml +18 -0
- data/support/mobile/android/app/src/main/res/values/styles.xml +32 -0
- data/support/mobile/android/app/src/main/res/values/themes.xml +53 -0
- data/support/mobile/android/app/src/main/res/values-night/colors.xml +11 -0
- data/support/mobile/android/app/src/main/res/values-night/themes.xml +33 -0
- data/support/mobile/android/app/src/main/res/xml/network_security_config.xml +12 -0
- data/support/mobile/android/app/src/stamped/AndroidManifest.xml +34 -0
- data/support/mobile/android/build.gradle.kts +8 -0
- data/support/mobile/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/support/mobile/android/gradle/wrapper/gradle-wrapper.properties +10 -0
- data/support/mobile/android/gradle.properties +14 -0
- data/support/mobile/android/gradlew +251 -0
- data/support/mobile/android/gradlew.bat +94 -0
- data/support/mobile/android/settings.gradle.kts +28 -0
- data/support/mobile/ios/App/AppDelegate.swift +5 -0
- data/support/mobile/ios/App/AuthFlow.swift +101 -0
- data/support/mobile/ios/App/EverywhereConfig.swift +84 -0
- data/support/mobile/ios/App/SceneDelegate.swift +103 -0
- data/support/mobile/ios/App.xcodeproj/project.pbxproj +4 -0
- data/support/mobile/ios/README.md +4 -1
- data/support/{macos → release/macos}/notarize.sh +2 -2
- metadata +97 -17
- data/support/github/build.yml +0 -85
- data/support/shell/src-tauri/gen/schemas/capabilities.json +0 -1
- /data/support/{shell → desktop}/splash/index.html +0 -0
- /data/support/{shell → desktop}/src-tauri/build.rs +0 -0
- /data/support/{shell → desktop}/src-tauri/gen/schemas/acl-manifests.json +0 -0
- /data/support/{shell → desktop}/src-tauri/gen/schemas/desktop-schema.json +0 -0
- /data/support/{shell → desktop}/src-tauri/gen/schemas/macOS-schema.json +0 -0
- /data/support/{shell → desktop}/src-tauri/icons/icon.png +0 -0
- /data/support/{shell → desktop}/src-tauri/src/updater.rs +0 -0
- /data/support/{macos → release/macos}/entitlements.plist +0 -0
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
require "dry/cli"
|
|
4
4
|
require_relative "../shellout"
|
|
5
5
|
require_relative "../paths"
|
|
6
|
+
require_relative "../android_sdk"
|
|
6
7
|
|
|
7
8
|
module Everywhere
|
|
8
9
|
module Commands
|
|
9
10
|
# Check that this machine can build native apps. Desktop checks always
|
|
10
|
-
# run; the iOS
|
|
11
|
-
#
|
|
11
|
+
# run; the iOS and Android sections join in when the app's build.targets
|
|
12
|
+
# include such a target, or explicitly via --target ios-* / android-*.
|
|
12
13
|
class Doctor < Dry::CLI::Command
|
|
13
|
-
desc "Check the toolchain (rbe-tebako, rust, brew deps; Xcode for iOS
|
|
14
|
+
desc "Check the toolchain (rbe-tebako, rust, brew deps; Xcode for iOS, SDK/JDK for Android)"
|
|
14
15
|
|
|
15
16
|
option :root, default: ".", desc: "App root (its build.targets pick the sections)"
|
|
16
17
|
option :target, default: nil, desc: "Also check a specific target's toolchain (e.g. ios-arm64)"
|
|
@@ -22,6 +23,7 @@ module Everywhere
|
|
|
22
23
|
ok &= check("homebrew bison") { !`brew --prefix bison 2>/dev/null`.strip.empty? }
|
|
23
24
|
|
|
24
25
|
ok &= ios_checks if ios_wanted?(root, target)
|
|
26
|
+
ok &= android_checks if android_wanted?(root, target)
|
|
25
27
|
|
|
26
28
|
puts
|
|
27
29
|
ok ? UI.success("ready to build") : UI.bad("fix the items above (see https://rubyeverywhere.com/docs/diy/requirements)")
|
|
@@ -64,6 +66,90 @@ module Everywhere
|
|
|
64
66
|
ok
|
|
65
67
|
end
|
|
66
68
|
|
|
69
|
+
def android_wanted?(root, target)
|
|
70
|
+
return true if target && Everywhere::Config.os_of(target) == "android"
|
|
71
|
+
|
|
72
|
+
Everywhere::Config.load(File.expand_path(root)).targets
|
|
73
|
+
.any? { |t| Everywhere::Config.os_of(t) == "android" }
|
|
74
|
+
rescue StandardError
|
|
75
|
+
false
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Every check here resolves by location through AndroidSdk, never off
|
|
79
|
+
# PATH: Android Studio installs the SDK, adb, the emulator and a JDK
|
|
80
|
+
# without exporting any of them, so a `which adb` would report a broken
|
|
81
|
+
# machine that in fact builds fine. Nothing auto-installs — SDK components
|
|
82
|
+
# are gigabytes — so each failure carries the exact command to run.
|
|
83
|
+
def android_checks
|
|
84
|
+
puts
|
|
85
|
+
UI.step("Android target")
|
|
86
|
+
sdk = Everywhere::AndroidSdk
|
|
87
|
+
root = sdk.sdk_root
|
|
88
|
+
|
|
89
|
+
ok = fix_check(labelled("Android SDK", root && UI.short_path(root)),
|
|
90
|
+
"install Android Studio (it provisions the SDK, adb, the emulator and a " \
|
|
91
|
+
"JDK), or point ANDROID_HOME at an existing SDK") { !root.nil? }
|
|
92
|
+
|
|
93
|
+
jdk = sdk.java_version
|
|
94
|
+
ok &= fix_check(labelled("JDK #{sdk::MINIMUM_JDK}+", jdk && "found #{jdk}"),
|
|
95
|
+
"install Android Studio (it bundles a JDK) or set JAVA_HOME to a " \
|
|
96
|
+
"JDK #{sdk::MINIMUM_JDK} or newer") { !jdk.nil? && jdk >= sdk::MINIMUM_JDK }
|
|
97
|
+
|
|
98
|
+
# This one has to come before adb, the emulator, the AVD and the
|
|
99
|
+
# platform, because every one of those remediations is an sdkmanager
|
|
100
|
+
# line — and sdkmanager is exactly what can be missing. Phase 0 found a
|
|
101
|
+
# machine with a full SDK, adb, the emulator, build-tools and an AVD but
|
|
102
|
+
# no cmdline-tools anywhere, so "run this sdkmanager command" was the
|
|
103
|
+
# one piece of advice that couldn't be followed. Reported, but NOT
|
|
104
|
+
# folded into `ok`: that machine builds Android apps fine, and failing
|
|
105
|
+
# doctor over a component it doesn't need would be a lie.
|
|
106
|
+
if sdk.cmdline_tools?
|
|
107
|
+
UI.ok(labelled("Android SDK command-line tools", UI.short_path(sdk.sdkmanager)))
|
|
108
|
+
else
|
|
109
|
+
UI.warn("Android SDK command-line tools missing — nothing below can be installed " \
|
|
110
|
+
"until they are: #{sdk.cmdline_tools_hint}")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
ok &= fix_check(labelled("adb", sdk.adb && UI.short_path(sdk.adb)),
|
|
114
|
+
sdk.install_hint("platform-tools")) { !sdk.adb.nil? }
|
|
115
|
+
|
|
116
|
+
ok &= fix_check(labelled("emulator", sdk.emulator && UI.short_path(sdk.emulator)),
|
|
117
|
+
sdk.install_hint("emulator")) { !sdk.emulator.nil? }
|
|
118
|
+
|
|
119
|
+
avds = sdk.avds
|
|
120
|
+
ok &= fix_check(labelled("an Android virtual device", avds.first),
|
|
121
|
+
sdk.create_avd_hint) { avds.any? }
|
|
122
|
+
|
|
123
|
+
platform = "platforms;android-#{sdk::COMPILE_SDK}"
|
|
124
|
+
ok &= fix_check(labelled(platform, listed(sdk.installed_platforms)),
|
|
125
|
+
sdk.install_hint(platform)) { sdk.platform? }
|
|
126
|
+
|
|
127
|
+
ok &= fix_check("bundled Android shell template",
|
|
128
|
+
"not shipped in this release of ruby_everywhere yet, so Android " \
|
|
129
|
+
"builds aren't available") { !Everywhere::Paths.android_dir.nil? }
|
|
130
|
+
ok
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# "adb (~/Library/Android/sdk/platform-tools/adb)" — the resolved location
|
|
134
|
+
# matters on Android in a way it doesn't on iOS, because there are several
|
|
135
|
+
# plausible SDK roots and the user can't tell from `which` which one we
|
|
136
|
+
# picked.
|
|
137
|
+
def labelled(label, detail) = detail ? "#{label} #{UI.dim("(#{detail})")}" : label
|
|
138
|
+
|
|
139
|
+
def listed(items) = items.empty? ? "none installed" : "have #{items.join(", ")}"
|
|
140
|
+
|
|
141
|
+
# check() prints one fixed label, but an Android remediation is only
|
|
142
|
+
# knowable after resolution (the sdkmanager path depends on where the SDK
|
|
143
|
+
# turned out to be), so a failure appends the exact command to run.
|
|
144
|
+
def fix_check(label, fix)
|
|
145
|
+
passed = yield
|
|
146
|
+
passed ? UI.ok(label) : UI.bad("#{label} — #{fix}")
|
|
147
|
+
passed
|
|
148
|
+
rescue StandardError
|
|
149
|
+
UI.bad("#{label} — #{fix}")
|
|
150
|
+
false
|
|
151
|
+
end
|
|
152
|
+
|
|
67
153
|
def check(label)
|
|
68
154
|
passed = yield
|
|
69
155
|
passed ? UI.ok(label) : UI.bad(label)
|
|
@@ -158,6 +158,17 @@ module Everywhere
|
|
|
158
158
|
# - label: Quit
|
|
159
159
|
# action: quit
|
|
160
160
|
|
|
161
|
+
# Desktop window chrome. title_bar: overlay floats the macOS traffic
|
|
162
|
+
# lights over your page with no title text (reserve the space with the
|
|
163
|
+
# .everywhere-titlebar-inset class from everywhere/native.css);
|
|
164
|
+
# frameless removes the system chrome entirely, and the page draws its
|
|
165
|
+
# own title bar and calls Everywhere.window.* for the controls.
|
|
166
|
+
# window:
|
|
167
|
+
# title_bar: overlay # decorated (default) | overlay | frameless
|
|
168
|
+
# title: false # draw the title text
|
|
169
|
+
# size: [1100, 750]
|
|
170
|
+
# min_size: [600, 400]
|
|
171
|
+
|
|
161
172
|
# Mobile tab bar (iOS today, Android soon). Served live from
|
|
162
173
|
# /everywhere/ios_v1.json too, so tab changes deploy with the app —
|
|
163
174
|
# no app-store release. Icons: ios = SF Symbol name.
|
|
@@ -177,6 +188,15 @@ module Everywhere
|
|
|
177
188
|
# ios:
|
|
178
189
|
# lazy_load_tabs: true # defer each tab's first load until it's tapped
|
|
179
190
|
# # (false = load every tab up front; omit = default)
|
|
191
|
+
#
|
|
192
|
+
# Rust you keep in native/desktop/ and compile into the desktop
|
|
193
|
+
# shell. Declaring anything here switches the desktop build to a
|
|
194
|
+
# per-app cargo compile — the first one takes minutes.
|
|
195
|
+
# desktop:
|
|
196
|
+
# commands: [scan_ports] # reachable as Everywhere.desktop.invoke("scan_ports")
|
|
197
|
+
# setup: true # run native/desktop/setup.rs at boot
|
|
198
|
+
# crates:
|
|
199
|
+
# serialport: "4.3"
|
|
180
200
|
|
|
181
201
|
# Durable build knobs (CLI flags still override per-run).
|
|
182
202
|
# build:
|
|
@@ -187,7 +207,7 @@ module Everywhere
|
|
|
187
207
|
# # # (`every build` / `every dev --ios`) work today;
|
|
188
208
|
# # # hosted platform builds for iOS aren't live yet.
|
|
189
209
|
# # - android-arm64 # future — mobile is remote mode only
|
|
190
|
-
#
|
|
210
|
+
# capabilities: [notifications, filesystem:read, clipboard] # desktop OS integration
|
|
191
211
|
|
|
192
212
|
# Per-platform overrides. Keys are platform names (macos / ios / android /
|
|
193
213
|
# windows / linux); anything here overrides the app: defaults above for that
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "dry/cli"
|
|
4
|
+
require_relative "../android_sdk"
|
|
5
|
+
require_relative "../config"
|
|
6
|
+
require_relative "../emulator"
|
|
4
7
|
require_relative "../simulator"
|
|
5
8
|
require_relative "../ui"
|
|
6
9
|
|
|
7
10
|
module Everywhere
|
|
8
11
|
module Commands
|
|
9
|
-
# Tail the native shell's logs.
|
|
10
|
-
# log
|
|
11
|
-
# --last replays recent history
|
|
12
|
+
# Tail the native shell's logs. Two platforms, one shape: the iOS Simulator's
|
|
13
|
+
# unified log scoped to the shell process, or Android's logcat scoped to the
|
|
14
|
+
# shell's process id. Watches by default; --last replays recent history and
|
|
15
|
+
# exits.
|
|
12
16
|
class Logs < Dry::CLI::Command
|
|
13
|
-
desc "Stream native shell logs (iOS Simulator; watches by default)"
|
|
17
|
+
desc "Stream native shell logs (iOS Simulator or Android; watches by default)"
|
|
14
18
|
|
|
15
|
-
option :ios, type: :boolean, default: false, desc: "iOS Simulator logs (
|
|
16
|
-
option :
|
|
19
|
+
option :ios, type: :boolean, default: false, desc: "iOS Simulator logs (unified log)"
|
|
20
|
+
option :android, type: :boolean, default: false, desc: "Android logs (logcat, scoped to the app's process)"
|
|
21
|
+
option :last, default: nil, desc: 'Show recent history instead of watching (e.g. "5m", "1h"; Android also takes a line count)'
|
|
17
22
|
option :udid, default: nil, desc: "Simulator UDID (default: the booted one)"
|
|
23
|
+
option :serial, default: nil, desc: "Android device serial (default: the running emulator)"
|
|
24
|
+
option :app_id, default: nil, desc: "Android applicationId (default: the one in config/everywhere.yml)"
|
|
18
25
|
option :verbose, type: :boolean, default: false, desc: "Everything the shell process logs, debug level included"
|
|
19
26
|
|
|
20
27
|
# The template contract fixes the product name (App.app), so the shell's
|
|
@@ -28,14 +35,56 @@ module Everywhere
|
|
|
28
35
|
PREDICATE = 'process == "App" AND eventType == logEvent AND NOT subsystem BEGINSWITH "com.apple"'
|
|
29
36
|
VERBOSE_PREDICATE = 'process == "App"'
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
# Android has no predicate language, so the same job is split in two:
|
|
39
|
+
# `--pid=` fixes the process (see #android_logs) and a filterspec fixes
|
|
40
|
+
# the priority floor.
|
|
41
|
+
#
|
|
42
|
+
# Inside our own process the analogue of iOS's Apple-framework chatter is
|
|
43
|
+
# the platform's own: ART's GC bookkeeping, binder transactions,
|
|
44
|
+
# chromium's internal tracing. Those sit at VERBOSE, so the default floor
|
|
45
|
+
# is DEBUG — which keeps Hotwire Native's logging (Hotwire-Core and
|
|
46
|
+
# Hotwire-Navigation both log at debug), keeps every WebView console
|
|
47
|
+
# message (chromium reports them at INFO), and drops the runtime's
|
|
48
|
+
# housekeeping. --verbose lowers the floor to VERBOSE.
|
|
49
|
+
#
|
|
50
|
+
# Deliberately NOT a tag list: filtering on Hotwire-Core/Hotwire-Navigation
|
|
51
|
+
# would be the obvious way to cut noise and would hide the two things a
|
|
52
|
+
# shell developer most wants — their own Log calls and their page's
|
|
53
|
+
# console output. Scoping by process keeps everything that is ours and
|
|
54
|
+
# nothing that isn't, which is the same trade the iOS predicate makes.
|
|
55
|
+
DEFAULT_LEVEL = "*:D"
|
|
56
|
+
VERBOSE_LEVEL = "*:V"
|
|
33
57
|
|
|
58
|
+
# `-v time` is the compact-style analogue: with the process already fixed,
|
|
59
|
+
# repeating its pid on every line is noise. --verbose widens to threadtime,
|
|
60
|
+
# which adds the thread id you need once you're reading runtime internals.
|
|
61
|
+
DEFAULT_FORMAT = "time"
|
|
62
|
+
VERBOSE_FORMAT = "threadtime"
|
|
63
|
+
|
|
64
|
+
def call(ios: false, android: false, last: nil, udid: nil, serial: nil, app_id: nil, verbose: false, **)
|
|
65
|
+
UI.die!("pick a platform — run: every logs --ios, or every logs --android") unless ios || android
|
|
66
|
+
UI.die!("--ios and --android are two separate log streams — pick one") if ios && android
|
|
67
|
+
|
|
68
|
+
if android
|
|
69
|
+
android_logs(serial: serial, app_id: app_id, last: last, verbose: verbose)
|
|
70
|
+
else
|
|
71
|
+
ios_logs(udid: udid, last: last, verbose: verbose)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# --- iOS ------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
def ios_logs(udid: nil, last: nil, verbose: false)
|
|
34
78
|
udid ||= Everywhere::Simulator.booted_udid
|
|
35
79
|
UI.die!("no booted iOS Simulator — start one with `every dev --ios`") unless udid
|
|
36
80
|
|
|
37
81
|
UI.step(last ? "iOS Simulator logs from the last #{UI.bold(last)}"
|
|
38
82
|
: "watching iOS Simulator logs #{UI.dim("(Ctrl-C to stop)")}")
|
|
83
|
+
# exec replaces this process, so anything still sitting in Ruby's stdout
|
|
84
|
+
# buffer dies with it — and stdout IS buffered whenever it's a pipe,
|
|
85
|
+
# which is exactly how `every dev`'s log toggle runs us. Without this
|
|
86
|
+
# the header above silently vanishes in the one context that spawns us.
|
|
87
|
+
$stdout.flush
|
|
39
88
|
exec(*argv(udid, last: last, verbose: verbose))
|
|
40
89
|
end
|
|
41
90
|
|
|
@@ -51,6 +100,66 @@ module Everywhere
|
|
|
51
100
|
end
|
|
52
101
|
argv + ["--style", "compact", "--predicate", verbose ? VERBOSE_PREDICATE : PREDICATE]
|
|
53
102
|
end
|
|
103
|
+
|
|
104
|
+
# --- Android --------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
# logcat carries every process on the device, so the pid lookup is the
|
|
107
|
+
# whole filter — and it's also why "the app isn't running" is a distinct,
|
|
108
|
+
# extremely common state that has to be said plainly rather than shown as
|
|
109
|
+
# an empty stream. Unlike iOS, the process name isn't fixed by the
|
|
110
|
+
# template (it's the applicationId), so the config supplies it.
|
|
111
|
+
def android_logs(serial: nil, app_id: nil, last: nil, verbose: false)
|
|
112
|
+
serial ||= Everywhere::Emulator.booted_serial
|
|
113
|
+
UI.die!("no Android emulator or device — start one with `every dev --android`") unless serial
|
|
114
|
+
|
|
115
|
+
application_id = app_id || Everywhere::Config.load(Dir.pwd).bundle_id(target: "android-arm64")
|
|
116
|
+
pid = Everywhere::Emulator.pid_of(serial, application_id)
|
|
117
|
+
unless pid
|
|
118
|
+
UI.die!("#{application_id} isn't running on #{serial} — start it with `every dev --android` " \
|
|
119
|
+
"(or pass --app-id if that isn't this app's applicationId)")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
UI.step(last ? "Android logs from the last #{UI.bold(window_label(last))}"
|
|
123
|
+
: "watching Android logs for #{UI.bold(application_id)} #{UI.dim("(Ctrl-C to stop)")}")
|
|
124
|
+
$stdout.flush # see ios_logs — exec discards a buffered header
|
|
125
|
+
exec(*android_argv(serial, pid, last: last, verbose: verbose))
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# `-d` dumps what's buffered and exits — the `log show` half of the iOS
|
|
129
|
+
# split — and `-t` bounds that dump. Without `-d`, logcat follows.
|
|
130
|
+
def android_argv(serial, pid, last: nil, verbose: false)
|
|
131
|
+
argv = [Everywhere::AndroidSdk.adb!, "-s", serial, "logcat", "--pid=#{pid}"]
|
|
132
|
+
argv += ["-d", "-t", logcat_window(last)] if last
|
|
133
|
+
argv + ["-v", verbose ? VERBOSE_FORMAT : DEFAULT_FORMAT,
|
|
134
|
+
verbose ? VERBOSE_LEVEL : DEFAULT_LEVEL]
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# logcat's -t takes a line count or a timestamp; it has no notion of "5m".
|
|
138
|
+
# So a bare number passes straight through as a count, and a duration in
|
|
139
|
+
# the iOS --last spelling is converted to the timestamp logcat wants.
|
|
140
|
+
#
|
|
141
|
+
# That timestamp is compared against the *device's* clock. An emulator
|
|
142
|
+
# inherits the host's clock and timezone so it lines up exactly; a
|
|
143
|
+
# physical device whose clock has drifted will return a little more or
|
|
144
|
+
# less than asked. A line count has no such ambiguity, which is why both
|
|
145
|
+
# spellings stay.
|
|
146
|
+
LOGCAT_TIME = "%m-%d %H:%M:%S.000"
|
|
147
|
+
DURATION_UNITS = { "s" => 1, "m" => 60, "h" => 3600, "d" => 86_400 }.freeze
|
|
148
|
+
|
|
149
|
+
def logcat_window(last)
|
|
150
|
+
text = last.to_s.strip
|
|
151
|
+
return text if text.match?(/\A\d+\z/)
|
|
152
|
+
|
|
153
|
+
if (match = text.match(/\A(\d+)([smhd])\z/i))
|
|
154
|
+
seconds = match[1].to_i * DURATION_UNITS.fetch(match[2].downcase)
|
|
155
|
+
return (Time.now - seconds).strftime(LOGCAT_TIME)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
UI.die!(%(--last takes a line count ("200") or a duration ("30s", "5m", "2h") — got #{last.inspect}))
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# "200" reads as a count, everything else as a duration.
|
|
162
|
+
def window_label(last) = last.to_s.match?(/\A\d+\z/) ? "#{last} lines" : last.to_s
|
|
54
163
|
end
|
|
55
164
|
end
|
|
56
165
|
end
|
|
@@ -12,7 +12,7 @@ module Everywhere
|
|
|
12
12
|
# Produce a signed, notarized, stapled, distributable artifact + release.json.
|
|
13
13
|
#
|
|
14
14
|
# `every release` wraps the existing signing engine
|
|
15
|
-
# (cli/support/macos/notarize.sh) rather than reimplementing
|
|
15
|
+
# (cli/support/release/macos/notarize.sh) rather than reimplementing
|
|
16
16
|
# codesign/notarytool, and emits the machine-readable receipt every build
|
|
17
17
|
# surface (local, CI, Platform) must produce. See
|
|
18
18
|
# platform/docs/build-engine.md §4, §7, §9.
|
|
@@ -20,7 +20,7 @@ module Everywhere
|
|
|
20
20
|
# Today only the macos builder is live; the target is parameterized so
|
|
21
21
|
# ios/android/windows/linux slot in as builders later.
|
|
22
22
|
class Release < Dry::CLI::Command
|
|
23
|
-
NOTARIZE = File.expand_path("../../../support/macos/notarize.sh", __dir__)
|
|
23
|
+
NOTARIZE = File.expand_path("../../../support/release/macos/notarize.sh", __dir__)
|
|
24
24
|
|
|
25
25
|
desc "Sign, notarize, staple, and emit release.json for a distributable build"
|
|
26
26
|
|