mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
Merge branch 'master' into ZEPPELIN-732-up
This commit is contained in:
commit
d5585911fd
48 changed files with 667 additions and 484 deletions
|
|
@ -132,15 +132,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -60,15 +60,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -230,15 +230,6 @@
|
|||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
61
dev/common_release.sh
Normal file
61
dev/common_release.sh
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#!/bin/bash
|
||||
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# common fucntions
|
||||
|
||||
if [[ -z "${TAR}" ]]; then
|
||||
TAR="/usr/bin/tar"
|
||||
fi
|
||||
|
||||
if [[ -z "${SHASUM}" ]]; then
|
||||
SHASUM="/usr/bin/shasum"
|
||||
fi
|
||||
|
||||
if [[ -z "${WORKING_DIR}" ]]; then
|
||||
WORKING_DIR="/tmp/zeppelin-release"
|
||||
fi
|
||||
|
||||
mkdir "${WORKING_DIR}"
|
||||
|
||||
usage() {
|
||||
echo "usage) $0 [Release version] [Branch or Tag]"
|
||||
echo " ex. $0 0.6.0 v0.6.0"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function git_clone() {
|
||||
echo "Clone the source"
|
||||
# clone source
|
||||
git clone https://git-wip-us.apache.org/repos/asf/zeppelin.git "${WORKING_DIR}/zeppelin"
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Can not clone source repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "${WORKING_DIR}/zeppelin"
|
||||
git checkout "${GIT_TAG}"
|
||||
echo "Checked out ${GIT_TAG}"
|
||||
|
||||
# remove unnecessary files
|
||||
rm "${WORKING_DIR}/zeppelin/.gitignore"
|
||||
rm -rf "${WORKING_DIR}/zeppelin/.git"
|
||||
rm -rf "${WORKING_DIR}/zeppelin/.github"
|
||||
rm -rf "${WORKING_DIR}/zeppelin/docs"
|
||||
}
|
||||
|
|
@ -18,114 +18,93 @@
|
|||
#
|
||||
|
||||
# The script helps making a release.
|
||||
# You need specify a release name and branch|tag name.
|
||||
# You need to specify release version and branch|tag name.
|
||||
#
|
||||
# Here's some helpful documents for the release
|
||||
# Here are some helpful documents for the release.
|
||||
# http://www.apache.org/dev/release.html
|
||||
# http://www.apache.org/dev/release-publishing
|
||||
# http://www.apache.org/dev/release-signing.html
|
||||
# http://www.apache.org/dev/publishing-maven-artifacts.html
|
||||
|
||||
if [[ -z "${TAR}" ]]; then
|
||||
TAR=/usr/bin/tar
|
||||
fi
|
||||
BASEDIR="$(dirname "$0")"
|
||||
. "${BASEDIR}/common_release.sh"
|
||||
echo "${BASEDIR}/common_release.sh"
|
||||
|
||||
if [[ -z "${SHASUM}" ]]; then
|
||||
SHASUM="/usr/bin/shasum -a 512"
|
||||
fi
|
||||
|
||||
|
||||
if [[ -z "${WORKING_DIR}" ]]; then
|
||||
WORKING_DIR=/tmp/zeppelin-release
|
||||
if [[ $# -ne 2 ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
if [[ -z "${GPG_PASSPHRASE}" ]]; then
|
||||
echo "You need GPG_PASSPHRASE variable set"
|
||||
exit 1
|
||||
echo "You need GPG_PASSPHRASE variable set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RELEASE_VERSION="$1"
|
||||
GIT_TAG="$2"
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "usage) $0 [Release name] [Branch or Tag]"
|
||||
echo " ex. $0 0.6.0 branch-0.6"
|
||||
exit 1
|
||||
fi
|
||||
function make_source_package() {
|
||||
# create source package
|
||||
cd ${WORKING_DIR}
|
||||
cp -r "zeppelin" "zeppelin-${RELEASE_VERSION}"
|
||||
${TAR} cvzf "zeppelin-${RELEASE_VERSION}.tgz" "zeppelin-${RELEASE_VERSION}"
|
||||
|
||||
RELEASE_NAME="${1}"
|
||||
BRANCH="${2}"
|
||||
|
||||
|
||||
if [[ -d "${WORKING_DIR}" ]]; then
|
||||
echo "Dir ${WORKING_DIR} already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir ${WORKING_DIR}
|
||||
|
||||
echo "Cloning the source and packaging"
|
||||
# clone source
|
||||
git clone -b ${BRANCH} git@github.com:apache/zeppelin.git ${WORKING_DIR}/zeppelin
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Can not clone source repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# remove unnecessary files
|
||||
rm ${WORKING_DIR}/zeppelin/.gitignore
|
||||
rm -rf ${WORKING_DIR}/zeppelin/.git
|
||||
|
||||
|
||||
|
||||
# create source package
|
||||
cd ${WORKING_DIR}
|
||||
cp -r zeppelin zeppelin-${RELEASE_NAME}
|
||||
${TAR} cvzf zeppelin-${RELEASE_NAME}.tgz zeppelin-${RELEASE_NAME}
|
||||
|
||||
echo "Signing the source package"
|
||||
cd ${WORKING_DIR}
|
||||
echo $GPG_PASSPHRASE | gpg --passphrase-fd 0 --armor --output zeppelin-${RELEASE_NAME}.tgz.asc --detach-sig ${WORKING_DIR}/zeppelin-${RELEASE_NAME}.tgz
|
||||
echo $GPG_PASSPHRASE | gpg --passphrase-fd 0 --print-md MD5 zeppelin-${RELEASE_NAME}.tgz > ${WORKING_DIR}/zeppelin-${RELEASE_NAME}.tgz.md5
|
||||
${SHASUM} zeppelin-${RELEASE_NAME}.tgz > ${WORKING_DIR}/zeppelin-${RELEASE_NAME}.tgz.sha512
|
||||
|
||||
|
||||
function make_binary_release() {
|
||||
BIN_RELEASE_NAME="${1}"
|
||||
BUILD_FLAGS="${2}"
|
||||
|
||||
cp -r ${WORKING_DIR}/zeppelin ${WORKING_DIR}/zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}
|
||||
cd ${WORKING_DIR}/zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}
|
||||
echo "mvn clean package -Pbuild-distr -DskipTests ${BUILD_FLAGS}"
|
||||
mvn clean package -Pbuild-distr -DskipTests ${BUILD_FLAGS}
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Build failed. ${BUILD_FLAGS}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# re-create package with proper dir name with binary license
|
||||
cd zeppelin-distribution/target/zeppelin-*
|
||||
mv zeppelin-* zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}
|
||||
cat ../../src/bin_license/LICENSE >> zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}/LICENSE
|
||||
cat ../../src/bin_license/NOTICE >> zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}/NOTICE
|
||||
cp ../../src/bin_license/licenses/* zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}/licenses/
|
||||
${TAR} cvzf zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}.tgz zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}
|
||||
|
||||
# sign bin package
|
||||
echo $GPG_PASSPHRASE | gpg --passphrase-fd 0 --armor --output zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}.tgz.asc --detach-sig zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}.tgz
|
||||
echo $GPG_PASSPHRASE | gpg --passphrase-fd 0 --print-md MD5 zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}.tgz > zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}.tgz.md5
|
||||
${SHASUM} zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}.tgz > zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}.tgz.sha512
|
||||
|
||||
mv zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}.tgz ${WORKING_DIR}/
|
||||
mv zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}.tgz.asc ${WORKING_DIR}/
|
||||
mv zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}.tgz.md5 ${WORKING_DIR}/
|
||||
mv zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}.tgz.sha512 ${WORKING_DIR}/
|
||||
|
||||
# clean up build dir
|
||||
rm -rf ${WORKING_DIR}/zeppelin-${RELEASE_NAME}-bin-${BIN_RELEASE_NAME}
|
||||
echo "Signing the source package"
|
||||
cd "${WORKING_DIR}"
|
||||
echo "${GPG_PASSPHRASE}" | gpg --passphrase-fd 0 --armor \
|
||||
--output "zeppelin-${RELEASE_VERSION}.tgz.asc" \
|
||||
--detach-sig "${WORKING_DIR}/zeppelin-${RELEASE_VERSION}.tgz"
|
||||
echo "${GPG_PASSPHRASE}" | gpg --passphrase-fd 0 \
|
||||
--print-md MD5 "zeppelin-${RELEASE_VERSION}.tgz" > \
|
||||
"${WORKING_DIR}/zeppelin-${RELEASE_VERSION}.tgz.md5"
|
||||
echo "${GPG_PASSPHRASE}" | gpg --passphrase-fd 0 \
|
||||
--print-md SHA512 "zeppelin-${RELEASE_VERSION}.tgz" > \
|
||||
"${WORKING_DIR}/zeppelin-${RELEASE_VERSION}.tgz.sha512"
|
||||
}
|
||||
|
||||
make_binary_release all "-Pspark-1.6 -Phadoop-2.4 -Pyarn -Ppyspark"
|
||||
function make_binary_release() {
|
||||
BIN_RELEASE_NAME="$1"
|
||||
BUILD_FLAGS="$2"
|
||||
|
||||
cp -r "${WORKING_DIR}/zeppelin" "${WORKING_DIR}/zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}"
|
||||
cd "${WORKING_DIR}/zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}"
|
||||
echo "mvn clean package -Pbuild-distr -DskipTests ${BUILD_FLAGS}"
|
||||
mvn clean package -Pbuild-distr -DskipTests ${BUILD_FLAGS}
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Build failed. ${BUILD_FLAGS}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# re-create package with proper dir name with binary license
|
||||
cd zeppelin-distribution/target/zeppelin-*
|
||||
mv zeppelin-* "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}"
|
||||
cat ../../src/bin_license/LICENSE >> "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}/LICENSE"
|
||||
cat ../../src/bin_license/NOTICE >> "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}/NOTICE"
|
||||
cp ../../src/bin_license/licenses/* "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}/licenses/"
|
||||
${TAR} cvzf "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}.tgz" "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}"
|
||||
|
||||
# sign bin package
|
||||
echo "${GPG_PASSPHRASE}" | gpg --passphrase-fd 0 --armor \
|
||||
--output "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}.tgz.asc" \
|
||||
--detach-sig "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}.tgz"
|
||||
echo "${GPG_PASSPHRASE}" | gpg --passphrase-fd 0 --print-md MD5 \
|
||||
"zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}.tgz" > \
|
||||
"zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}.tgz.md5"
|
||||
${SHASUM} -a 512 "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}.tgz" > \
|
||||
"zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}.tgz.sha512"
|
||||
|
||||
mv "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}.tgz" "${WORKING_DIR}/"
|
||||
mv "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}.tgz.asc" "${WORKING_DIR}/"
|
||||
mv "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}.tgz.md5" "${WORKING_DIR}/"
|
||||
mv "zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}.tgz.sha512" "${WORKING_DIR}/"
|
||||
|
||||
# clean up build dir
|
||||
rm -rf "${WORKING_DIR}/zeppelin-${RELEASE_VERSION}-bin-${BIN_RELEASE_NAME}"
|
||||
}
|
||||
|
||||
git_clone
|
||||
make_source_package
|
||||
make_binary_release all "-Pspark-1.6 -Phadoop-2.4 -Pyarn -Ppyspark -Psparkr -Pr"
|
||||
|
||||
# remove non release files and dirs
|
||||
rm -rf ${WORKING_DIR}/zeppelin
|
||||
rm -rf ${WORKING_DIR}/zeppelin-${RELEASE_NAME}
|
||||
rm -rf "${WORKING_DIR}/zeppelin"
|
||||
rm -rf "${WORKING_DIR}/zeppelin-${RELEASE_VERSION}"
|
||||
echo "Release files are created under ${WORKING_DIR}"
|
||||
|
|
|
|||
138
dev/publish_release.sh
Executable file
138
dev/publish_release.sh
Executable file
|
|
@ -0,0 +1,138 @@
|
|||
#!/bin/bash
|
||||
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# The script helps publishing release to maven.
|
||||
# You need to specify release version and branch|tag name.
|
||||
#
|
||||
# Here's some helpful documents for the release.
|
||||
# http://www.apache.org/dev/publishing-maven-artifacts.html
|
||||
|
||||
BASEDIR="$(dirname "$0")"
|
||||
. "${BASEDIR}/common_release.sh"
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
for var in GPG_PASSPHRASE ASF_USERID ASF_PASSWORD; do
|
||||
if [[ -z "${!var}" ]]; then
|
||||
echo "You need ${var} variable set"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
export MAVEN_OPTS="-Xmx2g -XX:MaxPermSize=512m"
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
RELEASE_VERSION="$1"
|
||||
GIT_TAG="$2"
|
||||
|
||||
PUBLISH_PROFILES="-Pspark-1.6 -Phadoop-2.4 -Pyarn -Ppyspark -Psparkr -Pr"
|
||||
PROJECT_OPTIONS="-pl !zeppelin-distribution"
|
||||
NEXUS_STAGING="https://repository.apache.org/service/local/staging"
|
||||
NEXUS_PROFILE="153446d1ac37c4"
|
||||
|
||||
function cleanup() {
|
||||
echo "Remove working directory and maven local repository"
|
||||
rm -rf ${WORKING_DIR}
|
||||
rm -rf ${tmp_repo}
|
||||
}
|
||||
|
||||
function curl_error() {
|
||||
ret=${1}
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
echo "curl response code is: ($ret)"
|
||||
echo "See https://curl.haxx.se/libcurl/c/libcurl-errors.html to know the detailed cause of error."
|
||||
echo -e "${RED}Failed to publish maven artifact to staging repository."
|
||||
echo -e "IMPORTANT: You will have to re-run publish_release.sh to complete maven artifact publish.${NC}"
|
||||
cleanup
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function publish_to_maven() {
|
||||
cd "${WORKING_DIR}/zeppelin"
|
||||
|
||||
# Force release version
|
||||
mvn versions:set -DnewVersion="${RELEASE_VERSION}"
|
||||
|
||||
# Using Nexus API documented here:
|
||||
# https://support.sonatype.com/hc/en-us/articles/213465868-Uploading-to-a-Staging-Repository-via-REST-API
|
||||
echo "Creating Nexus staging repository"
|
||||
repo_request="<promoteRequest><data><description>Apache Zeppelin ${RELEASE_VERSION}</description></data></promoteRequest>"
|
||||
out="$(curl -X POST -d "${repo_request}" -u "${ASF_USERID}:${ASF_PASSWORD}" \
|
||||
-H 'Content-Type:application/xml' -v \
|
||||
"${NEXUS_STAGING}/profiles/${NEXUS_PROFILE}/start")"
|
||||
create_ret=$?
|
||||
curl_error $create_ret
|
||||
staged_repo_id="$(echo "${out}" | sed -e 's/.*\(orgapachezeppelin-[0-9]\{4\}\).*/\1/')"
|
||||
echo "Created Nexus staging repository: ${staged_repo_id}"
|
||||
|
||||
tmp_repo="$(mktemp -d /tmp/zeppelin-repo-XXXXX)"
|
||||
|
||||
echo "mvn clean install -Ppublish-distr \
|
||||
-Dmaven.repo.local=${tmp_repo} \
|
||||
${PUBLISH_PROFILES} ${PROJECT_OPTIONS}"
|
||||
mvn clean install -Ppublish-distr -Dmaven.repo.local="${tmp_repo}" \
|
||||
${PUBLISH_PROFILES} ${PROJECT_OPTIONS}
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Build failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pushd "${tmp_repo}/org/apache/zeppelin"
|
||||
find . -type f | grep -v '\.jar$' | grep -v '\.pom$' |grep -v '\.war$' | xargs rm
|
||||
|
||||
echo "Creating hash and signature files"
|
||||
for file in $(find . -type f); do
|
||||
echo "${GPG_PASSPHRASE}" | gpg --passphrase-fd 0 --output "${file}.asc" \
|
||||
--detach-sig --armor "${file}"
|
||||
md5 -q "${file}" > "${file}.md5"
|
||||
${SHASUM} -a 1 "${file}" | cut -f1 -d' ' > "${file}.sha1"
|
||||
done
|
||||
|
||||
nexus_upload="${NEXUS_STAGING}/deployByRepositoryId/${staged_repo_id}"
|
||||
echo "Uplading files to ${nexus_upload}"
|
||||
for file in $(find . -type f); do
|
||||
# strip leading ./
|
||||
file_short="$(echo "${file}" | sed -e 's/\.\///')"
|
||||
dest_url="${nexus_upload}/org/apache/zeppelin/$file_short"
|
||||
echo " Uploading ${file_short}"
|
||||
curl -u "${ASF_USERID}:${ASF_PASSWORD}" --upload-file "${file_short}" "${dest_url}"
|
||||
upload_ret=$?
|
||||
curl_error $upload_ret
|
||||
done
|
||||
|
||||
echo "Closing nexus staging repository"
|
||||
repo_request="<promoteRequest><data><stagedRepositoryId>${staged_repo_id}</stagedRepositoryId><description>Apache Zeppelin ${RELEASE_VERSION}</description></data></promoteRequest>"
|
||||
out="$(curl -X POST -d "${repo_request}" -u "${ASF_USERID}:${ASF_PASSWORD}" \
|
||||
-H 'Content-Type:application/xml' -v \
|
||||
"${NEXUS_STAGING}}/profiles/${NEXUS_PROFILE}/finish")"
|
||||
close_ret=$?
|
||||
curl_error $close_ret
|
||||
echo "Closed Nexus staging repository: ${staged_repo_id}"
|
||||
popd
|
||||
echo "Complete publishing maven artifacts to apache staging repository"
|
||||
echo "Once release candidate pass the vote, do not forget to hit the release button in https://repository.apache.org"
|
||||
}
|
||||
|
||||
git_clone
|
||||
publish_to_maven
|
||||
cleanup
|
||||
|
|
@ -312,6 +312,7 @@ SELECT * FROM db_name;
|
|||
|
||||
```
|
||||
or
|
||||
|
||||
```sql
|
||||
%jdbc(prefix)
|
||||
SELECT * FROM db_name;
|
||||
|
|
|
|||
|
|
@ -16,12 +16,17 @@ group: manual
|
|||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>python</td>
|
||||
<td>zeppelin.python</td>
|
||||
<td>python</td>
|
||||
<td>Path of the already installed Python binary (could be python2 or python3).
|
||||
If python is not in your $PATH you can set the absolute directory (example : /usr/bin/python)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>zeppelin.python.maxResult</td>
|
||||
<td>1000</td>
|
||||
<td>Max number of dataframe rows to display.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## Enabling Python Interpreter
|
||||
|
|
@ -39,7 +44,7 @@ To access the help, type **help()**
|
|||
## Python modules
|
||||
The interpreter can use all modules already installed (with pip, easy_install...)
|
||||
|
||||
## Apply Zeppelin Dynamic Forms
|
||||
## Use Zeppelin Dynamic Forms
|
||||
You can leverage [Zeppelin Dynamic Form]({{BASE_PATH}}/manual/dynamicform.html) inside your Python code.
|
||||
|
||||
**Zeppelin Dynamic Form can only be used if py4j Python library is installed in your system. If not, you can install it with `pip install py4j`.**
|
||||
|
|
@ -60,7 +65,6 @@ print("".join(z.checkbox("f3", [("o1","1"), ("o2","2")],["1"])))
|
|||
|
||||
|
||||
|
||||
|
||||
## Zeppelin features not fully supported by the Python Interpreter
|
||||
|
||||
* Interrupt a paragraph execution (`cancel()` method) is currently only supported in Linux and MacOs. If interpreter runs in another operating system (for instance MS Windows) , interrupt a paragraph will close the whole interpreter. A JIRA ticket ([ZEPPELIN-893](https://issues.apache.org/jira/browse/ZEPPELIN-893)) is opened to implement this feature in a next release of the interpreter.
|
||||
|
|
@ -68,7 +72,7 @@ print("".join(z.checkbox("f3", [("o1","1"), ("o2","2")],["1"])))
|
|||
* Code-completion is currently not implemented.
|
||||
|
||||
## Matplotlib integration
|
||||
The python interpreter can display matplotlib graph with the function `zeppelin_show()`.
|
||||
The python interpreter can display matplotlib graph with the function `z.show()`.
|
||||
You need to have matplotlib module installed and a XServer running to use this functionality !
|
||||
|
||||
```python
|
||||
|
|
@ -76,20 +80,32 @@ print("".join(z.checkbox("f3", [("o1","1"), ("o2","2")],["1"])))
|
|||
import matplotlib.pyplot as plt
|
||||
plt.figure()
|
||||
(.. ..)
|
||||
zeppelin_show(plt)
|
||||
z.show(plt)
|
||||
plt.close()
|
||||
```
|
||||
zeppelin_show function can take optional parameters to adapt graph width and height
|
||||
|
||||
```python
|
||||
%python
|
||||
zeppelin_show(plt,width='50px')
|
||||
zeppelin_show(plt,height='150px')
|
||||
z.show(plt, width='50px')
|
||||
z.show(plt, height='150px')
|
||||
```
|
||||
|
||||
[](/docs/interpreter/screenshots/pythonMatplotlib.png)
|
||||
|
||||
|
||||
## Pandas integration
|
||||
[Zeppelin Display System]({{BASE_PATH}}/displaysystem/basicdisplaysystem.html#table) provides simple API to visualize data in Pandas DataFrames, same as in Matplotlib.
|
||||
|
||||
Example:
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
rates = pd.read_csv("bank.csv", sep=";")
|
||||
z.show(rates)
|
||||
```
|
||||
|
||||
|
||||
## Technical description
|
||||
|
||||
For in-depth technical details on current implementation plese reffer [python/README.md](https://github.com/apache/zeppelin/blob/master/python/README.md)
|
||||
|
|
|
|||
|
|
@ -79,15 +79,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -72,15 +72,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
|
|
|
|||
|
|
@ -294,15 +294,6 @@
|
|||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -84,15 +84,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -109,15 +109,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -107,15 +107,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -102,15 +102,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import java.util.Map;
|
|||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.zeppelin.interpreter.Interpreter;
|
||||
import org.apache.zeppelin.interpreter.InterpreterContext;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult;
|
||||
|
|
@ -361,12 +362,11 @@ public class JDBCInterpreter extends Interpreter {
|
|||
|
||||
return new InterpreterResult(Code.SUCCESS, msg.toString());
|
||||
|
||||
} catch (SQLException ex) {
|
||||
logger.error("Cannot run " + sql, ex);
|
||||
return new InterpreterResult(Code.ERROR, ex.getMessage());
|
||||
} catch (ClassNotFoundException e) {
|
||||
} catch (Exception e) {
|
||||
logger.error("Cannot run " + sql, e);
|
||||
return new InterpreterResult(Code.ERROR, e.getMessage());
|
||||
StringBuilder stringBuilder = new StringBuilder(e.getClass().toString()).append("\n");
|
||||
stringBuilder.append(StringUtils.join(e.getStackTrace(), "\n"));
|
||||
return new InterpreterResult(Code.ERROR, stringBuilder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,15 +61,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -146,15 +146,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -100,15 +100,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -66,15 +66,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
47
pom.xml
47
pom.xml
|
|
@ -370,24 +370,6 @@
|
|||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<configuration><!-- Default configuration for all reports -->
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>aggregate</id>
|
||||
<goals>
|
||||
<goal>aggregate</goal>
|
||||
</goals>
|
||||
<phase>site</phase>
|
||||
<configuration><!-- Specific configuration for the aggregate report -->
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-scm-plugin</artifactId>
|
||||
<version>1.8.1</version>
|
||||
|
|
@ -736,6 +718,7 @@
|
|||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
@ -744,6 +727,34 @@
|
|||
<skipTests>true</skipTests>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.10.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
|
|
|||
|
|
@ -95,15 +95,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -87,15 +87,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ package org.apache.zeppelin.python;
|
|||
import org.apache.zeppelin.display.GUI;
|
||||
import org.apache.zeppelin.interpreter.Interpreter;
|
||||
import org.apache.zeppelin.interpreter.InterpreterContext;
|
||||
import org.apache.zeppelin.interpreter.InterpreterPropertyBuilder;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
|
||||
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
|
||||
|
|
@ -50,27 +49,16 @@ public class PythonInterpreter extends Interpreter {
|
|||
public static final String BOOTSTRAP_INPUT_PY = "/bootstrap_input.py";
|
||||
public static final String ZEPPELIN_PYTHON = "zeppelin.python";
|
||||
public static final String DEFAULT_ZEPPELIN_PYTHON = "python";
|
||||
public static final String MAX_RESULT = "zeppelin.python.maxResult";
|
||||
|
||||
private Integer port;
|
||||
private GatewayServer gatewayServer;
|
||||
private long pythonPid;
|
||||
private Boolean py4J = false;
|
||||
private InterpreterContext context;
|
||||
private int maxResult;
|
||||
|
||||
PythonProcess process = null;
|
||||
|
||||
static {
|
||||
Interpreter.register(
|
||||
"python",
|
||||
"python",
|
||||
PythonInterpreter.class.getName(),
|
||||
new InterpreterPropertyBuilder()
|
||||
.add(ZEPPELIN_PYTHON, DEFAULT_ZEPPELIN_PYTHON,
|
||||
"Python directory. Default : python (assume python is in your $PATH)")
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
public PythonInterpreter(Properties property) {
|
||||
super(property);
|
||||
}
|
||||
|
|
@ -80,6 +68,7 @@ public class PythonInterpreter extends Interpreter {
|
|||
logger.info("Starting Python interpreter .....");
|
||||
logger.info("Python path is set to:" + property.getProperty(ZEPPELIN_PYTHON));
|
||||
|
||||
maxResult = Integer.valueOf(getProperty(MAX_RESULT));
|
||||
process = getPythonProcess();
|
||||
|
||||
try {
|
||||
|
|
@ -134,7 +123,9 @@ public class PythonInterpreter extends Interpreter {
|
|||
@Override
|
||||
public InterpreterResult interpret(String cmd, InterpreterContext contextInterpreter) {
|
||||
this.context = contextInterpreter;
|
||||
|
||||
if (cmd == null || cmd.isEmpty()) {
|
||||
return new InterpreterResult(Code.SUCCESS, "");
|
||||
}
|
||||
String output = sendCommandToPython(cmd);
|
||||
return new InterpreterResult(Code.SUCCESS, output.replaceAll(">>>", "")
|
||||
.replaceAll("\\.\\.\\.", "").trim());
|
||||
|
|
@ -193,12 +184,13 @@ public class PythonInterpreter extends Interpreter {
|
|||
|
||||
private String sendCommandToPython(String cmd) {
|
||||
String output = "";
|
||||
logger.info("Sending : \n" + (cmd.length() > 200 ? cmd.substring(0, 120) + "..." : cmd));
|
||||
logger.info("Sending : \n" + (cmd.length() > 200 ? cmd.substring(0, 200) + "..." : cmd));
|
||||
try {
|
||||
output = process.sendAndGetResult(cmd);
|
||||
} catch (IOException e) {
|
||||
logger.error("Error when sending commands to python process", e);
|
||||
}
|
||||
//logger.info("Got : \n" + output);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
@ -223,7 +215,7 @@ public class PythonInterpreter extends Interpreter {
|
|||
return context.getGui();
|
||||
}
|
||||
|
||||
public Integer getPy4JPort() {
|
||||
public Integer getPy4jPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
|
|
@ -247,4 +239,7 @@ public class PythonInterpreter extends Interpreter {
|
|||
return port;
|
||||
}
|
||||
|
||||
public int getMaxResult() {
|
||||
return maxResult;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ public class PythonProcess {
|
|||
String output = "";
|
||||
String line;
|
||||
while (!(line = reader.readLine()).contains("*!?flush reader!?*")) {
|
||||
logger.debug("Readed line from python shell : " + line);
|
||||
logger.debug("Read line from python shell : " + line);
|
||||
if (line.equals("...")) {
|
||||
logger.warn("Syntax error ! ");
|
||||
output += "Syntax error ! ";
|
||||
|
|
|
|||
0
python/src/main/resources/__init__.py
Normal file
0
python/src/main/resources/__init__.py
Normal file
|
|
@ -13,7 +13,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# PYTHON 2 / 3 comptability :
|
||||
# PYTHON 2 / 3 compatibility :
|
||||
# bootstrap.py must be runnable with Python 2 or 3
|
||||
|
||||
# Remove interactive mode displayhook
|
||||
|
|
@ -33,10 +33,11 @@ def intHandler(signum, frame): # Set the signal handler
|
|||
|
||||
signal.signal(signal.SIGINT, intHandler)
|
||||
|
||||
|
||||
def help():
|
||||
print ('%html')
|
||||
print ('<h2>Python Interpreter help</h2>')
|
||||
print ('<h3>Python 2 & 3 comptability</h3>')
|
||||
print ('<h3>Python 2 & 3 compatibility</h3>')
|
||||
print ('<p>The interpreter is compatible with Python 2 & 3.<br/>')
|
||||
print ('To change Python version, ')
|
||||
print ('change in the interpreter configuration the python to the ')
|
||||
|
|
@ -56,48 +57,101 @@ def help():
|
|||
'("o2","2")],["1"])))</pre>')
|
||||
print ('<h3>Matplotlib graph</h3>')
|
||||
print ('<div>The interpreter can display matplotlib graph with ')
|
||||
print ('the function zeppelin_show()</div>')
|
||||
print ('the function z.show()</div>')
|
||||
print ('<div> You need to already have matplotlib module installed ')
|
||||
print ('to use this functionality !</div><br/>')
|
||||
print ('''<pre>import matplotlib.pyplot as plt
|
||||
plt.figure()
|
||||
(.. ..)
|
||||
zeppelin_show(plt)
|
||||
z.show(plt)
|
||||
plt.close()
|
||||
</pre>''')
|
||||
print ('<div><br/> zeppelin_show function can take optional parameters ')
|
||||
print ('<div><br/> z.show function can take optional parameters ')
|
||||
print ('to adapt graph width and height</div>')
|
||||
print ("<div><b>example </b>:")
|
||||
print('''<pre>zeppelin_show(plt,width='50px')
|
||||
zeppelin_show(plt,height='150px') </pre></div>''')
|
||||
print ('''<pre>z.show(plt,width='50px')
|
||||
z.show(plt,height='150px') </pre></div>''')
|
||||
print ('<h3>Pandas DataFrame</h3>')
|
||||
print """
|
||||
<div>The interpreter can visualize Pandas DataFrame
|
||||
with the function z.show()
|
||||
<pre>
|
||||
import pandas as pd
|
||||
df = pd.read_csv("bank.csv", sep=";")
|
||||
z.show(df)
|
||||
</pre></div>
|
||||
"""
|
||||
|
||||
# Matplotlib show function
|
||||
def zeppelin_show(p, width="0", height="0"):
|
||||
img = io.StringIO()
|
||||
p.savefig(img, format='svg')
|
||||
img.seek(0)
|
||||
style = ""
|
||||
if(width != "0"):
|
||||
style += 'width:'+width
|
||||
if(height != "0"):
|
||||
if(len(style) != 0):
|
||||
style += ","
|
||||
style += 'height:'+height
|
||||
print("%html <div style='" + style + "'>" + img.read() + "<div>")
|
||||
|
||||
# If py4j is detected, these class will be override
|
||||
# with the implementation in bootstrap_input.py
|
||||
class PyZeppelinContext():
|
||||
class PyZeppelinContext(object):
|
||||
""" If py4j is detected, these class will be override
|
||||
with the implementation in bootstrap_input.py
|
||||
"""
|
||||
errorMsg = "You must install py4j Python module " \
|
||||
"(pip install py4j) to use Zeppelin dynamic forms features"
|
||||
|
||||
def __init__(self, zc):
|
||||
self.z = zc
|
||||
self.max_result = 1000
|
||||
|
||||
def input(self, name, defaultValue=""):
|
||||
print (self.errorMsg)
|
||||
|
||||
def select(self, name, options, defaultValue=""):
|
||||
print (self.errorMsg)
|
||||
|
||||
def checkbox(self, name, options, defaultChecked=[]):
|
||||
print (self.errorMsg)
|
||||
|
||||
def show(self, p, **kwargs):
|
||||
if hasattr(p, '__name__') and p.__name__ == "matplotlib.pyplot":
|
||||
self.show_matplotlib(p, **kwargs)
|
||||
elif type(p).__name__ == "DataFrame": # does not play well with sub-classes
|
||||
# `isinstance(p, DataFrame)` would req `import pandas.core.frame.DataFrame`
|
||||
# and so a dependency on pandas
|
||||
self.show_dataframe(p, **kwargs)
|
||||
|
||||
def show_dataframe(self, df, **kwargs):
|
||||
"""Pretty prints DF using Table Display System
|
||||
"""
|
||||
limit = len(df) > self.max_result
|
||||
header_buf = io.StringIO("")
|
||||
header_buf.write(df.columns[0])
|
||||
for col in df.columns[1:]:
|
||||
header_buf.write("\t")
|
||||
header_buf.write(col)
|
||||
header_buf.write("\n")
|
||||
|
||||
body_buf = io.StringIO("")
|
||||
rows = df.head(self.max_result).values if limit else df.values
|
||||
for row in rows:
|
||||
body_buf.write(row[0])
|
||||
for cell in row[1:]:
|
||||
body_buf.write("\t")
|
||||
body_buf.write(cell)
|
||||
body_buf.write("\n")
|
||||
body_buf.seek(0); header_buf.seek(0)
|
||||
#TODO(bzz): fix it, so it shows red notice, as in Spark
|
||||
print("%table " + header_buf.read() + body_buf.read()) # +
|
||||
# ("\n<font color=red>Results are limited by {}.</font>" \
|
||||
# .format(self.max_result) if limit else "")
|
||||
#)
|
||||
body_buf.close(); header_buf.close()
|
||||
|
||||
def show_matplotlib(self, p, width="0", height="0", **kwargs):
|
||||
"""Matplotlib show function
|
||||
"""
|
||||
img = io.StringIO()
|
||||
p.savefig(img, format='svg')
|
||||
img.seek(0)
|
||||
style = ""
|
||||
if (width != "0"):
|
||||
style += 'width:' + width
|
||||
if (height != "0"):
|
||||
if (len(style) != 0):
|
||||
style += ","
|
||||
style += 'height:' + height
|
||||
print("%html <div style='" + style + "'>" + img.read() + "<div>")
|
||||
img.close()
|
||||
|
||||
|
||||
z = PyZeppelinContext("")
|
||||
|
||||
|
|
|
|||
|
|
@ -16,20 +16,24 @@
|
|||
from py4j.java_gateway import JavaGateway
|
||||
from py4j.java_gateway import java_import, JavaGateway, GatewayClient
|
||||
|
||||
|
||||
client = GatewayClient(port=%PORT%)
|
||||
gateway = JavaGateway(client)
|
||||
java_import(gateway.jvm, "org.apache.zeppelin.display.Input")
|
||||
|
||||
class PyZeppelinContext():
|
||||
paramOption = gateway.jvm.org.apache.zeppelin.display.Input.ParamOption
|
||||
javaList = gateway.jvm.java.util.ArrayList
|
||||
|
||||
class Py4jZeppelinContext(PyZeppelinContext):
|
||||
"""A context impl that uses Py4j to communicate to JVM
|
||||
"""
|
||||
def __init__(self, zc):
|
||||
self.z = zc
|
||||
|
||||
super(Py4jZeppelinContext, self).__init__(zc)
|
||||
self.paramOption = gateway.jvm.org.apache.zeppelin.display.Input.ParamOption
|
||||
self.javaList = gateway.jvm.java.util.ArrayList
|
||||
self.max_result = 1000 #TODO(bzz): read `zeppelin.python.maxResult` from JVM
|
||||
|
||||
def input(self, name, defaultValue=""):
|
||||
return self.z.getGui().input(name, defaultValue)
|
||||
|
||||
|
||||
def select(self, name, options, defaultValue=""):
|
||||
javaOptions = gateway.new_array(self.paramOption, len(options))
|
||||
i = 0
|
||||
|
|
@ -37,7 +41,7 @@ class PyZeppelinContext():
|
|||
javaOptions[i] = self.paramOption(tuple[0], tuple[1])
|
||||
i += 1
|
||||
return self.z.getGui().select(name, defaultValue, javaOptions)
|
||||
|
||||
|
||||
def checkbox(self, name, options, defaultChecked=[]):
|
||||
javaOptions = gateway.new_array(self.paramOption, len(options))
|
||||
i = 0
|
||||
|
|
@ -49,4 +53,5 @@ class PyZeppelinContext():
|
|||
javaDefaultCheck.append(check)
|
||||
return self.z.getGui().checkbox(name, javaDefaultCheck, javaOptions)
|
||||
|
||||
z = PyZeppelinContext(gateway.entry_point)
|
||||
|
||||
z = Py4jZeppelinContext(gateway.entry_point)
|
||||
|
|
|
|||
21
python/src/main/resources/interpreter-setting.json
Normal file
21
python/src/main/resources/interpreter-setting.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[
|
||||
{
|
||||
"group": "python",
|
||||
"name": "python",
|
||||
"className": "org.apache.zeppelin.python.PythonInterpreter",
|
||||
"properties": {
|
||||
"zeppelin.python": {
|
||||
"envName": null,
|
||||
"propertyName": "zeppelin.python",
|
||||
"defaultValue": "python",
|
||||
"description": "Python directory. It is set to python by default.(assume python is in your $PATH)"
|
||||
},
|
||||
"zeppelin.python.maxResult": {
|
||||
"envName": null,
|
||||
"propertyName": "zeppelin.python.maxResult",
|
||||
"defaultValue": "1000",
|
||||
"description": "Max number of dataframe rows to display."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.apache.zeppelin.python;
|
||||
|
||||
import static org.apache.zeppelin.python.PythonInterpreter.*;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
|
@ -53,13 +54,17 @@ public class PythonInterpreterTest {
|
|||
|
||||
Logger logger = LoggerFactory.getLogger(PythonProcess.class);
|
||||
|
||||
public static final String ZEPPELIN_PYTHON = "zeppelin.python";
|
||||
public static final String DEFAULT_ZEPPELIN_PYTHON = "python";
|
||||
|
||||
PythonInterpreter pythonInterpreter = null;
|
||||
PythonProcess mockPythonProcess;
|
||||
String cmdHistory;
|
||||
|
||||
public static Properties getPythonTestProperties() {
|
||||
Properties p = new Properties();
|
||||
p.setProperty(ZEPPELIN_PYTHON, DEFAULT_ZEPPELIN_PYTHON);
|
||||
p.setProperty(MAX_RESULT, "1000");
|
||||
return p;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeTest() {
|
||||
cmdHistory = "";
|
||||
|
|
@ -79,20 +84,15 @@ public class PythonInterpreterTest {
|
|||
logger.error("Can't initiate python process", e);
|
||||
}
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.put(ZEPPELIN_PYTHON, DEFAULT_ZEPPELIN_PYTHON);
|
||||
pythonInterpreter = spy(new PythonInterpreter(properties));
|
||||
pythonInterpreter = spy(new PythonInterpreter(getPythonTestProperties()));
|
||||
|
||||
when(pythonInterpreter.getPythonProcess()).thenReturn(mockPythonProcess);
|
||||
|
||||
|
||||
try {
|
||||
when(mockPythonProcess.sendAndGetResult(eq("\n\nimport py4j\n"))).thenReturn("ImportError");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -111,19 +111,18 @@ public class PythonInterpreterTest {
|
|||
py4j JavaGateway is not running
|
||||
*/
|
||||
pythonInterpreter.open();
|
||||
assertNull(pythonInterpreter.getPy4JPort());
|
||||
assertNull(pythonInterpreter.getPy4jPort());
|
||||
|
||||
assertTrue(cmdHistory.contains("def help()"));
|
||||
assertTrue(cmdHistory.contains("class PyZeppelinContext():"));
|
||||
assertTrue(cmdHistory.contains("class PyZeppelinContext(object):"));
|
||||
assertTrue(cmdHistory.contains("z = PyZeppelinContext"));
|
||||
assertTrue(cmdHistory.contains("def zeppelin_show"));
|
||||
assertTrue(cmdHistory.contains("z.show"));
|
||||
assertFalse(cmdHistory.contains("GatewayClient"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPy4JInstalled() {
|
||||
|
||||
public void testPy4jInstalled() {
|
||||
|
||||
/*
|
||||
If Py4J installed, bootstrap_input.py
|
||||
|
|
@ -137,18 +136,17 @@ public class PythonInterpreterTest {
|
|||
e.printStackTrace();
|
||||
}
|
||||
pythonInterpreter.open();
|
||||
Integer py4jPort = pythonInterpreter.getPy4JPort();
|
||||
Integer py4jPort = pythonInterpreter.getPy4jPort();
|
||||
assertNotNull(py4jPort);
|
||||
|
||||
assertTrue(cmdHistory.contains("def help()"));
|
||||
assertTrue(cmdHistory.contains("class PyZeppelinContext():"));
|
||||
assertTrue(cmdHistory.contains("class PyZeppelinContext(object):"));
|
||||
assertTrue(cmdHistory.contains("z = PyZeppelinContext"));
|
||||
assertTrue(cmdHistory.contains("def zeppelin_show"));
|
||||
assertTrue(cmdHistory.contains("z.show"));
|
||||
assertTrue(cmdHistory.contains("GatewayClient(port=" + py4jPort + ")"));
|
||||
assertTrue(cmdHistory.contains("org.apache.zeppelin.display.Input"));
|
||||
|
||||
|
||||
assertTrue(checkSocketAdress(py4jPort));
|
||||
assertTrue(checkSocketAddress(py4jPort));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -162,12 +160,12 @@ public class PythonInterpreterTest {
|
|||
e.printStackTrace();
|
||||
}
|
||||
pythonInterpreter.open();
|
||||
Integer py4jPort = pythonInterpreter.getPy4JPort();
|
||||
Integer py4jPort = pythonInterpreter.getPy4jPort();
|
||||
|
||||
assertNotNull(py4jPort);
|
||||
pythonInterpreter.close();
|
||||
|
||||
assertFalse(checkSocketAdress(py4jPort));
|
||||
assertFalse(checkSocketAddress(py4jPort));
|
||||
try {
|
||||
verify(mockPythonProcess, times(1)).close();
|
||||
} catch (IOException e) {
|
||||
|
|
@ -189,7 +187,7 @@ public class PythonInterpreterTest {
|
|||
|
||||
|
||||
|
||||
private boolean checkSocketAdress(Integer py4jPort) {
|
||||
private boolean checkSocketAddress(Integer py4jPort) {
|
||||
Socket s = new Socket();
|
||||
SocketAddress sa = new InetSocketAddress("localhost", py4jPort);
|
||||
Boolean working = null;
|
||||
|
|
|
|||
|
|
@ -205,15 +205,6 @@
|
|||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -142,15 +142,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -66,15 +66,6 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -970,15 +970,6 @@
|
|||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>1.3.1</version>
|
||||
|
|
|
|||
|
|
@ -132,15 +132,6 @@
|
|||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.scala-tools</groupId>
|
||||
<artifactId>maven-scala-plugin</artifactId>
|
||||
|
|
|
|||
|
|
@ -80,18 +80,7 @@
|
|||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ public abstract class Job {
|
|||
return dateFinished;
|
||||
}
|
||||
|
||||
protected void setResult(Object result) {
|
||||
public void setResult(Object result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -327,15 +327,6 @@
|
|||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>2.7</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.scala-tools</groupId>
|
||||
<artifactId>maven-scala-plugin</artifactId>
|
||||
|
|
|
|||
22
zeppelin-web/src/app/interpreter/interpreter.filter.js
Normal file
22
zeppelin-web/src/app/interpreter/interpreter.filter.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* jshint loopfunc: true */
|
||||
/*
|
||||
* 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';
|
||||
|
||||
angular.module('zeppelinWebApp').filter('sortByKey', function () {
|
||||
return function (properties) {
|
||||
var sortedKeys = properties ? Object.keys(properties) : [];
|
||||
return sortedKeys.sort();
|
||||
};
|
||||
});
|
||||
|
|
@ -19,16 +19,16 @@ limitations under the License.
|
|||
Interpreters
|
||||
</h3>
|
||||
<div class="pull-right" style="margin-top:10px;">
|
||||
<span style="cursor:pointer;margin-right:8px;"
|
||||
<span style="cursor:pointer;margin-right:4px;"
|
||||
ng-click="showRepositoryInfo = !showRepositoryInfo"
|
||||
tooltip-placement="bottom" tooltip="Repository information">
|
||||
<i class="fa fa-cog" ng-style="{color: showRepositoryInfo ? '#3071A9' : 'black' }"></i>
|
||||
</span>
|
||||
<span class="btn btn-default fa fa-plus"
|
||||
ng-click="showAddNewSetting = !showAddNewSetting"
|
||||
style="margin-right:6px;">
|
||||
<button class="btn btn-default btn-sm"
|
||||
ng-click="showAddNewSetting = !showAddNewSetting">
|
||||
<i class="fa fa-plus"></i>
|
||||
Create
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -152,7 +152,7 @@ limitations under the License.
|
|||
</span>
|
||||
<span>Interpreter for note</span>
|
||||
</div>
|
||||
|
||||
|
||||
<br />
|
||||
<div class="col-md-12">
|
||||
<div class="checkbox">
|
||||
|
|
@ -189,11 +189,11 @@ limitations under the License.
|
|||
<th ng-if="valueform.$visible">action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="(key, value) in setting.properties" >
|
||||
<tr ng-repeat="key in setting.properties | sortByKey" >
|
||||
<td>{{key}}</td>
|
||||
<td>
|
||||
<span editable-textarea="setting.properties[key]" e-form="valueform" e-msd-elastic>
|
||||
{{value | breakFilter}}
|
||||
{{setting.properties[key] | breakFilter}}
|
||||
</span>
|
||||
</td>
|
||||
<td ng-if="valueform.$visible">
|
||||
|
|
|
|||
|
|
@ -61,32 +61,34 @@ limitations under the License.
|
|||
tooltip-placement="bottom" tooltip="Export the notebook">
|
||||
<i class="fa fa-download"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu" style="width:250px">
|
||||
<li>
|
||||
<div class="cron-preset-container">
|
||||
<div>
|
||||
<input type="text"
|
||||
dropdown-input
|
||||
placeholder="commit message"
|
||||
id="note.checkpoint.message"
|
||||
ng-model="note.checkpoint.message"/>
|
||||
<button type="button"
|
||||
class="btn btn-default btn-xs"
|
||||
ng-hide="viewOnly"
|
||||
ng-click="checkpointNotebook(note.checkpoint.message)"
|
||||
tooltip-placement="bottom" tooltip="Commit the notebook">Commit
|
||||
</button>
|
||||
</div>
|
||||
<button type="button"
|
||||
class="btn btn-default btn-xs dropdown-toggle"
|
||||
ng-hide="viewOnly"
|
||||
data-toggle="dropdown"
|
||||
tooltip-placement="bottom" tooltip="Version control">
|
||||
<i class="fa fa-file-code-o"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu" style="width:250px">
|
||||
<li>
|
||||
<div class="commit-container">
|
||||
<div>
|
||||
<input type="text"
|
||||
dropdown-input
|
||||
placeholder="commit message"
|
||||
id="note.checkpoint.message"
|
||||
style="width: 145px;"
|
||||
ng-model="note.checkpoint.message"/>
|
||||
<button type="button"
|
||||
class="btn btn-default btn-xs"
|
||||
ng-hide="viewOnly"
|
||||
ng-click="checkpointNotebook(note.checkpoint.message)"
|
||||
style="margin-left: 4px;"
|
||||
tooltip-placement="bottom" tooltip="Commit the notebook">Commit
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<button type="button"
|
||||
class="btn btn-default btn-xs dropdown-toggle"
|
||||
ng-hide="viewOnly"
|
||||
data-toggle="dropdown"
|
||||
tooltip-placement="bottom" tooltip="Version control">
|
||||
<i class="fa fa-file-code-o"></i>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
|
||||
<!-- put the delete action by itself for your protection -->
|
||||
|
|
@ -157,7 +159,7 @@ limitations under the License.
|
|||
data-toggle="modal"
|
||||
data-target="#shortcutModal"
|
||||
tooltip-placement="bottom" tooltip="List of shortcut">
|
||||
<i class="icon-question"></i>
|
||||
<i class="fa fa-keyboard-o"></i>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-default btn-xs"
|
||||
|
|
|
|||
|
|
@ -210,6 +210,19 @@
|
|||
border: 0;
|
||||
}
|
||||
|
||||
.commit-container {
|
||||
padding: 10px 20px 6px 20px;
|
||||
font-weight: normal;
|
||||
word-wrap: break-word;
|
||||
white-space: initial;
|
||||
}
|
||||
|
||||
/* overwrite bootstrap css for version control button */
|
||||
.btn-group > .btn + .dropdown-toggle {
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.cron-preset-container {
|
||||
padding: 10px 20px 0 20px;
|
||||
font-weight: normal;
|
||||
|
|
|
|||
|
|
@ -422,6 +422,23 @@ table.dataTable.table-condensed .sorting_desc:after {
|
|||
border-bottom: 2px solid #CCC;
|
||||
}
|
||||
|
||||
.handsontable .columnSorting.ascending::after {
|
||||
content: '\f160';
|
||||
margin-left: 3px;
|
||||
font-size: 12px;
|
||||
font-family: FontAwesome;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.handsontable .columnSorting.descending::after {
|
||||
content: '\f161';
|
||||
margin-left: 3px;
|
||||
font-size: 12px;
|
||||
margin-left: 3px;
|
||||
font-family: FontAwesome;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
/*
|
||||
Pivot CSS
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ limitations under the License.
|
|||
<script src="app/home/home.controller.js"></script>
|
||||
<script src="app/notebook/notebook.controller.js"></script>
|
||||
<script src="app/interpreter/interpreter.controller.js"></script>
|
||||
<script src="app/interpreter/interpreter.filter.js"></script>
|
||||
<script src="app/credential/credential.controller.js"></script>
|
||||
<script src="app/configuration/configuration.controller.js"></script>
|
||||
<script src="app/notebook/paragraph/paragraph.controller.js"></script>
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ public class Note implements Serializable, ParagraphJobListener {
|
|||
|
||||
private String getDefaultInterpreterName() {
|
||||
Optional<InterpreterSetting> settingOptional = replLoader.getDefaultInterpreterSetting();
|
||||
return settingOptional.isPresent() ? settingOptional.get().getName() : StringUtils.EMPTY;
|
||||
return settingOptional.isPresent() ? settingOptional.get().getGroup() : StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
void putDefaultReplName() {
|
||||
|
|
@ -229,17 +229,23 @@ public class Note implements Serializable, ParagraphJobListener {
|
|||
Map<String, Object> config = new HashMap<>(srcParagraph.getConfig());
|
||||
Map<String, Object> param = new HashMap<>(srcParagraph.settings.getParams());
|
||||
Map<String, Input> form = new HashMap<>(srcParagraph.settings.getForms());
|
||||
Gson gson = new Gson();
|
||||
InterpreterResult result = gson.fromJson(
|
||||
gson.toJson(srcParagraph.getReturn()),
|
||||
InterpreterResult.class);
|
||||
|
||||
newParagraph.setConfig(config);
|
||||
newParagraph.settings.setParams(param);
|
||||
newParagraph.settings.setForms(form);
|
||||
newParagraph.setText(srcParagraph.getText());
|
||||
newParagraph.setTitle(srcParagraph.getTitle());
|
||||
newParagraph.setReturn(result, null);
|
||||
|
||||
try {
|
||||
Gson gson = new Gson();
|
||||
String resultJson = gson.toJson(srcParagraph.getReturn());
|
||||
InterpreterResult result = gson.fromJson(resultJson, InterpreterResult.class);
|
||||
newParagraph.setReturn(result, null);
|
||||
} catch (Exception e) {
|
||||
// 'result' part of Note consists of exception, instead of actual interpreter results
|
||||
logger.warn("Paragraph " + srcParagraph.getId() + " has a result with exception. "
|
||||
+ e.getMessage());
|
||||
}
|
||||
|
||||
synchronized (paragraphs) {
|
||||
paragraphs.add(newParagraph);
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ public class NoteTest {
|
|||
@Test
|
||||
public void putDefaultReplNameIfInterpreterSettingPresent() {
|
||||
InterpreterSetting interpreterSetting = Mockito.mock(InterpreterSetting.class);
|
||||
when(interpreterSetting.getName()).thenReturn("spark");
|
||||
when(interpreterSetting.getGroup()).thenReturn("spark");
|
||||
when(replLoader.getDefaultInterpreterSetting())
|
||||
.thenReturn(Optional.of(interpreterSetting));
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ public class NoteTest {
|
|||
@Test
|
||||
public void addParagraphWithLastReplName() {
|
||||
InterpreterSetting interpreterSetting = Mockito.mock(InterpreterSetting.class);
|
||||
when(interpreterSetting.getName()).thenReturn("spark");
|
||||
when(interpreterSetting.getGroup()).thenReturn("spark");
|
||||
when(replLoader.getDefaultInterpreterSetting())
|
||||
.thenReturn(Optional.of(interpreterSetting));
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ public class NoteTest {
|
|||
@Test
|
||||
public void insertParagraphWithLastReplName() {
|
||||
InterpreterSetting interpreterSetting = Mockito.mock(InterpreterSetting.class);
|
||||
when(interpreterSetting.getName()).thenReturn("spark");
|
||||
when(interpreterSetting.getGroup()).thenReturn("spark");
|
||||
when(replLoader.getDefaultInterpreterSetting())
|
||||
.thenReturn(Optional.of(interpreterSetting));
|
||||
|
||||
|
|
@ -168,4 +168,4 @@ public class NoteTest {
|
|||
|
||||
assertEquals("spark", note.getLastReplName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ import org.apache.zeppelin.resource.LocalResourcePool;
|
|||
import org.apache.zeppelin.resource.ResourcePoolUtils;
|
||||
import org.apache.zeppelin.scheduler.Job;
|
||||
import org.apache.zeppelin.scheduler.Job.Status;
|
||||
import org.apache.zeppelin.scheduler.JobListener;
|
||||
import org.apache.zeppelin.scheduler.SchedulerFactory;
|
||||
import org.apache.zeppelin.search.SearchService;
|
||||
import org.apache.zeppelin.user.Credentials;
|
||||
|
|
@ -324,6 +323,33 @@ public class NotebookTest implements JobListenerFactory{
|
|||
assertNotNull(p2.getDateFinished());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExportAndImportNote() throws IOException, CloneNotSupportedException,
|
||||
InterruptedException {
|
||||
Note note = notebook.createNote(null);
|
||||
note.getNoteReplLoader().setInterpreters(factory.getDefaultInterpreterSettingList());
|
||||
|
||||
final Paragraph p = note.addParagraph();
|
||||
String simpleText = "hello world";
|
||||
p.setText(simpleText);
|
||||
|
||||
note.runAll();
|
||||
while (p.isTerminated() == false || p.getResult() == null) {
|
||||
Thread.yield();
|
||||
}
|
||||
|
||||
String exportedNoteJson = notebook.exportNote(note.getId());
|
||||
|
||||
Note importedNote = notebook.importNote(exportedNoteJson, "Title", null);
|
||||
|
||||
Paragraph p2 = importedNote.getParagraphs().get(0);
|
||||
|
||||
// Test
|
||||
assertEquals(p.getId(), p2.getId());
|
||||
assertEquals(p.text, p2.text);
|
||||
assertEquals(p.getResult().message(), p2.getResult().message());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloneNote() throws IOException, CloneNotSupportedException,
|
||||
InterruptedException {
|
||||
|
|
@ -346,6 +372,30 @@ public class NotebookTest implements JobListenerFactory{
|
|||
assertEquals(cp.getResult().message(), p.getResult().message());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloneNoteWithExceptionResult() throws IOException, CloneNotSupportedException,
|
||||
InterruptedException {
|
||||
Note note = notebook.createNote(null);
|
||||
note.getNoteReplLoader().setInterpreters(factory.getDefaultInterpreterSettingList());
|
||||
|
||||
final Paragraph p = note.addParagraph();
|
||||
p.setText("hello world");
|
||||
note.runAll();
|
||||
while (p.isTerminated() == false || p.getResult() == null) {
|
||||
Thread.yield();
|
||||
}
|
||||
// Force paragraph to have String type object
|
||||
p.setResult("Exception");
|
||||
|
||||
Note cloneNote = notebook.cloneNote(note.getId(), "clone note with Exception result", null);
|
||||
Paragraph cp = cloneNote.paragraphs.get(0);
|
||||
|
||||
// Keep same ParagraphID
|
||||
assertEquals(cp.getId(), p.getId());
|
||||
assertEquals(cp.text, p.text);
|
||||
assertNull(cp.getResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResourceRemovealOnParagraphNoteRemove() throws IOException {
|
||||
Note note = notebook.createNote(null);
|
||||
|
|
|
|||
Loading…
Reference in a new issue