Merge branch 'master' into fix/tutorialNote

This commit is contained in:
astroshim 2016-12-21 16:00:45 +09:00
commit eca8026471
39 changed files with 447 additions and 301 deletions

View file

@ -25,11 +25,11 @@ bower.json
In the override section at the bottom, include the Highlightjs stylesheet (eg. styles/github.css)
For the selected Ace Editor theme script, include it in the override section. (eg. src-noconflict/theme-github.js)
(bower will automatically add the appropriate .js and .css in app/index.html)
```
```diff
"src-noconflict/mode-sql.js",
"src-noconflict/mode-markdown.js",
"src-noconflict/keybinding-emacs.js",
"src-noconflict/ext-language_tools.js",
"src-noconflict/ext-language_tools.js",
+ "src-noconflict/theme-github.js"],
"version": "1.1.8",
"name": "ace-builds"
@ -48,13 +48,13 @@ Highlight.js style - depends on the style, a few themes have jpg - if so, one mu
### Example - change Ace Editor theme to monokai
app/scripts/controllers/paragraph.js
```
```diff
- $scope.editor.setTheme('ace/theme/github');
+ $scope.editor.setTheme('ace/theme/monokai');
```
bower.json
```
```diff
- "src-noconflict/theme-github.js"],
+ "src-noconflict/theme-monokai.js"],
```

View file

@ -84,9 +84,4 @@ if not exist %ZEPPELIN_PID_DIR% (
mkdir "%ZEPPELIN_PID_DIR%"
)
if not exist %ZEPPELIN_NOTEBOOK_DIR% (
echo Notebook dir doesn't exist, create %ZEPPELIN_NOTEBOOK_DIR%
mkdir "%ZEPPELIN_NOTEBOOK_DIR%"
)
"%ZEPPELIN_RUNNER%" %JAVA_OPTS% -cp %CLASSPATH% %ZEPPELIN_SERVER% "%*"

View file

@ -83,9 +83,4 @@ if [[ ! -d "${ZEPPELIN_PID_DIR}" ]]; then
$(mkdir -p "${ZEPPELIN_PID_DIR}")
fi
if [[ ! -d "${ZEPPELIN_NOTEBOOK_DIR}" ]]; then
echo "Pid dir doesn't exist, create ${ZEPPELIN_NOTEBOOK_DIR}"
$(mkdir -p "${ZEPPELIN_NOTEBOOK_DIR}")
fi
exec $ZEPPELIN_RUNNER $JAVA_OPTS -cp $ZEPPELIN_CLASSPATH_OVERRIDES:$CLASSPATH $ZEPPELIN_SERVER "$@"

View file

@ -47,6 +47,7 @@
<!--<li><a href="{{BASE_PATH}}/manual/dynamicinterpreterload.html">Dynamic Interpreter Loading</a></li>-->
<li><a href="{{BASE_PATH}}/manual/dependencymanagement.html">Interpreter Dependency Management</a></li>
<li><a href="{{BASE_PATH}}/manual/userimpersonation.html">Interpreter User Impersonation</a></li>
<li><a href="{{BASE_PATH}}/manual/interpreterexechooks.html">Interpreter Execution Hooks (Experimental)</a></li>
<li role="separator" class="divider"></li>
<li class="title"><span><b>Available Interpreters</b><span></li>
<li><a href="{{BASE_PATH}}/interpreter/alluxio.html">Alluxio</a></li>

View file

