Merge branch 'master' into sk-listview-merge

* master: (207 commits)
  Convert to using new React Native MainActivity template
  Create RealmReactPackage for our Android plugin
  Fix doc for Android
  NPM ignore react-native/android folder
  Skip building Android module under Xcode
  Skip building Android module for iOS tests
  gitignore Android downloads folder
  Update README with instructions to run on Android
  Use un-patched RN for Android by installing hook into JSC
  cleanup build system
  Use Realm in node_modules for ReactTests on Android
  Change Demo => ReactTests
  adding a 'publishAndroid' task to generate the AAR with prebuilt .so files
  Adjust POM_NAME
  Use consistent package naming
  Remove old Demo files
  Add copyright to JNI file
  Cleanup platform.hpp
  Make our Android module buildable as a dependency
  Add `npm test` command
  ...
This commit is contained in:
Scott Kyle 2016-02-15 14:49:31 -08:00
commit 3e1889d342
115 changed files with 2694 additions and 355 deletions

7
.gitignore vendored
View File

@ -97,3 +97,10 @@ build/
# node.js
node_modules/
npm-debug.log
# Android/IJ
/android/
.idea
.gradle
local.properties

View File

@ -12,12 +12,21 @@ The ReactNative example project is in the `examples/ReactExample` directory. You
## ReactNative Project Setup
- Create a new ReactNative project: `react-native init <project-name>`
- Change directories into the new project (`cd <project-name>`) and add the `realm` dependency: `npm install --save git+ssh://git@github.com/realm/realm-js.git#beta` (please note it's **essential** to leave the `#beta` at the end)
### iOS
- Open the generated Xcode project (`ios/<project-name>.xcodeproj`)
- Making sure the top-level project is selected in the sidebar, change the `iOS Deployment Target` to at least `8.0` in the project settings.
- Right-click the `Libraries` group in the sidebar and click `Add Files to “<project-name>”`. Select `node_modules/realm/RealmJS.xcodeproj` from the dialog.
- Drag `RealmReact.framework` from the `Products` directory under `RealmJS.xcodeproj` into the `Embedded Binaries` section in the `General` tab for your app's target settings.
- In the `Build Phases` tab for your app's target settings, make sure `RealmReact.framework` is added to the `Link Binary with Library` build phase.
- You can now `require('realm')` in your app's JS to use Realm!
- You can now `require('realm')` in your iOS app's JS to use Realm!
### Android
- Run this command from the project directory: `react-native link realm`
- Open `MainActivity.java` inside your project:
- Add `import io.realm.react.RealmReactPackage;` under the other imports.
- Add `new RealmReactPackage()` to the list returned by the `getPackages()` method.
- You can now `require('realm')` in your Android app's JS to use Realm!
## Getting Started
Start with creating a `realm` by passing it an array of `objectSchema` (object types and their properties) for each type of object it will contain:
@ -96,7 +105,7 @@ You can see more examples of how to use these APIs in the [ReactExample](https:/
The `realmConfig` passed to the constructor can contain the following:
- `schema` required when first accessing a realm - array of `ObjectSchema` or object constructors (see below)
- `path` optional - defaults to `Realm.defaultPath` (which initially is `'Documents/default.realm'`)
- `path` optional - defaults to `Realm.defaultPath` (which initially is `'Documents/default.realm'` for iOS and inside the [internal storage](http://developer.android.com/reference/android/content/Context.html#getFilesDir()) `/data/data/<packagename>/files/` for Android)
- `schemaVersion` optional - defaults to `0` but must be specified and incremented after changing the schema
### ObjectSchema

View File

@ -7,13 +7,24 @@
# Some modules have their own node_modules with overlap
.*/node_modules/node-haste/.*
# Ignore react-tools where there are overlaps, but don't ignore anything that
# react-native relies on
.*/node_modules/react-tools/src/vendor/core/ExecutionEnvironment.js
.*/node_modules/react-tools/src/browser/eventPlugins/ResponderEventPlugin.js
.*/node_modules/react-tools/src/browser/ui/React.js
.*/node_modules/react-tools/src/core/ReactInstanceHandles.js
.*/node_modules/react-tools/src/event/EventPropagators.js
# Ugh
.*/node_modules/babel.*
.*/node_modules/babylon.*
.*/node_modules/invariant.*
# Ignore react and fbjs where there are overlaps, but don't ignore
# anything that react-native relies on
.*/node_modules/fbjs-haste/.*/__tests__/.*
.*/node_modules/fbjs-haste/__forks__/Map.js
.*/node_modules/fbjs-haste/__forks__/Promise.js
.*/node_modules/fbjs-haste/__forks__/fetch.js
.*/node_modules/fbjs-haste/core/ExecutionEnvironment.js
.*/node_modules/fbjs-haste/core/isEmpty.js
.*/node_modules/fbjs-haste/crypto/crc32.js
.*/node_modules/fbjs-haste/stubs/ErrorUtils.js
.*/node_modules/react-haste/React.js
.*/node_modules/react-haste/renderers/dom/ReactDOM.js
.*/node_modules/react-haste/renderers/shared/event/eventPlugins/ResponderEventPlugin.js
# Ignore commoner tests
.*/node_modules/commoner/test/.*
@ -22,7 +33,10 @@
.*/react-tools/node_modules/commoner/lib/reader.js
# Ignore jest
.*/react-native/node_modules/jest-cli/.*
.*/node_modules/jest-cli/.*
# Ignore Website
.*/website/.*
[include]
@ -32,13 +46,18 @@ node_modules/react-native/Libraries/react-native/react-native-interface.js
[options]
module.system=haste
munge_underscores=true
module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
module.name_mapper='^[./a-zA-Z0-9$_-]+\.png$' -> 'RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FixMe
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-3]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-3]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-8]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-8]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
[version]
0.13.1
0.18.1

View File

@ -1,28 +0,0 @@
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
project.xcworkspace
# node.js
#
node_modules/
npm-debug.log

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,78 @@
apply plugin: "com.android.application"
/**
* The react.gradle file registers two tasks: bundleDebugJsAndAssets and bundleReleaseJsAndAssets.
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation
* entryFile: "index.android.js",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"]
* ]
*/
apply from: "react.gradle"
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "io.realm.react.example"
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "1.0"
ndk {
abiFilters "armeabi-v7a", "x86"
}
}
buildTypes {
release {
minifyEnabled false // Set this to true to enable Proguard
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
}
dependencies {
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.facebook.react:react-native:0.18.0'
compile project(':realm')
}

View File

@ -0,0 +1,60 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Disabling obfuscation is useful if you collect stack traces from production crashes
# (unless you are using a system that supports de-obfuscate the stack traces).
-dontobfuscate
# React Native
# Keep our interfaces so they can be used by other ProGuard rules.
# See http://sourceforge.net/p/proguard/bugs/466/
-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
# Do not strip any method/class that is annotated with @DoNotStrip
-keep @com.facebook.proguard.annotations.DoNotStrip class *
-keepclassmembers class * {
@com.facebook.proguard.annotations.DoNotStrip *;
}
-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
void set*(***);
*** get*();
}
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
-keep class * extends com.facebook.react.bridge.NativeModule { *; }
-keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; }
-keepclassmembers class * { @com.facebook.react.uimanager.ReactProp <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.ReactPropGroup <methods>; }
# okhttp
-keepattributes Signature
-keepattributes *Annotation*
-keep class com.squareup.okhttp.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-dontwarn com.squareup.okhttp.**
# okio
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn okio.**

View File

@ -0,0 +1,87 @@
import org.apache.tools.ant.taskdefs.condition.Os
def config = project.hasProperty("react") ? project.react : [];
def bundleAssetName = config.bundleAssetName ?: "index.android.bundle"
def entryFile = config.entryFile ?: "index.android.js"
// because elvis operator
def elvisFile(thing) {
return thing ? file(thing) : null;
}
def reactRoot = elvisFile(config.root) ?: file("../../")
def jsBundleDirDebug = elvisFile(config.jsBundleDirDebug) ?:
file("$buildDir/intermediates/assets/debug")
def jsBundleDirRelease = elvisFile(config.jsBundleDirRelease) ?:
file("$buildDir/intermediates/assets/release")
def resourcesDirDebug = elvisFile(config.resourcesDirDebug) ?:
file("$buildDir/intermediates/res/merged/debug")
def resourcesDirRelease = elvisFile(config.resourcesDirRelease) ?:
file("$buildDir/intermediates/res/merged/release")
def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]
def jsBundleFileDebug = file("$jsBundleDirDebug/$bundleAssetName")
def jsBundleFileRelease = file("$jsBundleDirRelease/$bundleAssetName")
task bundleDebugJsAndAssets(type: Exec) {
// create dirs if they are not there (e.g. the "clean" task just ran)
doFirst {
jsBundleDirDebug.mkdirs()
resourcesDirDebug.mkdirs()
}
// set up inputs and outputs so gradle can cache the result
inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
outputs.dir jsBundleDirDebug
outputs.dir resourcesDirDebug
// set up the call to the react-native cli
workingDir reactRoot
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "true", "--entry-file",
entryFile, "--bundle-output", jsBundleFileDebug, "--assets-dest", resourcesDirDebug
} else {
commandLine "react-native", "bundle", "--platform", "android", "--dev", "true", "--entry-file",
entryFile, "--bundle-output", jsBundleFileDebug, "--assets-dest", resourcesDirDebug
}
enabled config.bundleInDebug ?: false
}
task bundleReleaseJsAndAssets(type: Exec) {
// create dirs if they are not there (e.g. the "clean" task just ran)
doFirst {
jsBundleDirRelease.mkdirs()
resourcesDirRelease.mkdirs()
}
// set up inputs and outputs so gradle can cache the result
inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
outputs.dir jsBundleDirRelease
outputs.dir resourcesDirRelease
// set up the call to the react-native cli
workingDir reactRoot
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine "cmd","/c", "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file",
entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease
} else {
commandLine "react-native", "bundle", "--platform", "android", "--dev", "false", "--entry-file",
entryFile, "--bundle-output", jsBundleFileRelease, "--assets-dest", resourcesDirRelease
}
enabled config.bundleInRelease ?: true
}
gradle.projectsEvaluated {
// hook bundleDebugJsAndAssets into the android build process
bundleDebugJsAndAssets.dependsOn mergeDebugResources
bundleDebugJsAndAssets.dependsOn mergeDebugAssets
processDebugResources.dependsOn bundleDebugJsAndAssets
// hook bundleReleaseJsAndAssets into the android build process
bundleReleaseJsAndAssets.dependsOn mergeReleaseResources
bundleReleaseJsAndAssets.dependsOn mergeReleaseAssets
processReleaseResources.dependsOn bundleReleaseJsAndAssets
}

