Do you have best practices etc somewhere written d...
# touchlab-tools
p
Do you have best practices etc somewhere written down / defined regarding mono repos? Right now we have three different repositories. For iOS we have a swift package (which also includes the generated swift code as well as string resources) that’s being published by our CI and android integrates shared using a submodule. However now we’re at a stage where almost all developers participate in the shared code. As a consequence of that, the separation causes a big overhead. How do you recommend to setup for a mono repo?
r
That's a big question, but something like KaMPKit is usually a good starting point. We don't currently have a standard setup for having SPM hook into the Kotlin build process, so we usually use cocoapods for these kinds of setups, but you could also manually add a run script to call into the Kotlin build.
p
And do you get an auto build with cocoapods? (So can you for instance modify a kt file, press run in xcode and it triggers a compilation?)
r
yeah. The podspec that the kotlin cocoapods plugin adds an equivalent run script automatically
p
Summoning @Miguel Schulz, for some reason our iOS team has a strong dislike against cocoapods.
r
If you don't like cocoapods, do the script manually
m
@Paul Woitaschek we just made bad experiences with it, lots of problems to solve all the time. A 3rd party dependency to add 3rd party dependencies ^^ I think we tried it with a script and ran into some issues with cached version of the framework being used? The thing is: our iOS project is pretty modularized and we don’t directly inject SharedCode into the iOSApplication target. We have the binary in a swift package, that is used by another swift package, that is used in a framework, and that is then injected into the iOS and watchOS target. There are these build tool plugins since last year that can run on every build, also for swift packages. And these can also execute scripts. Maybe that’s a solution that could work?
p
Plugins run in a sandbox environment, so they can only write to a pluginWorkDirectory.
I'm not sure what exactly that means but that sounds like it could become a blocker. Besides that it looks like it could be our solution
r
yeah I dug into plugins a while ago and sandboxing was an issue. I think they've expanded some capabilities since then though. If you take a look I'd be interested to hear how it goes
p
I assume that If that doesn't work out, then we can't use swift packages which depend on our shared code. Then the only solution would be to get rid of the packages 😬
But anyways, I think that a mono repo is naturally one of the logical steps many projects will head towards eventually. And how to do that is a question for which it would be good to have an answer to - as a community
https://github.com/apple/swift-evolution/blob/main/proposals/0303-swiftpm-extensible-build-tools.md
The plugin is run — either by interpreting it or by compiling it to an executable and running it — in a sandbox that prevents network access and that restricts file system access.
Meeh
m
We are currently testing a solution that seems to works quite well. We are using a local swift package for shared code that is build in a prebuild step of the target schema. The prebuild step is also running
xcodebuild -resolvePackageDependencies
command because this seems to fix autocomplete issues in xcode
p
But will that work with packages who depend on the shared code themselves?
m
Yep, we have a package that depends on the local shared package. It references the shared package by path
p
What exactly does you prebuild step do?
m
It creates the xcframework. The package file for the local swift package will always be the same because the xcframework will be in the same relative local path. So basically we have: • Prebuild step that builds the xcframework • Swift package that references the package file for the local shared swift package • Package file for the local shared swift package that always point to the same xcframework path
m
Could you send that part of the package.swift as an example, to see how you dynamically resolve that local path? Because it will vary from machine to machine
p
No it won't as it can be relative 💡
path: ./shared or even ./../shared. I think I recently tried that out
m
You got it 😉
As a side note, this fixed setup has also some side benefits, e.g. xcode kotlin plugin for debugging needs a folder reference for source code that is always the same (relatively) so can be committed (less setup work for the devs)
m
Ok now it clicked
p
@Miguel Schulz you can checkout that monobranch repo I created, it should be pretty straight forward. Iirc one problem was the case where you did a fresh checkout and the framework isn't there yet. Then xcode was somehow getting in a weird state
m
Yep the first time the dev has to run the same command that is in the prebuild step manually
p
And it works reliability? I think I tried out something similar and you had to build twice until the changes were really applied
m
What changes are you referring? Autocomplete or the linked framework?
p
The framework
Let's say you have a fun greet()="hey" and change it to"kittens" then I had to build twice until kittens was displayed
m
We didn't see this issue, I guess the resolvePackageDependencies helps on this
p
Yes that makes sense
m
@Paul Woitaschek Maybe we can play around with a post checkout hook to run the prebuilt step automatically for cases where no framework is there yet
p
Hmm, it seems to work for the main target but then fails for the package targets
m
It looks something wrong with your config, we have it working for package targets
Btw you have to run the command in the prebuild step of a scheme, not in the build phase because it's too late
p
Ah yes after restarting xcode I see a different issue because apparently xcode doesn’t source env vars. What is a schema?
m
At the top, you can choose to not only build the application target, but also individual packages or their test schemes. I think it has to be added to every package their that should use the shared framework
p
Holy moly it worked!
(we don’t have that Yess; I hacked that in to test ^^)
m
Force push it to main
p
Do you have a solution on how to select the targets we need at that stage? I.e. I’d only like to run our assemble command with the simulator targets, else this will take very long
m
According to this, there is an env var to check if you are building for simulator or not and depending on that, we call the right assemble command?
t
One thing to note about Pre-Build scripts, unless they fixed it in Xcode, it was super difficult to debug when they weren't working. It'd fail, but you wouldn't really know why or what happened. So just keep that in mind (and the project's readme)
m
I think now we can see why it fails, the icon on the right expands the script logs
t
Interesting, good to know, thanks!
m
In case you are interested, I wrote an article about this
p
Nice, thanks for sharing!
@Marco Righini Did you have any problems with deploying to a (connected) device?
@Marco Righini Are you having problems with memory with that approach? It seems that the java memory is never freed
m
Nope, we are not experiencing it