@ -143,6 +143,7 @@ Join to our [Mailing list](https://zeppelin.apache.org/community.html) and repor
* [Interpreter Installation](./manual/interpreterinstallation.html): Install not only community managed interpreters but also 3rd party interpreters
* [Interpreter Dependency Management](./manual/dependencymanagement.html) when you include external libraries to interpreter
* [Interpreter User Impersonation](./manual/userimpersonation.html) when you want to run interpreter as end user
* [Interpreter Execution Hooks](./manual/interpreterexechooks.html) to specify additional code to be executed by an interpreter at pre and post-paragraph code execution
* Available Interpreters: currently, about 20 interpreters are available in Apache Zeppelin.
####Display System

View file

@ -63,7 +63,7 @@ wget http://www.gutenberg.org/ebooks/10.txt.utf-8
{% highlight scala %}
%flink
case class WordCount(word: String, frequency: Int)
val bible:DataSet[String] = env.readTextFile("10.txt.utf-8")
val bible:DataSet[String] = benv.readTextFile("10.txt.utf-8")
val partialCounts: DataSet[WordCount] = bible.flatMap{
line =>
"""\b\w+\b""".r.findAllIn(line).map(word => WordCount(word, 1))

View file

@ -0,0 +1,81 @@
---
layout: page
title: "Interpreter Execution Hooks (Experimental)"
description: "Apache Zeppelin allows for users to specify additional code to be executed by an interpreter at pre and post-paragraph code execution."
group: manual
---
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
{% include JB/setup %}
# Interpreter Execution Hooks (Experimental)
<div id="toc"></div>
## Overview
Apache Zeppelin allows for users to specify additional code to be executed by an interpreter at pre and post-paragraph code execution.
This is primarily useful if you need to run the same set of code for all of the paragraphs within your notebook at specific times.
Currently, this feature is only available for the spark and pyspark interpreters.
To specify your hook code, you may use `z.registerHook()`.
For example, enter the following into one paragraph:
```python
%pyspark
z.registerHook("post_exec", "print 'This code should be executed before the parapgraph code!'")
z.registerHook("pre_exec", "print 'This code should be executed after the paragraph code!'")
```
These calls will not take into effect until the next time you run a paragraph.
In another paragraph, enter
```python
%pyspark
print "This code should be entered into the paragraph by the user!"
```
The output should be:
```
This code should be executed before the paragraph code!
This code should be entered into the paragraph by the user!
This code should be executed after the paragraph code!
```
If you ever need to know the hook code, use `z.getHook()`:
```python
%pyspark
print z.getHook("post_exec")
print 'This code should be executed after the paragraph code!'
```
Any call to `z.registerHook()` will automatically overwrite what was previously registered.
To completely unregister a hook event, use `z.unregisterHook(eventCode)`.
Currently only `"post_exec"` and `"pre_exec"` are valid event codes for the Zeppelin Hook Registry system.
Finally, the hook registry is internally shared by other interpreters in the same group.
This would allow for hook code for one interpreter REPL to be set by another as follows:
```scala
%spark
z.unregisterHook("post_exec", "pyspark")
```
The API is identical for both the spark (scala) and pyspark (python) implementations.
### Caveats
Calls to `z.registerHook("pre_exec", ...)` should be made with care. If there are errors in your specified hook code, this will cause the interpreter REPL to become unable to execute any code pass the pre-execute stage making it impossible for direct calls to `z.unregisterHook()` to take into effect. Current workarounds include calling `z.unregisterHook()` from a different interpreter REPL in the same interpreter group (see above) or manually restarting the interpreter group in the UI.

View file

@ -82,49 +82,3 @@ interpreter.start()
The above code will start interpreter thread inside your process. Once the interpreter is started you can configure zeppelin to connect to RemoteInterpreter by checking **Connect to existing process** checkbox and then provide **Host** and **Port** on which interpreter process is listening as shown in the image below:
<img src="../assets/themes/zeppelin/img/screenshots/existing_interpreter.png" width="450px">
## (Experimental) Interpreter Execution Hooks
Zeppelin allows for users to specify additional code to be executed by an interpreter at pre and post-paragraph code execution. This is primarily useful if you need to run the same set of code for all of the paragraphs within your notebook at specific times. Currently, this feature is only available for the spark and pyspark interpreters. To specify your hook code, you may use '`z.registerHook()`. For example, enter the following into one paragraph:
```python
%pyspark
z.registerHook("post_exec", "print 'This code should be executed before the parapgraph code!'")
z.registerHook("pre_exec", "print 'This code should be executed after the paragraph code!'")
```
These calls will not take into effect until the next time you run a paragraph. In another paragraph, enter
```python
%pyspark
print "This code should be entered into the paragraph by the user!"
```
The output should be:
```
This code should be executed before the paragraph code!
This code should be entered into the paragraph by the user!
This code should be executed after the paragraph code!
```
If you ever need to know the hook code, use `z.getHook()`:
```python
%pyspark
print z.getHook("post_exec")
```
```
print 'This code should be executed after the paragraph code!'
```
Any call to `z.registerHook()` will automatically overwrite what was previously registered. To completely unregister a hook event, use `z.unregisterHook(eventCode)`. Currently only `"post_exec"` and `"pre_exec"` are valid event codes for the Zeppelin Hook Registry system.
Finally, the hook registry is internally shared by other interpreters in the same group. This would allow for hook code for one interpreter REPL to be set by another as follows:
```scala
%spark
z.unregisterHook("post_exec", "pyspark")
```
The API is identical for both the spark (scala) and pyspark (python) implementations.
### Caveats
Calls to `z.registerHook("pre_exec", ...)` should be made with care. If there are errors in your specified hook code, this will cause the interpreter REPL to become unable to execute any code pass the pre-execute stage making it impossible for direct calls to `z.unregisterHook()` to take into effect. Current workarounds include calling `z.unregisterHook()` from a different interpreter REPL in the same interpreter group (see above) or manually restarting the interpreter group in the UI.

View file

@ -118,14 +118,16 @@ cd zeppelin
Package Zeppelin.
```
mvn clean package -DskipTests -Pspark-1.6 -Dflink.version=1.1.2
mvn clean package -DskipTests -Pspark-1.6 -Dflink.version=1.1.3 -Pscala-2.10
```
`-DskipTests` skips build tests- you're not developing (yet), so you don't need to do tests, the clone version *should* build.
`-Pspark-1.6` tells maven to build a Zeppelin with Spark 1.6. This is important because Zeppelin has its own Spark interpreter and the versions must be the same.
`-Dflink.version=1.1.2` tells maven specifically to build Zeppelin with Flink version 1.1.2.
`-Dflink.version=1.1.3` tells maven specifically to build Zeppelin with Flink version 1.1.3.
-`-Pscala-2.10` tells maven to build with Scala v2.10.
**Note:** You may wish to include additional build flags such as `-Ppyspark` or `-Psparkr`. See [the build section of github for more details](https://github.com/apache/zeppelin#build).
@ -162,7 +164,7 @@ Create a new notebook named "Flink Test" and copy and paste the following code.
%flink // let Zeppelin know what interpreter to use.
val text = env.fromElements("In the time of chimpanzees, I was a monkey", // some lines of text to analyze
val text = benv.fromElements("In the time of chimpanzees, I was a monkey", // some lines of text to analyze
"Butane in my veins and I'm out to cut the junkie",
"With the plastic eyeballs, spray paint the vegetables",
"Dog food stalls with the beefcake pantyhose",
@ -252,16 +254,16 @@ Building from source is recommended where possible, for simplicity in this tuto
To download the Flink Binary use `wget`
```bash
wget "http://mirror.cogentco.com/pub/apache/flink/flink-1.0.3/flink-1.0.3-bin-hadoop24-scala_2.10.tgz"
tar -xzvf flink-1.0.3-bin-hadoop24-scala_2.10.tgz
wget "http://mirror.cogentco.com/pub/apache/flink/flink-1.1.3/flink-1.1.3-bin-hadoop24-scala_2.10.tgz"
tar -xzvf flink-1.1.3-bin-hadoop24-scala_2.10.tgz
```
This will download Flink 1.0.3, compatible with Hadoop 2.4. You do not have to install Hadoop for this binary to work, but if you are using Hadoop, please change `24` to your appropriate version.
This will download Flink 1.1.3, compatible with Hadoop 2.4. You do not have to install Hadoop for this binary to work, but if you are using Hadoop, please change `24` to your appropriate version.
Start the Flink Cluster.
```bash
flink-1.0.3/bin/start-cluster.sh
flink-1.1.3/bin/start-cluster.sh
```
###### Building From source
@ -270,13 +272,13 @@ If you wish to build Flink from source, the following will be instructive. Note
See the [Flink Installation guide](https://github.com/apache/flink/blob/master/README.md) for more detailed instructions.
Return to the directory where you have been downloading, this tutorial assumes that is `$HOME`. Clone Flink, check out release-1.0, and build.
Return to the directory where you have been downloading, this tutorial assumes that is `$HOME`. Clone Flink, check out release-1.1.3-rc2, and build.
```
cd $HOME
git clone https://github.com/apache/flink.git
cd flink
git checkout release-1.0
git checkout release-1.1.3-rc2
mvn clean install -DskipTests
```
@ -297,8 +299,8 @@ If no task managers are present, restart the Flink cluster with the following co
(if binaries)
```
flink-1.0.3/bin/stop-cluster.sh
flink-1.0.3/bin/start-cluster.sh
flink-1.1.3/bin/stop-cluster.sh
flink-1.1.3/bin/start-cluster.sh
```
@ -320,12 +322,12 @@ Using binaries is also
To download the Spark Binary use `wget`
```bash
wget "http://mirrors.koehn.com/apache/spark/spark-1.6.1/spark-1.6.1-bin-hadoop2.4.tgz"
tar -xzvf spark-1.6.1-bin-hadoop2.4.tgz
mv spark-1.6.1-bin-hadoop4.4 spark
wget "http://d3kbcqa49mib13.cloudfront.net/spark-1.6.3-bin-hadoop2.6.tgz"
tar -xzvf spark-1.6.3-bin-hadoop2.6.tgz
mv spark-1.6.3-bin-hadoop2.6 spark
```
This will download Spark 1.6.1, compatible with Hadoop 2.4. You do not have to install Hadoop for this binary to work, but if you are using Hadoop, please change `2.4` to your appropriate version.
This will download Spark 1.6.3, compatible with Hadoop 2.6. You do not have to install Hadoop for this binary to work, but if you are using Hadoop, please change `2.6` to your appropriate version.
###### Building From source
@ -335,7 +337,7 @@ See the [Spark Installation](https://github.com/apache/spark/blob/master/README.
Return to the directory where you have been downloading, this tutorial assumes that is $HOME. Clone Spark, check out branch-1.6, and build.
**Note:** Recall, we're only checking out 1.6 because it is the most recent Spark for which a Zeppelin profile exists at
the time of writing. You are free to check out other version, just make sure you build Zeppelin against the correct version of Spark.
the time of writing. You are free to check out other version, just make sure you build Zeppelin against the correct version of Spark. However if you use Spark 2.0, the word count example will need to be changed as Spark 2.0 is not compatible with the following examples.
```

View file

@ -33,7 +33,7 @@
<name>Zeppelin: Elasticsearch interpreter</name>
<properties>
<elasticsearch.version>2.3.3</elasticsearch.version>
<elasticsearch.version>2.4.3</elasticsearch.version>
<guava.version>18.0</guava.version>
<json-flattener.version>0.1.6</json-flattener.version>
</properties>

View file

@ -35,6 +35,7 @@ private[scio] object DisplayHelpers {
private[scio] val tab = "\t"
private[scio] val newline = "\n"
private[scio] val table = "%table"
private[scio] val endTable = "%text"
private[scio] val rowLimitReachedMsg =
s"$newline<font color=red>Results are limited to " + maxResults + s" rows.</font>$newline"
private[scio] val bQSchemaIncomplete =
@ -52,6 +53,7 @@ private[scio] object DisplayHelpers {
println(sCollectionEmptyMsg)
} else {
println(s"$table value$newline${it.take(maxResults).map(printer).mkString(newline)}")
println(endTable)
notifyIfTruncated(it)
}
}
@ -64,6 +66,7 @@ private[scio] object DisplayHelpers {
println(sCollectionEmptyMsg)
} else {
println(s"$table value$newline${it.take(maxResults).map(printer).mkString(newline)}")
println(endTable)
notifyIfTruncated(it)
}
}
@ -77,6 +80,7 @@ private[scio] object DisplayHelpers {
} else {
val content = it.take(maxResults).map{ case (k, v) => s"$k$tab$v" }.mkString(newline)
println(s"$table key${tab}value$newline$content")
println(endTable)
notifyIfTruncated(it)
}
}
@ -97,6 +101,7 @@ private[scio] object DisplayHelpers {
val firstStr = first.productIterator.mkString(tab)
val content = it.take(maxResults - 1).map(_.productIterator.mkString(tab)).mkString(newline)
println(s"$table $header$newline$firstStr$newline$content")
println(endTable)
notifyIfTruncated(it)
}
}
@ -125,6 +130,7 @@ private[scio] object DisplayHelpers {
.map(r => fieldNames.map(r.get).mkString(tab))
.mkString(newline)
println(s"$table $header$newline$firstStr$newline$content")
println(endTable)
notifyIfTruncated(it)
}
}
@ -151,6 +157,7 @@ private[scio] object DisplayHelpers {
.mkString(newline)
println(s"$table $header$newline$content")
println(endTable)
notifyIfTruncated(it)
}
}

View file

@ -48,6 +48,7 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
// -----------------------------------------------------------------------------------------------
private val anyValHeader = s"$table value"
private val endTable = DisplayHelpers.endTable
"DisplayHelpers" should "support Integer SCollection via AnyVal" in {
import org.apache.zeppelin.scio.DisplaySCollectionImplicits.ZeppelinSCollection
@ -59,8 +60,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
o should contain theSameElementsAs Seq(anyValHeader,
"1",
"2",
"3")
"3",
endTable)
o.head should be(anyValHeader)
o.last should be(endTable)
}
it should "support Long SCollection via AnyVal" in {
@ -73,8 +76,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
o should contain theSameElementsAs Seq(anyValHeader,
"1",
"2",
"3")
"3",
endTable)
o.head should be(anyValHeader)
o.last should be(endTable)
}
it should "support Double SCollection via AnyVal" in {
@ -87,8 +92,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
o should contain theSameElementsAs Seq(anyValHeader,
"1.0",
"2.0",
"3.0")
"3.0",
endTable)
o.head should be(anyValHeader)
o.last should be(endTable)
}
it should "support Float SCollection via AnyVal" in {
@ -101,8 +108,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
o should contain theSameElementsAs Seq(anyValHeader,
"1.0",
"2.0",
"3.0")
"3.0",
endTable)
o.head should be(anyValHeader)
o.last should be(endTable)
}
it should "support Short SCollection via AnyVal" in {
@ -115,8 +124,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
o should contain theSameElementsAs Seq(anyValHeader,
"1",
"2",
"3")
"3",
endTable)
o.head should be(anyValHeader)
o.last should be(endTable)
}
it should "support Byte SCollection via AnyVal" in {
@ -129,8 +140,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
o should contain theSameElementsAs Seq(anyValHeader,
"1",
"2",
"3")
"3",
endTable)
o.head should be(anyValHeader)
o.last should be(endTable)
}
it should "support Boolean SCollection via AnyVal" in {
@ -143,8 +156,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
o should contain theSameElementsAs Seq(anyValHeader,
"true",
"false",
"true")
"true",
endTable)
o.head should be(anyValHeader)
o.last should be(endTable)
}
it should "support Char SCollection via AnyVal" in {
@ -157,8 +172,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
o should contain theSameElementsAs Seq(anyValHeader,
"a",
"b",
"c")
"c",
endTable)
o.head should be(anyValHeader)
o.last should be(endTable)
}
it should "support SCollection of AnyVal over row limit" in {
@ -199,8 +216,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
o should contain theSameElementsAs Seq(stringHeader,
"a",
"b",
"c")
"c",
endTable)
o.head should be (stringHeader)
o.last should be (endTable)
}
it should "support empty SCollection of String" in {
@ -240,8 +259,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
}
o should contain theSameElementsAs Seq(kvHeader,
s"3${tab}4",
s"1${tab}2")
s"1${tab}2",
endTable)
o.head should be (kvHeader)
o.last should be (endTable)
}
it should "support KV (str keys) SCollection" in {
@ -253,8 +274,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
}
o should contain theSameElementsAs Seq(kvHeader,
s"foo${tab}2",
s"bar${tab}4")
s"bar${tab}4",
endTable)
o.head should be (kvHeader)
o.last should be (endTable)
}
it should "support KV (str values) SCollection" in {
@ -266,8 +289,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
}
o should contain theSameElementsAs Seq(kvHeader,
s"2${tab}foo",
s"4${tab}bar")
s"4${tab}bar",
endTable)
o.head should be (kvHeader)
o.last should be (endTable)
}
it should "support empty KV SCollection" in {
@ -305,8 +330,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
in.closeAndDisplay()
}
}
o should contain theSameElementsAs (Seq(tupleHeader) ++ Seq.fill(3)(s"1${tab}2${tab}3"))
o should contain theSameElementsAs
(Seq(tupleHeader, endTable) ++ Seq.fill(3)(s"1${tab}2${tab}3"))
o.head should be(tupleHeader)
o.last should be (endTable)
}
it should "support SCollection of Tuple of 22" in {
@ -318,9 +345,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
in.closeAndDisplay()
}
}
o should contain theSameElementsAs (Seq(tupleHeader) ++
o should contain theSameElementsAs (Seq(tupleHeader, endTable) ++
Seq.fill(3)((1 to 21).map(i => s"$i$tab").mkString + "22"))
o.head should be(tupleHeader)
o.last should be (endTable)
}
it should "support SCollection of Case Class of 22" in {
@ -332,9 +360,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
in.closeAndDisplay()
}
}
o should contain theSameElementsAs (Seq(tupleHeader) ++
o should contain theSameElementsAs (Seq(tupleHeader, endTable) ++
Seq.fill(3)((1 to 21).map(i => s"$i$tab").mkString + "22"))
o.head should be(tupleHeader)
o.last should be (endTable)
}
it should "support SCollection of Case Class" in {
@ -344,9 +373,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
in.closeAndDisplay()
}
}
o should contain theSameElementsAs (Seq(testCaseClassHeader) ++
o should contain theSameElementsAs (Seq(testCaseClassHeader, endTable) ++
Seq.fill(3)(s"1${tab}foo${tab}2.0"))
o.head should be(testCaseClassHeader)
o.last should be (endTable)
}
it should "support empty SCollection of Product" in {
@ -423,9 +453,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
in.closeAndDisplay()
}
}
o should contain theSameElementsAs (Seq(avroGenericRecordHeader) ++
o should contain theSameElementsAs (Seq(avroGenericRecordHeader, endTable) ++
Seq.fill(3)(s"1${tab}1.0${tab}user1${tab}checking"))
o.head should be(avroGenericRecordHeader)
o.last should be (endTable)
}
it should "support SCollection of SpecificRecord Avro" in {
@ -436,9 +467,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
in.closeAndDisplay()
}
}
o should contain theSameElementsAs (Seq(avroAccountHeader) ++
o should contain theSameElementsAs (Seq(avroAccountHeader, endTable) ++
Seq.fill(3)(s"2${tab}checking${tab}user2${tab}2.0"))
o.head should be(avroAccountHeader)
o.last should be (endTable)
}
it should "support empty SCollection of SpecificRecord Avro" in {
@ -509,9 +541,10 @@ class DisplayHelpersTest extends FlatSpec with Matchers {
in.closeAndDisplay(bQSchema)
}
}
o should contain theSameElementsAs (Seq(bQHeader) ++
o should contain theSameElementsAs (Seq(bQHeader, endTable) ++
Seq.fill(3)(s"3${tab}3.0${tab}checking${tab}user3"))
o.head should be(bQHeader)
o.last should be (endTable)
}
it should "print error on empty BQ schema" in {

View file

@ -42,6 +42,7 @@ public class SparkRInterpreter extends Interpreter {
private static final Logger logger = LoggerFactory.getLogger(SparkRInterpreter.class);
private static String renderOptions;
private SparkInterpreter sparkInterpreter;
private ZeppelinR zeppelinR;
private SparkContext sc;
@ -70,7 +71,7 @@ public class SparkRInterpreter extends Interpreter {
int port = SparkRBackend.port();
SparkInterpreter sparkInterpreter = getSparkInterpreter();
this.sparkInterpreter = getSparkInterpreter();
this.sc = sparkInterpreter.getSparkContext();
SparkVersion sparkVersion = new SparkVersion(sc.version());
ZeppelinRContext.setSparkContext(sc);
@ -185,7 +186,11 @@ public class SparkRInterpreter extends Interpreter {
@Override
public int getProgress(InterpreterContext context) {
return 0;
if (sparkInterpreter != null) {
return sparkInterpreter.getProgress(context);
} else {
return 0;
}
}
@Override

View file

@ -16,20 +16,18 @@
*/
package org.apache.zeppelin.spark;
import org.apache.zeppelin.display.AngularObjectRegistry;
import org.apache.zeppelin.display.GUI;
import org.apache.zeppelin.interpreter.*;
import org.apache.zeppelin.interpreter.InterpreterResult.Type;
import org.apache.zeppelin.resource.LocalResourcePool;
import org.apache.zeppelin.user.AuthenticationInfo;
import org.junit.After;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.*;
import org.junit.rules.TemporaryFolder;
import org.junit.runners.MethodSorters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
@ -40,10 +38,13 @@ import static org.junit.Assert.*;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class PySparkInterpreterMatplotlibTest {
@Rule
public TemporaryFolder tmpDir = new TemporaryFolder();
public static SparkInterpreter sparkInterpreter;
public static PySparkInterpreter pyspark;
public static InterpreterGroup intpGroup;
private File tmpDir;
public static Logger LOGGER = LoggerFactory.getLogger(PySparkInterpreterTest.class);
private InterpreterContext context;
@ -79,7 +80,7 @@ public class PySparkInterpreterMatplotlibTest {
}
}
public static Properties getPySparkTestProperties() {
private Properties getPySparkTestProperties() throws IOException {
Properties p = new Properties();
p.setProperty("master", "local[*]");
p.setProperty("spark.app.name", "Zeppelin Test");
@ -87,6 +88,7 @@ public class PySparkInterpreterMatplotlibTest {
p.setProperty("zeppelin.spark.maxResult", "1000");
p.setProperty("zeppelin.spark.importImplicit", "true");
p.setProperty("zeppelin.pyspark.python", "python");
p.setProperty("zeppelin.dep.localrepo", tmpDir.newFolder().getAbsolutePath());
return p;
}
@ -106,10 +108,6 @@ public class PySparkInterpreterMatplotlibTest {
@Before
public void setUp() throws Exception {
tmpDir = new File(System.getProperty("java.io.tmpdir") + "/ZeppelinLTest_" + System.currentTimeMillis());
System.setProperty("zeppelin.dep.localrepo", tmpDir.getAbsolutePath() + "/local-repo");
tmpDir.mkdirs();
intpGroup = new InterpreterGroup();
intpGroup.put("note", new LinkedList<Interpreter>());
@ -137,24 +135,6 @@ public class PySparkInterpreterMatplotlibTest {
new InterpreterOutput(null));
}
@After
public void tearDown() throws Exception {
delete(tmpDir);
}
private void delete(File file) {
if (file.isFile()) file.delete();
else if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File f : files) {
delete(f);
}
}
file.delete();
}
}
@Test
public void dependenciesAreInstalled() {
// matplotlib

View file

@ -16,20 +16,22 @@
*/
package org.apache.zeppelin.spark;
import org.apache.zeppelin.display.AngularObjectRegistry;
import org.apache.zeppelin.display.GUI;
import org.apache.zeppelin.interpreter.*;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
import org.apache.zeppelin.resource.LocalResourcePool;
import org.apache.zeppelin.user.AuthenticationInfo;
import org.junit.After;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runners.MethodSorters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@ -39,14 +41,17 @@ import static org.junit.Assert.*;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class PySparkInterpreterTest {
@Rule
public TemporaryFolder tmpDir = new TemporaryFolder();
public static SparkInterpreter sparkInterpreter;
public static PySparkInterpreter pySparkInterpreter;
public static InterpreterGroup intpGroup;
private File tmpDir;
public static Logger LOGGER = LoggerFactory.getLogger(PySparkInterpreterTest.class);
private InterpreterContext context;
public static Properties getPySparkTestProperties() {
private Properties getPySparkTestProperties() throws IOException {
Properties p = new Properties();
p.setProperty("master", "local[*]");
p.setProperty("spark.app.name", "Zeppelin Test");
@ -54,6 +59,7 @@ public class PySparkInterpreterTest {
p.setProperty("zeppelin.spark.maxResult", "1000");
p.setProperty("zeppelin.spark.importImplicit", "true");
p.setProperty("zeppelin.pyspark.python", "python");
p.setProperty("zeppelin.dep.localrepo", tmpDir.newFolder().getAbsolutePath());
return p;
}
@ -73,10 +79,6 @@ public class PySparkInterpreterTest {
@Before
public void setUp() throws Exception {
tmpDir = new File(System.getProperty("java.io.tmpdir") + "/ZeppelinLTest_" + System.currentTimeMillis());
System.setProperty("zeppelin.dep.localrepo", tmpDir.getAbsolutePath() + "/local-repo");
tmpDir.mkdirs();
intpGroup = new InterpreterGroup();
intpGroup.put("note", new LinkedList<Interpreter>());
@ -104,24 +106,6 @@ public class PySparkInterpreterTest {
new InterpreterOutput(null));
}
@After
public void tearDown() throws Exception {
delete(tmpDir);
}
private void delete(File file) {
if (file.isFile()) file.delete();
else if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File f : files) {
delete(f);
}
}
file.delete();
}
}
@Test
public void testBasicIntp() {
if (getSparkVersionNumber() > 11) {

View file

@ -19,7 +19,7 @@ package org.apache.zeppelin.spark;
import static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@ -35,20 +35,24 @@ import org.apache.zeppelin.user.AuthenticationInfo;
import org.apache.zeppelin.display.GUI;
import org.apache.zeppelin.interpreter.*;
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
import org.junit.After;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runners.MethodSorters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SparkInterpreterTest {
@Rule
public TemporaryFolder tmpDir = new TemporaryFolder();
public static SparkInterpreter repl;
public static InterpreterGroup intpGroup;
private InterpreterContext context;
private File tmpDir;
public static Logger LOGGER = LoggerFactory.getLogger(SparkInterpreterTest.class);
/**
@ -65,28 +69,24 @@ public class SparkInterpreterTest {
return version;
}
public static Properties getSparkTestProperties() {
public static Properties getSparkTestProperties(TemporaryFolder tmpDir) throws IOException {
Properties p = new Properties();
p.setProperty("master", "local[*]");
p.setProperty("spark.app.name", "Zeppelin Test");
p.setProperty("zeppelin.spark.useHiveContext", "true");
p.setProperty("zeppelin.spark.maxResult", "1000");
p.setProperty("zeppelin.spark.importImplicit", "true");
p.setProperty("zeppelin.dep.localrepo", tmpDir.newFolder().getAbsolutePath());
return p;
}
@Before
public void setUp() throws Exception {
tmpDir = new File(System.getProperty("java.io.tmpdir") + "/ZeppelinLTest_" + System.currentTimeMillis());
System.setProperty("zeppelin.dep.localrepo", tmpDir.getAbsolutePath() + "/local-repo");
tmpDir.mkdirs();
if (repl == null) {
intpGroup = new InterpreterGroup();
intpGroup.put("note", new LinkedList<Interpreter>());
repl = new SparkInterpreter(getSparkTestProperties());
repl = new SparkInterpreter(getSparkTestProperties(tmpDir));
repl.setInterpreterGroup(intpGroup);
intpGroup.get("note").add(repl);
repl.open();
@ -102,24 +102,6 @@ public class SparkInterpreterTest {
new InterpreterOutput(null));
}
@After
public void tearDown() throws Exception {
delete(tmpDir);
}
private void delete(File file) {
if (file.isFile()) file.delete();
else if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File f : files) {
delete(f);
}
}
file.delete();
}
}
@Test
public void testBasicIntp() {
assertEquals(InterpreterResult.Code.SUCCESS,
@ -194,7 +176,7 @@ public class SparkInterpreterTest {
}
@Test
public void testSparkSql(){
public void testSparkSql() throws IOException {
repl.interpret("case class Person(name:String, age:Int)\n", context);
repl.interpret("val people = sc.parallelize(Seq(Person(\"moon\", 33), Person(\"jobs\", 51), Person(\"gates\", 51), Person(\"park\", 34)))\n", context);
assertEquals(Code.SUCCESS, repl.interpret("people.take(3)", context).code());
@ -202,7 +184,7 @@ public class SparkInterpreterTest {
if (getSparkVersionNumber() <= 11) { // spark 1.2 or later does not allow create multiple SparkContext in the same jvm by default.
// create new interpreter
SparkInterpreter repl2 = new SparkInterpreter(getSparkTestProperties());
SparkInterpreter repl2 = new SparkInterpreter(getSparkTestProperties(tmpDir));
repl2.setInterpreterGroup(intpGroup);
intpGroup.get("note").add(repl2);
repl2.open();
@ -236,9 +218,9 @@ public class SparkInterpreterTest {
}
@Test
public void shareSingleSparkContext() throws InterruptedException {
public void shareSingleSparkContext() throws InterruptedException, IOException {
// create another SparkInterpreter
SparkInterpreter repl2 = new SparkInterpreter(getSparkTestProperties());
SparkInterpreter repl2 = new SparkInterpreter(getSparkTestProperties(tmpDir));
repl2.setInterpreterGroup(intpGroup);
intpGroup.get("note").add(repl2);
repl2.open();
@ -252,10 +234,10 @@ public class SparkInterpreterTest {
}
@Test
public void testEnableImplicitImport() {
public void testEnableImplicitImport() throws IOException {
if (getSparkVersionNumber() >= 13) {
// Set option of importing implicits to "true", and initialize new Spark repl
Properties p = getSparkTestProperties();
Properties p = getSparkTestProperties(tmpDir);
p.setProperty("zeppelin.spark.importImplicit", "true");
SparkInterpreter repl2 = new SparkInterpreter(p);
repl2.setInterpreterGroup(intpGroup);
@ -269,11 +251,11 @@ public class SparkInterpreterTest {
}
@Test
public void testDisableImplicitImport() {
public void testDisableImplicitImport() throws IOException {
if (getSparkVersionNumber() >= 13) {
// Set option of importing implicits to "false", and initialize new Spark repl
// this test should return error status when creating DataFrame from sequence
Properties p = getSparkTestProperties();
Properties p = getSparkTestProperties(tmpDir);
p.setProperty("zeppelin.spark.importImplicit", "false");
SparkInterpreter repl2 = new SparkInterpreter(p);
repl2.setInterpreterGroup(intpGroup);

View file

@ -17,8 +17,6 @@
package org.apache.zeppelin.spark;
import static org.junit.Assert.*;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Properties;
@ -29,25 +27,28 @@ import org.apache.zeppelin.user.AuthenticationInfo;
import org.apache.zeppelin.display.GUI;
import org.apache.zeppelin.interpreter.*;
import org.apache.zeppelin.interpreter.InterpreterResult.Type;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.junit.rules.TemporaryFolder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class SparkSqlInterpreterTest {
@Rule
public TemporaryFolder tmpDir = new TemporaryFolder();
private SparkSqlInterpreter sql;
private SparkInterpreter repl;
private InterpreterContext context;
private InterpreterGroup intpGroup;
Logger LOGGER = LoggerFactory.getLogger(SparkSqlInterpreterTest.class);
@Before
public void setUp() throws Exception {
Properties p = new Properties();
p.putAll(SparkInterpreterTest.getSparkTestProperties());
p.putAll(SparkInterpreterTest.getSparkTestProperties(tmpDir));
p.setProperty("zeppelin.spark.maxResult", "1000");
p.setProperty("zeppelin.spark.concurrentSQL", "false");
p.setProperty("zeppelin.spark.sql.stacktrace", "false");
@ -82,10 +83,6 @@ public class SparkSqlInterpreterTest {
new LinkedList<InterpreterContextRunner>(), new InterpreterOutput(null));
}
@After
public void tearDown() throws Exception {
}
boolean isDataFrameSupported() {
return SparkInterpreterTest.getSparkVersionNumber() >= 13;
}

View file

@ -266,6 +266,7 @@ The text of each license is also included at licenses/LICENSE-[project]-[version
(The MIT License) Java String Similarity 0.12 (info.debatty:java-string-similarity:0.12 - https://github.com/tdebatty/java-string-similarity)
(The MIT License) Java LSH 0.10 (info.debatty:java-lsh:0.10 - https://github.com/tdebatty/java-LSH)
(The MIT License) JSoup 1.6.1 (org.jsoup:jsoup:1.6.1 - https://github.com/jhy/jsoup/)
(The MIT License) ngclipboard v1.1.1 (https://github.com/sachinchoolur/ngclipboard) - https://github.com/sachinchoolur/ngclipboard/blob/1.1.1/LICENSE)
========================================================================
BSD-style licenses

View file

@ -17,14 +17,15 @@
package org.apache.zeppelin.dep;
import java.io.File;
import org.apache.commons.lang3.Validate;
import org.apache.maven.repository.internal.MavenRepositorySystemSession;
import org.sonatype.aether.RepositorySystem;
import org.sonatype.aether.RepositorySystemSession;
import org.sonatype.aether.repository.LocalRepository;
import org.sonatype.aether.repository.RemoteRepository;
import java.nio.file.Paths;
/**
* Manage mvn repository.
*/
@ -35,21 +36,11 @@ public class Booter {
public static RepositorySystemSession newRepositorySystemSession(
RepositorySystem system, String localRepoPath) {
Validate.notNull(localRepoPath, "localRepoPath should have a value");
MavenRepositorySystemSession session = new MavenRepositorySystemSession();
// find homedir
String home = System.getenv("ZEPPELIN_HOME");
if (home == null) {
home = System.getProperty("zeppelin.home");
}
if (home == null) {
home = "..";
}
String path = home + "/" + localRepoPath;
LocalRepository localRepo =
new LocalRepository(new File(path).getAbsolutePath());
LocalRepository localRepo = new LocalRepository(resolveLocalRepoPath(localRepoPath));
session.setLocalRepositoryManager(system.newLocalRepositoryManager(localRepo));
// session.setTransferListener(new ConsoleTransferListener());
@ -61,10 +52,24 @@ public class Booter {
return session;
}
static String resolveLocalRepoPath(String localRepoPath) {
// todo decouple home folder resolution
// find homedir
String home = System.getenv("ZEPPELIN_HOME");
if (home == null) {
home = System.getProperty("zeppelin.home");
}
if (home == null) {
home = "..";
}
return Paths.get(home).resolve(localRepoPath).toAbsolutePath().toString();
}
public static RemoteRepository newCentralRepository() {
return new RemoteRepository("central", "default", "http://repo1.maven.org/maven2/");
}
public static RemoteRepository newLocalRepository() {
return new RemoteRepository("local",
"default", "file://" + System.getProperty("user.home") + "/.m2/repository");

View file

@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zeppelin.dep;
import org.junit.Test;
import java.nio.file.Paths;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class BooterTest {
@Test
public void should_return_absolute_path() {
String resolvedPath = Booter.resolveLocalRepoPath("path");
assertTrue(Paths.get(resolvedPath).isAbsolute());
}
@Test
public void should_not_change_absolute_path() {
String absolutePath
= Paths.get("first", "second").toAbsolutePath().toString();
String resolvedPath = Booter.resolveLocalRepoPath(absolutePath);
assertThat(resolvedPath, equalTo(absolutePath));
}
@Test(expected = NullPointerException.class)
public void should_throw_exception_for_null() {
Booter.resolveLocalRepoPath(null);
}
}

View file

@ -169,8 +169,11 @@ public class NotebookServer extends WebSocketServlet implements
LOG.debug("{} message: invalid ticket {} != {}", messagereceived.op,
messagereceived.ticket, ticket);
} else {
LOG.warn("{} message: invalid ticket {} != {}", messagereceived.op,
messagereceived.ticket, ticket);
if (!messagereceived.op.equals(OP.PING)) {
conn.send(serializeMessage(new Message(OP.ERROR_INFO).put("info",
"Your ticket is invalid possibly due to server restart. "
+ "Please refresh the page and login again.")));
}
}
return;
}

View file

@ -103,50 +103,32 @@ module.exports = function(grunt) {
}
},
'goog-webfont-dl': {
patuaOne: {
googlefonts: {
build: {
options: {
ttf: true,
eot: true,
woff: true,
woff2: true,
svg: true,
fontname: 'Patua One',
fontstyles: '400',
fontdest: '<%= yeoman.app %>/fonts/',
cssdest: '<%= yeoman.app %>/fonts/Patua-One.css',
cssprefix: '',
subset: ''
}
},
sourceCodePro: {
options: {
ttf: true,
eot: true,
woff: true,
woff2: true,
svg: true,
fontname: 'Source Code Pro',
fontstyles: '300, 400, 500',
fontdest: '<%= yeoman.app %>/fonts/',
cssdest: '<%= yeoman.app %>/fonts/Source-Code-Pro.css',
cssprefix: '',
subset: ''
}
},
roboto: {
options: {
ttf: true,
eot: true,
woff: true,
woff2: true,
svg: true,
fontname: 'Roboto',
fontstyles: '300, 400, 500',
fontdest: '<%= yeoman.app %>/fonts/',
cssdest: '<%= yeoman.app %>/fonts/Roboto.css',
cssprefix: '',
subset: ''
fontPath: '<%= yeoman.app %>/fonts/',
httpPath: '../fonts/',
cssFile: '<%= yeoman.app %>/fonts/google-fonts.css',
formats: {
eot: true,
ttf: true,
woff: true,
svg: true
},
fonts: [
{
family: 'Patua One',
styles: [400]
},
{
family: 'Source Code Pro',
styles: [300, 400, 500]
},
{
family: 'Roboto',
styles: [300, 400, 500]
}
]
}
}
},
@ -493,6 +475,11 @@ module.exports = function(grunt) {
cwd: 'bower_components/jquery-ui/themes/base/images',
src: '{,*/}*.{png,jpg,jpeg,gif}',
dest: '.tmp/styles/images'
}, {
expand: true,
cwd: 'bower_components/ngclipboard',
src: 'dist/**',
dest: '.tmp'
}, {
expand: true,
cwd: 'bower_components/MathJax',
@ -546,6 +533,11 @@ module.exports = function(grunt) {
cwd: 'bower_components/jquery-ui/themes/base/images',
src: '{,*/}*.{png,jpg,jpeg,gif}',
dest: '<%= yeoman.dist %>/styles/images'
}, {
expand: true,
cwd: 'bower_components/ngclipboard',
src: 'dist/**',
dest: '<%= yeoman.dist %>'
}, {
expand: true,
cwd: 'bower_components/MathJax',
@ -624,7 +616,6 @@ module.exports = function(grunt) {
'htmlhint',
'clean:dist',
'wiredep',
'goog-webfont-dl',
'useminPrepare',
'concurrent:dist',
'postcss',

View file

@ -34,7 +34,8 @@
"moment-duration-format": "^1.3.0",
"select2": "^4.0.3",
"github-markdown-css": "^2.4.0",
"MathJax": "2.7.0"
"MathJax": "2.7.0",
"ngclipboard": "^1.1.1"
},
"devDependencies": {
"angular-mocks": "1.5.0"

View file

@ -4,11 +4,11 @@
"version": "0.0.0",
"engines" : { "node" : ">=6.0.0" },
"scripts": {
"postinstall": "node_modules/.bin/bower install --silent",
"build": "./node_modules/.bin/grunt build",
"start": "./node_modules/.bin/grunt serve",
"test": "./node_modules/.bin/grunt test",
"pretest": "./node_modules/.bin/npm install karma-phantomjs-launcher"
"postinstall": "bower install --silent && grunt googlefonts",
"build": "grunt build",
"start": "grunt serve",
"test": "grunt test",
"pretest": "npm install karma-phantomjs-launcher"
},
"dependencies": {
"grunt-angular-templates": "^0.5.7",
@ -34,7 +34,7 @@
"grunt-contrib-watch": "^0.6.1",
"grunt-eslint": "^18.1.0",
"grunt-filerev": "^0.2.1",
"grunt-goog-webfont-dl": "^0.1.2",
"grunt-google-fonts": "^0.4.0",
"grunt-htmlhint": "^0.9.13",
"grunt-jscs": "^2.1.0",
"grunt-karma": "~2.0.0",

View file

@ -86,9 +86,10 @@
<exclude>src/styles/font-awesome*</exclude>
<exclude>src/fonts/Simple-Line*</exclude>
<exclude>src/fonts/simple-line*</exclude>
<exclude>src/fonts/Patua-One*</exclude>
<exclude>src/fonts/Roboto*</exclude>
<exclude>src/fonts/Source-Code-Pro*</exclude>
<exclude>src/fonts/patua-one*</exclude>
<exclude>src/fonts/roboto*</exclude>
<exclude>src/fonts/source-code-pro*</exclude>
<exclude>src/fonts/google-fonts.css</exclude>
<exclude>bower.json</exclude>
<exclude>package.json</exclude>
<exclude>*.md</exclude>

View file

@ -33,7 +33,8 @@
'xeditable',
'ngToast',
'focus-if',
'ngResource'
'ngResource',
'ngclipboard'
])
.filter('breakFilter', function() {
return function(text) {

View file

@ -112,11 +112,6 @@
var top = $id.offset().top - 103;
angular.element('html, body').scrollTo({top: top, left: 0});
}
// force notebook reload on user change
$scope.$on('setNoteMenu', function(event, note) {
initNotebook();
});
},
1000
);
@ -125,6 +120,11 @@
initNotebook();
// force notebook reload on user change
$scope.$on('setNoteMenu', function(event, note) {
initNotebook();
});
$scope.focusParagraphOnClick = function(clickEvent) {
if (!$scope.note) {
return;

View file

@ -39,8 +39,15 @@ limitations under the License.
type="button">
</span>
<ul class="dropdown-menu" role="menu" style="width:200px;z-index:1002">
<li ng-click="$event.stopPropagation()" style="text-align:center;margin-top:4px;">
{{paragraph.id}}
<li ng-controller="clipboardCtrl" ng-click="$event.stopPropagation()" style="text-align:center;margin-top:4px;">
<a ngclipboard
ngclipboard-success="complete($event)"
ngclipboard-error="clipError($event)"
data-clipboard-text="{{paragraph.id}}"
tooltip-placement="top"
tooltip="{{tooltip}}">
<span>{{paragraph.id}}</span>
</a>
</li>
<li role="separator" class="divider"></li>
<li>

View file

@ -556,6 +556,7 @@
$scope.editor.commands.removeCommand('showSettingsMenu');
$scope.editor.commands.bindKey('ctrl-alt-l', null);
$scope.editor.commands.bindKey('ctrl-alt-w', null);
// autocomplete on 'ctrl+.'
$scope.editor.commands.bindKey('ctrl-.', 'startAutocomplete');
@ -1092,10 +1093,12 @@
} else {
$scope.showTitle($scope.paragraph);
}
}else if (keyEvent.ctrlKey && keyEvent.shiftKey && keyCode === 67) { // Ctrl + Alt + c
} else if (keyEvent.ctrlKey && keyEvent.shiftKey && keyCode === 67) { // Ctrl + Alt + c
$scope.copyPara('below');
} else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 76) { // Ctrl + Alt + l
$scope.clearParagraphOutput($scope.paragraph);
} else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 87) { // Ctrl + Alt + w
$scope.goToSingleParagraph();
} else {
noShortcutDefined = true;
}

View file

@ -165,7 +165,8 @@ table.dataTable.table-condensed .sorting_desc:after {
}
.paragraph .control span {
margin-left: 4px;
margin-left: 4px;
margin-right: 4px;
}
.paragraph .control {

View file

@ -0,0 +1,36 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').controller('clipboardCtrl', clipboardCtrl);
clipboardCtrl.$inject = ['$scope'];
function clipboardCtrl($scope) {
$scope.complete = function(e) {
$scope.copied = true;
$scope.tooltip = 'Copied!';
setTimeout(function() {
$scope.tooltip = 'Copy to clipboard';
}, 400);
};
$scope.$watch('input', function() {
$scope.copied = false;
$scope.tooltip = 'Copy to clipboard';
});
$scope.clipError = function(e) {
console.log('Error: ' + e.name + ' - ' + e.message);
$scope.tooltip = 'Not supported browser';
};
}
})();

View file

@ -199,6 +199,17 @@ limitations under the License.
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="keys">
<kbd class="kbd-dark">Ctrl</kbd> + <kbd class="kbd-dark">{{ isMac ? 'Option' : 'Alt'}}</kbd> + <kbd class="kbd-dark">w</kbd>
</div>
</div>
<div class="col-md-8">
Link this paragraph
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="keys">

View file

@ -34,7 +34,6 @@ limitations under the License.
name="defaultInterpreter"
id="defaultInterpreter"
ng-options="option.name for option in interpreterSettings">
<option value="">--Select--</option>
</select>
</div>
</div>

View file

@ -39,7 +39,7 @@
defaultInterpreterId = $scope.note.defaultInterpreter.id;
}
vm.websocketMsgSrv.createNotebook($scope.note.notename, defaultInterpreterId);
$scope.note.defaultInterpreter = null;
$scope.note.defaultInterpreter = $scope.interpreterSettings[0];
} else {
var noteId = $routeParams.noteId;
vm.websocketMsgSrv.cloneNote(noteId, $scope.note.notename);
@ -104,6 +104,9 @@
$scope.$on('interpreterSettings', function(event, data) {
$scope.interpreterSettings = data.interpreterSettings;
//initialize default interpreter with Spark interpreter
$scope.note.defaultInterpreter = data.interpreterSettings[0];
});
var init = function() {

View file

@ -65,9 +65,7 @@ limitations under the License.
<link rel="stylesheet" href="fonts/font-awesome.min.css" />
<link rel="stylesheet" href="fonts/simple-line-icons.css" />
<link rel="stylesheet" href="fonts/custom-font.css" />
<link rel="stylesheet" href="fonts/Patua-One.css" />
<link rel="stylesheet" href="fonts/Source-Code-Pro.css" />
<link rel="stylesheet" href="fonts/Roboto.css" />
<link rel="stylesheet" href="fonts/google-fonts.css" />
<!-- endbuild -->
<link rel="stylesheet" ng-href="assets/styles/looknfeel/{{looknfeel}}.css" />
<link rel="stylesheet" href="assets/styles/printMode.css" />
@ -165,6 +163,8 @@ limitations under the License.
<script src="bower_components/moment-duration-format/lib/moment-duration-format.js"></script>
<script src="bower_components/select2/dist/js/select2.js"></script>
<script src="bower_components/MathJax/MathJax.js"></script>
<script src="bower_components/clipboard/dist/clipboard.js"></script>
<script src="bower_components/ngclipboard/dist/ngclipboard.js"></script>
<!-- endbower -->
<!-- endbuild -->
<!-- build:js({.tmp,src}) scripts/scripts.js -->
@ -198,6 +198,7 @@ limitations under the License.
<script src="app/search/result-list.controller.js"></script>
<script src="app/notebookRepos/notebookRepos.controller.js"></script>
<script src="components/arrayOrderingSrv/arrayOrdering.service.js"></script>
<script src="components/clipboard/clipboard.controller.js"></script>
<script src="components/navbar/navbar.controller.js"></script>
<script src="components/ngescape/ngescape.directive.js"></script>
<script src="components/interpreter/interpreter.directive.js"></script>

View file

@ -66,6 +66,8 @@ module.exports = function(config) {
'bower_components/moment-duration-format/lib/moment-duration-format.js',
'bower_components/select2/dist/js/select2.js',
'bower_components/MathJax/MathJax.js',
'bower_components/clipboard/dist/clipboard.js',
'bower_components/ngclipboard/dist/ngclipboard.js',
'bower_components/angular-mocks/angular-mocks.js',
// endbower
'.tmp/app/app.js',

View file

@ -121,4 +121,20 @@ describe('Controller: NotebookCtrl', function() {
expect(scope.note.name).toEqual(newName);
expect(websocketMsgSrvMock.updateNote).toHaveBeenCalled();
});
it('should reload note info once per one "setNoteMenu" event', function() {
spyOn(websocketMsgSrvMock, 'getNote');
spyOn(websocketMsgSrvMock, 'listRevisionHistory');
scope.$broadcast('setNoteMenu');
expect(websocketMsgSrvMock.getNote.calls.count()).toEqual(1);
expect(websocketMsgSrvMock.listRevisionHistory.calls.count()).toEqual(1);
websocketMsgSrvMock.getNote.calls.reset();
websocketMsgSrvMock.listRevisionHistory.calls.reset();
scope.$broadcast('setNoteMenu');
expect(websocketMsgSrvMock.getNote.calls.count()).toEqual(1);
expect(websocketMsgSrvMock.listRevisionHistory.calls.count()).toEqual(1);
});
});

View file

@ -291,7 +291,7 @@ public class ZeppelinConfiguration extends XMLConfiguration {
return getRelativeDir(
String.format("%s/%s",
getConfDir(),
getString(path)));
path));
}
}
@ -320,7 +320,7 @@ public class ZeppelinConfiguration extends XMLConfiguration {
return getRelativeDir(
String.format("%s/%s",
getConfDir(),
getString(path)));
path));
}
}

View file

@ -514,21 +514,19 @@ public class Note implements Serializable, ParagraphJobListener {
/**
* Run all paragraphs sequentially.
*/
public void runAll() {
public synchronized void runAll() {
String cronExecutingUser = (String) getConfig().get("cronExecutingUser");
if (null == cronExecutingUser) {
cronExecutingUser = "anonymous";
}
synchronized (paragraphs) {
for (Paragraph p : paragraphs) {
if (!p.isEnabled()) {
continue;
}
AuthenticationInfo authenticationInfo = new AuthenticationInfo();
authenticationInfo.setUser(cronExecutingUser);
p.setAuthenticationInfo(authenticationInfo);
run(p.getId());
for (Paragraph p : getParagraphs()) {
if (!p.isEnabled()) {
continue;
}
AuthenticationInfo authenticationInfo = new AuthenticationInfo();
authenticationInfo.setUser(cronExecutingUser);
p.setAuthenticationInfo(authenticationInfo);
run(p.getId());
}
}