View File

@ -0,0 +1,23 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.realm.react.example">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>

View File

@ -0,0 +1,43 @@
package io.realm.react.example;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import java.util.Arrays;
import java.util.List;
import io.realm.react.RealmReactPackage;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "ReactExample";
}
/**
* Returns whether dev mode should be enabled.
* This enables e.g. the dev menu.
*/
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
/**
* A list of packages used by the app. If the app uses additional views
* or modules besides the default ones, add more packages here.
*/
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RealmReactPackage()
);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">ReactExample</string>
</resources>

View File

@ -0,0 +1,8 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1,24 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
jcenter()
jcenter {
url "http://dl.bintray.com/mkonicek/maven"
}
maven { url "https://jitpack.io" }
}
}

View File

@ -0,0 +1,20 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.useDeprecatedNdk=true

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip

164
examples/ReactExample/android/gradlew vendored Executable file
View File

@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

View File

@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,6 @@
rootProject.name = 'ReactExample'
include ':app'
include ':realm'
project(':realm').projectDir = new File(rootProject.projectDir, '../node_modules/realm/android')

View File

@ -6,21 +6,58 @@
const React = require('react-native');
module.exports = React.StyleSheet.create({
const { Navigator, Platform, StyleSheet } = React;
const { NavBarHeight, TotalNavHeight } = Navigator.NavigationBar.Styles.General;
const iOS = (Platform.OS == 'ios');
module.exports = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'stretch',
backgroundColor: '#ffffff',
backgroundColor: '#fff',
},
navigator: {
flex: 1,
},
navBar: {
backgroundColor: '#f0727d',
},
navBarView: {
alignItems: 'center',
flexDirection: 'row',
height: NavBarHeight,
},
navBarLeftArrow: {
color: '#fff',
fontSize: 40,
fontWeight: '200',
letterSpacing: 2,
marginTop: -6,
},
navBarLeftButton: {
paddingLeft: 8,
},
navBarRightButton: {
paddingRight: 8,
},
navBarText: {
color: '#fff',
fontSize: 18,
},
navBarTitleText: {
fontWeight: '500',
},
navScene: {
top: TotalNavHeight,
},
listItem: {
borderColor: "#c8c7cc",
borderColor: '#c8c7cc',
borderBottomWidth: 0.5,
alignItems: 'stretch',
alignSelf: 'stretch',
justifyContent: 'center',
flexDirection: 'row',
flex: 1,
height: 44,
@ -34,20 +71,26 @@ module.exports = React.StyleSheet.create({
listItemCheckbox: {
borderColor: '#ccc',
borderWidth: 1,
textAlign: 'center',
width: 16,
height: 16,
lineHeight: 14,
},
listItemCheckboxText: {
width: 14,
height: 14,
fontSize: iOS ? 14 : 10,
textAlign: 'center',
},
listItemCount: {
borderColor: '#ccc',
borderWidth: 1,
borderRadius: 8,
textAlign: 'center',
fontSize: 12,
width: 24,
height: 18,
lineHeight: 16,
},
listItemCountText: {
backgroundColor: 'transparent',
fontSize: iOS ? 12 : 11,
textAlign: 'center',
},
listItemInput: {
fontFamily: 'System',
@ -56,16 +99,17 @@ module.exports = React.StyleSheet.create({
flex: 1,
},
listItemText: {
alignSelf: 'center',
fontFamily: 'System',
fontSize: 15,
flexDirection: 'column',
flex: 1,
lineHeight: 30,
},
listItemTextSpecial: {
fontStyle: 'italic',
},
listItemDelete: {
backgroundColor: 'transparent',
paddingLeft: 12,
paddingRight: 12,
flexDirection: 'column',

View File

@ -10,7 +10,13 @@ const TodoListView = require('./todo-listview');
const realm = require('./realm');
const styles = require('./styles');
const { NavigatorIOS } = React;
const {
Navigator,
StatusBarIOS,
Text,
TouchableOpacity,
View,
} = React;
class TodoApp extends React.Component {
constructor(props) {
@ -25,6 +31,12 @@ class TodoApp extends React.Component {
// This is a Results object, which will live-update.
this.todoLists = todoLists;
// Bind all the methods that we will be passing as props.
this.renderScene = this.renderScene.bind(this);
this._addNewTodoList = this._addNewTodoList.bind(this);
this._onPressTodoList = this._onPressTodoList.bind(this);
this.state = {};
}
@ -33,6 +45,12 @@ class TodoApp extends React.Component {
return refs.listItemView || refs.listView;
}
componentWillMount() {
if (StatusBarIOS) {
StatusBarIOS.setStyle('light-content');
}
}
render() {
let extraItems = [
{name: 'Complete', items: realm.objects('Todo', 'done = true')},
@ -46,16 +64,31 @@ class TodoApp extends React.Component {
ref: 'listView',
items: this.todoLists,
extraItems: extraItems,
onPressItem: (list) => this._onPressTodoList(list),
onPressItem: this._onPressTodoList,
},
backButtonTitle: 'Lists',
rightButtonTitle: 'Add',
onRightButtonPress: () => this._addNewTodoList(),
onRightButtonPress: this._addNewTodoList,
};
return (
<NavigatorIOS ref="nav" initialRoute={route} style={styles.navigator} />
let navigationBar = (
<Navigator.NavigationBar routeMapper={RouteMapper} style={styles.navBar} />
);
return (
<Navigator
ref="nav"
initialRoute={route}
navigationBar={navigationBar}
renderScene={this.renderScene}
sceneStyle={styles.navScene}
style={styles.navigator}
/>
);
}
renderScene(route) {
return <route.component {...route.passProps} />
}
_addNewTodoItem(list) {
@ -125,4 +158,50 @@ class TodoApp extends React.Component {
}
}
const RouteMapper = {
LeftButton(route, navigator, index, navState) {
if (index == 0) {
return null;
}
let prevRoute = navState.routeStack[index - 1];
return (
<TouchableOpacity onPress={() => navigator.pop()}>
<View style={[styles.navBarView, styles.navBarLeftButton]}>
<Text style={styles.navBarLeftArrow}></Text>
<Text style={styles.navBarText}>
{prevRoute.backButtonTitle || prevRoute.title || 'Back'}
</Text>
</View>
</TouchableOpacity>
);
},
RightButton(route) {
if (!route.rightButtonTitle) {
return null;
}
return (
<TouchableOpacity onPress={route.onRightButtonPress}>
<View style={[styles.navBarView, styles.navBarRightButton]}>
<Text style={styles.navBarText}>
{route.rightButtonTitle}
</Text>
</View>
</TouchableOpacity>
);
},
Title(route) {
return (
<View style={styles.navBarView}>
<Text style={[styles.navBarText, styles.navBarTitleText]}>
{route.title}
</Text>
</View>
);
},
};
module.exports = TodoApp;

View File

@ -38,10 +38,12 @@ class TodoItem extends TodoListItem {
return (
<TouchableWithoutFeedback onPress={this._onPressCheckbox}>
<View style={styles.listItemLeftSide}>
<Text style={styles.listItemCheckbox}>
<View style={styles.listItemCheckbox}>
<Text style={styles.listItemCheckboxText}>
{this.done ? '✓' : ''}
</Text>
</View>
</View>
</TouchableWithoutFeedback>
);
}

View File

@ -8,7 +8,15 @@ const React = require('react-native');
const realm = require('./realm');
const styles = require('./styles');
const { Text, TextInput, TouchableWithoutFeedback, View } = React;
const {
Platform,
Text,
TextInput,
TouchableWithoutFeedback,
View,
} = React;
const iOS = (Platform.OS == 'ios');
class TodoListItem extends React.Component {
constructor(props) {
@ -90,7 +98,7 @@ class TodoListItem extends React.Component {
return (
<TouchableWithoutFeedback onPress={this.props.onPressDelete}>
<View style={styles.listItemDelete}>
<Text>𐄂</Text>
<Text>{iOS ? '𐄂' : '×'}</Text>
</View>
</TouchableWithoutFeedback>
);

View File

@ -162,10 +162,12 @@ class TodoListExtraItem extends TodoListItem {
renderLeftSide() {
return (
<View style={styles.listItemLeftSide}>
<Text style={styles.listItemCount}>
<View style={styles.listItemCount}>
<Text style={styles.listItemCountText}>
{this.props.item.items.length}
</Text>
</View>
</View>
);
}

View File

@ -0,0 +1,10 @@
/* Copyright 2015 Realm Inc - All Rights Reserved
* Proprietary and Confidential
*/
'use strict';
const React = require('react-native');
const TodoApp = require('./components/todo-app');
React.AppRegistry.registerComponent('ReactExample', () => TodoApp);

View File

@ -0,0 +1,14 @@
#!/bin/bash
set -o pipefail
set -e
PATH="/opt/android-sdk-linux/platform-tools:$PATH"
rm -rf node_modules/realm
npm install realm
adb reverse tcp:8081 tcp:8081
adb forward tcp:8082 tcp:8082
react-native run-android

1
lib/.npmignore Normal file
View File

@ -0,0 +1 @@
*.orig

View File

@ -4,11 +4,16 @@
"private": true,
"main": "lib/index.js",
"files": [
"android",
"lib",
"react-native",
"scripts",
"src",
"vendor",
"RealmJS.xcodeproj"
]
],
"scripts": {
"test": "scripts/test.sh",
"prepublish": "scripts/prepublish.sh"
}
}

3
react-native/.npmignore Normal file
View File

@ -0,0 +1,3 @@
android/
*.orig

1
react-native/android/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
downloads/

View File

@ -0,0 +1,5 @@
build/
.idea
.gradle
local.properties

View File

@ -0,0 +1,289 @@
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
classpath 'de.undercouch:gradle-download-task:1.2'
}
}
allprojects {
repositories {
mavenLocal()
jcenter()
}
}
apply plugin: 'com.android.library'
apply plugin: 'maven'
apply plugin: 'signing'
apply plugin: 'de.undercouch.download'
import de.undercouch.gradle.tasks.download.Download
import org.apache.tools.ant.taskdefs.condition.Os
import org.apache.tools.ant.filters.ReplaceTokens
// We download various C++ open-source dependencies into downloads.
// We then copy both the downloaded code and our custom makefiles and headers into third-party-ndk.
// After that we build native code from src/main/jni with module path pointing at third-party-ndk.
def downloadsDir = new File("$projectDir/downloads")
def jscDownloadDir = new File("$projectDir/src/main/jni/jsc")
def coreDownloadDir = new File("$projectDir/src/main/jni")
ext.coreVersion = '0.95.6'
def publishDir = new File("$projectDir/../../android/")
task createNativeDepsDirectories {
downloadsDir.mkdirs()
}
task downloadJSCHeaders(type: Download) {
def jscAPIBaseURL = 'https://svn.webkit.org/repository/webkit/!svn/bc/174650/trunk/Source/JavaScriptCore/API/'
def jscHeaderFiles = ['JSBase.h', 'JSContextRef.h', 'JSObjectRef.h', 'JSRetainPtr.h', 'JSStringRef.h', 'JSValueRef.h', 'WebKitAvailability.h']
def output = new File(jscDownloadDir, 'JavaScriptCore')
output.mkdirs()
src(jscHeaderFiles.collect { headerName -> "$jscAPIBaseURL$headerName" })
onlyIfNewer true
overwrite false
dest output
}
task downloadRealmCore(type: Download) {
src "http://static.realm.io/downloads/core/realm-core-android-${project.coreVersion}.tar.gz"
onlyIfNewer true
overwrite false
dest new File(downloadsDir, "realm-core-android-${project.coreVersion}.tar.gz")
}
task prepareRealmCore(dependsOn: downloadRealmCore, type:Copy) {
from tarTree(downloadRealmCore.dest)
into "$coreDownloadDir/core"
//Fixing Core file naming 'arm-*' to 'armeabi-*'
doLast {
exec {
workingDir = "$coreDownloadDir/core"
commandLine = [
"bash",
"-c",
"find . -name \"*-arm-*\" -exec sh -c \"echo {} | sed -e s/arm/armeabi/g | xargs mv {} \" \\;"
]
}
}
}
def getNdkBuildName() {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
return "ndk-build.cmd"
} else {
return "ndk-build"
}
}
def findNdkBuildFullPath() {
// we allow to provide full path to ndk-build tool
if (hasProperty('ndk.command')) {
return property('ndk.command')
}
// or just a path to the containing directory
if (hasProperty('ndk.path')) {
def ndkDir = property('ndk.path')
return new File(ndkDir, getNdkBuildName()).getAbsolutePath()
}
if (System.getenv('ANDROID_NDK') != null) {
def ndkDir = System.getenv('ANDROID_NDK')
return new File(ndkDir, getNdkBuildName()).getAbsolutePath()
}
def ndkDir = android.hasProperty('plugin') ? android.plugin.ndkFolder :
plugins.getPlugin('com.android.library').sdkHandler.getNdkFolder()
if (ndkDir) {
return new File(ndkDir, getNdkBuildName()).getAbsolutePath()
}
return null
}
def getNdkBuildFullPath() {
def ndkBuildFullPath = findNdkBuildFullPath()
if (ndkBuildFullPath == null) {
throw new GradleScriptException(
"ndk-build binary cannot be found, check if you've set " +
"\$ANDROID_NDK environment variable correctly or if ndk.dir is " +
"setup in local.properties",
null)
}
if (!new File(ndkBuildFullPath).canExecute()) {
throw new GradleScriptException(
"ndk-build binary " + ndkBuildFullPath + " doesn't exist or isn't executable.\n" +
"Check that the \$ANDROID_NDK environment variable, or ndk.dir in local.proerties, is set correctly.\n" +
"(On Windows, make sure you escape backslashes in local.properties or use forward slashes, e.g. C:\\\\ndk or C:/ndk rather than C:\\ndk)",
null)
}
return ndkBuildFullPath
}
task buildReactNdkLib(dependsOn: [downloadJSCHeaders,prepareRealmCore], type: Exec) {
inputs.file('src/main/jni')
outputs.dir("$buildDir/realm-react-ndk/all")
commandLine getNdkBuildFullPath(),
'NDK_PROJECT_PATH=null',
"NDK_APPLICATION_MK=$projectDir/src/main/jni/Application.mk",
'NDK_OUT=' + temporaryDir,
"NDK_LIBS_OUT=$buildDir/realm-react-ndk/all",
'-C', file('src/main/jni').absolutePath,
'NDK_LOG=1',
'NDK_DEBUG=' + (DEBUG_BUILD.toBoolean() ? '1' : '0'),
'--jobs', Runtime.runtime.availableProcessors(),
'V=1'
}
task cleanReactNdkLib(type: Exec) {
commandLine getNdkBuildFullPath(),
'-C', file('src/main/jni').absolutePath,
'clean'
}
task packageReactNdkLibs(dependsOn: buildReactNdkLib, type: Copy) {
from "$buildDir/realm-react-ndk/all"
exclude '**/libjsc.so'
exclude '**/gdbserver'
exclude '**/gdb.setup'
into "$buildDir/realm-react-ndk/exported"
}
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir "$buildDir/realm-react-ndk/exported"
res.srcDirs = ['src/main/res/devsupport', 'src/main/res/shell']
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn packageReactNdkLibs
}
clean.dependsOn cleanReactNdkLib
lintOptions {
abortOnError false
}
}
task publishAndroid(dependsOn: packageReactNdkLibs, type: Copy) {
// Copy task can only have one top level
into "$publishDir"
// copy java source
into ('/src/main') {
from "$projectDir/src/main"
exclude '**/jni/**'
}
// add compiled shared object
into ('/src/main/jniLibs') {
from "$buildDir/realm-react-ndk/exported/"
}
// copy gradle wrapper files
FileTree gradleWrapper = fileTree(projectDir).include('gradlew*').include('gradle/**')
into ('/') {
from gradleWrapper
}
// copy and rename template build.gradle
into ('/') {
from "$projectDir/publish_android_template"
rename { String fileName ->
'build.gradle'
}
}
}
// publishing into maven local
def configureRealmReactNativePom(def pom) {
pom.project {
name POM_NAME
artifactId POM_ARTIFACT_ID
packaging POM_PACKAGING
description POM_DESCRIPTION
url 'https://github.com/realm/realm-js'
issueManagement {
system 'github'
url 'https://github.com/realm/realm-js/issues'
}
scm {
url 'scm:https://github.com/realm/realm-js'
connection 'scm:git@github.com:realm/realm-js.git'
developerConnection 'scm:git@github.com:realm/realm-js.git'
}
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution 'repo'
}
}
}
}
afterEvaluate { project ->
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.srcDirs
include '**/*.java'
}
android.libraryVariants.all { variant ->
def name = variant.name.capitalize()
task "jar${name}"(type: Jar, dependsOn: variant.javaCompile) {
from variant.javaCompile.destinationDir
}
}
artifacts {
archives androidSourcesJar
}
version = VERSION_NAME
group = GROUP
signing {
required { false }
sign configurations.archives
}
task installArchives(type: Upload) {
configuration = configurations.archives
repositories.mavenDeployer {
beforeDeployment {
MavenDeployment deployment -> signing.signPom(deployment)
}
repository url: "file://${System.properties['user.home']}/.m2/repository"
configureRealmReactNativePom pom
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'org.nanohttpd:nanohttpd:2.2.0'
compile 'com.facebook.react:react-native:0.18.0'
}

View File

@ -0,0 +1,9 @@
VERSION_NAME=0.0.1-SNAPSHOT
GROUP=io.realm.react
POM_NAME=RealmReactAndroid
POM_ARTIFACT_ID=realm-react-native
POM_PACKAGING=aar
POM_DESCRIPTION=Android Realm React Native module. Realm is a mobile database: a replacement for SQLite & ORMs
DEBUG_BUILD=true
android.useDeprecatedNdk=true

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Wed Feb 10 01:35:36 GMT 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-bin.zip

164
react-native/android/gradlew vendored Executable file
View File

@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
react-native/android/gradlew.bat vendored Normal file
View File

@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,33 @@
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.3.1'
}
}
allprojects {
repositories {
mavenLocal()
jcenter()
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 22
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'org.nanohttpd:nanohttpd:2.2.0'
compile 'com.facebook.react:react-native:0.18.0'
}

View File

@ -0,0 +1,3 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.realm.react">
<application />
</manifest>

View File

@ -0,0 +1,129 @@
package io.realm.react;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.soloader.SoLoader;
import java.io.IOException;
import java.lang.IllegalStateException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import fi.iki.elonen.NanoHTTPD;
public class RealmReactModule extends ReactContextBaseJavaModule {
private static final int DEFAULT_PORT = 8082;
private AndroidWebServer webServer;
private Handler handler = new Handler(Looper.getMainLooper());
static {
SoLoader.loadLibrary("realmreact");
}
public RealmReactModule(ReactApplicationContext reactContext) {
super(reactContext);
String fileDir;
try {
fileDir = reactContext.getFilesDir().getCanonicalPath();
} catch (IOException e) {
throw new IllegalStateException(e);
}
setDefaultRealmFileDirectory(fileDir);
}
@Override
public String getName() {
return "Realm";
}
@Override
public Map<String, Object> getConstants() {
// FIXME: Only start web server when in Chrome debug mode!
startWebServer();
return Collections.EMPTY_MAP;
}
@Override
public void onCatalystInstanceDestroy() {
stopWebServer();
}
private void startWebServer() {
setupChromeDebugModeRealmJsContext();
webServer = new AndroidWebServer(DEFAULT_PORT);
try {
webServer.start();
Log.i("Realm", "Starting the debugging WebServer, Host: " + webServer.getHostname() + " Port: " + webServer.getListeningPort());
} catch (IOException e) {
e.printStackTrace();
}
}
private void stopWebServer() {
if (webServer != null) {
Log.i("Realm", "Stopping the webserver");
webServer.stop();
}
}
class AndroidWebServer extends NanoHTTPD {
public AndroidWebServer(int port) {
super(port);
}
public AndroidWebServer(String hostname, int port) {
super(hostname, port);
}
@Override
public Response serve(IHTTPSession session) {
final String cmdUri = session.getUri();
final HashMap<String, String> map = new HashMap<String, String>();
try {
session.parseBody(map);
} catch (IOException e) {
e.printStackTrace();
} catch (ResponseException e) {
e.printStackTrace();
}
final String json = map.get("postData");
final String[] jsonResponse = new String[1];
final CountDownLatch latch = new CountDownLatch(1);
// Process the command on the UI thread
handler.post(new Runnable() {
@Override
public void run() {
jsonResponse[0] = processChromeDebugCommand(cmdUri, json);
latch.countDown();
}
});
try {
latch.await();
Response response = newFixedLengthResponse(jsonResponse[0]);
response.addHeader("Access-Control-Allow-Origin", "http://localhost:8081");
return response;
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
}
// fileDir: path of the internal storage of the application
private native void setDefaultRealmFileDirectory(String fileDir);
// responsible for creating the rpcServer that will accept the chrome Websocket command
private native long setupChromeDebugModeRealmJsContext();
// this receives one command from Chrome debug then return the processing we should post back
private native String processChromeDebugCommand(String cmd, String args);
}

View File

@ -0,0 +1,28 @@
package io.realm.react;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.uimanager.ViewManager;
public class RealmReactPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.<NativeModule>singletonList(new RealmReactModule(reactContext));
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

View File

@ -0,0 +1 @@
core/

View File

@ -0,0 +1,54 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := realm-android-$(TARGET_ARCH_ABI)
LOCAL_EXPORT_C_INCLUDES := core/include
LOCAL_SRC_FILES := core/librealm-android-$(TARGET_ARCH_ABI).a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libjsc
LOCAL_EXPORT_C_INCLUDES := jsc
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := librealmreact
LOCAL_SRC_FILES := \
src/js_list.cpp \
src/js_results.cpp \
src/js_init.cpp \
src/js_realm.cpp \
src/js_util.cpp \
src/js_object.cpp \
src/js_schema.cpp \
src/rpc.cpp \
src/android/platform.cpp \
src/android/io_realm_react_RealmReactModule.cpp \
src/android/jsc_override.cpp \
src/object-store/index_set.cpp \
src/object-store/list.cpp \
src/object-store/object_schema.cpp \
src/object-store/object_store.cpp \
src/object-store/results.cpp \
src/object-store/schema.cpp \
src/object-store/shared_realm.cpp \
src/object-store/parser/parser.cpp \
src/object-store/parser/query_builder.cpp \
src/object-store/impl/transact_log_handler.cpp \
vendor/base64.cpp
LOCAL_C_INCLUDES := src
LOCAL_C_INCLUDES += src/object-store
LOCAL_C_INCLUDES += src/object-store/parser
LOCAL_C_INCLUDES += vendor
LOCAL_C_INCLUDES += vendor/PEGTL
LOCAL_C_INCLUDES += $(JAVA_HOME)/include
LOCAL_C_INCLUDES += $(JAVA_HOME)/include/darwin
LOCAL_C_INCLUDES += core/include
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
LOCAL_STATIC_LIBRARIES := realm-android-$(TARGET_ARCH_ABI)
LOCAL_SHARED_LIBRARIES := libjsc
include $(BUILD_SHARED_LIBRARY)

View File

@ -0,0 +1,20 @@
APP_BUILD_SCRIPT := Android.mk
APP_ABI := armeabi-v7a x86
APP_PLATFORM := android-9
APP_MK_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
NDK_MODULE_PATH := $(APP_MK_DIR)$(HOST_DIRSEP)$(THIRD_PARTY_NDK_DIR)$(HOST_DIRSEP)$(APP_MK_DIR)first-party
APP_STL := gnustl_static
APP_CPPFLAGS := -std=c++14
APP_CPPFLAGS += -frtti
APP_CPPFLAGS += -fexceptions
APP_CPPFLAGS += -DREALM_HAVE_CONFIG
# Make sure every shared lib includes a .note.gnu.build-id header
APP_LDFLAGS := -Wl,--build-id
APP_LDFLAGS += -llog
NDK_TOOLCHAIN_VERSION := 4.9

View File

@ -0,0 +1 @@
JavaScriptCore/

View File

@ -0,0 +1 @@
../../../../../src/

View File

@ -0,0 +1 @@
../../../../../vendor

1
scripts/.npmignore Normal file
View File

@ -0,0 +1 @@
*.orig

View File

@ -3,7 +3,7 @@
set -e
set -o pipefail
: ${REALM_CORE_VERSION:=0.95.5} # set to "current" to always use the current build
: ${REALM_CORE_VERSION:=0.95.6} # set to "current" to always use the current build
echo "Downloading dependency: core ${REALM_CORE_VERSION}"

13
scripts/prepublish.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
set -e
set -o pipefail
cd "$(dirname "$0")/.."
if [ -n "$SKIP_ANDROID_BUILD" -o -n "$XCODE_VERSION_ACTUAL" ]; then
echo 'Skipped building Android module'
else
rm -rf android
(cd react-native/android && ./gradlew publishAndroid)
fi

View File

@ -3,7 +3,17 @@
set -o pipefail
set -e
while pgrep -q Simulator; do
TARGET="$1"
CONFIGURATION="${2:-"Debug"}"
DESTINATION=
PATH="/opt/android-sdk-linux/platform-tools:$PATH"
SRCROOT=$(cd "$(dirname "$0")/.." && pwd)
# Start current working directory at the root of the project.
cd "$SRCROOT"
if [[ $TARGET != *-android ]]; then
while pgrep -q Simulator; do
# Kill all the current simulator processes as they may be from a
# different Xcode version
pkill Simulator 2>/dev/null || true
@ -11,20 +21,37 @@ while pgrep -q Simulator; do
pkill -9 Simulator 2>/dev/null || true
done
DESTINATION="-destination id=$(xcrun simctl list devices | grep -v unavailable | grep -m 1 -o '[0-9A-F\-]\{36\}')"
DESTINATION="-destination id=$(xcrun simctl list devices | grep -v unavailable | grep -m 1 -o '[0-9A-F\-]\{36\}')"
TARGET=$1
CONFIGURATION=${2:-"Debug"}
PACKAGER_OUT="packager_out.txt"
# Inform the prepublish script to skip building Android modules.
export SKIP_ANDROID_BUILD=1
fi
function start_packager()
{
rm -f $PACKAGER_OUT
sh ./node_modules/react-native/packager/packager.sh | tee packager_out.txt &
while :;
do
if grep -Fxq "React packager ready." packager_out.txt
then
PACKAGER_OUT="$SRCROOT/packager_out.txt"
LOGCAT_OUT="$SRCROOT/logcat_out.txt"
cleanup() {
# Kill all child processes.
pkill -P $$ || true
pkill node || true
rm -f "$PACKAGER_OUT" "$LOGCAT_OUT"
}
open_chrome() {
local dir
for dir in "$HOME/Applications" "/Applications"; do
if [ -d "$dir/Google Chrome.app" ]; then
open "$dir/Google Chrome.app"
break
fi
done
}
start_packager() {
./node_modules/react-native/packager/packager.sh | tee "$PACKAGER_OUT" &
while :; do
if grep -Fxq "React packager ready." "$PACKAGER_OUT"; then
break
else
echo "Waiting for packager."
@ -33,44 +60,87 @@ function start_packager()
done
}
function kill_packager()
{
rm -f $PACKAGER_OUT
pkill node || true
unlock_device() {
adb shell input keyevent 82
}
kill_packager
# Cleanup now and also cleanup when this script exits.
cleanup
trap cleanup EXIT
if [ "$TARGET" = "realmjs" ]; then
case "$TARGET" in
"realmjs")
xcodebuild -scheme RealmJS -configuration "$CONFIGURATION" -sdk iphonesimulator $DESTINATION build test
elif [ "$TARGET" = "react-tests" ]; then
;;
"react-tests")
pushd tests/react-test-app
if [ -d ~/Applications/Google\ Chrome.app ]; then
open ~/Applications/Google\ Chrome.app
fi
if [ -f ../../target=node_modules/react_tests_node_modules.zip ]; then
unzip -q ../../target=node_modules/react_tests_node_modules.zip
fi
npm update react-native
open_chrome
start_packager
popd
xcodebuild -scheme RealmReact -configuration "$CONFIGURATION" -sdk iphonesimulator $DESTINATION build test
elif [ "$TARGET" = "react-example" ]; then
;;
"react-example")
pushd examples/ReactExample
if [ -f ../../target=node_modules/react_example_node_modules.zip ]; then
unzip -q ../../target=node_modules/react_example_node_modules.zip
fi
npm update react-native
start_packager
cd ios
pushd ios
xcodebuild -scheme ReactExample -configuration "$CONFIGURATION" -sdk iphonesimulator build $DESTINATION
popd
else
echo "Invalid target '${TARGET}'"
fi
;;
"react-tests-android")
if [[ $CONFIGURATION == 'Debug' ]]; then
exit 0
fi
kill_packager
[ -s "${HOME}/.nvm/nvm.sh" ] && . "${HOME}/.nvm/nvm.sh"
nvm use 5.4.0 || true
pushd react-native/android
./gradlew installarchives
popd
pushd tests/react-test-app
npm install
open_chrome
start_packager
./run-android.sh
# Despite the docs claiming -c to work, it doesn't, so `-T 1` alleviates that.
adb logcat -c
adb logcat -T 1 | tee "$LOGCAT_OUT" &
while :; do
if grep -q "__REALM_REACT_ANDROID_TESTS_COMPLETED__" "$LOGCAT_OUT"; then
break
else
echo "Waiting for tests."
sleep 2
fi
done
rm -f tests.xml
adb pull /sdcard/tests.xml .
# Stop running child processes before printing results.
cleanup
echo "********* TESTS COMPLETED *********";
echo "********* File location: $(pwd)/tests.xml *********";
cat tests.xml
;;
*)
echo "Invalid target '${TARGET}'"
exit 1
esac

1
src/.npmignore Normal file
View File

@ -0,0 +1 @@
*.orig

View File

@ -0,0 +1,49 @@
/* Copyright 2016 Realm Inc - All Rights Reserved
* Proprietary and Confidential
*/
#include <jni.h>
#include <android/log.h>
#include "io_realm_react_RealmReactModule.h"
#include "rpc.hpp"
#include "platform.hpp"
static realm_js::RPCServer *s_rpc_server;
JNIEXPORT void JNICALL Java_io_realm_react_RealmReactModule_setDefaultRealmFileDirectory
(JNIEnv *env, jclass, jstring fileDir)
{
__android_log_print(ANDROID_LOG_VERBOSE, "JSRealm", "setDefaultRealmFileDirectory");
// Setting the internal storage path for the application
const char* strFileDir = env->GetStringUTFChars(fileDir, NULL);
realm::set_default_realm_file_directory(strFileDir);
env->ReleaseStringUTFChars(fileDir , strFileDir);
__android_log_print(ANDROID_LOG_DEBUG, "JSRealm", "Absolute path: %s", realm::default_realm_file_directory().c_str());
}
JNIEXPORT jlong JNICALL Java_io_realm_react_RealmReactModule_setupChromeDebugModeRealmJsContext
(JNIEnv *, jclass)
{
__android_log_print(ANDROID_LOG_VERBOSE, "JSRealm", "setupChromeDebugModeRealmJsContext");
if (s_rpc_server) {
delete s_rpc_server;
}
s_rpc_server = new realm_js::RPCServer();
return (jlong)s_rpc_server;
}
JNIEXPORT jstring JNICALL Java_io_realm_react_RealmReactModule_processChromeDebugCommand
(JNIEnv *env, jclass, jstring chrome_cmd, jstring chrome_args)
{
__android_log_print(ANDROID_LOG_VERBOSE, "JSRealm", "processChromeDebugCommand");
const char* cmd = env->GetStringUTFChars(chrome_cmd, NULL);
const char* args = env->GetStringUTFChars(chrome_args, NULL);
realm_js::json json = realm_js::json::parse(args);
realm_js::json response = s_rpc_server->perform_request(cmd, json);
env->ReleaseStringUTFChars(chrome_cmd, cmd);
env->ReleaseStringUTFChars(chrome_args, args);
return env->NewStringUTF(response.dump().c_str());
}

View File

@ -0,0 +1,35 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class io_realm_react_RealmReactModule */
#ifndef _Included_io_realm_react_RealmReactModule
#define _Included_io_realm_react_RealmReactModule
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: io_realm_react_RealmReactModule
* Method: setDefaultRealmFileDirectory
*/
JNIEXPORT void JNICALL Java_io_realm_react_RealmReactModule_setDefaultRealmFileDirectory
(JNIEnv *, jclass, jstring);
/*
* Class: io_realm_react_RealmReactModule
* Method: setupChromeDebugModeRealmJsContext
*/
JNIEXPORT jlong JNICALL Java_io_realm_react_RealmReactModule_setupChromeDebugModeRealmJsContext
(JNIEnv *, jclass);
/*
* Class: io_realm_react_RealmReactModule
* Method: processChromeDebugCommand
*/
JNIEXPORT jstring JNICALL Java_io_realm_react_RealmReactModule_processChromeDebugCommand
(JNIEnv *, jclass, jstring, jstring);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,94 @@
/* Copyright 2016 Realm Inc - All Rights Reserved
* Proprietary and Confidential
*/
#include <dlfcn.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <mutex>
#include <JavaScriptCore/JSContextRef.h>
#include "js_init.h"
#include "shared_realm.hpp"
#if __arm__
#define HOOK_SIZE 8
#else
#define HOOK_SIZE 5
#endif
static void swap_function() __attribute__((constructor));
static JSGlobalContextRef create_context(JSContextGroupRef group, JSClassRef global_class)
{
static std::mutex s_mutex;
std::lock_guard<std::mutex> lock(s_mutex);
// Replace JSGlobalContextCreateInGroup with its original implementation and call it.
swap_function();
JSGlobalContextRef ctx = JSGlobalContextCreateInGroup(group, global_class);
// Reinstall the hook.
swap_function();
// Clear cache from previous instances.
realm::Realm::s_global_cache.clear();
RJSInitializeInContext(ctx);
return ctx;
}
static void swap_function()
{
static int8_t s_orig_code[HOOK_SIZE];
static bool s_swapped = false;
int8_t *orig_func = (int8_t*)&JSGlobalContextCreateInGroup;
int8_t *new_func = (int8_t*)&create_context;
#if __arm__
bool orig_thumb = (uintptr_t)orig_func % 4 != 0;
if (orig_thumb) {
orig_func--;
}
#endif
size_t page_size = sysconf(_SC_PAGESIZE);
uintptr_t page_start = (uintptr_t)orig_func & ~(page_size - 1);
uintptr_t code_end = (uintptr_t)orig_func + HOOK_SIZE;
// Make this memory region writable.
mprotect((void*)page_start, code_end - page_start, PROT_READ | PROT_WRITE | PROT_EXEC);
if (s_swapped) {
// Copy original code back into place.
memcpy(orig_func, s_orig_code, HOOK_SIZE);
} else {
// Store the original code before replacing it.
memcpy(s_orig_code, orig_func, HOOK_SIZE);
#if __arm__
if (orig_thumb) {
// LDR PC, [PC, #0]; BX PC;
memcpy(orig_func, "\x00\x4f\x38\x47", 4);
memcpy(orig_func + 4, &new_func, 4);
} else {
// LDR PC, [PC, #0];
memcpy(orig_func, "\x00\xf0\x9f\xe5", 4);
memcpy(orig_func + 4, &new_func, 4);
}
#else
int32_t jmp_offset = (int64_t)new_func - (int64_t)orig_func - HOOK_SIZE;
// Change original function to jump to our new one.
*orig_func = 0xE9; // JMP
*(int32_t*)(orig_func + 1) = jmp_offset;
#endif
}
s_swapped = !s_swapped;
// Return this region to no longer being writable.
mprotect((void*)page_start, code_end - page_start, PROT_READ | PROT_EXEC);
}

34
src/android/platform.cpp Normal file
View File

@ -0,0 +1,34 @@
/* Copyright 2015 Realm Inc - All Rights Reserved
* Proprietary and Confidential
*/
#include "../platform.hpp"
#include "../js_init.h"
#include <string>
#include <stdlib.h>
std::string s_default_realm_directory;
namespace realm {
void set_default_realm_file_directory(std::string dir)
{
s_default_realm_directory = dir;
}
std::string default_realm_file_directory()
{
return s_default_realm_directory;
}
void ensure_directory_exists_for_file(const std::string &fileName)
{
}
void remove_realm_files_from_directory(const std::string &directory)
{
std::string cmd = "rm " + s_default_realm_directory + "/*.realm " +
s_default_realm_directory + "/*.realm.lock";
system(cmd.c_str());
}
}

View File

@ -2,15 +2,16 @@
* Proprietary and Confidential
*/
#import "js_init.h"
#import "js_realm.hpp"
#import "js_object.hpp"
#import "js_util.hpp"
#import "js_schema.hpp"
#import "platform.hpp"
#include "js_init.h"
#include "js_realm.hpp"
#include "js_object.hpp"
#include "js_util.hpp"
#include "js_schema.hpp"
#include "platform.hpp"
#include "shared_realm.hpp"
#include <algorithm>
#include <cassert>
extern "C" {

View File

@ -2,7 +2,9 @@
* Proprietary and Confidential
*/
#import <JavaScriptCore/JavaScriptCore.h>
#pragma once
#include <JavaScriptCore/JSBase.h>
#ifdef __cplusplus
extern "C" {

View File

@ -8,6 +8,8 @@
#include "js_util.hpp"
#include "object_accessor.hpp"
#include <assert.h>
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
using namespace realm;

View File

@ -2,9 +2,11 @@
* Proprietary and Confidential
*/
#import "js_util.hpp"
#import "shared_realm.hpp"
#import "list.hpp"
#pragma once
#include "js_util.hpp"
#include "shared_realm.hpp"
#include "list.hpp"
JSClassRef RJSListClass();
JSObjectRef RJSListCreate(JSContextRef ctx, realm::List &list);

View File

@ -2,15 +2,15 @@
* Proprietary and Confidential
*/
#import "js_util.hpp"
#import "js_object.hpp"
#import "js_results.hpp"
#import "js_schema.hpp"
#import "js_list.hpp"
#import "js_realm.hpp"
#include "js_util.hpp"
#include "js_object.hpp"
#include "js_results.hpp"
#include "js_schema.hpp"
#include "js_list.hpp"
#include "js_realm.hpp"
#import "object_store.hpp"
#import "object_accessor.hpp"
#include "object_store.hpp"
#include "object_accessor.hpp"
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
using namespace realm;
@ -63,6 +63,10 @@ JSObjectRef RJSObjectCreate(JSContextRef ctx, Object object) {
return jsObject;
}
extern JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, const ObjectSchema &object_schema, JSObjectRef array);
namespace realm {
template<> bool RJSAccessor::dict_has_value_for_key(JSContextRef ctx, JSValueRef dict, const std::string &prop_name) {
JSObjectRef object = RJSValidatedValueToObject(ctx, dict);
JSStringRef propStr = RJSStringForString(prop_name);
@ -218,8 +222,6 @@ template<> JSValueRef RJSAccessor::from_datetime(JSContextRef ctx, DateTime dt)
return JSObjectMakeDate(ctx, 1, &time, NULL);
}
extern JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, const ObjectSchema &object_schema, JSObjectRef array);
template<> size_t RJSAccessor::to_existing_object_index(JSContextRef ctx, JSValueRef &val) {
JSObjectRef object = RJSValidatedValueToObject(ctx, val);
if (JSValueIsObjectOfClass(ctx, val, RJSObjectClass())) {
@ -254,3 +256,5 @@ template<> JSValueRef RJSAccessor::list_value_at_index(JSContextRef ctx, JSValue
template<> JSValueRef RJSAccessor::from_list(JSContextRef ctx, List list) {
return RJSListCreate(ctx, list);
}
}

View File

@ -2,7 +2,9 @@
* Proprietary and Confidential
*/
#import "js_util.hpp"
#pragma once
#include "js_util.hpp"
namespace realm {
class Object;

View File

@ -2,18 +2,19 @@
* Proprietary and Confidential
*/
#import "js_realm.hpp"
#import "js_object.hpp"
#import "js_results.hpp"
#import "js_list.hpp"
#import "js_schema.hpp"
#import "platform.hpp"
#include "js_realm.hpp"
#include "js_object.hpp"
#include "js_results.hpp"
#include "js_list.hpp"
#include "js_schema.hpp"
#include "platform.hpp"
#import "shared_realm.hpp"
#import "object_accessor.hpp"
#import "binding_context.hpp"
#include "shared_realm.hpp"
#include "object_accessor.hpp"
#include "binding_context.hpp"
#import <set>
#include <set>
#include <cassert>
using namespace realm;
@ -104,8 +105,12 @@ std::map<std::string, JSValueRef> &RJSPrototypes(Realm *realm) {
return static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->m_prototypes;
}
static std::string s_defaultPath = realm::default_realm_file_directory() + "/default.realm";
// static std::string s_defaultPath = realm::default_realm_file_directory() + "/default.realm";
static std::string s_defaultPath = "";
std::string RJSDefaultPath() {
if (s_defaultPath.size() == 0) {
s_defaultPath = realm::default_realm_file_directory() + "/default.realm";
}
return s_defaultPath;
}
void RJSSetDefaultPath(std::string path) {
@ -158,7 +163,7 @@ JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t a
static JSStringRef schemaString = JSStringCreateWithUTF8CString("schema");
JSValueRef schemaValue = RJSValidatedPropertyValue(ctx, object, schemaString);
if (!JSValueIsUndefined(ctx, schemaValue)) {
config.schema = std::make_unique<Schema>(RJSParseSchema(ctx, RJSValidatedValueToObject(ctx, schemaValue), defaults, prototypes));
config.schema.reset(new Schema(RJSParseSchema(ctx, RJSValidatedValueToObject(ctx, schemaValue), defaults, prototypes)));
}
static JSStringRef schemaVersionString = JSStringCreateWithUTF8CString("schemaVersion");
@ -179,7 +184,7 @@ JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t a
ensure_directory_exists_for_file(config.path);
SharedRealm realm = Realm::get_shared_realm(config);
if (!realm->m_binding_context) {
realm->m_binding_context = std::make_unique<RJSRealmDelegate>(realm, JSContextGetGlobalContext(ctx));
realm->m_binding_context.reset(new RJSRealmDelegate(realm, JSContextGetGlobalContext(ctx)));
}
RJSDefaults(realm.get()) = defaults;
RJSPrototypes(realm.get()) = prototypes;

View File

@ -2,7 +2,9 @@
* Proprietary and Confidential
*/
#import "js_util.hpp"
#pragma once
#include "js_util.hpp"
#include <map>
namespace realm {

View File

@ -2,12 +2,12 @@
* Proprietary and Confidential
*/
#import "js_results.hpp"
#import "js_object.hpp"
#import "object_accessor.hpp"
#import "results.hpp"
#import "parser.hpp"
#import "query_builder.hpp"
#include "js_results.hpp"
#include "js_object.hpp"
#include "object_accessor.hpp"
#include "results.hpp"
#include "parser.hpp"
#include "query_builder.hpp"
using namespace realm;
@ -46,7 +46,7 @@ bool ResultsSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef proper
try {
std::string indexStr = RJSStringForJSString(propertyName);
if (indexStr != "length") {
std::stol(RJSStringForJSString(propertyName));
stot<long>(RJSStringForJSString(propertyName));
}
// attempts to assign to 'length' or an index should throw an exception

View File

@ -2,7 +2,10 @@
* Proprietary and Confidential
*/
#import "js_util.hpp"
#pragma once
#include "js_util.hpp"
#include <memory>
namespace realm {
class Realm;

View File

@ -2,8 +2,8 @@
* Proprietary and Confidential
*/
#import "js_schema.hpp"
#import "object_store.hpp"
#include "js_schema.hpp"
#include "object_store.hpp"
namespace realm {
struct SchemaWrapper {

View File

@ -2,8 +2,10 @@
* Proprietary and Confidential
*/
#import "js_util.hpp"
#import <map>
#pragma once
#include "js_util.hpp"
#include <map>
namespace realm {
class Schema;

View File

@ -2,7 +2,8 @@
* Proprietary and Confidential
*/
#import "js_util.hpp"
#include "js_util.hpp"
#include <JavaScriptCore/JSStringRef.h>
using namespace realm;
@ -32,7 +33,7 @@ std::string RJSStringForJSString(JSStringRef jsString) {
}
std::string RJSStringForValue(JSContextRef ctx, JSValueRef value) {
JSValueRef exception = NULL;
JSValueRef exception = nullptr;
JSStringRef jsString = JSValueToStringCopy(ctx, value, &exception);
if (!jsString) {
throw RJSException(ctx, exception);

View File

@ -2,12 +2,22 @@
* Proprietary and Confidential
*/
#include <JavaScriptCore/JavaScriptCore.h>
#pragma once
#include <JavaScriptCore/JSContextRef.h>
#include <JavaScriptCore/JSObjectRef.h>
#include <JavaScriptCore/JSStringRef.h>
#include <math.h>
#include <string>
#include <sstream>
#include <stdexcept>
#include <cmath>
#include "property.hpp"
#include "schema.hpp"
template<typename T>
inline void RJSFinalize(JSObjectRef object) {
delete static_cast<T>(JSObjectGetPrivate(object));
@ -173,8 +183,19 @@ static inline size_t RJSValidatedListLength(JSContextRef ctx, JSObjectRef object
return RJSValidatedValueToNumber(ctx, lengthValue);
}
template<typename T>
T stot(const std::string s) {
std::istringstream iss(s);
T value;
iss >> value;
if (iss.fail()) {
throw std::invalid_argument("Cannot convert string '" + s + "'");
}
return value;
}
static inline size_t RJSValidatedPositiveIndex(std::string indexStr) {
long index = std::stol(indexStr);
long index = stot<long>(indexStr);
if (index < 0) {
throw std::out_of_range(std::string("Index ") + indexStr + " cannot be less than zero.");
}

View File

@ -0,0 +1,15 @@
# Realm Object Store
Cross-platform code used accross bindings. Binding developers can choose to use some or all the included functionality
- `object_store`/`schema`/`object_schema`/`property` - contains the structures and logic used to setup and modify realm files and their schema.
- `shared_realm` - wraps the object_store apis to provide transactions, notifications, realm caching, migrations, and other higher level functionality.
- `object_accessor`/`results`/`list` - accessor classes, object creation/update pipeline, and helpers for creating platform specific property getters and setters.
- `parser`/`query_builder` - cross platform query parser and query builder - requires and object_accessor specialization for argument support. Depends on https://github.com/ColinH/PEGTL
## Building
TBD
## Testing
TBD

View File

@ -293,10 +293,12 @@ public:
// Things that just mark the field as modified
bool set_int(size_t col, size_t row, int_fast64_t) { return mark_dirty(row, col); }
bool set_int_unique(size_t col, size_t row, int_fast64_t) { return mark_dirty(row, col); }
bool set_bool(size_t col, size_t row, bool) { return mark_dirty(row, col); }
bool set_float(size_t col, size_t row, float) { return mark_dirty(row, col); }
bool set_double(size_t col, size_t row, double) { return mark_dirty(row, col); }
bool set_string(size_t col, size_t row, StringData) { return mark_dirty(row, col); }
bool set_string_unique(size_t col, size_t row, StringData) { return mark_dirty(row, col); }
bool set_binary(size_t col, size_t row, BinaryData) { return mark_dirty(row, col); }
bool set_date_time(size_t col, size_t row, DateTime) { return mark_dirty(row, col); }
bool set_table(size_t col, size_t row) { return mark_dirty(row, col); }
@ -304,8 +306,6 @@ public:
bool set_link(size_t col, size_t row, size_t, size_t) { return mark_dirty(row, col); }
bool set_null(size_t col, size_t row) { return mark_dirty(row, col); }
bool nullify_link(size_t col, size_t row, size_t) { return mark_dirty(row, col); }
bool set_int_unique(size_t col, size_t row, int_fast64_t) { return mark_dirty(row, col); }
bool set_string_unique(size_t col, size_t row, StringData) { return mark_dirty(row, col); }
// Doesn't change any data
bool optimize_table() { return true; }

View File

@ -21,6 +21,7 @@
#include <cstdlib>
#include <vector>
#include <stddef.h>
namespace realm {
class IndexSet {

View File

@ -68,7 +68,7 @@ Query List::get_query() {
void List::verify_valid_row(std::size_t row_ndx, bool insertion) {
size_t size = m_link_view->size();
if (row_ndx > size || (!insertion && row_ndx == size)) {
throw std::out_of_range(std::string("Index ") + std::to_string(row_ndx) + " is outside of range 0..." + std::to_string(size) + ".");
throw std::out_of_range(std::string("Index ") + to_string(row_ndx) + " is outside of range 0..." + to_string(size) + ".");
}
}

View File

@ -520,7 +520,7 @@ bool ObjectStore::is_empty(const Group *group) {
InvalidSchemaVersionException::InvalidSchemaVersionException(uint64_t old_version, uint64_t new_version) :
m_old_version(old_version), m_new_version(new_version)
{
m_what = "Provided schema version " + std::to_string(old_version) + " is less than last set version " + std::to_string(new_version) + ".";
m_what = "Provided schema version " + to_string(old_version) + " is less than last set version " + to_string(new_version) + ".";
}
DuplicatePrimaryKeyValueException::DuplicatePrimaryKeyValueException(std::string const& object_type, Property const& property) :
@ -589,7 +589,7 @@ MismatchedPropertiesException::MismatchedPropertiesException(std::string const&
m_what = "Target object type for property '" + old_property.name + "' do not match. Old type '" + old_property.object_type + "', new type '" + new_property.object_type + "'";
}
else if (new_property.is_nullable != old_property.is_nullable) {
m_what = "Nullability for property '" + old_property.name + "' has changed from '" + std::to_string(old_property.is_nullable) + "' to '" + std::to_string(new_property.is_nullable) + "'.";
m_what = "Nullability for property '" + old_property.name + "' has changed from '" + to_string(old_property.is_nullable) + "' to '" + to_string(new_property.is_nullable) + "'.";
}
}

View File

@ -27,6 +27,8 @@
#include <realm/group.hpp>
#include <realm/link_view.hpp>
#include <sstream>
namespace realm {
class ObjectSchemaValidationException;
class Schema;
@ -233,6 +235,13 @@ namespace realm {
private:
std::string m_primary_key;
};
template<typename T>
std::string to_string(T value) {
std::ostringstream oss;
oss << value;
return oss.str();
}
}
#endif /* defined(REALM_OBJECT_STORE_HPP) */

View File

@ -227,7 +227,7 @@ template<> struct action< or_op >
template<> struct action< rule > { \
static void apply( const input & in, ParserState & state ) { \
DEBUG_PRINT_TOKEN(in.string()); \
state.add_expression(Expression{type, in.string()}); }};
state.add_expression(Expression(type, in.string())); }};
EXPRESSION_ACTION(dq_string_content, Expression::Type::String)
EXPRESSION_ACTION(sq_string_content, Expression::Type::String)
@ -334,7 +334,7 @@ Predicate parse(const std::string &query)
return std::move(out_predicate);
}
void analyzeGrammar()
void analyze_grammar()
{
analyze<pred>();
}

View File

@ -30,6 +30,7 @@ struct Expression
{
enum class Type { None, Number, String, KeyPath, Argument, True, False } type = Type::None;
std::string s;
Expression(Type t = Type::None, std::string s = "") : type(t), s(s) {}
};
struct Predicate
@ -78,8 +79,8 @@ struct Predicate
Predicate parse(const std::string &query);
void analyzeGrammar();
bool testGrammar();
void analyze_grammar();
bool test_grammar();
}
}

View File

@ -29,28 +29,41 @@ namespace realm {
namespace query_builder {
using namespace parser;
template<typename T>
T stot(const std::string s) {
std::istringstream iss(s);
T value;
iss >> value;
if (iss.fail()) {
throw std::invalid_argument("Cannot convert string '" + s + "'");
}
return value;
}
// check a precondition and throw an exception if it is not met
// this should be used iff the condition being false indicates a bug in the caller
// of the function checking its preconditions
#define precondition(condition, message) if (!__builtin_expect(condition, 1)) { throw std::runtime_error(message); }
// FIXME: TrueExpression and FalseExpression should be supported by core in some way
struct TrueExpression : realm::Expression {
size_t find_first(size_t start, size_t end) const override
class TrueExpression : public realm::Expression {
public:
virtual size_t find_first(size_t start, size_t end) const
{
if (start != end)
return start;
return not_found;
}
void set_table() override {}
const Table* get_table() const override { return nullptr; }
virtual void set_table(const Table* table) {}
virtual const Table* get_table() const { return nullptr; }
};
struct FalseExpression : realm::Expression {
size_t find_first(size_t, size_t) const override { return not_found; }
void set_table() override {}
const Table* get_table() const override { return nullptr; }
class FalseExpression : public realm::Expression {
public:
virtual size_t find_first(size_t, size_t) const { return not_found; }
virtual void set_table(const Table* table) {}
virtual const Table* get_table() const { return nullptr; }
};
using KeyPath = std::vector<std::string>;
@ -262,12 +275,12 @@ void add_link_constraint_to_query(realm::Query &query,
auto link_argument(const PropertyExpression &propExpr, const parser::Expression &argExpr, Arguments &args)
{
return args.object_index_for_argument(std::stoi(argExpr.s));
return args.object_index_for_argument(stot<int>(argExpr.s));
}
auto link_argument(const parser::Expression &argExpr, const PropertyExpression &propExpr, Arguments &args)
{
return args.object_index_for_argument(std::stoi(argExpr.s));
return args.object_index_for_argument(stot<int>(argExpr.s));
}
@ -289,7 +302,7 @@ struct ValueGetter<DateTime, TableGetter> {
if (value.type != parser::Expression::Type::Argument) {
throw std::runtime_error("You must pass in a date argument to compare");
}
DateTime dt = args.datetime_for_argument(std::stoi(value.s));
DateTime dt = args.datetime_for_argument(stot<int>(value.s));
return dt.get_datetime();
}
};
@ -299,7 +312,7 @@ struct ValueGetter<bool, TableGetter> {
static bool convert(TableGetter&&, const parser::Expression & value, Arguments &args)
{
if (value.type == parser::Expression::Type::Argument) {
return args.bool_for_argument(std::stoi(value.s));
return args.bool_for_argument(stot<int>(value.s));
}
if (value.type != parser::Expression::Type::True && value.type != parser::Expression::Type::False) {
throw std::runtime_error("Attempting to compare bool property to a non-bool value");
@ -313,9 +326,9 @@ struct ValueGetter<Double, TableGetter> {
static Double convert(TableGetter&&, const parser::Expression & value, Arguments &args)
{
if (value.type == parser::Expression::Type::Argument) {
return args.double_for_argument(std::stoi(value.s));
return args.double_for_argument(stot<int>(value.s));
}
return std::stod(value.s);
return stot<double>(value.s);
}
};
@ -324,9 +337,9 @@ struct ValueGetter<Float, TableGetter> {
static Float convert(TableGetter&&, const parser::Expression & value, Arguments &args)
{
if (value.type == parser::Expression::Type::Argument) {
return args.float_for_argument(std::stoi(value.s));
return args.float_for_argument(stot<int>(value.s));
}
return std::stof(value.s);
return stot<float>(value.s);
}
};
@ -335,9 +348,9 @@ struct ValueGetter<Int, TableGetter> {
static Int convert(TableGetter&&, const parser::Expression & value, Arguments &args)
{
if (value.type == parser::Expression::Type::Argument) {
return args.long_for_argument(std::stoi(value.s));
return args.long_for_argument(stot<int>(value.s));
}
return std::stoll(value.s);
return stot<long long>(value.s);
}
};
@ -346,7 +359,7 @@ struct ValueGetter<String, TableGetter> {
static std::string convert(TableGetter&&, const parser::Expression & value, Arguments &args)
{
if (value.type == parser::Expression::Type::Argument) {
return args.string_for_argument(std::stoi(value.s));
return args.string_for_argument(stot<int>(value.s));
}
if (value.type != parser::Expression::Type::String) {
throw std::runtime_error("Attempting to compare String property to a non-String value");
@ -360,7 +373,7 @@ struct ValueGetter<Binary, TableGetter> {
static std::string convert(TableGetter&&, const parser::Expression & value, Arguments &args)
{
if (value.type == parser::Expression::Type::Argument) {
return args.binary_for_argument(std::stoi(value.s));
return args.binary_for_argument(stot<int>(value.s));
}
throw std::runtime_error("Binary properties must be compared against a binary argument.");
}
@ -371,7 +384,7 @@ auto value_of_type_for_query(TableGetter&& tables, Value&& value, Arguments &arg
{
const bool isColumn = std::is_same<PropertyExpression, typename std::remove_reference<Value>::type>::value;
using helper = std::conditional_t<isColumn, ColumnGetter<RetType, TableGetter>, ValueGetter<RetType, TableGetter>>;
return helper::convert(std::forward<TableGetter>(tables), std::forward<Value>(value), args);
return helper::convert(tables, value, args);
}
template <typename A, typename B>

View File

@ -69,7 +69,7 @@ class ArgumentConverter : public Arguments
ValueType &argument_at(size_t index) {
if (index >= m_arguments.size()) {
throw std::out_of_range((std::string)"Argument index " + std::to_string(index) + " out of range 0.." + std::to_string(m_arguments.size()-1));
throw std::out_of_range((std::string)"Argument index " + to_string(index) + " out of range 0.." + to_string(m_arguments.size()-1));
}
return m_arguments[index];
}

View File

@ -134,7 +134,7 @@ static std::vector<std::string> invalid_queries = {
namespace realm {
namespace parser {
bool testGrammar()
bool test_grammar()
{
bool success = true;
for (auto &query : valid_queries) {

View File

@ -36,19 +36,19 @@ using namespace realm;
Results::Results(SharedRealm r, const ObjectSchema &o, Query q, SortOrder s)
: m_realm(std::move(r))
, m_object_schema(&o)
, m_query(std::move(q))
, m_table(m_query.get_table().get())
, m_sort(std::move(s))
, m_mode(Mode::Query)
, m_object_schema(&o)
{
}
Results::Results(SharedRealm r, const ObjectSchema &o, Table& table)
: m_realm(std::move(r))
, m_object_schema(&o)
, m_table(&table)
, m_mode(Mode::Table)
, m_object_schema(&o)
{
}

View File

@ -135,9 +135,10 @@ public:
// The input index parameter was out of bounds
struct OutOfBoundsIndexException : public std::out_of_range
{
OutOfBoundsIndexException(size_t r, size_t c) : requested(r), valid_count(c),
std::out_of_range((std::string)"Requested index " + std::to_string(r) +
" greater than max " + std::to_string(c)) {}
OutOfBoundsIndexException(size_t r, size_t c) :
std::out_of_range((std::string)"Requested index " + to_string(r) +
" greater than max " + to_string(c)),
requested(r), valid_count(c) {}
const size_t requested;
const size_t valid_count;
};
@ -150,7 +151,7 @@ public:
// The input Row object belongs to a different table
struct IncorrectTableException : public std::runtime_error {
IncorrectTableException(StringData e, StringData a, const std::string &error) :
expected(e), actual(a), std::runtime_error(error) {}
std::runtime_error(error), expected(e), actual(a) {}
const StringData expected;
const StringData actual;
};

View File

@ -21,6 +21,7 @@
#include <string>
#include <vector>
#include <string>
namespace realm {
class ObjectSchema;

View File

@ -18,10 +18,13 @@
#include "shared_realm.hpp"
#if __APPLE__
#include "external_commit_helper.hpp"
#endif
#include "binding_context.hpp"
#include "schema.hpp"
#include "transact_log_handler.hpp"
#include "impl/transact_log_handler.hpp"
#include <realm/commit_log.hpp>
#include <realm/group_shared.hpp>
@ -84,6 +87,10 @@ Realm::Realm(Config config)
throw RealmFileException(RealmFileException::Kind::Exists, ex.get_path(),
"File at path '" + ex.get_path() + "' already exists.");
}
catch (util::File::NotFound const& ex) {
throw RealmFileException(RealmFileException::Kind::NotFound, ex.get_path(),
"File at path '" + ex.get_path() + "' does not exist.");
}
catch (util::File::AccessError const& ex) {
throw RealmFileException(RealmFileException::Kind::AccessError, ex.get_path(),
"Unable to open a realm at path '" + ex.get_path() + "'");
@ -101,9 +108,11 @@ Realm::Realm(Config config)
}
Realm::~Realm() {
#if __APPLE__
if (m_notifier) { // might not exist yet if an error occurred during init
m_notifier->remove_realm(this);
}
#endif
}
Group *Realm::read_group()
@ -154,11 +163,15 @@ SharedRealm Realm::get_shared_realm(Config config)
// FIXME - need to validate that schemas match
realm->m_config.schema = std::make_unique<Schema>(*existing->m_config.schema);
#if __APPLE__
realm->m_notifier = existing->m_notifier;
realm->m_notifier->add_realm(realm.get());
#endif
}
else {
#if __APPLE__
realm->m_notifier = std::make_shared<ExternalCommitHelper>(realm.get());
#endif
// otherwise get the schema from the group
realm->m_config.schema = std::make_unique<Schema>(ObjectStore::schema_from_group(realm->read_group()));
@ -290,7 +303,9 @@ void Realm::commit_transaction()
m_in_transaction = false;
transaction::commit(*m_shared_group, *m_history, m_binding_context.get());
#if __APPLE__
m_notifier->notify_others();
#endif
}
void Realm::cancel_transaction()
@ -398,15 +413,17 @@ uint64_t Realm::get_schema_version(const realm::Realm::Config &config)
void Realm::close()
{
#if __APPLE__
if (m_notifier) {
m_notifier->remove_realm(this);
}
m_notifier = nullptr;
#endif
m_group = nullptr;
m_shared_group = nullptr;
m_history = nullptr;
m_read_only_group = nullptr;
m_notifier = nullptr;
m_binding_context = nullptr;
}

View File

@ -25,6 +25,7 @@
#include <mutex>
#include <thread>
#include <vector>
#include <mutex>
namespace realm {
class ClientHistory;
@ -124,7 +125,9 @@ namespace realm {
Group *m_group = nullptr;
#if __APPLE__
std::shared_ptr<_impl::ExternalCommitHelper> m_notifier;
#endif
public:
std::unique_ptr<BindingContext> m_binding_context;

View File

@ -1,29 +1,29 @@
/* Copyright 2015 Realm Inc - All Rights Reserved
/* Copyright 2016 Realm Inc - All Rights Reserved
* Proprietary and Confidential
*/
#ifndef REALM_PLATFORM_HPP
#define REALM_PLATFORM_HPP
#pragma once
#include <string>
namespace realm {
extern std::string s_default_realm_directory;
namespace realm {
//
// These methods are used internally and must be implemented
// separately for eadh platform
// separately for each platform
//
// set the directory where realm files should be stored
void set_default_realm_file_directory(std::string dir);
// return the directory in which realm files can/should be written to
std::string default_realm_file_directory();
// create the directories for the given filename
void ensure_directory_exists_for_file(const std::string &file);
// remoave all realm files in the given directory
// remove all realm files in the given directory
void remove_realm_files_from_directory(const std::string &directory);
}
#endif /* REALM_PLATFORM_HPP */

View File

@ -2,7 +2,7 @@
* Proprietary and Confidential
*/
#import "rpc.hpp"
#include "rpc.hpp"
#include <dlfcn.h>
#include <map>
@ -18,6 +18,7 @@
#include "object_accessor.hpp"
#include "shared_realm.hpp"
#include "results.hpp"
#include <cassert>
using RJSAccessor = realm::NativeAccessor<JSValueRef, JSContextRef>;
using namespace realm_js;

View File

@ -4,8 +4,8 @@
#pragma once
#import "json.hpp"
#import <JavaScriptCore/JavaScriptCore.h>
#include "json.hpp"
#include <JavaScriptCore/JSBase.h>
namespace realm {
class ObjectSchema;

View File

@ -12,8 +12,8 @@
@implementation GrammerTests
- (void)testGrammer {
realm::parser::analyzeGrammar();
XCTAssertTrue(realm::parser::testGrammar());
realm::parser::analyze_grammar();
XCTAssertTrue(realm::parser::test_grammar());
}
@end

View File

@ -62,7 +62,8 @@ function runQuerySuite(suite) {
return args;
}
for (var test of suite.tests) {
for (var index in suite.tests) {
var test = suite.tests[index];
if (test[0] == "QueryCount") {
var length = realm.objects.apply(realm, getArgs(2)).length;
TestCase.assertEqual(test[1], length, "Query '" + args[1] + "' on type '" + args[0] + "' expected " + test[1] + " results, got " + length);

View File

@ -95,9 +95,8 @@ module.exports = BaseTest.extend({
var newPath = util.realmPathForFile('default2.realm');
Realm.defaultPath = newPath;
defaultRealm = new Realm({schema: []});
TestCase.assertEqual(defaultRealm.path, newPath);
TestCase.assertEqual(Realm.defaultPath, newPath);
TestCase.assertEqual(defaultRealm.path, newPath, "should use updated default realm path");
TestCase.assertEqual(Realm.defaultPath, newPath, "defaultPath should have been updated");
},
testRealmCreate: function() {

View File

@ -1,3 +1,4 @@
apply plugin: 'android-sdk-manager'
apply plugin: "com.android.application"
/**
@ -54,7 +55,7 @@ android {
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.reacttests"
applicationId "io.realm.react.testapp"
minSdkVersion 16
targetSdkVersion 22
versionCode 1
@ -72,7 +73,8 @@ android {
}
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:0.14.+"
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.facebook.react:react-native:0.18.0'
compile project(':realm')
compile project(':react-native-fs')
}

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Wed Oct 21 11:34:03 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip

160
tests/react-test-app/android/app/gradlew vendored Executable file
View File

@ -0,0 +1,160 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

Some files were not shown because too many files have changed in this diff Show More