Skip to content

Commit 7c52a4d

Browse files
author
Tarik Eshaq
authored
Removes Application services submodule (#14)
1 parent f63709d commit 7c52a4d

File tree

14 files changed

+415
-30
lines changed

14 files changed

+415
-30
lines changed

.github/workflows/update-as.yml

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,6 @@ jobs:
4747
git config user.email "[email protected]"
4848
git config user.name "Firefox Sync Engineering"
4949
git checkout -b update-as-to-${{ env.AS_VERSION }}
50-
51-
# Update the submodule if we haven't ran those jobs yet
52-
# note that we commit here
53-
- name: Update the submodule to the release application services
54-
if: env.ALREADY_CREATED == 'false'
55-
run: |
56-
cd external/application-services
57-
git fetch --all --tags
58-
git checkout $AS_VERSION
59-
cd ../..
60-
git commit -am "Updates application services submodule to $AS_VERSION"
6150
- name: Update Package.swift with new xcframework URL and checksum
6251
if: env.ALREADY_CREATED == 'false'
6352
run: |
@@ -83,7 +72,7 @@ jobs:
8372
- name: Runs make_tag script
8473
if: env.ALREADY_CREATED == 'false'
8574
run: |
86-
./make_tag.sh ${AS_VERSION:1}
75+
./make_tag.sh --as-version ${{ env.AS_VERSION }} ${AS_VERSION:1}
8776
- name: Create Pull Request
8877
if: env.ALREADY_CREATED == 'false'
8978
run: |

.gitmodules

Lines changed: 0 additions & 3 deletions
This file was deleted.

Package.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,17 @@ let package = Package(
5151
),
5252
.target(
5353
name: "Sync15",
54-
path: "external/application-services/components/sync15/ios"
54+
path: "generated/sync15"
5555
),
5656
.target(
5757
name: "RustLog",
5858
dependencies: ["MozillaRustComponentsWrapper"],
59-
path: "external/application-services/components/rc_log/ios"
59+
path: "generated/rc_log"
6060
),
6161
.target(
6262
name: "Viaduct",
6363
dependencies: ["MozillaRustComponentsWrapper"],
64-
path: "external/application-services/components/viaduct/ios"
64+
path: "generated/viaduct"
6565
),
6666
.target(
6767
name: "Nimbus",

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ and its release artifacts:
3030

3131
Key points:
3232

33-
* The `rust-components-swift` repo includes the `application-services` repo as a git submodule.
3433
* The `application-services` repo publishes a binary artifact `MozillaRustComponents.xcframework.zip` containing
3534
the Rust code and FFI definitions for all components, compiled together into a single library.
3635
* The `Package.swift` file references `MozillaRustComponents.xcframework.zip` as a Swift binary target.
@@ -43,9 +42,8 @@ Key points:
4342
Whenever a new release of the underlying components is availble, we need to tag a new release
4443
in this repo to make them available to Swift components. To do so:
4544

46-
* Update the git submodule under `./external` to the new release of the underlying components.
4745
* Edit `Package.swift` to update the URL and checksum of `MozillaRustComponents.xcframework.zip`.
48-
* Run `./make_tag.sh X.Y.Z` to create the new tag.
46+
* Run `./make_tag.sh --as-version {APP_SERVICES_VERSION} X.Y.Z` to create the new tag.
4947
* Run `git push origin X.Y.Z` to publish it to GitHub.
5048

5149
## Adding a new component
@@ -54,7 +52,6 @@ To add a new component to be distributed via this repo, you'll need to:
5452

5553
* Add its Rust code and `.h` files to the build for the `MozillaRustComponents.xcframework.zip` bundle,
5654
following the docs for the [`ios-rust` crate](https://github.com/mozilla/application-services/tree/main/megazords/ios).
57-
* Add the source for the component to this repository as a git submodule under `./external`.
5855
* If the component needs to dynamically generate any Swift code (e.g. for UniFFI bindings, or Glean metrics),
5956
add logic for doing so to the `./generate.sh` script in this repository.
6057
* Swift packages can't dynamically generate code at build time, so we use the `./generate.sh` script
@@ -86,5 +83,11 @@ To test out some local changes to this repo:
8683
* In a consuming application, delete the Swift Package dependency on `https://github.com/mozilla/rust-components-swift`
8784
and replace it with a dependency on `file:///path/to/your/local/checkout/rust-components-swift` at the `0.0.` release.
8885

86+
### Testing against a local application-services checkout
87+
To run against a local application services checkout, the `make_tag.sh` script supports setting a local path using a `-l` flag, for example:
88+
```sh
89+
./make_tag -l ../application-services 0.0.1
90+
```
91+
8992
That's it! The consuming application should be able to import the package from your local checkout.
9093

external/README.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

external/application-services

Lines changed: 0 additions & 1 deletion
This file was deleted.

generate.sh

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
1313
if [ -n "$1" ]; then
1414
APP_SERVICES_DIR=$1
1515
else
16-
APP_SERVICES_DIR="$THIS_DIR/external/application-services"
16+
APP_SERVICES_DIR="$THIS_DIR/application-services"
1717
fi
1818

1919
UNIFFI_BINDGEN=(cargo run --manifest-path "$APP_SERVICES_DIR/tools/embedded-uniffi-bindgen/Cargo.toml")
@@ -123,3 +123,40 @@ protoc --proto_path="$APP_SERVICES_DIR/components/places/src" --swift_out="$PLAC
123123

124124
# Copy the hand-written Swift, since it all needs to be together in one directory.
125125
cp -r "$APP_SERVICES_DIR/components/places/ios/Places" "$PLACES_DIR/Places"
126+
127+
###
128+
#
129+
# Sync15
130+
#
131+
###
132+
133+
SYNC15_DIR="$THIS_DIR/generated/sync15"
134+
rm -rf "$SYNC15_DIR" && mkdir -p "$SYNC15_DIR"
135+
136+
# We only need to copy the hand-written Swift, sync15 does not use `uniffi` yet
137+
cp -r "$APP_SERVICES_DIR/components/sync15/ios/" $SYNC15_DIR
138+
139+
###
140+
#
141+
# RustLog
142+
#
143+
###
144+
145+
RUST_LOG_DIR="$THIS_DIR/generated/rc_log"
146+
rm -rf "$RUST_LOG_DIR" && mkdir -p "$RUST_LOG_DIR"
147+
148+
# We only need to copy the hand-written Swift, RustLog does not use `uniffi` yet
149+
cp -r "$APP_SERVICES_DIR/components/rc_log/ios/" $RUST_LOG_DIR
150+
151+
152+
###
153+
#
154+
# Viaduct
155+
#
156+
###
157+
158+
VIADUCT_DIR="$THIS_DIR/generated/viaduct"
159+
rm -rf "$VIADUCT_DIR" && mkdir -p "$VIADUCT_DIR"
160+
161+
# We only need to copy the hand-written Swift, Viaduct does not use `uniffi` yet
162+
cp -r "$APP_SERVICES_DIR/components/viaduct/ios/" $VIADUCT_DIR

generated/rc_log/RustLog.swift

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
import Foundation
6+
#if canImport(MozillaRustComponents)
7+
import MozillaRustComponents
8+
#endif
9+
10+
/// The level of a log message
11+
public enum LogLevel: Int32 {
12+
/// The log message in question is verbose information which
13+
/// may contain user PII.
14+
case trace = 2
15+
/// The log message in question is verbose information,
16+
/// but should contain no PII.
17+
case debug
18+
/// The log message is informational
19+
case info
20+
/// The log message is a warning
21+
case warn
22+
/// The log message indicates an error.
23+
case error
24+
25+
init(safeRawValue value: Int32) {
26+
if let result = LogLevel(rawValue: value) {
27+
self = result
28+
return
29+
}
30+
31+
if value < LogLevel.trace.rawValue {
32+
self = .trace
33+
} else {
34+
self = .error
35+
}
36+
}
37+
}
38+
39+
/// An enum representing a maximum log level. It is used with
40+
/// `RustLog.shared.setLevelFilter`.
41+
///
42+
/// This is roughly equivalent to LogLevel, however contains
43+
/// `Off`, for filtering all logging.
44+
public enum LogLevelFilter: Int32 {
45+
/// Disable all logging
46+
case off
47+
/// Only allow `error` logs.
48+
case error
49+
/// Allow `warn` and `error` logs.
50+
case warn
51+
/// Allow `warn`, `error`, and `info` logs.
52+
case info
53+
/// Allow `warn`, `error`, `info`, and `debug` logs. The default.
54+
case debug
55+
/// Allow all logs, including those that may contain PII.
56+
case trace
57+
}
58+
59+
/// The type of the log callback. You can provide a value of this type to
60+
/// `RustLog.shared.enable` or `RustLog.shared.tryEnable`, and it will be called for
61+
/// all log messages emitted by Rust code.
62+
///
63+
/// The first argument is the level of the log. The maximum value of this can
64+
/// be provided using the `RustLog.shared.setLevelFilter` method.
65+
///
66+
/// The second argument is the tag, which is typically a rust module path
67+
/// string. It might be nil in some cases that aren't documented by the
68+
/// underlying rust log crate.
69+
///
70+
/// The last argument is the log message. It will not be nil.
71+
///
72+
/// This callback should return `true` to indicate everything is fine, and
73+
/// false if we should disable the logger. You cannot call `disable()`
74+
/// from inside the callback (it's protected by a dispatch queue you're
75+
/// already running on).
76+
public typealias LogCallback = (_ level: LogLevel, _ tag: String?, _ message: String) -> Bool
77+
78+
/// The public interface to Rust's logger.
79+
///
80+
/// This is a singleton, and should be used via the
81+
/// `shared` static member.
82+
public class RustLog {
83+
fileprivate let state = RustLogState()
84+
fileprivate let queue = DispatchQueue(label: "com.mozilla.appservices.rust-log")
85+
/// The singleton instance of RustLog
86+
public static let shared = RustLog()
87+
88+
private init() {}
89+
90+
/// True if the logger currently has a bound callback.
91+
public var isEnabled: Bool {
92+
return queue.sync { state.isEnabled }
93+
}
94+
95+
/// Set the current log callback.
96+
///
97+
/// Note that by default, after enabling the level filter
98+
/// will be at the `debug` level. If you want to increase or decrease it,
99+
/// you may use `setLevelFilter`
100+
///
101+
///
102+
/// See alse `tryEnable`.
103+
///
104+
/// Throws:
105+
///
106+
/// - `RustLogError.alreadyEnabled`: If we're already enabled. Explicitly disable first.
107+
///
108+
/// - `RustLogError.unexpectedError`: If the rust code panics. This shouldn't happen,
109+
/// but if it does, we would appreciate reports from telemetry or similar
110+
public func enable(_ callback: @escaping LogCallback) throws {
111+
try queue.sync {
112+
try state.enable(callback)
113+
}
114+
}
115+
116+
/// Set the level filter (the maximum log level) of the logger.
117+
///
118+
/// Throws:
119+
/// - `RustLogError.unexpectedError`: If the rust code panics. This shouldn't happen,
120+
/// but if it does, we would appreciate reports from telemetry or similar
121+
public func setLevelFilter(filter: LogLevelFilter) throws {
122+
// Note: Doesn't need to synchronize.
123+
try rustCall { error in
124+
rc_log_adapter_set_max_level(filter.rawValue, error)
125+
}
126+
}
127+
128+
/// Disable the previously set logger. This also sets the level filter to `.off`.
129+
///
130+
/// Does nothing if the logger is disabled
131+
public func disable() {
132+
queue.sync {
133+
state.disable()
134+
}
135+
}
136+
137+
/// Enable the logger if possible.
138+
///
139+
/// Returns false in the cases where `enable` would throw, true otherwise.
140+
///
141+
/// If it would throw due to a panic, it also writes some information about
142+
/// the panic to the provided callback
143+
public func tryEnable(_ callback: @escaping LogCallback) -> Bool {
144+
return queue.sync {
145+
state.tryEnable(callback)
146+
}
147+
}
148+
149+
/// Log a test message at `.info` severity.
150+
public func logTestMessage(message: String) {
151+
rc_log_adapter_test__log_msg(message)
152+
}
153+
}
154+
155+
/// The type of errors reported by RustLog. These either indicate bugs
156+
/// in our logging code (as in `UnexpectedError`), or usage errors
157+
/// (as in `AlreadyEnabled`)
158+
public enum RustLogError: Error {
159+
/// This generally means a panic occurred, or something went very wrong.
160+
/// We would appreciate bug reports about when these appear in the wild, if they do.
161+
case unexpectedError(message: String)
162+
163+
/// Error indicating that the log adapter cannot be enabled
164+
/// because it is already enabled.
165+
///
166+
/// This is a usage error, either `disable` it first, or
167+
/// use `RustLog.shared.tryEnable`
168+
case alreadyEnabled
169+
}
170+
171+
@discardableResult
172+
private func rustCall<T>(_ callback: (UnsafeMutablePointer<RcLogError>) throws -> T) throws -> T {
173+
var err = RcLogError(code: 0, message: nil)
174+
let result = try callback(&err)
175+
if err.code != 0 {
176+
let message: String
177+
if let messageP = err.message {
178+
defer { rc_log_adapter_destroy_string(messageP) }
179+
message = String(cString: messageP)
180+
} else {
181+
message = "Bug: No message provided with code \(err.code)!"
182+
}
183+
throw RustLogError.unexpectedError(message: message)
184+
}
185+
return result
186+
}
187+
188+
// This is the function actually passed to Rust.
189+
private func logCallbackFunc(level: Int32, optTagP: UnsafePointer<CChar>?, msgP: UnsafePointer<CChar>) {
190+
guard let callback = RustLog.shared.state.callback else {
191+
return
192+
}
193+
let msg = String(cString: msgP)
194+
// Probably a better way to do this...
195+
let tag: String?
196+
if let optTagP = optTagP {
197+
tag = String(cString: optTagP)
198+
} else {
199+
tag = nil
200+
}
201+
RustLog.shared.queue.async {
202+
if !callback(LogLevel(safeRawValue: level), tag, msg) {
203+
RustLog.shared.state.disable()
204+
}
205+
}
206+
}
207+
208+
// This implements everything, but without synchronization. It needs to be
209+
// guarded by a queue, which is done by the RustLog class.
210+
private class RustLogState {
211+
var adapter: OpaquePointer?
212+
var callback: LogCallback?
213+
214+
var isEnabled: Bool { return adapter != nil }
215+
216+
func enable(_ callback: @escaping LogCallback) throws {
217+
if isEnabled {
218+
throw RustLogError.alreadyEnabled
219+
}
220+
assert(self.callback == nil)
221+
self.callback = callback
222+
adapter = try rustCall { error in
223+
rc_log_adapter_create(logCallbackFunc, error)
224+
}
225+
}
226+
227+
func disable() {
228+
guard let adapter = adapter else {
229+
return
230+
}
231+
self.adapter = nil
232+
callback = nil
233+
rc_log_adapter_destroy(adapter)
234+
}
235+
236+
func tryEnable(_ callback: @escaping LogCallback) -> Bool {
237+
if isEnabled {
238+
return false
239+
}
240+
do {
241+
try enable(callback)
242+
return true
243+
} catch {
244+
_ = callback(.error,
245+
"RustLog.swift",
246+
"RustLog.enable failed: \(error)")
247+
return false
248+
}
249+
}
250+
}

0 commit comments

Comments
 (0)