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

Migrate to netstandard #1248

Merged
merged 45 commits into from
Mar 21, 2017
Merged

Migrate to netstandard #1248

merged 45 commits into from
Mar 21, 2017

Conversation

nirinchev
Copy link
Member

@nirinchev nirinchev commented Feb 22, 2017

Description

Notable changes:

  • System.Json is not part of netstandard, so I've taken dependency on Newtonsoft.Json
  • Schema is woven at compile time in ModuleWeaver.WeaveSchema. Had to expose public property RealmSchema.DefaultTypes and set it in the application entry point. Theoretically that would allow people to modify it before the first call to Realm.GetInstance().
  • Realm.BuildTasks defaults to mscorlib when resolving dependencies. Had to do that as the default assembly resolver fails to resolve dependencies such as System.Runtime, etc. that are just reference assemblies.

Fixes #1080

TODO

  • Changelog entry
  • Tests (if applicable)
  • Update PCL (if applicable)
  • Address IReflectableType (RealmObject.cs)
  • Address Win32 Path (NativeCommon.cs)
  • Fix the schema generation (RealmSchema.cs)
  • Fix realm assembly weaving (task fails). Currently falls back to mscorlib if an assembly can't be resolved. Not sure how correct that behavior is.
  • Add Realm.Sync
  • Properly create realms in SpecialFolder.Personal (RealmConfigurationBase, SharedRealmHandleExtensions)
  • Compiler crash in SharedRealmHandleExtensions.ResetForTesting. Filed a bug report. Works fine in VS. Fixed in mono master.
  • Compiler crash in SyncConfiguration.CreateRealm. Filed a bug report. Works fine in VS. Fixed in mono master.
  • Jenkinsfile (needs update for DataBinding projects)
  • Nuspecs (needs update for DataBinding projects)
  • Validate docfx generates proper documentation
  • Weave schema properly, even if assembly does not have EntryPoint (needed for tests)
  • Failing Session test: Session_Error_ShouldPassCorrectSession

High-level overview of what's changed

  • Added Realm/Realm and Realm/Realm.Sync .NET standard 1.4 projects. Those will be packaged in the NuGet and will be the only .dll's we ship.
  • Renamed Tests to Manual Tests as those are run manually rather than by CI.
  • Moved all test projects (platform specific + shared) to Tests.
  • Removed platform specific Realm projects.
  • Got rid of the try-finally pattern for assigning handles.
  • Hacky: BuildTasks falls back to mscorlib if it fails to resolve an assembly (as System.Runtime, etc. are not real ones). As which types we use is very deterministic, it's not an issue, but it's something to watch out for.
  • Weave the default schema on compile - as we don't have access to AppDomain.Current in .NET Standard, we can't inspect the default types at runtime. The current solution will weave logic to call AddDefaultTypes either in the Assembly.EntryPoint or if it doesn't exist, in the module initializer (that's needed for unit tests on windows). It will walk the graph of all referenced assemblies and pull in their types. It's good enough for merging, but should be tested with complex graphs.
  • System.Json is gone, so add Newtonsoft.Json as a dependency for Realm.Sync.
  • Use Reflection to find Environment.SpecialFolder.Personal (default location of realm files). This will not work on UWP and will need to be extended.
  • Add new NuGet - Realm.DataBinding that Realm.Database depends on. It is platform specific and has PCL (bait and switch), iOS, and Android versions (a shared project) and contains all the IReflectableType-related implementations. Needed as TypeDelegator will not be available until netstandard 2.0. The weaver will weave IReflectableType implementation to user objects by calling TypeInfoHelper.GetInfo.
  • Updated Jenkinsfile, nuspecs, docfx.json

After merging

  • Test that NuGet dependencies are correct, especially on Windows (i.e. I can create a new app, add Realm and have everything working as expected).
  • Test default schema with non-trivial project graphs.
  • Verify that IReflectableType is properly woven on PCL models as well.

@nirinchev
Copy link
Member Author

I'm happy to announce that non-sync tests pass (except IReflectableType) 🎉

if (platformPI.GetValue(osVersion).ToString() == "Win32NT")
{
// We know we're on Win32 so Assembly.Location is available
var assemblyLocationPI = typeof(Assembly).GetProperty("Location", BindingFlags.Public | BindingFlags.Instance);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UWP might also report Win32NT, so this should be guarded

@nirinchev nirinchev force-pushed the ni/netstandard2 branch 4 times, most recently from 6a91d2b to 52c032b Compare March 9, 2017 01:42
Copy link
Contributor

@kristiandupont kristiandupont left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few questions and I am sure I am missing things because I can't see the entire diff in my browser, but overall looks good.

using System.Reflection;

[assembly: AssemblyDescription("Realm is a mobile database: a replacement for SQLite")]
[assembly: AssemblyCopyright("Copyright © 2017 Realm")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read recently that the year you put in a copyright statement is supposed to represent the earliest year from which the copyright applies. Thus, it should not be updated. I am not sure if that info was valid and I don't think it really matters as at least half of the web then gets this wrong, but since we're being overly pedantic on the .net team, I thought I'd bring it up.. :-)

namespace Realms
{
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented")]
public static class TypeInfoHelper
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to be public?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's called by the woven IReflectableType.GetType implementation.

<projectUrl>http://github.com/realm/realm-dotnet</projectUrl>
<iconUrl>http://realm.io/img/favicon-32x32.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Realm is a mobile database: a replacement for SQLite and ORMs</description>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we'd want a specific description for this package?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I didn't feel like coming up with something, so I just copy-pasted the old one.

@@ -503,11 +503,5 @@ protected void RaisePropertyChanged([CallerMemberName] string propertyName = nul
protected virtual void OnPropertyChanged(string propertyName)
{
}

TypeInfo IReflectableType.GetTypeInfo()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are automatic transactions not supported any more?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are - the new package Realm.Databinding contains the logic for automatic transactions and the IReflectableType implementation is woven to all user types.

@@ -293,13 +293,15 @@ public void Write(Action action)
}

/// <summary>
/// Execute an action inside a temporary <see cref="Transaction"/> on a worker thread. If no exception is thrown,
/// Execute an action inside a temporary <see cref="Transaction"/> on a worker thread, <b>if</b> called from UI thread. If no exception is thrown,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe "Execute an action in a temporary transaction. If called from the UI thread, this will take place on a worker thread."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's from @AndyDentFree's PR: #1253, haven't changed it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but you did add to it :-)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I did - it was merged in this branch which is why you're seeing it compared to master :P

@@ -45,7 +45,7 @@ private static class NativeMethods

public unsafe delegate void RefreshAccessTokenCallbackDelegate(IntPtr session_handle_ptr);

public unsafe delegate void SessionErrorCallback(IntPtr session_handle_ptr, ErrorCode error_code, sbyte* message_buf, IntPtr message_len, IntPtr user_info_pairs, int user_info_pairs_len);
public unsafe delegate void SessionErrorCallback(IntPtr session_handle_ptr, ErrorCode error_code, byte* message_buf, IntPtr message_len, IntPtr user_info_pairs, int user_info_pairs_len);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the use of sbyte just a typo?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't say I'm 100% sure :) The thing is, there's no longer a string ctor that accepts sbyte* in .NET standard, but converting to byte* and using Encoding.GetString seems to do the trick (passes the tests at least).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Well those calls look nicer to me anyway.

Copy link
Contributor

@AndyDentFree AndyDentFree left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good and a huge body of work!

[assembly: AssemblyCompany("Realm Inc.")]
[assembly: AssemblyProduct("Realm C#")]

[assembly: AssemblyVersion("1.0.0.0")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this correspond to the Realm release version numbers? Maybe add a comment line explaining context.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking was that it should not be tied to the Realm version numbers as that is a package we'll rarely update (I hope). But it does add a bit of complexity to the release procedure if we decide to update it as that would require a bump in the dependency versions (which I'll document once this PR is finalized and merged).


xbuildCmd = '/usr/local/bin/xbuild'
def nuget = '/usr/local/bin/nuget'
nugetCmd = '/usr/local/bin/nuget'
def windowsNugetCmd = 'C:\\ProgramData\\chocolatey\\bin\\NuGet.exe'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this require that nuget was installed on Windows using the Chocolatey package manager? If so, is that documented anywhere? Does it matter to anyone building outside of Realm?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes - it requires a chocolatey install of nuget on our CI slaves. I'm not sure if we have documentation about CI setup anywhere. Ping @fealebenpae.

Copy link
Member

@fealebenpae fealebenpae Mar 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, we don't. And this change only matters to Jenkins. People building manually (us, included) will just restore packages like they always would - through Visual Studio.

<projectUrl>http://github.com/realm/realm-dotnet</projectUrl>
<iconUrl>http://realm.io/img/favicon-32x32.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Realm is a mobile database: a replacement for SQLite and ORMs</description>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the description could indicate this is useless by itself and is a supporting nuget for Realm.Database?

@@ -17,8 +17,18 @@
<tags>Realm database db persistence sqlite</tags>
<dependencies>
<dependency id="Fody" version="1.29.4"/>
<dependency id="Realm.DataBinding" version="1.0.0"/>
<dependency id="DotNetCross.Memory.Unsafe" version="0.2.2"/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we removing DotNetCross.Memory.Unsafe or leaving that change for a separate PR later?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's leave it for later as this one's already huge and would prefer not to add more points where things might break :)

[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented")]
public static class TypeInfoHelper
{
// Holds Type -> RealmObjectTypeInfo map to avoid creating a new TypeDelegator for each IReflectableType.GetTypeInfo invocation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment still valid with dropping using IReflectableType directly for RealmObject?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes - it's still valid, as we're weaving call to TypeInfoHelper.GetInfo in the user's assembly, so caching types is useful.

@nirinchev nirinchev merged commit 9e0e15a into master Mar 21, 2017
@nirinchev nirinchev deleted the ni/netstandard2 branch March 21, 2017 14:10
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

.NET Standard package
4 participants